view treepkg/sbuilder.py @ 579:97a5e09c84dc tip

Fix: pass url to command expand to be able to checkout a new git repository
author Bjoern Ricks <bricks@intevation.de>
date Sat, 03 Sep 2011 12:32:32 +0000
parents 5fa4b938a939
children
line wrap: on
line source
# Copyright (C) 2010 by Intevation GmbH
# Authors:
# 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.

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

import sys
import os
import shutil
import logging
import tempfile

import util
import run
import builder
from cmdexpand import cmdexpand


class SbdmockBuilder(builder.Builder):

    """Represents a way to run and manage a specific sbdmock instance
    to build binary for Maemo within scratchbox environment"""

    basetgz_dir = util.filenameproperty("base")
    build_dir = util.filenameproperty("build")
    result_dir = util.filenameproperty("result")
    aptcache_dir = util.filenameproperty("aptcache")
    extra_pkg_dir = util.filenameproperty("extra-pkg")

    def __init__(self, builderconfig, root_cmd, release_signing_keyid=None):
        """Initialize the Builder instance with the configuration file.
        The root_cmd parameter should be a list with a command that can
        be used to get root permissions.  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.
        """
        if not os.path.exists(builderconfig):
            raise RuntimeError("Config file %s for sbdmock does not exist.",
                  builderconfig)

        if not os.path.isabs(builderconfig):
            raise RuntimeError("Config file %s must be an absolute filename.",
                  builderconfig)

        self.builderconfig = builderconfig
        self.root_cmd = root_cmd
        self.release_signing_keyid = release_signing_keyid
        self.base_dir = os.path.dirname(self.builderconfig)
        self.mounted_dirs = []

    def init_builder(self, distribution, mirrorsite, extramirrors):
        """Initializes the builder instance"""

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

        # create the builder directories.  basedir is created implicitly by
        # creating its subdirectories.
        for attr in ["build_dir", "result_dir", "aptcache_dir",
                     "extra_pkg_dir"]:
            directory = getattr(self, attr)
            replacements[attr] = directory
            print "creating directory:", repr(directory)
            util.ensure_directory(directory)

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

        # turn the extra-pkg directory into a proper deb archive
        print "turning the extra-pkg dir into a debian archive"
        self.update_extra_pkg_dir()

    def update(self, suppress_output=True, log_info=True):
        """Runs nothing"""
        if log_info:
            logging.info("Update of apt cache is done on every start. skipping ...")

    def build(self, dsc_file, binary_dir=None, logfile=None, 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 builder chroot
                         environment
           extra_packages -- Extra packages to install
           extra_env -- mapping with extra environment variables to set
                        when runing the builder process.  If builder
                        is started via sudo, make sure that sudo does
                        not remove these variables when it starts
                        builder
        """
        args = []
        if logfile is not None:
            logdir = os.path.dirname(logfile)
            args.extend(["--rootlog=scratchlog.txt"])
            args.extend(["--buildlog=%s" % logfile])
            args.extend(["--logdir=%s" % logdir])
        if binary_dir is not None:
            args.extend(["--resultdir=%s" % binary_dir])
            util.ensure_directory(binary_dir)
        if bindmounts:
            self.mount(bindmounts)
#        for pkg in extra_packages:
#            args.extend(["--extrapackages", pkg])
        
        logging.info("Mointing extra-pkg apt repository")
                
        self.mount([self.extra_pkg_dir])

        logging.info("Starting build process with sbdmock ...")


        cmd = cmdexpand("/usr/bin/sbdmock --cleanbuilddir"
                           " --config=$builderconfig"
#                           " --dbo=" # aren't build options setable in treepkg.cfg?
                           " -u -b $dsc @args",
                           builderconfig=self.builderconfig,
                           dsc=dsc_file, args=args)
        logging.debug("sbdmock cmd: %s" % cmd)
        
        try:
            run.call(cmd, suppress_output=True, extra_env=extra_env)

            # remove the source package files put into the binary directory
            # by pbuilder (BR: not sure if this is necessary for sbdmock)
            if binary_dir is not None:
                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))
        finally:
            # remove all mounted directories
            self.umount_all()

    def run_script(self, script, logfile, bindmounts=(), save_after_exec=False):
        """Execute a script in builder's chroot environment
        Parameters:
           script -- A list of strings with the command line to invoke the
                     script
           logfile -- name of the logfile of the build
           bindmounts -- Sequence of directory names that should be
                         bind-mounted in the builder chroot
                         environment (optional)
           save_after_exec -- Boolean indicating whether the chroot
                              environment should be copied back so that
                              modifications are available in subsequent
                              uses of the builder instance.
        """

        if not script[0]:
                raise RuntimeError("No script to execute was passed")

        args = []
        if logfile is not None:
            logdir = os.path.dirname(logfile)
            args.extend(["--rootlog=%s" % logfile])
            args.extend(["--logdir=%s" % logdir])
        if bindmounts:
            self.mount(bindmounts)
        
        self.mount([self.extra_pkg_dir])

        cmd = cmdexpand("/usr/bin/sbdmock exec $script --cleanbuilddir"
                        " --config=$builderconfig"
#                       " --dbo=" # aren't build options setable in treepkg.cfg?
                        " -u @args",
                        builderconfig=self.builderconfig,
                        script=script[0],
                        args=args)
        logging.debug("sbdmock cmd: %s" % cmd)

        try:
            run.call(cmd, suppress_output=False)
        finally:
            if logfile is not None:
                logdir = os.path.dirname(logfile)
            self.umount_all()

    def login(self, bindmounts=(), save_after_login=False):
        """Start an interactive shell in the builder environment"""
        args = []
        for mount in bindmounts:
            args.extend(["--bindmounts", mount])
        if save_after_login:
            args.extend(["--save-after-login"])

        logging.info("Mointing extra-pkg apt repository")

        self.mount([self.extra_pkg_dir])

        logging.info("Login into scratchbox...")



        cmd = cmdexpand("/usr/bin/sbdmock login --cleanbuilddir"
                           " --config=$builderconfig"
#                           " --dbo=" # aren't build options setable in treepkg.cfg?
                           " -u @args",
                           builderconfig=self.builderconfig,
                           args=args)
        logging.debug("sbdmock cmd: %s" % cmd)

        run.call(cmd, suppress_output=False)

    def mount(self, bindmounts):
        for mount in bindmounts:
            mount_dir = "/scratchbox/users/%s/%s" % (util.getuser(), mount)
            util.ensure_directory(mount_dir)
            logging.info("Mounting %s to %s" % (mount, mount_dir))
            run.call(cmdexpand("@rootcmd mount --bind $mount $mountdir", rootcmd=self.root_cmd, mount=mount, mountdir=mount_dir))

            #add mountpoint to a variable to for unmounting later
            self.mounted_dirs.append(mount_dir)

    def umount(self, mounts):
        for mount in mounts:
            logging.info("Unmounting %s" % mount)
            run.call(cmdexpand("@rootcmd umount $dir", rootcmd=self.root_cmd, dir=mount))
            self.mounted_dirs.remove(mount)

    def umount_all(self):
        mounts = self.mounted_dirs[:]
        self.umount(mounts)
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)