diff options
| author | Colin Walters <walters@verbum.org> | 2010-02-23 11:50:24 -0500 |
|---|---|---|
| committer | Colin Walters <walters@verbum.org> | 2010-02-23 11:50:24 -0500 |
| commit | 7eeea948dcab8e38f8c8a3c018a31f42f9f70639 (patch) | |
| tree | a103a572431839e540af11f57448693f4e6ea7f4 | |
| download | fedpkg-make-pull-7eeea948dcab8e38f8c8a3c018a31f42f9f70639.tar.gz fedpkg-make-pull-7eeea948dcab8e38f8c8a3c018a31f42f9f70639.tar.xz fedpkg-make-pull-7eeea948dcab8e38f8c8a3c018a31f42f9f70639.zip | |
Initial import
| -rwxr-xr-x | fedpkg-make-pull | 271 |
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() |
