/[soft]/mga-gnome/trunk/mga-gnome
ViewVC logotype

Contents of /mga-gnome/trunk/mga-gnome

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3034 - (show annotations) (download)
Wed Feb 22 20:47:36 2012 UTC (12 years, 1 month ago) by ovitters
File size: 14670 byte(s)
don't print a stack trace when mgarepo or bm fails
1 #!/usr/bin/python
2
3 import os
4 import os.path
5 import sys
6 import re
7 import subprocess
8 import urllib2
9 import urlparse
10 import argparse
11 import errno
12 import tempfile
13 import shutil
14 from sgmllib import SGMLParser
15
16 MEDIA="Core Release Source"
17 URL="http://download.gnome.org/sources/"
18 PKGROOT='~/pkgs'
19
20 re_version = re.compile(r'([-.]|\d+|[^-.\d]+)')
21
22 def version_cmp(a, b):
23 """Compares two versions
24
25 Returns
26 -1 if a < b
27 0 if a == b
28 1 if a > b
29
30 Logic from Bugzilla::Install::Util::vers_cmp"""
31 A = re_version.findall(a.lstrip('0'))
32 B = re_version.findall(b.lstrip('0'))
33
34 while A and B:
35 a = A.pop(0)
36 b = B.pop(0)
37
38 if a == b:
39 continue
40 elif a == '-':
41 return -1
42 elif b == '-':
43 return 1
44 elif a == '.':
45 return -1
46 elif b == '.':
47 return 1
48 elif a.isdigit() and b.isdigit():
49 c = cmp(a, b) if (a.startswith('0') or b.startswith('0')) else cmp(int(a, 10), int(b, 10))
50 if c:
51 return c
52 else:
53 c = cmp(a.upper(), b.upper())
54 if c:
55 return c
56
57 return cmp(len(A), len(B))
58
59 def get_latest_version(versions, max_version=None):
60 """Gets the latest version number
61
62 if max_version is specified, gets the latest version number before
63 max_version"""
64 latest = None
65 for version in versions:
66 if ( latest is None or version_cmp(version, latest) > 0 ) \
67 and ( max_version is None or version_cmp(version, max_version) < 0 ):
68 latest = version
69 return latest
70
71 def line_input (file):
72 for line in file:
73 if line[-1] == '\n':
74 yield line[:-1]
75 else:
76 yield line
77
78 def call_editor(filename):
79 """Return a sequence of possible editor binaries for the current platform"""
80
81 editors = []
82
83 for varname in 'VISUAL', 'EDITOR':
84 if varname in os.environ:
85 editors.append(os.environ[varname])
86
87 editors.extend(('/usr/bin/editor', 'vi', 'pico', 'nano', 'joe'))
88
89 for editor in editors:
90 try:
91 ret = subprocess.call([editor, filename])
92 except OSError, e:
93 if e.errno == 2:
94 continue
95 raise
96
97 if ret == 127:
98 continue
99
100 return True
101
102 class urllister(SGMLParser):
103 def reset(self):
104 SGMLParser.reset(self)
105 self.urls = []
106
107 def start_a(self, attrs):
108 href = [v for k, v in attrs if k=='href']
109 if href:
110 self.urls.extend(href)
111
112 class SpecFile(object):
113 re_update_version = re.compile(r'^(?P<pre>Version:\s*)(?P<version>.+)(?P<post>\s*)$', re.MULTILINE + re.IGNORECASE)
114 re_update_release = re.compile(r'^(?P<pre>Release:\s*)(?P<release>%mkrel \d+)(?P<post>\s*)$', re.MULTILINE + re.IGNORECASE)
115
116 def __init__(self, path):
117 self.path = path
118 self.cwd = os.path.dirname(path)
119
120 @property
121 def version(self):
122 return subprocess.check_output(["rpm", "--specfile", self.path, "--queryformat", "%{VERSION}\n"]).splitlines()[0]
123 def update(self, version):
124 """Update specfile (increase version)"""
125 cur_version = self.version
126
127 if version_cmp(version, cur_version) != 1:
128 print >>sys.stderr, "ERROR: Version %s is older than current version %s!" % (version, cur_version)
129 return False
130
131 with open(self.path, "rw") as f:
132 data = f.read()
133
134 if data.count("%mkrel") != 1:
135 print "WARNING: Multiple %mkrel found; don't know what to do!"
136 return False
137
138 data, nr = self.re_update_version.subn(r'\g<pre>%s\g<post>' % version, data, 1)
139 if nr != 1:
140 print "WARNING: Could not increase version!"
141 return False
142
143 data, nr = self.re_update_release.subn(r'\g<pre>%mkrel 1\g<post>', data, 1)
144 if nr != 1:
145 print "WARNING: Could not reset release!"
146 return False
147
148 # Overwrite file with new version number
149 write_file(self.path, data)
150
151
152 # Check RPM also agrees that version number has increased
153 if self.version != version:
154 print "ERROR: Increased version to %s, but RPM doesn't agree!?!" % version
155 return False
156
157 try:
158 # Download new tarball
159 subprocess.check_call(['mgarepo', 'sync', '-d'], cwd=self.cwd)
160 # Check patches still apply
161 subprocess.check_call(['bm', '-p', '--nodeps'], cwd=self.cwd)
162 except subprocess.CalledProcessError:
163 return False
164
165 return True
166
167 class Patch(object):
168 """Do things with patches"""
169
170 re_dep3 = re.compile(r'^(?:#\s*)?(?P<header>[-A-Za-z0-9]+?):\s*(?P<data>.*)$')
171 re_dep3_cont = re.compile(r'^#?\s+(?P<data>.*)$')
172
173 def __init__(self, path, show_path=False):
174 """Path: path to patch (might not exist)"""
175 self.path = path
176 self.show_path = show_path
177
178 def __str__(self):
179 return self.path if self.show_path else os.path.basename(self.path)
180
181 def add_dep3(self):
182 """Add DEP-3 headers to a patch file"""
183 if self.dep3['valid']:
184 return False
185
186 new_headers = (
187 ('Author', self.svn_author),
188 ('Subject', ''),
189 ('Applied-Upstream', ''),
190 ('Forwarded', ''),
191 ('Bug', ''),
192 )
193
194 with tempfile.NamedTemporaryFile(dir=os.path.dirname(self.path), delete=False) as fdst:
195 with open(self.path, "r") as fsrc:
196 # Start with any existing DEP3 headers
197 for i in range(self.dep3['last_nr']):
198 fdst.write(fsrc.read())
199
200 # After that add the DEP3 headers
201 add_line = False
202 for header, data in new_headers:
203 if header in self.dep3['headers']:
204 continue
205
206 # XXX - wrap this at 80 chars
207 add_line = True
208 print >>fdst, "%s: %s" % (header, "" if data is None else data)
209
210 if add_line: print >>fdst, ""
211 # Now copy any other data and the patch
212 shutil.copyfileobj(fsrc, fdst)
213
214 fdst.flush()
215 os.rename(fdst.name, self.path)
216
217 call_editor(self.path)
218
219 #Author: fwang
220 #Subject: Build fix: Fix glib header inclusion
221 #Applied-Upstream: commit:30602
222 #Forwarded: yes
223 #Bug: http://bugzilla.abisource.com/show_bug.cgi?id=13247
224
225 def _read_dep3(self):
226 """Read DEP-3 headers from an existing patch file
227
228 This will also parse git headers"""
229 dep3 = {}
230 headers = {}
231
232 last_header = None
233 last_nr = 0
234 nr = 0
235 try:
236 with open(self.path, "r") as f:
237 for line in line_input(f):
238 nr += 1
239 # stop trying to parse when real patch begins
240 if line == '---':
241 break
242
243 r = self.re_dep3.match(line)
244 if r:
245 info = r.groupdict()
246
247 # Avoid matching URLS
248 if info['data'].startswith('//') and info['header'].lower () == info['header']:
249 continue
250
251 headers[info['header']] = info['data']
252 last_header = info['header']
253 last_nr = nr
254 continue
255
256 r = self.re_dep3_cont.match(line)
257 if r:
258 info = r.groupdict()
259 if last_header:
260 headers[last_header] = " ".join((headers[last_header], info['data']))
261 last_nr = nr
262 continue
263
264 last_header = None
265 except IOError:
266 pass
267
268 dep3['valid'] = \
269 (('Description' in headers and headers['Description'].strip() != '')
270 or ('Subject' in headers and headers['Subject'].strip() != '')) \
271 and (('Origin' in headers and headers['Origin'].strip() != '') \
272 or ('Author' in headers and headers['Author'].strip() != '') \
273 or ('From' in headers and headers['From'].strip() != ''))
274 dep3['last_nr'] = last_nr
275 dep3['headers'] = headers
276
277 self._dep3 = dep3
278
279 @property
280 def dep3(self):
281 if not hasattr(self, '_dep3'):
282 self._read_dep3()
283
284 return self._dep3
285
286 @property
287 def svn_author(self):
288 if not hasattr(self, '_svn_author'):
289 p = subprocess.Popen(['svn', 'log', '-q', "--", self.path], stdout=subprocess.PIPE, close_fds=True)
290 contents = p.stdout.read().strip("\n").splitlines()
291 ecode = p.wait()
292 if ecode == 0:
293 for line in contents:
294 if ' | ' not in line:
295 continue
296
297 fields = line.split(' | ')
298 if len(fields) >= 3:
299 self._svn_author = fields[1]
300
301 if not hasattr(self, '_svn_author'):
302 return None
303
304 return self._svn_author
305
306 def get_upstream_names():
307 urlopen = urllib2.build_opener()
308
309 good_dir = re.compile('^[-A-Za-z0-9_+.]+/$')
310
311 # Get the files
312 usock = urlopen.open(URL)
313 parser = urllister()
314 parser.feed(usock.read())
315 usock.close()
316 parser.close()
317 files = parser.urls
318
319 tarballs = set([filename.replace('/', '') for filename in files if good_dir.search(filename)])
320
321 return tarballs
322
323 def get_downstream_names():
324 re_file = re.compile(r'^(?P<module>.*?)[_-](?:(?P<oldversion>([0-9]+[\.])*[0-9]+)-)?(?P<version>([0-9]+[\.\-])*[0-9]+)\.(?P<format>(?:tar\.|diff\.)?[a-z][a-z0-9]*)$')
325
326 p = subprocess.Popen(['urpmf', '--files', '.', "--media", MEDIA], stdout=subprocess.PIPE, close_fds=True)
327 contents = p.stdout.read().strip("\n").splitlines()
328 ecode = p.wait()
329 if ecode != 0:
330 sys.exit(1)
331
332 FILES = {}
333 TARBALLS = {}
334
335 for line in contents:
336 try:
337 srpm, filename = line.split(":")
338 except ValueError:
339 print >>sys.stderr, line
340 continue
341
342 if '.tar' in filename:
343 r = re_file.match(filename)
344 if r:
345 fileinfo = r.groupdict()
346 module = fileinfo['module']
347
348 if module not in TARBALLS:
349 TARBALLS[module] = set()
350 TARBALLS[module].add(srpm)
351
352 if srpm not in FILES:
353 FILES[srpm] = set()
354 FILES[srpm].add(filename)
355
356 return TARBALLS, FILES
357
358
359 def write_file(path, data):
360 with tempfile.NamedTemporaryFile(dir=os.path.dirname(path), delete=False) as fdst:
361 fdst.write(data)
362 fdst.flush()
363 os.rename(fdst.name, path)
364
365 def cmd_co(options, parser):
366 upstream = get_upstream_names()
367 downstream, downstream_files = get_downstream_names()
368
369 cwd = os.path.expanduser(PKGROOT)
370
371 matches = upstream & set(downstream.keys())
372 for module in matches:
373 print module, "\t".join(downstream[module])
374 for package in downstream[module]:
375 subprocess.call(['mgarepo', 'co', package], cwd=cwd)
376
377 def cmd_ls(options, parser):
378 upstream = get_upstream_names()
379 downstream, downstream_files = get_downstream_names()
380
381 matches = upstream & set(downstream.keys())
382 for module in matches:
383 print "\n".join(downstream[module])
384
385 def cmd_patches(options, parser):
386 upstream = get_upstream_names()
387 downstream, downstream_files = get_downstream_names()
388
389 path = os.path.expanduser(PKGROOT)
390
391 import pprint
392
393 matches = upstream & set(downstream.keys())
394 for module in sorted(matches):
395 for srpm in downstream[module]:
396 for filename in downstream_files[srpm]:
397 if '.patch' in filename or '.diff' in filename:
398
399 p = Patch(os.path.join(path, srpm, "SOURCES", filename), show_path=options.path)
400 valid = ""
401 forwarded = ""
402 if p.dep3['headers']:
403 forwarded = p.dep3['headers'].get('Forwarded', "no")
404 if p.dep3['valid']:
405 valid="VALID"
406 print "\t".join((module, srpm, str(p), forwarded, valid))
407
408 def cmd_dep3(options, parser):
409 p = Patch(options.patch)
410 p.add_dep3()
411
412 def cmd_package_new_version(options, parser):
413 cwd = os.path.expanduser(PKGROOT)
414 package = options.package
415
416 subprocess.call(['mgarepo', 'co', package], cwd=cwd)
417 s = SpecFile(os.path.join(cwd, package, "SPECS", "%s.spec" % package))
418 print s.version
419 if not s.update(options.version):
420 sys.exit(1)
421
422
423 def main():
424 description = """Mageia GNOME commands."""
425 epilog="""Report bugs to Olav Vitters"""
426 parser = argparse.ArgumentParser(description=description,epilog=epilog)
427
428 # SUBPARSERS
429 subparsers = parser.add_subparsers(title='subcommands')
430 # install
431 subparser = subparsers.add_parser('co', help='checkout all GNOME modules')
432 subparser.set_defaults(
433 func=cmd_co
434 )
435
436 subparser = subparsers.add_parser('packages', help='list all GNOME packages')
437 subparser.set_defaults(
438 func=cmd_ls
439 )
440
441 subparser = subparsers.add_parser('patches', help='list all GNOME patches')
442 subparser.add_argument("-p", "--path", action="store_true", dest="path",
443 help="Show full path to patch")
444 subparser.set_defaults(
445 func=cmd_patches, path=False
446 )
447
448 subparser = subparsers.add_parser('dep3', help='Add dep3 headers')
449 subparser.add_argument("patch", help="Patch")
450 subparser.set_defaults(
451 func=cmd_dep3, path=False
452 )
453
454 subparser = subparsers.add_parser('increase', help='Increase version number')
455 subparser.add_argument("package", help="Package name")
456 subparser.add_argument("version", help="Version number")
457 subparser.set_defaults(
458 func=cmd_package_new_version, path=False
459 )
460
461 if len(sys.argv) == 1:
462 parser.print_help()
463 sys.exit(2)
464
465 options = parser.parse_args()
466
467 try:
468 options.func(options, parser)
469 except KeyboardInterrupt:
470 print('Interrupted')
471 sys.exit(1)
472 except EOFError:
473 print('EOF')
474 sys.exit(1)
475 except IOError, e:
476 if e.errno != errno.EPIPE:
477 raise
478 sys.exit(0)
479
480 if __name__ == "__main__":
481 main()

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.30