summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorColin Walters <walters@verbum.org>2010-02-23 11:50:24 -0500
committerColin Walters <walters@verbum.org>2010-02-23 11:50:24 -0500
commit7eeea948dcab8e38f8c8a3c018a31f42f9f70639 (patch)
treea103a572431839e540af11f57448693f4e6ea7f4
downloadfedpkg-make-pull-7eeea948dcab8e38f8c8a3c018a31f42f9f70639.tar.gz
fedpkg-make-pull-7eeea948dcab8e38f8c8a3c018a31f42f9f70639.tar.xz
fedpkg-make-pull-7eeea948dcab8e38f8c8a3c018a31f42f9f70639.zip
Initial import
-rwxr-xr-xfedpkg-make-pull271
1 files changed, 271 insertions, 0 deletions
diff --git a/fedpkg-make-pull b/fedpkg-make-pull
new file mode 100755
index 0000000..b4f38c9
--- /dev/null
+++ b/fedpkg-make-pull
@@ -0,0 +1,271 @@
+#!/usr/bin/python
+
+# make-pull.py
+# Licensed under the new-BSD license (http://www.opensource.org/licenses/bsd-license.php)
+# Copyright (C) 2010 Red Hat, Inc.
+# Written by Colin Walters <walters@verbum.org>
+#
+# Using a key in the .spec file "#VCS", support various operations using
+# the upstream version control repository:
+#
+# $ make-pull
+# Create a .srpm of the latest upstream code
+# $ make-pull --apply
+# Patch the existing .spec, sources files for the latest upstream
+# $ make-pull --tag 0xdeadbeef
+# Create a .srpm from the tag/branch identifier
+# $ make-pull --apply --patch 0xdeadbeef
+# Update the .spec file to include patch 0xdeadbeef from upstream
+#
+
+import os
+import sys
+import re
+import urlparse
+import getopt
+import subprocess
+
+class Vcs(object):
+ def __init__(self, parsedurl):
+ self._parsed_url = parsedurl
+ # Deliberately drop params/query
+ self._nonfragment_url_string = urlparse.urlunparse((parsedurl.scheme,
+ parsedurl.netloc,
+ parsedurl.path,
+ '', '', ''))
+ self._branch = self._parsed_url.fragment
+
+ def checkout(self, destdir):
+ """Retrieve a new copy of the source tree, saving as destdir"""
+ pass
+
+ def update(self, directory):
+ """Update directory from the latest upstream"""
+ pass
+
+ def get_scheme(self):
+ return self._parsed_url.scheme
+
+ def get_id(self, directory):
+ pass
+
+ def _vcs_exec(self, *args, **kwargs):
+ kwargs['stdout'] = sys.stdout
+ kwargs['stderr'] = subprocess.STDOUT
+ subprocess.check_call(*args, **kwargs)
+
+ @classmethod
+ def new_from_url(cls, url):
+ parsed_url = urlparse.urlparse(url)
+ if parsed_url.scheme == 'git':
+ return GitVcs(parsed_url)
+
+class GitVcs(Vcs):
+ def checkout(self, destdir):
+ self._vcs_exec(['git', 'clone', '--depth=1', self._nonfragment_url_string, destdir])
+
+ def update(self, directory):
+ self._vcs_exec(['git', 'pull', '-r'], cwd=directory)
+
+ def get_id(self, directory):
+ output = subprocess.Popen(['git', 'show', '--format=%H'], stdout=subprocess.PIPE, cwd=directory).communicate()[0]
+ return output.split('\n')[0]
+
+class BuildSystem(object):
+ def __init__(self, directory):
+ self._directory = directory
+
+ @classmethod
+ def new_from_directory(cls, directory):
+ autogen_path = os.path.join(directory, 'autogen.sh')
+ if os.path.exists(autogen_path):
+ f = open(autogen_path)
+ for line in f:
+ if line.find('gnome-autogen.sh') >= 0:
+ f.close()
+ return GnomeAutotools(directory)
+ f.close()
+ if os.path.exists(os.path.join(directory, 'Makefile.am')):
+ return Autotools(directory)
+
+ def get_bootstrap_buildrequires(self):
+ pass
+
+class Autotools(BuildSystem):
+ def get_bootstrap_buildrequires(self):
+ return ['libtool', 'automake', 'autoconf']
+
+class GnomeAutotools(Autotools):
+ def get_bootstrap_buildrequires(self):
+ bootstrap = super(GnomeAutotools, self).get_bootstrap_buildrequires()
+ bootstrap.append('gnome-common')
+ return bootstrap
+
+class Spec(object):
+ def __init__(self, filename):
+ self._filename = filename
+ f = open(filename)
+ self._lines = f.readlines()
+ f.close()
+
+ self._append_buildrequires = []
+ self._new_release = None
+ self._source_dirname = None
+ self._source_archivename = None
+
+ def add_buildrequires(self, new_buildrequires):
+ self._append_buildrequires = new_buildrequires
+
+ def increment_release_snapshot(self, identifier):
+ cur_release = self._get_key('Release')
+ release_has_dist = cur_release.endswith('%{?dist}')
+ if release_has_dist:
+ cur_release = cur_release[:-8]
+ snapshot_release_re = re.compile(r'^([0-9]+)\.')
+ numeric_re = re.compile(r'^([0-9]+)$')
+ match = snapshot_release_re.match(cur_release)
+ if match:
+ relint = int(match.group(1)) + 1
+ else:
+ match = numeric_re.match(cur_release)
+ if not match:
+ raise ValueError("Can't handle Release value: %r" % (cur_release, ))
+ relint = int(cur_release) + 1
+ new_release = '%d.%s' % (relint, identifier)
+ if release_has_dist:
+ new_release += '%{?dist}'
+
+ self._new_release = new_release
+
+ def set_source(self, dirname, archivename):
+ self._source_dirname = dirname
+ self._source_archivename = archivename
+
+ def save(self, new_filename):
+ output = open(new_filename, 'w')
+ for line in self._lines:
+ if line.startswith('Release:'):
+ output.write('Release: %s\n' % self._new_release)
+ elif line.startswith('Source0:'):
+ output.write('Source0: %s\n' % self._source_archivename)
+ elif line.startswith('%setup'): # This is dumb, need to automate this in RPM
+ output.write('%%setup -q -n %s\n' % self._source_dirname)
+ else:
+ output.write(line)
+
+ output.close()
+
+ def get_version(self):
+ return self._get_key('Version')
+
+ def get_vcs(self):
+ for line in self._lines:
+ if line.startswith('#VCS:'):
+ return line[5:].strip()
+ raise ValueError("No such key #VCS in file %r" % (self._filename, ))
+
+ def _get_key(self, key):
+ key = key + ':'
+ for line in self._lines:
+ if line.startswith(key):
+ return line[len(key):].strip()
+ raise ValueError("No such key %r in file %r" % (key, self._filename))
+
+def main():
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], 'f', ['force', '--apply', '--srpm'])
+ except getopt.GetoptError, e:
+ print unicode(e)
+ print ""
+ print "Usage: make-pull.py [-f]"
+ sys.exit(1)
+
+ force = False
+ opt_apply = False
+ opt_srpm = True
+ for o, a in opts:
+ if o in ('-f', '--force'):
+ force = True
+ elif o in ('--apply', ):
+ opt_apply = True
+ opt_srpm = False
+
+ targetspec = None
+ for filename in os.listdir('.'):
+ if filename.endswith('.spec'):
+ targetspec = filename
+
+ if targetspec is None:
+ sys.stderr.write("Couldn't find spec file\n")
+ sys.exit(1)
+ spec = Spec(targetspec)
+ name = targetspec[:-5]
+ version = spec.get_version()
+
+ try:
+ vcsurl = spec.get_vcs()
+ except ValueError, e:
+ sys.stderr.write(unicode(e) + '\n')
+ sys.exit(1)
+
+ vcs = Vcs.new_from_url(vcsurl)
+
+ targetdir = '%s.%s' % (name, vcs.get_scheme())
+
+ if os.path.exists(targetdir):
+ print "Updating from %r existing directory %r" % (vcsurl, targetdir)
+ oldid = vcs.get_id(targetdir)
+ vcs.update(targetdir)
+ newid = vcs.get_id(targetdir)
+ if oldid == newid and not force:
+ print "No changes upstream"
+ sys.exit(0)
+ else:
+ print "Checking out from %r into new directory %r" % (vcsurl, targetdir)
+ vcs.checkout(targetdir)
+ newid = vcs.get_id(targetdir)
+
+ buildsys = BuildSystem.new_from_directory(targetdir)
+ if buildsys is None:
+ print "WARNING: Unrecognized buildsystem in directory %r" % (targetdir, )
+ bootstrap_deps = []
+ else:
+ bootstrap_deps = buildsys.get_bootstrap_buildrequires()
+
+ snapshot_dirname = '%s-%s%s%s' % (name, version, vcs.get_scheme(), newid)
+ snapshot_archivename = snapshot_dirname + '.tar.bz2'
+ subprocess.check_call(['tar', '-cj', '--transform=s,^,' + snapshot_dirname + ',', '-f', '../' + snapshot_archivename, '.'], cwd=targetdir)
+
+ new_specname = '%s-%s%s.spec.tmp' % (name, vcs.get_scheme(), newid)
+
+ spec.add_buildrequires(bootstrap_deps)
+ spec.set_source(snapshot_dirname, snapshot_archivename)
+ spec.increment_release_snapshot(newid)
+ spec.save(new_specname)
+
+ if opt_srpm:
+ tempdir_name = new_specname + '.dir'
+ os.mkdir(tempdir_name)
+ os.rename(snapshot_archivename, os.path.join(tempdir_name, snapshot_archivename))
+ os.rename(new_specname, os.path.join(tempdir_name, targetspec))
+ subprocess.check_call(['rpmbuild', '--nodeps',
+ '--define', '_sourcedir .',
+ '--define', '_specdir .',
+ '--define', '_builddir .',
+ '--define', '_rpmdir .',
+ '--define', '_srcrpmdir .',
+ '-bs', targetspec], cwd=tempdir_name)
+ srpm_name = filter(lambda x: x.endswith('.src.rpm'), os.listdir(tempdir_name))[0]
+ os.rename(os.path.join(tempdir_name, srpm_name), srpm_name)
+ os.unlink(os.path.join(tempdir_name, snapshot_archivename))
+ os.unlink(os.path.join(tempdir_name, targetspec))
+ os.rmdir(tempdir_name)
+ print "Created SRPM: %s" % (srpm_name, )
+ elif opt_apply:
+ os.rename(new_specname, targetspec)
+ subprocess.check_call(['make', 'new-sources', 'FILES=' + snapshot_archivename])
+ print "Updated %s and sources" % (targetspec, )
+ sys.exit(0)
+
+if __name__ == '__main__':
+ main()