From 0882ed2136c95a015735d3dcb44ff066f1016119 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Sat, 11 Aug 2018 16:47:43 +0300 Subject: Add: initial commit --- ick_helpers.py | 231 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 231 insertions(+) create mode 100644 ick_helpers.py diff --git a/ick_helpers.py b/ick_helpers.py new file mode 100644 index 0000000..731d4fd --- /dev/null +++ b/ick_helpers.py @@ -0,0 +1,231 @@ +import glob +import os +import re +import sys +import subprocess + + +verbose = True + +def debug(*args): + if verbose: + print('DEBUG:', *args) + + +class Exec: + + def __init__(self, dirname): + self.dirname = dirname + + def run(self, *args, **kwargs): + if 'cwd' not in kwargs: + kwargs['cwd'] = self.dirname + if 'check' not in kwargs: + kwargs['check'] = True + if 'stdout' not in kwargs: + kwargs['stdout'] = subprocess.PIPE + if 'stderr' not in kwargs: + kwargs['stderr'] = subprocess.STDOUT + + debug('RUN:', args, kwargs) + x = subprocess.run(args, **kwargs) + if kwargs['stdout'] == subprocess.PIPE: + if x.stdout: + sys.stdout.write(x.stdout.decode('UTF-8')) + return x + + def get_stdout(self, *args, **kwargs): + kwargs['check'] = True + kwargs['stdout'] = subprocess.PIPE + x = self.run(*args, **kwargs) + return x.stdout.decode('UTF-8') + + def run_silently(self, *args, **kwargs): + kwargs['stdout'] = kwargs['stderr'] = subprocess.DEVNULL + kwargs['check'] = False + return self.run(*args, **kwargs) + + def is_signed_tag(self, tag): + x = self.run_silently('git', 'tag', '--verify', tag) + return x.returncode == 0 + + def is_named_as_release_tag(self, tag, project): + prefix = tag[:len(project)] + suffix = tag[len(prefix):] + return prefix == project and re.match(r'^-\d+\.\d+(\.\d+)*$', suffix) + + def is_release_tag(self, tag, project): + if not self.is_signed_tag(tag): + debug('tag is not signed:', tag) + return False + if not self.is_named_as_release_tag(tag, project): + debug('tag is not named correctly for a release tag:', tag) + return False + debug('seems to be a release tag:', tag) + return True + + def get_debian_source_package(self): + output = self.get_stdout('dpkg-parsechangelog', '-S', 'Source') + return output.strip() + + def get_version_from_tag(self, tag): + parts = tag.split('-', 1) + debug('tag parts:', parts) + assert len(parts) == 2 + return parts[1] + + def find_all_tags(self): + output = self.get_stdout('git', 'tag', '-l') + return output.splitlines() + + def find_release_tags(self, project): + tags = self.find_all_tags() + return [ + tag + for tag in tags + if self.is_release_tag(tag, project) + ] + + def create_tarball_from_tag(self, tag, filename): + self.run('git', 'archive', '-o', 'temp.tar', tag) + self.run('xz', '-9', 'temp.tar') + self.run('mv', 'temp.tar.xz', filename) + + +class Version: + + def __init__(self, full_version): + self._full_version = full_version + + @property + def full(self): + return self._full_version + + @property + def upstream(self): + parts = self._full_version.split('-', 1) + return parts[0] + + @property + def debian(self): + parts = self._full_version.split('-', 1) + if len(parts) == 1: + return None + return parts[1] + + +class DebianReleaseBuilder: + + def __init__(self, ex, resultsdir): + self.ex = ex + self.results = resultsdir + + def build(self, tag): + debug('Building release from tag', tag) + cwd = os.getcwd() + + self.checkout(tag) + + upstream_tarball = self.create_upstream_tarball(tag) + debug('upstream_tarball:', upstream_tarball) + self.stash(upstream_tarball) + + source = self.get_source_package() + version = self.get_version() + debug('Source package:', source) + debug('Version:', version) + + orig_tarball = self.create_debian_orig_tarball( + upstream_tarball, source, version) + self.create_dsc() + self.build_deb() + + debian_files = glob.glob('{}_{}*'.format(source, version.upstream)) + debug('DEBIAN:', debian_files) + self.stash(*debian_files) + + filenames = glob.glob('{}_{}*'.format(source, version.upstream)) + filenames.append(upstream_tarball) + self.cleanup(filenames) + + debug() + + def checkout(self, tag): + self.ex.run('git', 'checkout', 'master', check=False) + self.ex.run('git', 'branch', '-d', '__ickbuild', check=False) + self.ex.run('git', 'checkout', '-b', '__ickbuild', tag) + + def create_upstream_tarball(self, tag): + basename = '{}.tar.xz'.format(tag) + tarball = os.path.abspath(basename) + self.ex.create_tarball_from_tag(tag, tarball) + return basename + + def create_debian_orig_tarball(self, upstream_tarball, source, version): + tarball = '{}_{}.orig.tar.xz'.format(source, version.upstream) + os.link(upstream_tarball, tarball) + return tarball + + def get_source_package(self): + output = self.ex.get_stdout('dpkg-parsechangelog', '-S', 'Source') + return output.strip() + + def get_version(self): + output = self.ex.get_stdout('dpkg-parsechangelog', '-S', 'Version') + return Version(output.strip()) + + def create_dsc(self): + self.ex.run('dpkg-buildpackage', '-S', '--no-sign') + + def build_deb(self): + self.ex.run('dpkg-buildpackage', '-b', '--no-sign') + + def stash(self, *filenames): + if not os.path.exists(self.results): + os.mkdir(self.results) + for filename in filenames: + dst = os.path.join(self.results, filename) + debug('STASH:', filename, '->', dst) + os.link(filename, dst) + + def cleanup(self, filenames): + for filename in filenames: + debug('DELETE', filename) + os.remove(filename) + + +known_tags = '.known_tags' + +def get_known_tags(): + if os.path.exists(known_tags): + with open(known_tags) as f: + return [line.strip() for line in f.readlines()] + return [] + + +def remember_tag(tag): + with open(known_tags, 'a') as f: + f.write('{}\n'.format(tag)) + + +def find_upstream_dirs(sources): + for source in sources: + dirname = source['location'] + control = os.path.join(dirname, 'debian', 'control') + if os.path.exists(control): + yield dirname + + +def build_debian_releases(sources, resultsdir): + known_tags = get_known_tags() + debug('KNOWN:', known_tags) + dirnames = find_upstream_dirs(sources) + for dirname in dirnames: + ex = Exec(dirname) + project = ex.get_debian_source_package() + tags = ex.find_release_tags(project) + builder = DebianReleaseBuilder(ex, resultsdir) + for tag in tags: + if tag not in known_tags: + builder.build(tag) + remember_tag(tag) -- cgit v1.2.1