bh@287: #! /usr/bin/python bh@247: # Copyright (C) 2007, 2008, 2009 by Intevation GmbH bh@89: # Authors: bh@89: # Bernhard Herzog bh@89: # bh@89: # This program is free software under the GPL (>=v2) bh@89: # Read the file COPYING coming with the software for details. bh@89: bh@89: """Publishes selected packages created by treepkg""" bh@89: bh@89: import sys bh@89: import os bh@89: import shutil bh@256: import shlex bh@89: from optparse import OptionParser bh@89: from ConfigParser import SafeConfigParser bh@89: bh@89: import treepkgcmd bh@256: from treepkg.readconfig import read_config_section, convert_bool bh@89: from treepkg.run import call, capture_output bh@89: from treepkg.cmdexpand import cmdexpand bh@89: from treepkg.util import ensure_directory, listdir_abs bh@89: bh@89: bh@89: def remove_trailing_slashes(s): bh@89: return s.rstrip("/") bh@89: bh@89: def expand_filename(filename): bh@89: """ bh@89: Applies os.path.expanduser and os.path.expandvars to filename bh@89: """ bh@89: return os.path.expandvars(os.path.expanduser(filename)) bh@89: bh@256: config_desc = ["distribution", "section", "num_newest", bh@249: "build_user", "build_host", "build_listpackages", bh@256: "publish_user", "publish_host", bh@256: ("after_upload_hook", shlex.split), bh@256: ("publish_remove_old_packages", convert_bool), bh@89: ("publish_dir", remove_trailing_slashes), bh@89: ("cachedir", bh@89: lambda s: expand_filename(remove_trailing_slashes(s)))] bh@89: bh@89: def read_config(filename): bh@89: parser = SafeConfigParser() bh@89: parser.read([filename]) bh@89: return read_config_section(parser, "publishpackages", config_desc) bh@89: bh@89: def parse_commandline(): bh@89: parser = OptionParser() bh@89: parser.set_defaults(config_file=os.path.join(treepkgcmd.topdir, bh@263: "publishpackages.cfg"), bh@263: quiet=False) bh@89: parser.add_option("--config-file", bh@89: help=("The configuration file." bh@89: " Default is publishpackages.cfg")) bh@89: parser.add_option("--revision", bh@89: help=("The revision whose files are to be published." bh@247: " If not given, the latest revision is used" bh@247: " The value may be given as REV-RULESREV to specify" bh@247: " both the main source revision and the revision of" bh@247: " the packaging rules")) bh@89: parser.add_option("--dist", bh@89: help=("The debian distribution name to use on" bh@89: " the publishing system")) bh@89: parser.add_option("--section", bh@89: help=("The debian distribution section name to use on" bh@89: " the publishing system")) bh@89: parser.add_option("--track", bh@89: help=("The package track whose files are to be" bh@200: " published. If not given, files of all tracks" bh@200: " will be published")) bh@263: parser.add_option("--quiet", action="store_true", bh@263: help=("Do not print progress meters or other" bh@263: " informational output")) bh@89: return parser.parse_args() bh@89: bh@256: def prefix_for_remote_command(user, host): bh@256: """Returns the ssh call needed to run a command on a remote host. bh@256: If host is empty, the function assumes the command is to be run on bh@256: the local host as the same user that exectutes this function, so bh@256: that no ssh or other call is needed. bh@256: """ bh@256: prefix = [] bh@256: if host: bh@256: prefix.extend(["ssh", "%s@%s" % (user, host)]) bh@256: return prefix bh@89: bh@256: bh@263: def copy_to_cache(variables, track, revision, arch, quiet): bh@200: listpackages_vars = variables.copy() bh@200: bh@89: if arch == "source": bh@200: listpackages_vars["pkgtype"] = "--source" bh@89: else: bh@200: listpackages_vars["pkgtype"] = "--binary" bh@200: bh@200: if track: bh@200: listpackages_vars["track"] = ["--track", track] bh@200: else: bh@200: listpackages_vars["track"] = [] bh@200: bh@200: if revision: bh@200: listpackages_vars["revision"] = ["--revision", revision] bh@200: else: bh@200: listpackages_vars["revision"] = [] bh@89: bh@256: runremote = prefix_for_remote_command(variables["build_user"], bh@256: variables["build_host"]) bh@256: files = capture_output(cmdexpand("@runremote $build_listpackages" bh@256: " @track @revision $pkgtype" bh@256: " --newest=$num_newest", bh@256: runremote=runremote, bh@318: **listpackages_vars)).splitlines() bh@200: bh@89: # scp the packages to the cache dir bh@89: cachedir = variables["cachedir"] bh@89: shutil.rmtree(cachedir, ignore_errors=True) bh@89: ensure_directory(cachedir) bh@318: if files: bh@318: if variables["build_host"]: bh@318: userhost = "%(build_user)s@%(build_host)s:" % variables bh@318: files = [userhost + filename for filename in files] bh@318: scp_flags = [] bh@318: if quiet: bh@318: scp_flags.append("-q") bh@318: call(cmdexpand("scp -p @scp_flags @files $cachedir/", files=files, bh@318: scp_flags=scp_flags, **variables)) bh@256: bh@256: bh@263: def copy_to_publishdir(variables, dist, section, arch, quiet): bh@256: destdir = os.path.join(variables["publish_dir"], dist, section, arch) bh@256: remote_destdir = destdir bh@256: if variables["publish_host"]: bh@256: remote_destdir = (("%(publish_user)s@%(publish_host)s:" % variables) bh@256: + remote_destdir) bh@256: runremote = prefix_for_remote_command(variables["publish_user"], bh@256: variables["publish_host"]) bh@256: bh@256: call(cmdexpand("@runremote mkdir --parents $destdir", bh@256: runremote=runremote, destdir=destdir, **variables)) bh@256: rsync_flags = [] bh@256: if variables["publish_remove_old_packages"]: bh@256: rsync_flags.append("--delete") bh@263: if quiet: bh@263: rsync_flags.append("--quiet") bernhard@320: call(cmdexpand("rsync @rsync_flags -r --perms --times --omit-dir-times" bernhard@320: " $cachedir/ $remote_destdir/", bh@256: rsync_flags=rsync_flags, remote_destdir=remote_destdir, bh@89: **variables)) bh@89: bh@256: bh@263: def publish_packages_arch(variables, track, revision, dist, section, arch, bh@263: quiet): bh@263: copy_to_cache(variables, track, revision, arch, quiet) bh@263: copy_to_publishdir(variables, dist, section, arch, quiet) bh@89: bh@89: bh@263: def publish_packages(config_filename, track, revision, dist, section, quiet): bh@89: config = read_config(config_filename) bh@89: bh@249: if dist is None: bh@249: dist = config["distribution"] bh@249: if section is None: bh@249: section = config["section"] bh@249: bh@89: for arch in ["binary-i386", "source"]: bh@263: publish_packages_arch(config, track, revision, dist, section, arch, bh@263: quiet) bh@89: bh@89: # update apt archive bh@256: call(config["after_upload_hook"]) bh@89: bh@89: def main(): bh@89: options, args = parse_commandline() bh@89: publish_packages(options.config_file, options.track, options.revision, bh@263: options.dist, options.section, options.quiet) bh@89: bh@89: main()