#!/usr/bin/python # vim: set fileencoding=utf-8 : # # (C) 2009,2012,2015,2016 Guido Guenther # # gbp-posttag-push: post tag hook to be called by git-buildpackage to push out # the newly created tag and to forward the remote branch to that position # # it checks for explicit push destinations, if none are found it pushes back to # where the branch got merged from. Before pushing it checks if the tag is # signed. # # use: # [buildpackage] # posttag = gbp-posttag-push # # Options: # -d: dry-run # -u: push upstream branch too, if not on remote already # --verbose: verbose command output from __future__ import print_function import glob import os import subprocess import sys import gbp.log from gbp.command_wrappers import Command, CommandExecFailed from gbp.config import GbpOptionParserDebian from gbp.deb.git import DebianGitRepository from gbp.deb.source import DebianSource from gbp.errors import GbpError from gbp.git.vfs import GitVfs from gbp.scripts.common import ExitCodes class Env(object): pass def get_push_targets(env): """get a list of push targets""" dests = {} cmd = "git config --get-regexp 'remote\..*\.push' '^%s(:.*)?$'" % env.branch for remote in subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True).communicate()[0].split("\n"): if not len(remote): continue repo, refspec = remote.split() repo = ".".join(repo.split('.')[1:-1]) # remote..push try: remote = refspec.split(':')[1] # src:dest except IndexError: remote = refspec dests[repo] = remote return dests def get_pull(env): """where did we pull from?""" cmd = 'git config --get branch."%s".remote' % env.branch remote = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True).communicate()[0].strip() if not remote: remote = 'origin' return {remote: env.branch} def git_push_sim(*args): print("git push %s" % " ".join(args)) def get_upstream_tag(repo, tag, tag_format): # FIXME: This assumes the debian version is the last part after the slash: version = tag.split('/')[-1] upstream = version.rsplit('-')[0] tag = tag_format % dict(version=upstream) if repo.has_tag(tag): return tag return None def build_parser(name): # Until we moved this out of examples os.environ['GBP_DISABLE_SECTION_DEPRECTATION'] = '1' GbpOptionParserDebian.defaults['upload-cmd'] = "" GbpOptionParserDebian.help['upload-cmd'] = "Upload command, default is '%(upload-cmd)s'" try: parser = GbpOptionParserDebian(command=os.path.basename(name), usage='%prog [options]') except GbpError as err: gbp.log.err(err) return None parser.add_option("-d", "--dry-run", dest="dryrun", default=False, action="store_true", help="dry run, don't push.") parser.add_option("-u", "--push-upstream", dest="push_upstream", default=False, action="store_true", help="also push upstream branch changes") parser.add_config_file_option(option_name="upstream-branch", dest="upstream_branch") parser.add_config_file_option(option_name="upstream-tag", dest="upstream_tag") parser.add_config_file_option(option_name="debian-tag", dest="debian_tag") parser.add_config_file_option(option_name="upload-cmd", dest="upload_cmd") parser.add_config_file_option(option_name="color", dest="color", type='tristate') parser.add_config_file_option(option_name="color-scheme", dest="color_scheme") parser.add_option("--verbose", action="store_true", dest="verbose", default=False, help="verbose command execution") return parser def parse_args(argv): parser = build_parser(argv[0]) if not parser: return None, None return parser.parse_args(argv) def find_changes(sourcename, version): glob_ex = "../%s_%s_*.changes" % (sourcename, version) gbp.log.info("Looking for changes at %s" % glob_ex) return glob.glob(glob_ex) def upload_changes(changes, cmd, dryrun): ret = 0 for name in changes: gbp.log.info("Running %s" % " ".join([cmd, name])) try: if not dryrun: Command(cmd, [name], shell=False)() except CommandExecFailed: gbp.log.err("Upload of '%s' failed." % name) ret = 1 return ret def main(argv): retval = 0 env = Env() upstream_sha1 = None (options, args) = parse_args(argv) if not options: return ExitCodes.parse_error gbp.log.setup(options.color, options.verbose, options.color_scheme) repo = DebianGitRepository('.') if options.dryrun: gbp.log.warn("Dry run mode. Not pushing, not uploading.") repo.push = git_push_sim repo.push_tag = git_push_sim for envvar in ["GBP_TAG", "GBP_BRANCH", "GBP_SHA1"]: var = os.getenv(envvar) if var: env.__dict__.setdefault("%s" % envvar.split("_")[1].lower(), var) else: gbp.log.err("%s not set." % envvar, file=sys.stderr) return 1 dests = get_push_targets(env) if not dests: dests = get_pull(env) upstream_tag = get_upstream_tag(repo, env.tag, options.upstream_tag) if upstream_tag: upstream_sha1 = repo.rev_parse("%s^{}" % upstream_tag) if not repo.verify_tag(env.tag): gbp.log.info("Not pushing non-existent or unsigned tag '%s'." % env.tag, file=sys.stderr) return 0 source = DebianSource(GitVfs(repo, env.tag)) for dest in dests: gbp.log.info("Pushing %s to %s" % (env.tag, dest)) repo.push_tag(dest, env.tag) gbp.log.info("Pushing %s to %s %s" % (env.sha1, dest, dests[dest])) repo.push(dest, env.sha1, dests[dest]) if options.push_upstream and upstream_tag: gbp.log.info("Pushing %s to %s" % (upstream_tag, dest)) repo.push_tag(dest, upstream_tag) if not repo.branch_contains("%s/%s" % (dest, options.upstream_branch), upstream_sha1, remote=True): gbp.log.info("Pushing %s to %s %s" % (upstream_sha1, dest, options.upstream_branch)) repo.push(dest, upstream_sha1, options.upstream_branch) if options.upload_cmd: version = repo.tag_to_version(env.tag, options.debian_tag) changes = find_changes(source.sourcepkg, version) if len(changes): retval = upload_changes(changes, options.upload_cmd, options.dryrun) else: gbp.log.info("No changes file found, nothing to upload.") else: gbp.log.info("No upload command defined, not uploading to the archive") return retval if __name__ == '__main__': sys.exit(main(sys.argv)) # vim:et:ts=4:sw=4:et:sts=4:ai:set list listchars=tab\:»·,trail\:·: