view treepkg/builder.py @ 171:c0ea6cbb0fd2

Add "--debbuildopts -b" to "pbuilder build" command line to stop pbuilder from creating a source package. The .changes would otherwise contain references to that new source package instead of the one we passed to pbuilder. The checksums for the two source packages would be different so the .changes file would not match the source package that treepkg produces.
author Bernhard Herzog <bh@intevation.de>
date Mon, 23 Jun 2008 16:12:01 +0000
parents bfcb2bbf9a52
children 97435e92411a
line wrap: on
line source
# Copyright (C) 2007, 2008 by Intevation GmbH
# Authors:
# Bernhard Herzog <bh@intevation.de>
#
# This program is free software under the GPL (>=v2)
# Read the file COPYING coming with the software for details.

"""Build binary packages from source packages"""

import sys
import os
import shutil
import logging

import util
import run
from cmdexpand import cmdexpand


class PBuilder(object):

    """Represents a way to run and manage a specific pbuilder instance"""

    pbuilderrc_template = '''\
# This file was automatically generated by initpbuilder.py.
# for the possible settings see "man pbuilderrc"

BASETGZ=%(basedir)s/base.tgz
BUILDPLACE=%(builddir)s
USEPROC=yes
USEDEVPTS=yes
BUILDRESULT=%(resultdir)s
DISTRIBUTION=%(distribution)s
APTCACHE=%(basedir)s/aptcache
APTCACHEHARDLINK=yes
REMOVEPACKAGES=lilo
MIRRORSITE="%(mirrorsite)s"
OTHERMIRROR="%(othermirror)s"
BINDMOUNTS="%(extra-pkgdir)s"
PKGNAME_LOGFILE=yes
'''


    def __init__(self, pbuilderrc, root_cmd):
        """Initialize the PBuilder instance with the configuration file.
        The root_cmd parameter should be a list with a command that can
        be used to get root permissions to run pbuilder.  It may be an
        empty list if no command is needed.  It's a list so that
        commands with several shell-words can be used without having to
        worry about quoting.
        """
        self.pbuilderrc = pbuilderrc
        self.root_cmd = root_cmd

    def init_pbuilder(self, distribution, mirrorsite, extramirrors):
        """Initializes the pbuilder instance"""
        if not os.path.isabs(self.pbuilderrc):
            print >>sys.stderr, "pbuilderrc must be an absolute filename"
            sys.exit(1)

        if os.path.exists(self.pbuilderrc):
            print >>sys.stderr, ("pbuilderrc %r already exists."
                                 % self.pbuilderrc)
            sys.exit(1)

        basedir = os.path.dirname(self.pbuilderrc)
        replacements = dict(basedir=basedir,
                            distribution=distribution,
                            mirrorsite=mirrorsite)

        # create the pbuilder directories.  basedir is created implicitly by
        # creating its subdirectories.
        for subdir in ["base", "build", "result", "aptcache", "extra-pkg"]:
            directory = os.path.join(basedir, subdir)
            replacements[subdir + "dir"] = directory
            print "creating directory:", repr(directory)
            util.ensure_directory(directory)

        # build OTHERMIRROR value.  We always include the extra-pkg dir.
        othermirror = "deb file://%(extra-pkgdir)s ./" % replacements
        if extramirrors:
            othermirror += " | " + extramirrors
        replacements["othermirror"] = othermirror

        # create the pbuilderrcfile
        print "creating pbuilderrc:", repr(self.pbuilderrc)
        util.writefile(self.pbuilderrc, self.pbuilderrc_template % replacements)

        # turn the extra-pkg directory into a proper deb archive
        print "turning the extra-pkg dir into a debian archive"
        extra_pkgdir = replacements["extra-pkgdir"]
        run.call(cmdexpand("apt-ftparchive packages ."),
                 stdout=open(os.path.join(extra_pkgdir, "Packages"), "w"),
                 cwd=extra_pkgdir)

        # create the base.tgz chroot
        print "running pbuilder create"
        run.call(cmdexpand("@root_cmd pbuilder create --configfile $pbuilderrc",
                           root_cmd=self.root_cmd, pbuilderrc=self.pbuilderrc))


    def build(self, dsc_file, binary_dir, logfile, bindmounts=(),
              extra_packages=(), extra_env=None):
        """Build a binary packager from a source package
        Parameters:
           dsc_file -- name of the debian .dsc file of the source package
           binary_dir -- name of the directory to receive the binary packages
           logfile -- name of the logfile of the build
           bindmounts -- Sequence of directory names that should be
                         bind-mounted in the pbuilder chroot
                         environment
           extra_packages -- Extra packages to install
           extra_env -- mapping with extra environment variables to set
                        when runing the pbuilder process.  If pbuilder
                        is started via sudo, make sure that sudo does
                        not remove these variables when it starts
                        pbuilder
        """
        util.ensure_directory(binary_dir)
        args = []
        for mount in bindmounts:
            args.extend(["--bindmounts", mount])
        for pkg in extra_packages:
            args.extend(["--extrapackages", pkg])
        run.call(cmdexpand("@rootcmd /usr/sbin/pbuilder build"
                           " --configfile $pbuilderrc @args"
                           " --logfile $logfile --buildresult $bindir"
                           " --debbuildopts -b $dsc",
                           rootcmd=self.root_cmd, pbuilderrc=self.pbuilderrc,
                           logfile=logfile, bindir=binary_dir, dsc=dsc_file,
                           args=args),
                 suppress_output=True,
                 extra_env=extra_env)
        # remove the source package files put into the binary directory
        # by pbuilder
        for filename in os.listdir(binary_dir):
            if os.path.splitext(filename)[1] not in (".deb", ".changes"):
                os.remove(os.path.join(binary_dir, filename))

    def add_binaries_to_extra_pkg(self, filenames):
        """Adds binary packages to the extra-pkg directory.
        The filenames parameter should be sequence of absolute
        filenames.  The files named will be copied to the extra-pkg
        directory which is assumed to reside in the same directory as
        the pbuilderrc.  Afterwards, the method generates a Packages
        file in the directory and runs pbuilder update.  All of this
        assumes that pbuilder was set up the way bin/initpbuilder.py
        does.
        """
        extrapkg_dir = os.path.join(os.path.dirname(self.pbuilderrc),
                                    "extra-pkg")
        for filename in filenames:
            logging.info("Copying %s into %s", filename, extrapkg_dir)
            shutil.copy(filename, extrapkg_dir)
        logging.info("Running apt-ftparchive in %s", extrapkg_dir)
        run.call(cmdexpand("apt-ftparchive packages ."),
                 stdout=open(os.path.join(extrapkg_dir, "Packages"), "w"),
                 cwd=extrapkg_dir)
        logging.info("Running pbuilder update for %s", self.pbuilderrc)
        run.call(cmdexpand("@rootcmd /usr/sbin/pbuilder update"
                           " --configfile $pbuilderrc",
                           rootcmd=self.root_cmd, pbuilderrc=self.pbuilderrc),
                 suppress_output=True)

    def run_script(self, script, logfile, bindmounts=()):
        """Execute a script in pbuilder's chroot environment
        Parameters:
           script -- The filename of the script
           logfile -- name of the logfile of the build
           bindmounts -- Sequence of directory names that should be
                         bind-mounted in the pbuilder chroot
                         environment (optional)
        """
        logging.info("Running pbuilder execute on %s", script)
        args = []
        if logfile:
            args.extend(["--logfile", logfile])
            # create the logfile.  This makes sure that it is owned by
            # the user the tree packager is running as and not root, as
            # would be the case when it is created indirectly by
            # pbuilder
            open(logfile, "w").close()
        for mount in bindmounts:
            args.extend(["--bindmounts", mount])

        run.call(cmdexpand("@rootcmd /usr/sbin/pbuilder execute"
                           " --configfile $pbuilderrc @args $script",
                           rootcmd=self.root_cmd, pbuilderrc=self.pbuilderrc,
                           args=args, script=script),
                 suppress_output=False)
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)