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

Annotation of /mga-gnome/trunk/mga-gnome

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3039 - (hide annotations) (download)
Thu Feb 23 20:10:41 2012 UTC (8 years, 4 months ago) by ovitters
File size: 15609 byte(s)
don't change packages which have uncommitted changes
1 ovitters 2932 #!/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 ovitters 2936 import errno
12 ovitters 2944 import tempfile
13     import shutil
14 ovitters 2932 from sgmllib import SGMLParser
15    
16     MEDIA="Core Release Source"
17     URL="http://download.gnome.org/sources/"
18     PKGROOT='~/pkgs'
19    
20 ovitters 3012 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 ovitters 2936 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 ovitters 2955 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 ovitters 2932 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 ovitters 3012 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 ovitters 3037
124 ovitters 3012 def update(self, version):
125     """Update specfile (increase version)"""
126     cur_version = self.version
127    
128 ovitters 3037 compare = version_cmp(version, cur_version)
129    
130     if compare == 0:
131     print >>sys.stderr, "ERROR: Already at version %s!" % (cur_version)
132     return False
133    
134     if compare != 1:
135 ovitters 3012 print >>sys.stderr, "ERROR: Version %s is older than current version %s!" % (version, cur_version)
136     return False
137    
138 ovitters 3039 # XXX - os.path.join is hackish
139     if subprocess.check_output(["svn", "diff", os.path.join(self.path, '..')]) != '':
140     print >>sys.stderr, "ERROR: Package has uncommitted changes!"
141     return False
142    
143 ovitters 3012 with open(self.path, "rw") as f:
144     data = f.read()
145    
146     if data.count("%mkrel") != 1:
147 ovitters 3037 print >>sys.stderr, "ERROR: Multiple %mkrel found; don't know what to do!"
148 ovitters 3012 return False
149    
150     data, nr = self.re_update_version.subn(r'\g<pre>%s\g<post>' % version, data, 1)
151     if nr != 1:
152 ovitters 3037 print >>sys.stderr, "ERROR: Could not increase version!"
153 ovitters 3012 return False
154    
155     data, nr = self.re_update_release.subn(r'\g<pre>%mkrel 1\g<post>', data, 1)
156     if nr != 1:
157 ovitters 3037 print >>sys.stderr, "ERROR: Could not reset release!"
158 ovitters 3012 return False
159    
160     # Overwrite file with new version number
161     write_file(self.path, data)
162    
163    
164     # Check RPM also agrees that version number has increased
165     if self.version != version:
166     print "ERROR: Increased version to %s, but RPM doesn't agree!?!" % version
167     return False
168    
169 ovitters 3034 try:
170     # Download new tarball
171     subprocess.check_call(['mgarepo', 'sync', '-d'], cwd=self.cwd)
172     # Check patches still apply
173     subprocess.check_call(['bm', '-p', '--nodeps'], cwd=self.cwd)
174     except subprocess.CalledProcessError:
175     return False
176 ovitters 3012
177     return True
178    
179 ovitters 2936 class Patch(object):
180     """Do things with patches"""
181    
182     re_dep3 = re.compile(r'^(?:#\s*)?(?P<header>[-A-Za-z0-9]+?):\s*(?P<data>.*)$')
183     re_dep3_cont = re.compile(r'^#?\s+(?P<data>.*)$')
184    
185     def __init__(self, path, show_path=False):
186     """Path: path to patch (might not exist)"""
187     self.path = path
188     self.show_path = show_path
189    
190     def __str__(self):
191     return self.path if self.show_path else os.path.basename(self.path)
192    
193     def add_dep3(self):
194 ovitters 2955 """Add DEP-3 headers to a patch file"""
195 ovitters 2944 if self.dep3['valid']:
196     return False
197    
198     new_headers = (
199     ('Author', self.svn_author),
200     ('Subject', ''),
201     ('Applied-Upstream', ''),
202     ('Forwarded', ''),
203     ('Bug', ''),
204     )
205    
206     with tempfile.NamedTemporaryFile(dir=os.path.dirname(self.path), delete=False) as fdst:
207     with open(self.path, "r") as fsrc:
208     # Start with any existing DEP3 headers
209     for i in range(self.dep3['last_nr']):
210     fdst.write(fsrc.read())
211    
212     # After that add the DEP3 headers
213     add_line = False
214     for header, data in new_headers:
215     if header in self.dep3['headers']:
216     continue
217    
218     # XXX - wrap this at 80 chars
219     add_line = True
220 ovitters 2955 print >>fdst, "%s: %s" % (header, "" if data is None else data)
221 ovitters 2944
222     if add_line: print >>fdst, ""
223     # Now copy any other data and the patch
224     shutil.copyfileobj(fsrc, fdst)
225    
226     fdst.flush()
227     os.rename(fdst.name, self.path)
228    
229 ovitters 2955 call_editor(self.path)
230    
231 ovitters 2936 #Author: fwang
232     #Subject: Build fix: Fix glib header inclusion
233     #Applied-Upstream: commit:30602
234     #Forwarded: yes
235     #Bug: http://bugzilla.abisource.com/show_bug.cgi?id=13247
236    
237     def _read_dep3(self):
238 ovitters 2955 """Read DEP-3 headers from an existing patch file
239    
240     This will also parse git headers"""
241 ovitters 2936 dep3 = {}
242 ovitters 2944 headers = {}
243 ovitters 2936
244     last_header = None
245 ovitters 2944 last_nr = 0
246     nr = 0
247 ovitters 2936 try:
248     with open(self.path, "r") as f:
249     for line in line_input(f):
250 ovitters 2944 nr += 1
251     # stop trying to parse when real patch begins
252 ovitters 2936 if line == '---':
253     break
254    
255     r = self.re_dep3.match(line)
256     if r:
257     info = r.groupdict()
258 ovitters 3012
259     # Avoid matching URLS
260     if info['data'].startswith('//') and info['header'].lower () == info['header']:
261     continue
262    
263 ovitters 2944 headers[info['header']] = info['data']
264 ovitters 2936 last_header = info['header']
265 ovitters 2944 last_nr = nr
266 ovitters 2936 continue
267    
268     r = self.re_dep3_cont.match(line)
269     if r:
270     info = r.groupdict()
271     if last_header:
272 ovitters 2944 headers[last_header] = " ".join((headers[last_header], info['data']))
273     last_nr = nr
274 ovitters 2936 continue
275    
276     last_header = None
277     except IOError:
278     pass
279 ovitters 2944
280     dep3['valid'] = \
281     (('Description' in headers and headers['Description'].strip() != '')
282     or ('Subject' in headers and headers['Subject'].strip() != '')) \
283     and (('Origin' in headers and headers['Origin'].strip() != '') \
284     or ('Author' in headers and headers['Author'].strip() != '') \
285     or ('From' in headers and headers['From'].strip() != ''))
286     dep3['last_nr'] = last_nr
287     dep3['headers'] = headers
288    
289 ovitters 2936 self._dep3 = dep3
290    
291     @property
292     def dep3(self):
293     if not hasattr(self, '_dep3'):
294     self._read_dep3()
295    
296     return self._dep3
297    
298 ovitters 2944 @property
299     def svn_author(self):
300     if not hasattr(self, '_svn_author'):
301     p = subprocess.Popen(['svn', 'log', '-q', "--", self.path], stdout=subprocess.PIPE, close_fds=True)
302     contents = p.stdout.read().strip("\n").splitlines()
303     ecode = p.wait()
304     if ecode == 0:
305     for line in contents:
306     if ' | ' not in line:
307     continue
308 ovitters 2936
309 ovitters 2944 fields = line.split(' | ')
310     if len(fields) >= 3:
311     self._svn_author = fields[1]
312    
313 ovitters 2955 if not hasattr(self, '_svn_author'):
314     return None
315    
316 ovitters 2944 return self._svn_author
317    
318 ovitters 2932 def get_upstream_names():
319     urlopen = urllib2.build_opener()
320    
321     good_dir = re.compile('^[-A-Za-z0-9_+.]+/$')
322    
323     # Get the files
324     usock = urlopen.open(URL)
325     parser = urllister()
326     parser.feed(usock.read())
327     usock.close()
328     parser.close()
329     files = parser.urls
330    
331     tarballs = set([filename.replace('/', '') for filename in files if good_dir.search(filename)])
332    
333     return tarballs
334    
335     def get_downstream_names():
336     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]*)$')
337    
338     p = subprocess.Popen(['urpmf', '--files', '.', "--media", MEDIA], stdout=subprocess.PIPE, close_fds=True)
339     contents = p.stdout.read().strip("\n").splitlines()
340     ecode = p.wait()
341     if ecode != 0:
342     sys.exit(1)
343    
344     FILES = {}
345     TARBALLS = {}
346    
347     for line in contents:
348     try:
349     srpm, filename = line.split(":")
350     except ValueError:
351     print >>sys.stderr, line
352     continue
353    
354     if '.tar' in filename:
355     r = re_file.match(filename)
356     if r:
357     fileinfo = r.groupdict()
358     module = fileinfo['module']
359    
360     if module not in TARBALLS:
361     TARBALLS[module] = set()
362     TARBALLS[module].add(srpm)
363    
364     if srpm not in FILES:
365     FILES[srpm] = set()
366     FILES[srpm].add(filename)
367    
368     return TARBALLS, FILES
369    
370 ovitters 3012
371     def write_file(path, data):
372     with tempfile.NamedTemporaryFile(dir=os.path.dirname(path), delete=False) as fdst:
373     fdst.write(data)
374     fdst.flush()
375     os.rename(fdst.name, path)
376    
377 ovitters 2932 def cmd_co(options, parser):
378     upstream = get_upstream_names()
379     downstream, downstream_files = get_downstream_names()
380    
381     cwd = os.path.expanduser(PKGROOT)
382    
383     matches = upstream & set(downstream.keys())
384     for module in matches:
385     print module, "\t".join(downstream[module])
386     for package in downstream[module]:
387     subprocess.call(['mgarepo', 'co', package], cwd=cwd)
388    
389     def cmd_ls(options, parser):
390     upstream = get_upstream_names()
391     downstream, downstream_files = get_downstream_names()
392    
393     matches = upstream & set(downstream.keys())
394     for module in matches:
395     print "\n".join(downstream[module])
396    
397     def cmd_patches(options, parser):
398     upstream = get_upstream_names()
399     downstream, downstream_files = get_downstream_names()
400    
401     path = os.path.expanduser(PKGROOT)
402    
403 ovitters 2936 import pprint
404    
405 ovitters 2932 matches = upstream & set(downstream.keys())
406     for module in sorted(matches):
407     for srpm in downstream[module]:
408     for filename in downstream_files[srpm]:
409     if '.patch' in filename or '.diff' in filename:
410 ovitters 3012
411 ovitters 2936 p = Patch(os.path.join(path, srpm, "SOURCES", filename), show_path=options.path)
412 ovitters 3012 valid = ""
413     forwarded = ""
414 ovitters 2944 if p.dep3['headers']:
415 ovitters 3012 forwarded = p.dep3['headers'].get('Forwarded', "no")
416 ovitters 2944 if p.dep3['valid']:
417 ovitters 3012 valid="VALID"
418     print "\t".join((module, srpm, str(p), forwarded, valid))
419 ovitters 2932
420 ovitters 2944 def cmd_dep3(options, parser):
421     p = Patch(options.patch)
422     p.add_dep3()
423    
424 ovitters 3012 def cmd_package_new_version(options, parser):
425     package = options.package
426    
427 ovitters 3038 cwd = os.path.join(os.path.expanduser(PKGROOT), package)
428    
429 ovitters 3012 subprocess.call(['mgarepo', 'co', package], cwd=cwd)
430 ovitters 3038 s = SpecFile(os.path.join(cwd, "SPECS", "%s.spec" % package))
431 ovitters 3037 print "%s => %s" % (s.version, options.version)
432 ovitters 3012 if not s.update(options.version):
433     sys.exit(1)
434    
435 ovitters 3038 if options.submit:
436     try:
437     # checkin changes
438     subprocess.check_call(['mgarepo', 'ci', '-m', 'new version'], cwd=cwd)
439     # and submit
440     subprocess.check_call(['mgarepo', 'submit'], cwd=cwd)
441     except subprocess.CalledProcessError:
442     sys.exit(1)
443 ovitters 3012
444 ovitters 3038
445 ovitters 2932 def main():
446     description = """Mageia GNOME commands."""
447     epilog="""Report bugs to Olav Vitters"""
448     parser = argparse.ArgumentParser(description=description,epilog=epilog)
449    
450     # SUBPARSERS
451     subparsers = parser.add_subparsers(title='subcommands')
452     # install
453     subparser = subparsers.add_parser('co', help='checkout all GNOME modules')
454     subparser.set_defaults(
455     func=cmd_co
456     )
457    
458     subparser = subparsers.add_parser('packages', help='list all GNOME packages')
459     subparser.set_defaults(
460     func=cmd_ls
461     )
462    
463     subparser = subparsers.add_parser('patches', help='list all GNOME patches')
464     subparser.add_argument("-p", "--path", action="store_true", dest="path",
465 ovitters 2944 help="Show full path to patch")
466 ovitters 2932 subparser.set_defaults(
467     func=cmd_patches, path=False
468     )
469    
470 ovitters 2944 subparser = subparsers.add_parser('dep3', help='Add dep3 headers')
471     subparser.add_argument("patch", help="Patch")
472     subparser.set_defaults(
473     func=cmd_dep3, path=False
474     )
475 ovitters 2932
476 ovitters 3012 subparser = subparsers.add_parser('increase', help='Increase version number')
477     subparser.add_argument("package", help="Package name")
478     subparser.add_argument("version", help="Version number")
479 ovitters 3038 subparser.add_argument("-s", "--submit", action="store_true", dest="submit",
480     help="Commit changes and submit")
481 ovitters 3012 subparser.set_defaults(
482 ovitters 3038 func=cmd_package_new_version, submit=False
483 ovitters 3012 )
484    
485 ovitters 2932 if len(sys.argv) == 1:
486     parser.print_help()
487     sys.exit(2)
488    
489     options = parser.parse_args()
490    
491     try:
492     options.func(options, parser)
493     except KeyboardInterrupt:
494     print('Interrupted')
495     sys.exit(1)
496     except EOFError:
497     print('EOF')
498     sys.exit(1)
499     except IOError, e:
500     if e.errno != errno.EPIPE:
501     raise
502     sys.exit(0)
503    
504     if __name__ == "__main__":
505     main()

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.28