#!/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, GitRepositoryError 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) 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) return 0 source = DebianSource(GitVfs(repo, env.tag)) try: 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") except (GbpError, GitRepositoryError) as err: if str(err): gbp.log.err(err) retval = 1 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\:·: