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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.30