view contrib/bin/copy-latest-pkgs.py @ 542:dc17b62d3cdd

contrib: Added copy-latest-pkgs.py to copy/hardlink latest packages from the mill to the next higher attention level.
author Sascha Teichmann <teichmann@intevation.de>
date Tue, 11 Jan 2011 17:20:02 +0000
parents
children 247a10201cdd
line wrap: on
line source
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
#
# Copyright (C) 2011 by Intevation GmbH
# Authors:
# Sascha L. Teichmann <sascha.teichmann@intevation.de>
#
# This program is free software under the GPL (>=v2)
# Read the file COPYING coming with the software for details.

import os
import re
import sys
import subprocess
import logging
import traceback

from optparse import OptionParser
from shutil   import copyfile

log = logging.getLogger(__name__) 
log.setLevel(logging.WARNING)
log.addHandler(logging.StreamHandler(sys.stderr))

SAEGEWERKER = "saegewerker"

FIELD = re.compile("([a-zA-Z]+):\s*(.+)")


class DebCmp(object):
    """Helper class to make deb files comparable
       by there versions.
    """

    def __init__(self, version, path):
        self.version = version
        self.path    = path

    def __cmp__(self, other):
        if self.version == other.version:
            return 0
        if (subprocess.call([
            "dpkg", "--compare-versions", 
            self.version, "gt", other.version]) == 0):
            return +1
        if (subprocess.call([
            "dpkg", "--compare-versions", 
            self.version, "lt", other.version]) == 0):
            return -1
        return 0

    def __str__(self):
        return "version: %s / path: %s" % (
            self.version,
            self.path)

def deb_info(deb, fields=["Package", "Version"]):
    """Extract some meta info from a deb file."""
    po = subprocess.Popen(
        ["dpkg-deb", "-f", deb] + fields,
        stdout=subprocess.PIPE)
    out = po.communicate()[0]
    return dict([m.groups()
                for m in map(FIELD.match, out.splitlines()) if m])


def copy_pkgs(src, dst, options):

    archs = {}

    for arch in os.listdir(src):
        if arch == 'source': continue
        arch_dir = os.path.join(src, arch)
        if not os.path.isdir(arch_dir): continue
        log.debug("found arch: '%s'" % arch)

        tracks = {}

        for track in os.listdir(arch_dir):
            track_dir = os.path.join(arch_dir, track)
            if not os.path.isdir(track_dir): continue

            packages = {}

            log.debug("track dir: '%s'" % track_dir)
            for f in os.listdir(track_dir):
                if not f.endswith(".deb"): continue
                deb_path = os.path.join(track_dir, f)
                if not os.path.isfile(deb_path): continue

                info = deb_info(deb_path)
                deb_cmp = DebCmp(info['Version'], deb_path)

                packages.setdefault(info['Package'], []).append(deb_cmp)

            tracks[track] =[max(debs) for  debs in packages.itervalues()]

        archs[arch] = tracks

    copy   = options.no_hardlinks and copyfile or os.link
    action = options.no_hardlinks and "copy" or "link"

    for arch, tracks in archs.iteritems():
        log.debug("writing arch '%s'" % arch)
        for track, debs in tracks.iteritems():
            log.debug("  writing track '%s'" % track)
            dst_dir = os.path.join(dst, arch, track)
            if not os.path.exists(dst_dir):
                try:
                    os.makedirs(dst_dir)
                except:
                    log.warn(traceback.format_exc())
                    continue

            for deb in debs:
                src_path = deb.path
                dst_path = os.path.join(dst_dir, os.path.basename(src_path))
                log.info("    %s '%s' -> '%s'" % (action, src_path, dst_path))
                if os.path.isfile(dst_path):
                    try:    os.remove(dst_path)
                    except: log.warn(traceback.format_exc()); continue
                try:    copy(src_path, dst_path)
                except: log.warn(traceback.format_exc())


def main():
    usage = "usage: %prog [options] src-dir dst-dir"
    parser = OptionParser(usage=usage)
    parser.add_option(
        "-v", "--verbose", action="store_true",
        dest="verbose",
        help="verbose output")
    parser.add_option(
        "-d", "--dry-run", action="store_true",
        dest="dry_run", default=False,
        help="don't copy the deb files")
    parser.add_option(
        "-n", "--no-saegewerker", action="store_true",
        dest="no_saegewerker", default=False,
        help="Don't force run as '%s'" % SAEGEWERKER)
    parser.add_option(
        "-l", "--no-hardlinks", action="store_false",
        dest="no_hardlinks", default=False,
        help="copy files instead of hard linking")

    options, args = parser.parse_args()

    if len(args) < 2:
        log.error("need at least two arguments")
        sys.exit(1)

    src, dst = args[0], args[1]

    for d in (src, dst):
        if not os.path.isdir(d):
            log.error("'%s' is not a directory." % d)
            sys.exit(1)

    if options.verbose: log.setLevel(logging.INFO)

    if not options.no_saegewerker and os.environ['USER'] != SAEGEWERKER:
        log.error("Need to run as '%s'" % SAEGEWERKER)
        sys.exit(1)

    copy_pkgs(src, dst, options)

if __name__ == '__main__':
    main()
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)