diff bin/publishdebianpackages.py @ 440:383d23c6bfde

Merged revisions 346-386 via svnmerge from svn+ssh://svn.wald.intevation.org/treepkg/branches/treepkg-status ........ r346 | bricks | 2010-07-07 17:40:48 +0200 (Mi, 07 Jul 2010) | 2 lines added classed for treepkg status xml generation ........ r347 | bricks | 2010-07-08 12:07:39 +0200 (Do, 08 Jul 2010) | 10 lines renamed new status dir to info because of a naming conflict with status.py let the user specify a treepkg name in the config the name is propagated to PackagerGroup [treepkg] name: <treepkgname> becomes: pg = PackagerGroup(...) pg.name ........ r348 | bricks | 2010-07-08 15:25:07 +0200 (Do, 08 Jul 2010) | 3 lines moved test file to test main dir fixed missing : after def statement ........ r349 | bricks | 2010-07-08 17:59:52 +0200 (Do, 08 Jul 2010) | 2 lines added treepkg_dir andd tracks_dir attributes to PackageGroup ........ r350 | bricks | 2010-07-08 18:00:32 +0200 (Do, 08 Jul 2010) | 2 lines changed <millpath> to <trackspath> ........ r351 | bricks | 2010-07-08 18:08:39 +0200 (Do, 08 Jul 2010) | 2 lines check if config file exists to get usefull error output ........ r352 | bricks | 2010-07-08 18:11:13 +0200 (Do, 08 Jul 2010) | 2 lines write first info about tracks ........ r353 | bricks | 2010-07-09 12:20:49 +0200 (Fr, 09 Jul 2010) | 2 lines get all log files ........ r354 | bricks | 2010-07-09 14:42:42 +0200 (Fr, 09 Jul 2010) | 2 lines added md5sum function ........ r355 | bricks | 2010-07-09 15:15:15 +0200 (Fr, 09 Jul 2010) | 4 lines implemented nearly all info only arch and os info are missing ........ r356 | bricks | 2010-07-09 16:19:17 +0200 (Fr, 09 Jul 2010) | 2 lines Bugfix: source was not defined ........ r357 | bricks | 2010-07-09 16:44:52 +0200 (Fr, 09 Jul 2010) | 3 lines fixed some typos added missing add_checksum methond ........ r358 | bricks | 2010-07-09 17:06:15 +0200 (Fr, 09 Jul 2010) | 2 lines fixed status line for revision ........ r359 | bricks | 2010-07-12 14:10:34 +0200 (Mo, 12 Jul 2010) | 2 lines let the user specify num revisions that should be shown in the info ........ r360 | bricks | 2010-07-12 14:21:39 +0200 (Mo, 12 Jul 2010) | 2 lines missed in last commit ........ r361 | bricks | 2010-07-12 17:06:22 +0200 (Mo, 12 Jul 2010) | 2 lines add os config statement ........ r362 | bricks | 2010-07-12 17:47:42 +0200 (Mo, 12 Jul 2010) | 3 lines moved packages and logs to revision tag implemented os and arch info ........ r363 | bricks | 2010-07-13 14:23:28 +0200 (Di, 13 Jul 2010) | 2 lines updated test readconfig for os config variable ........ r364 | bricks | 2010-07-13 14:24:14 +0200 (Di, 13 Jul 2010) | 2 lines moved common publish functions to a seperate module ........ r365 | bricks | 2010-07-13 16:26:11 +0200 (Di, 13 Jul 2010) | 2 lines moved arch info to each package info ........ r366 | bricks | 2010-07-13 18:46:17 +0200 (Di, 13 Jul 2010) | 2 lines inital checkin for new publishpackages processing ........ r367 | bricks | 2010-07-21 17:52:15 +0200 (Mi, 21 Jul 2010) | 2 lines implemented parsing from xml string ........ r368 | bricks | 2010-07-22 12:17:42 +0200 (Do, 22 Jul 2010) | 2 lines copy binary-all packages in all binary-xyz dirs ........ r369 | bricks | 2010-07-22 12:26:40 +0200 (Do, 22 Jul 2010) | 2 lines fixed small bugs ........ r370 | bricks | 2010-07-22 13:02:36 +0200 (Do, 22 Jul 2010) | 2 lines added a new root element which is called TreepkgRoot for Treepkg Info classes ........ r371 | bricks | 2010-07-22 13:09:52 +0200 (Do, 22 Jul 2010) | 3 lines fixed some small issues remember: run pychecker BEFORE the commit ........ r372 | bricks | 2010-07-22 18:01:43 +0200 (Do, 22 Jul 2010) | 2 lines improved publishdebianpackages and fixed a lot of bugs in the xml info parsing part ........ r373 | bricks | 2010-07-23 18:40:38 +0200 (Fr, 23 Jul 2010) | 2 lines implemented CacheDb to store copied Packages from build host ........ r374 | bricks | 2010-07-26 10:28:48 +0200 (Mo, 26 Jul 2010) | 2 lines moved data handling in publishdebianpackages into seperate module ........ r375 | bricks | 2010-07-26 11:42:07 +0200 (Mo, 26 Jul 2010) | 2 lines fixed some typos ........ r376 | bricks | 2010-07-26 12:12:40 +0200 (Mo, 26 Jul 2010) | 2 lines first version of incremental copying debian packages to cachedir ........ r377 | bricks | 2010-07-26 14:58:50 +0200 (Mo, 26 Jul 2010) | 2 lines incremental copying only changed debian packages ........ r378 | bricks | 2010-07-26 15:39:10 +0200 (Mo, 26 Jul 2010) | 3 lines use md5 instead of hashlib module (md5 is deprecated in favour of hashlib in python 2.5) ........ r379 | bricks | 2010-07-26 15:46:19 +0200 (Mo, 26 Jul 2010) | 2 lines make treepkg compatible to python 2.4 ........ r380 | bricks | 2010-07-26 15:50:49 +0200 (Mo, 26 Jul 2010) | 2 lines fixed last commit (db instead of sqlite3) ........ r381 | bricks | 2010-07-27 10:54:15 +0200 (Di, 27 Jul 2010) | 2 lines fixed wrong import statement ........ r382 | bricks | 2010-07-27 10:54:34 +0200 (Di, 27 Jul 2010) | 2 lines removed unnecessary debug output ........ r383 | bricks | 2010-07-27 18:28:22 +0200 (Di, 27 Jul 2010) | 2 lines check if upload hook is empty ........ r384 | bricks | 2010-07-28 09:35:21 +0200 (Mi, 28 Jul 2010) | 2 lines run rsync only an arch dirs that are present in the current treepkg ........ r385 | bricks | 2010-07-28 09:35:54 +0200 (Mi, 28 Jul 2010) | 2 lines add helper tool to list content of a cache db ........ r386 | bricks | 2010-07-28 10:33:48 +0200 (Mi, 28 Jul 2010) | 3 lines fixed a typo regex fails if option is empty ........
author Bjoern Ricks <bricks@intevation.de>
date Fri, 06 Aug 2010 13:28:47 +0000
parents 56f7da71d41e
children 3d65b3176159
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/publishdebianpackages.py	Fri Aug 06 13:28:47 2010 +0000
@@ -0,0 +1,251 @@
+#! /usr/bin/python
+# Copyright (C) 2007 - 2010 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh@intevation.de>
+# Bjoern Ricks    <bjoern.ricks@intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+"""Publishes selected packages created by treepkg"""
+
+import os
+import os.path
+import re
+import sys
+import shlex
+
+from optparse import OptionParser
+from ConfigParser import SafeConfigParser
+
+import treepkgcmd
+from treepkg.readconfig import read_config_section, convert_bool
+from treepkg.run import call, capture_output
+from treepkg.cmdexpand import cmdexpand
+from treepkg.publish import *
+from treepkg.util import md5sum
+from treepkg.info.status import TreepkgInfo
+from treepkg.info.data import Package
+from treepkg.info.data import CacheDb
+
+EMPTY = re.compile(r'\s*')
+
+config_desc = ["distribution", "section", "num_newest",
+               "build_user", "build_host", "build_listpackages",
+               "publish_user", "publish_host", 
+               ("architectures", shlex.split, "armel i386 source"),
+               ("after_upload_hook", shlex.split),
+               ("publish_remove_old_packages", convert_bool),
+               ("publish_dir", remove_trailing_slashes),
+               ("cachedb",
+                lambda s: expand_filename(remove_trailing_slashes(s))),
+               ("cachedir",
+                lambda s: expand_filename(remove_trailing_slashes(s)))]
+
+
+def read_config(filename):
+    if not os.path.exists(filename):
+        print >>sys.stderr, "Config file %s does not exist" % filename
+        sys.exit(1)
+    parser = SafeConfigParser()
+    parser.read([filename])
+    return read_config_section(parser, "publishpackages", config_desc)
+
+def parse_commandline():
+    parser = OptionParser()
+    parser.set_defaults(config_file=os.path.join(treepkgcmd.topdir,
+                                                 "publishpackages.cfg"),
+                        quiet=False)
+    parser.add_option("--config-file",
+                      help=("The configuration file."
+                            " Default is publishpackages.cfg"))
+    parser.add_option("--dist",
+                      help=("The debian distribution name to use on"
+                            " the publishing system"))
+    parser.add_option("--section",
+                      help=("The debian distribution section name to use on"
+                            " the publishing system"))
+    parser.add_option("--track",
+                      help=("The package track whose files are to be"
+                            " published. If not given, files of all tracks"
+                            " will be published"))
+    parser.add_option("--quiet", action="store_true",
+                      help=("Do not print progress meters or other"
+                            " informational output"))
+    return parser.parse_args()
+
+def get_treepkg_info(variables):
+    runremote = prefix_for_remote_command(variables["build_user"],
+                                          variables["build_host"])
+    xml = capture_output(cmdexpand("@runremote $build_listpackages"
+                                     " --newest=$num_newest"
+                                     " --only-successful",
+                                     runremote=runremote,
+                                     **variables))
+    return TreepkgInfo.fromxml(xml)
+
+def get_binary_arch(arch): 
+    if not arch is None and not arch.startswith("binary") and \
+            not arch == "source":
+            arch = "binary-" + arch
+    return arch
+
+def check_package_is_new(packagename, destdir, packagemd5sum):
+    destpackage = os.path.join(destdir, packagename)
+    if not os.path.isfile(destpackage):
+        return True
+    destmd5sum = md5sum(destpackage)
+    return (destmd5sum != packagemd5sum)
+
+def get_md5sum(packageinfo):
+    md5sum = ""
+    if packageinfo:
+        for checksum in packageinfo.checksums:
+            if checksum.type == "md5":
+                md5sum = checksum.checksum
+                break
+    return md5sum
+
+def sort_trackname_arch(a, b):
+    if a.trackname < b.trackname: return -1
+    if a.trackname > b.trackname: return +1
+    return cmp(a.arch, b.arch)
+
+def copy_files_to_destdir(destdir, files, variables, quiet = False):
+    scp_flags = []
+    if quiet:
+        scp_flags.append("-q")
+
+    if not os.path.exists(destdir):
+        os.makedirs(destdir)
+    if files:
+        if variables["build_host"]:
+            userhost = "%(build_user)s@%(build_host)s:" % variables
+            files = [userhost + filename for filename in files]
+        # scp the packages to the cache dir 
+        call(cmdexpand("scp -p @scp_flags @files $cachedir/", files=files,
+                        scp_flags=scp_flags, cachedir=destdir))
+
+def remove_old_packages(cachedb, newpackages, quiet):
+    newfiles = [package.filename for package in newpackages]
+    oldpackages = cachedb.get_old_packages(newfiles)
+    for package in oldpackages:
+        # better check if the file really exists
+        if os.path.isfile(package.filename):
+            if not quiet:
+                print "removing file %s" % package.filename
+            os.remove(package.filename)
+    cachedb.remove_packages(oldpackages)
+
+def copy_packages_to_destdir(cachedb, dir, packages, variables, quiet = False):
+    packages.sort(cmp=sort_trackname_arch)
+    package = packages[0]
+    trackname = package.trackname
+    arch = package.arch
+    destdir = os.path.join(dir, arch, trackname)
+    files = []
+    for package in packages:
+        cachedb.add_package(package)
+        if package.trackname != trackname or \
+           package.arch != arch:
+            copy_files_to_destdir(destdir, files, variables, quiet)
+            trackname = package.trackname
+            arch = package.arch
+            destdir = os.path.join(dir, arch, trackname)
+            files = []
+        # add only to copy files list if the packages differ
+        if check_package_is_new(package.name, destdir, package.md5sum):
+            files.append(package.sourcepath)
+            if not quiet:
+                print "copy new file: %s" % package.name
+    copy_files_to_destdir(destdir, files, variables, quiet)
+           
+def copy_to_cachedir(variables, track, revision, quiet = False, architectures=None):
+    cachedir = variables["cachedir"]
+    cachdebfilename = variables["cachedb"]
+    if not quiet:
+        print "using cachedb: %s" % cachdebfilename
+    cachedb = CacheDb(cachdebfilename)
+    newpackages = []
+    treepkginfo = get_treepkg_info(variables)
+    #allowedarchs = set([]) # contains all wanted architectures (incl. source)
+    allarchs = set([]) # contains all present architectures (incl. source)
+    binaryallpackages = []
+    # change e.g. armel in binary-armel
+    if not architectures is None:
+        allowedarchs = set([get_binary_arch(a) for a in architectures])
+    else:
+        allowedarchs = set([])
+    for track in treepkginfo.tracks:
+        for rev in track.revisions:
+            for packageinfo in rev.packages:
+                arch = get_binary_arch(packageinfo.arch)
+                if packageinfo.type == "binary":
+                    # skip other files
+                    if packageinfo.arch is None:
+                        continue
+                    # handle binary-all
+                    if arch == "binary-all":
+                        # add trackname for subdir name
+                        packageinfo.trackname = track.name
+                        binaryallpackages.append(packageinfo)
+                        continue
+                    allarchs.add(arch)
+                elif packageinfo.type == "source":
+                    arch = packageinfo.type
+                # only copy requested archs
+                if len(allowedarchs) == 0 or \
+                   arch in allowedarchs:
+                    filename = os.path.join(cachedir, arch, track.name,
+                                            packageinfo.name)
+                    newpackage = Package(filename, track.name, packageinfo.name,
+                                         packageinfo.path, arch,
+                                         get_md5sum(packageinfo))
+                    newpackages.append(newpackage)
+    # copy binary-all packages
+    sourcearch = set(["source"])
+    if len(allowedarchs) == 0:
+        binallarchs = allarchs - sourcearch 
+    elif len(allarchs) == 0:
+        binallarchs = allowedarchs - sourcearch
+    else:
+        binallarchs = (allowedarchs & allarchs) - sourcearch
+    for packageinfo in binaryallpackages:
+        for arch in binallarchs:
+            filename = os.path.join(cachedir, arch, packageinfo.trackname,
+                                    packageinfo.name)
+            newpackage = Package(filename, packageinfo.trackname, packageinfo.name,
+                                 packageinfo.path, arch, get_md5sum(packageinfo))
+            newpackages.append(newpackage)
+    copy_packages_to_destdir(cachedb, cachedir, newpackages, variables, quiet)
+    remove_old_packages(cachedb, newpackages, quiet)
+    return binallarchs
+
+def publish_packages(config_filename, track, revision, dist, section, quiet):
+    config = read_config(config_filename)
+
+    if dist is None:
+        dist = config["distribution"]
+    if section is None:
+        section = config["section"]
+
+    architectures = config["architectures"]
+    allarchs = copy_to_cachedir(config, track, revision, quiet, architectures)
+    for arch in allarchs:
+        copy_to_publishdir(config, dist, section, arch, quiet)
+
+    # update apt archive
+    if not config["after_upload_hook"] or \
+        not EMPTY.match(config["after_upload_hook"]):
+        if not quiet:
+            print "running after upload hook"
+        call(config["after_upload_hook"])
+
+def main():
+    options, args = parse_commandline()
+    revision = None # for future use cases
+    publish_packages(options.config_file, options.track, revision,
+                     options.dist, options.section, options.quiet)
+
+if __name__ == "__main__":
+    main()
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)