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

Diff of /mga-gnome/trunk/mga-gnome

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 2936 by ovitters, Sun Feb 12 12:23:46 2012 UTC revision 3037 by ovitters, Thu Feb 23 19:43:09 2012 UTC
# Line 9  import urllib2 Line 9  import urllib2
9  import urlparse  import urlparse
10  import argparse  import argparse
11  import errno  import errno
12    import tempfile
13    import shutil
14  from sgmllib import SGMLParser  from sgmllib import SGMLParser
15    
16  MEDIA="Core Release Source"  MEDIA="Core Release Source"
17  URL="http://download.gnome.org/sources/"  URL="http://download.gnome.org/sources/"
18  PKGROOT='~/pkgs'  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):  def line_input (file):
72      for line in file:      for line in file:
73          if line[-1] == '\n':          if line[-1] == '\n':
# Line 22  def line_input (file): Line 75  def line_input (file):
75          else:          else:
76              yield line              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):  class urllister(SGMLParser):
103      def reset(self):      def reset(self):
104          SGMLParser.reset(self)          SGMLParser.reset(self)
# Line 32  class urllister(SGMLParser): Line 109  class urllister(SGMLParser):
109          if href:          if href:
110              self.urls.extend(href)              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    
124        def update(self, version):
125            """Update specfile (increase version)"""
126            cur_version = self.version
127    
128            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                print >>sys.stderr, "ERROR: Version %s is older than current version %s!" % (version, cur_version)
136                return False
137    
138            with open(self.path, "rw") as f:
139                data = f.read()
140    
141                if data.count("%mkrel") != 1:
142                    print >>sys.stderr, "ERROR: Multiple %mkrel found; don't know what to do!"
143                    return False
144    
145                data, nr = self.re_update_version.subn(r'\g<pre>%s\g<post>' % version, data, 1)
146                if nr != 1:
147                    print >>sys.stderr, "ERROR: Could not increase version!"
148                    return False
149    
150                data, nr = self.re_update_release.subn(r'\g<pre>%mkrel 1\g<post>', data, 1)
151                if nr != 1:
152                    print >>sys.stderr, "ERROR: Could not reset release!"
153                    return False
154    
155                # Overwrite file with new version number
156                write_file(self.path, data)
157    
158    
159            # Check RPM also agrees that version number has increased
160            if self.version != version:
161                print "ERROR: Increased version to %s, but RPM doesn't agree!?!" % version
162                return False
163    
164            try:
165                # Download new tarball
166                subprocess.check_call(['mgarepo', 'sync', '-d'], cwd=self.cwd)
167                # Check patches still apply
168                subprocess.check_call(['bm', '-p', '--nodeps'], cwd=self.cwd)
169            except subprocess.CalledProcessError:
170                return False
171    
172            return True
173    
174  class Patch(object):  class Patch(object):
175      """Do things with patches"""      """Do things with patches"""
176    
# Line 47  class Patch(object): Line 186  class Patch(object):
186          return self.path if self.show_path else os.path.basename(self.path)          return self.path if self.show_path else os.path.basename(self.path)
187    
188      def add_dep3(self):      def add_dep3(self):
189          pass          """Add DEP-3 headers to a patch file"""
190            if self.dep3['valid']:
191                return False
192    
193            new_headers = (
194                ('Author', self.svn_author),
195                ('Subject', ''),
196                ('Applied-Upstream', ''),
197                ('Forwarded', ''),
198                ('Bug', ''),
199            )
200    
201            with tempfile.NamedTemporaryFile(dir=os.path.dirname(self.path), delete=False) as fdst:
202                with open(self.path, "r") as fsrc:
203                    # Start with any existing DEP3 headers
204                    for i in range(self.dep3['last_nr']):
205                        fdst.write(fsrc.read())
206    
207                    # After that add the DEP3 headers
208                    add_line = False
209                    for header, data in new_headers:
210                        if header in self.dep3['headers']:
211                            continue
212    
213                        # XXX - wrap this at 80 chars
214                        add_line = True
215                        print >>fdst, "%s: %s" % (header, "" if data is None else data)
216    
217                    if add_line: print >>fdst, ""
218                    # Now copy any other data and the patch
219                    shutil.copyfileobj(fsrc, fdst)
220    
221                fdst.flush()
222                os.rename(fdst.name, self.path)
223    
224            call_editor(self.path)
225    
226      #Author: fwang      #Author: fwang
227      #Subject: Build fix: Fix glib header inclusion      #Subject: Build fix: Fix glib header inclusion
228      #Applied-Upstream: commit:30602      #Applied-Upstream: commit:30602
# Line 55  class Patch(object): Line 230  class Patch(object):
230      #Bug: http://bugzilla.abisource.com/show_bug.cgi?id=13247      #Bug: http://bugzilla.abisource.com/show_bug.cgi?id=13247
231    
232      def _read_dep3(self):      def _read_dep3(self):
233          """This will also parse git headers"""          """Read DEP-3 headers from an existing patch file
234    
235            This will also parse git headers"""
236          dep3 = {}          dep3 = {}
237            headers = {}
238    
239          last_header = None          last_header = None
240            last_nr = 0
241            nr = 0
242          try:          try:
243              with open(self.path, "r") as f:              with open(self.path, "r") as f:
244                  for line in line_input(f):                  for line in line_input(f):
245                      # Check for start of real patch                      nr += 1
246                        # stop trying to parse when real patch begins
247                      if line == '---':                      if line == '---':
248                          break                          break
249    
250                      r = self.re_dep3.match(line)                      r = self.re_dep3.match(line)
251                      if r:                      if r:
252                          info = r.groupdict()                          info = r.groupdict()
253                          dep3[info['header']] = info['data']  
254                            # Avoid matching URLS
255                            if info['data'].startswith('//') and info['header'].lower () == info['header']:
256                                continue
257    
258                            headers[info['header']] = info['data']
259                          last_header = info['header']                          last_header = info['header']
260                            last_nr = nr
261                          continue                          continue
262    
263                      r = self.re_dep3_cont.match(line)                      r = self.re_dep3_cont.match(line)
264                      if r:                      if r:
265                          info = r.groupdict()                          info = r.groupdict()
266                          if last_header:                          if last_header:
267                              dep3[last_header] = " ".join((dep3[last_header], info['data']))                              headers[last_header] = " ".join((headers[last_header], info['data']))
268                                last_nr = nr
269                          continue                          continue
270    
271                      last_header = None                      last_header = None
272          except IOError:          except IOError:
273              pass              pass
274    
275            dep3['valid'] = \
276                (('Description' in headers and headers['Description'].strip() != '')
277                    or ('Subject' in headers and headers['Subject'].strip() != '')) \
278                and (('Origin' in headers and headers['Origin'].strip() != '') \
279                    or ('Author' in headers and headers['Author'].strip() != '') \
280                    or ('From' in headers and headers['From'].strip() != ''))
281            dep3['last_nr'] = last_nr
282            dep3['headers'] = headers
283    
284          self._dep3 = dep3          self._dep3 = dep3
285    
286      @property      @property
# Line 92  class Patch(object): Line 290  class Patch(object):
290    
291          return self._dep3          return self._dep3
292    
293        @property
294        def svn_author(self):
295            if not hasattr(self, '_svn_author'):
296                p = subprocess.Popen(['svn', 'log', '-q', "--", self.path], stdout=subprocess.PIPE, close_fds=True)
297                contents = p.stdout.read().strip("\n").splitlines()
298                ecode = p.wait()
299                if ecode == 0:
300                    for line in contents:
301                        if ' | ' not in line:
302                            continue
303    
304                        fields = line.split(' | ')
305                        if len(fields) >= 3:
306                            self._svn_author = fields[1]
307    
308            if not hasattr(self, '_svn_author'):
309                return None
310    
311            return self._svn_author
312    
313  def get_upstream_names():  def get_upstream_names():
314      urlopen = urllib2.build_opener()      urlopen = urllib2.build_opener()
# Line 145  def get_downstream_names(): Line 362  def get_downstream_names():
362    
363      return TARBALLS, FILES      return TARBALLS, FILES
364    
365    
366    def write_file(path, data):
367        with tempfile.NamedTemporaryFile(dir=os.path.dirname(path), delete=False) as fdst:
368            fdst.write(data)
369            fdst.flush()
370            os.rename(fdst.name, path)
371    
372  def cmd_co(options, parser):  def cmd_co(options, parser):
373      upstream = get_upstream_names()      upstream = get_upstream_names()
374      downstream, downstream_files = get_downstream_names()      downstream, downstream_files = get_downstream_names()
# Line 178  def cmd_patches(options, parser): Line 402  def cmd_patches(options, parser):
402          for srpm in downstream[module]:          for srpm in downstream[module]:
403              for filename in downstream_files[srpm]:              for filename in downstream_files[srpm]:
404                  if '.patch' in filename or '.diff' in filename:                  if '.patch' in filename or '.diff' in filename:
405    
406                      p = Patch(os.path.join(path, srpm, "SOURCES", filename), show_path=options.path)                      p = Patch(os.path.join(path, srpm, "SOURCES", filename), show_path=options.path)
407                      print "\t".join((module, srpm, str(p)))                      valid = ""
408                      if p.dep3:                      forwarded = ""
409                          pprint.pprint(p.dep3)                      if p.dep3['headers']:
410                            forwarded = p.dep3['headers'].get('Forwarded', "no")
411                            if p.dep3['valid']:
412                                valid="VALID"
413                        print "\t".join((module, srpm, str(p), forwarded, valid))
414    
415    def cmd_dep3(options, parser):
416        p = Patch(options.patch)
417        p.add_dep3()
418    
419    def cmd_package_new_version(options, parser):
420        cwd = os.path.expanduser(PKGROOT)
421        package = options.package
422    
423        subprocess.call(['mgarepo', 'co', package], cwd=cwd)
424        s = SpecFile(os.path.join(cwd, package, "SPECS", "%s.spec" % package))
425        print "%s => %s" % (s.version, options.version)
426        if not s.update(options.version):
427            sys.exit(1)
428    
429    
430  def main():  def main():
431      description = """Mageia GNOME commands."""      description = """Mageia GNOME commands."""
# Line 203  def main(): Line 447  def main():
447    
448      subparser = subparsers.add_parser('patches', help='list all GNOME patches')      subparser = subparsers.add_parser('patches', help='list all GNOME patches')
449      subparser.add_argument("-p", "--path", action="store_true", dest="path",      subparser.add_argument("-p", "--path", action="store_true", dest="path",
450                                         help="Full path to patch")                                         help="Show full path to patch")
451      subparser.set_defaults(      subparser.set_defaults(
452          func=cmd_patches, path=False          func=cmd_patches, path=False
453      )      )
454    
455        subparser = subparsers.add_parser('dep3', help='Add dep3 headers')
456        subparser.add_argument("patch", help="Patch")
457        subparser.set_defaults(
458            func=cmd_dep3, path=False
459        )
460    
461        subparser = subparsers.add_parser('increase', help='Increase version number')
462        subparser.add_argument("package", help="Package name")
463        subparser.add_argument("version", help="Version number")
464        subparser.set_defaults(
465            func=cmd_package_new_version, path=False
466        )
467    
468      if len(sys.argv) == 1:      if len(sys.argv) == 1:
469          parser.print_help()          parser.print_help()

Legend:
Removed from v.2936  
changed lines
  Added in v.3037

  ViewVC Help
Powered by ViewVC 1.1.30