[elbe-devel] merge of the logging branch

Bastian Germann bage at linutronix.de
Thu Aug 29 11:49:20 CEST 2019


> On Wed, Aug 28, 2019 at 03:14:04PM +0200, Bastian Germann wrote:
>>> Hi...
>>>
>>> i have merged devel/torbenh/betterlog-rebase-v8 into master
>>> now.
>>>
>>> since sending it via "git format-patch" and "git send-email"
>>> does not work, i have pushed it to lxcvs (devel/torbenh/logging-merge)
>>>
>>> and i will include the output of git show here:
> 
> ok... i think i have fixed that now.
> I have also added the missing Reviewed-by: tag in 
> devel/torbenh/better-log-rebase-v8
> 
> i have pushed it again to devel/torbenh/logging-merge
> and here is git show again:
> 
> -----------------------------------------------------------------------------------------
> commit 91cfdefe16db5d6166bcc8bb4c2ae8c434c609c8
> Merge: ce3f3820d ecff15c9b
> Author: Torben Hohn <torben.hohn at linutronix.de>
> Date:   Thu Aug 29 10:59:42 2019 +0200
> 
>     Merge branch 'devel/torbenh/better-log-rebase-v8' into devel/torbenh/logging-merge
>     
>     because of the large number of expected conflicts, this branch
>     is not rebased onto master. It is merged.
>     
>     there still remain a few codefragments, which have been added after v8
>     that are not converted to the new logging infrastructure.
>     This will get done after this merge commit.
>     
>     
>     # Conflicts:
>     #       elbepack/cdroms.py
>     #       elbepack/commands/chroot.py
>     #       elbepack/dump.py
>     #       elbepack/efilesystem.py
>     #       elbepack/elbeproject.py
>     #       elbepack/finetuning.py
>     #       elbepack/fstab.py
>     #       elbepack/hdimg.py
>     #       elbepack/pkgutils.py
>     #       elbepack/repomanager.py
>     #       elbepack/updatepkg.py
>     
>     Signed-off-by: Torben Hohn <torben.hohn at linutronix.de>

Reviewed-by: Bastian Germann <bage at linutronix.de>

> 
> diff --cc debian/python-elbe-common.install
> index 84c9be547,f60941c76..9283b0dcd
> --- a/debian/python-elbe-common.install
> +++ b/debian/python-elbe-common.install
> @@@ -20,9 -19,9 +20,10 @@@
>   ./usr/lib/python2.*/*-packages/elbepack/egpg.py
>   ./usr/lib/python2.*/*-packages/elbepack/hashes.py
>   ./usr/lib/python2.*/*-packages/elbepack/initvmaction.py
>  +./usr/lib/python2.*/*-packages/elbepack/isooptions.py
>   ./usr/lib/python2.*/*-packages/elbepack/kvm.py
>   ./usr/lib/python2.*/*-packages/elbepack/licencexml.py
> + ./usr/lib/python2.*/*-packages/elbepack/log.py
>   ./usr/lib/python2.*/*-packages/elbepack/pbuilderaction.py
>   ./usr/lib/python2.*/*-packages/elbepack/pkgutils.py
>   ./usr/lib/python2.*/*-packages/elbepack/xmlpreprocess.py
> diff --cc debian/python3-elbe-common.install
> index daff125ff,ec8edc3e4..e0764b2ff
> --- a/debian/python3-elbe-common.install
> +++ b/debian/python3-elbe-common.install
> @@@ -20,9 -19,9 +20,10 @@@
>   ./usr/lib/python3.*/*-packages/elbepack/egpg.py
>   ./usr/lib/python3.*/*-packages/elbepack/hashes.py
>   ./usr/lib/python3.*/*-packages/elbepack/initvmaction.py
>  +./usr/lib/python3.*/*-packages/elbepack/isooptions.py
>   ./usr/lib/python3.*/*-packages/elbepack/kvm.py
>   ./usr/lib/python3.*/*-packages/elbepack/licencexml.py
> + ./usr/lib/python3.*/*-packages/elbepack/log.py
>   ./usr/lib/python3.*/*-packages/elbepack/pbuilderaction.py
>   ./usr/lib/python3.*/*-packages/elbepack/pkgutils.py
>   ./usr/lib/python3.*/*-packages/elbepack/xmlpreprocess.py
> diff --cc elbepack/cdroms.py
> index 3ba67f7bf,2d8649fcb..d89191ce8
> --- a/elbepack/cdroms.py
> +++ b/elbepack/cdroms.py
> @@@ -16,8 -18,7 +18,8 @@@ from elbepack.repomanager import CdromB
>   from elbepack.repomanager import CdromInitRepo
>   from elbepack.aptpkgutils import XMLPackage
>   from elbepack.filesystem import Filesystem, hostfs
> - from elbepack.shellhelper import CommandError
> + from elbepack.shellhelper import CommandError, do
>  +from elbepack.isooptions import get_iso_options
>   
>   CDROM_SIZE = 640 * 1000 * 1000
>   
> @@@ -103,22 -88,10 +89,15 @@@ def mk_source_cdrom(rfs, arch, codename
>   
>       repo.finalize()
>   
>  -    return repo.buildiso(os.path.join(target, "src-cdrom.iso"))
>  +    if xml is not None:
>  +        options = get_iso_options(log, xml)
>  +    else:
>  +        options = ""
>  +
>  +    return repo.buildiso(os.path.join(target, "src-cdrom.iso"), options=options)
>   
> - def mk_binary_cdrom(
> -         rfs,
> -         arch,
> -         codename,
> -         init_codename,
> -         xml,
> -         target,
> -         log,
> -         cdrom_size=CDROM_SIZE):
> + def mk_binary_cdrom(rfs, arch, codename, init_codename, xml, target,
> +                     cdrom_size=CDROM_SIZE):
>       # pylint: disable=too-many-arguments
>       # pylint: disable=too-many-locals
>       # pylint: disable=too-many-branches
> diff --cc elbepack/commands/chroot.py
> index a65d27e65,c3a8e5772..10e7535e0
> --- a/elbepack/commands/chroot.py
> +++ b/elbepack/commands/chroot.py
> @@@ -14,7 -15,7 +15,8 @@@ import loggin
>   
>   from elbepack.elbeproject import ElbeProject
>   from elbepack.elbexml import ValidationError, ValidationMode
>  +from elbepack.shellhelper import system, CommandError
> + from elbepack.log import elbe_logging
>   
>   
>   def run_command(argv):
> @@@ -36,40 -37,33 +38,41 @@@
>           oparser.print_help()
>           sys.exit(20)
>   
> -     try:
> -         project = ElbeProject(
> -             args[0],
> -             override_buildtype=opt.buildtype,
> -             skip_validate=opt.skip_validation,
> -             url_validation=ValidationMode.NO_CHECK)
> -     except ValidationError as e:
> -         print(str(e))
> -         print("xml validation failed. Bailing out")
> -         sys.exit(20)
> +     with elbe_logging({"streams":sys.stdout}):
> +         try:
> +             project = ElbeProject(args[0],
> +                                   override_buildtype=opt.buildtype,
> +                                   skip_validate=opt.skip_validation,
> +                                   url_validation=ValidationMode.NO_CHECK)
> +         except ValidationError:
> +             logging.exception("XML validation failed.  Bailing out")
> +             sys.exit(20)
>   
> -     os.environ["LANG"] = "C"
> -     os.environ["LANGUAGE"] = "C"
> -     os.environ["LC_ALL"] = "C"
> -     # TODO: howto set env in chroot?
> -     os.environ["PS1"] = project.xml.text('project/name') + ': \w\$'
> +         os.environ["LANG"] = "C"
> +         os.environ["LANGUAGE"] = "C"
> +         os.environ["LC_ALL"] = "C"
> +         # TODO: howto set env in chroot?
> +         os.environ["PS1"] = project.xml.text('project/name') + ': \w\$'
>   
> -     cmd = "/bin/bash"
> +         cmd = "/bin/bash"
>   
> -     if len(args) > 1:
> -         cmd = ""
> -         cmd2 = args[1:]
> -         for c in cmd2:
> -             cmd += (c + " ")
> +         if len(args) > 1:
> +             cmd = ""
> +             cmd2 = args[1:]
> +             for c in cmd2:
> +                 cmd += (c + " ")
>   
> -     if opt.target:
> -         try:
> -             with project.targetfs:
> -                 system("/usr/sbin/chroot %s %s" % (project.targetpath, cmd))
> -         except CommandError as e:
> -             print(repr(e))
> -     else:
> -         try:
> -             with project.buildenv:
> -                 system("/usr/sbin/chroot %s %s" % (project.chrootpath, cmd))
> -         except CommandError as e:
> -             print(repr(e))
> +         if opt.target:
>  -            with project.targetfs:
>  -                os.system("/usr/sbin/chroot %s %s" % (project.targetpath, cmd))
> ++            try:
> ++                with project.targetfs:
> ++                    system("/usr/sbin/chroot %s %s" %
> ++                           (project.targetpath, cmd))
> ++            except CommandError as e:
> ++                print(repr(e))
> +         else:
>  -            with project.buildenv:
>  -                os.system("/usr/sbin/chroot %s %s" % (project.chrootpath, cmd))
> ++            try:
> ++                with project.buildenv:
> ++                    system("/usr/sbin/chroot %s %s" %
> ++                           (project.chrootpath, cmd))
> ++            except CommandError as e:
> ++                print(repr(e))
> diff --cc elbepack/efilesystem.py
> index faa2a1834,c39a80e2f..162e3947f
> --- a/elbepack/efilesystem.py
> +++ b/elbepack/efilesystem.py
> @@@ -21,7 -20,7 +20,11 @@@ from elbepack.hdimg import do_hdim
>   from elbepack.fstab import fstabentry
>   from elbepack.licencexml import copyright_xml
>   from elbepack.packers import default_packer
> - from elbepack.shellhelper import system
>  -from elbepack.shellhelper import CommandError, do, chroot, get_command_out
> ++from elbepack.shellhelper import (system,
> ++                                  CommandError,
> ++                                  do,
> ++                                  chroot,
> ++                                  get_command_out)
>   
>   
>   def copy_filelist(src, filelist, dst):
> diff --cc elbepack/elbeproject.py
> index d9690321e,545d0c270..d18dfdf25
> --- a/elbepack/elbeproject.py
> +++ b/elbepack/elbeproject.py
> @@@ -12,9 -12,9 +12,9 @@@ import sy
>   import os
>   import datetime
>   import io
> + import logging
>   
> - from elbepack.asciidoclog import ASCIIDocLog, StdoutLog
> - from elbepack.shellhelper import CommandError, system
>  -from elbepack.shellhelper import CommandError, do, chroot
> ++from elbepack.shellhelper import CommandError, system, do, chroot
>   
>   from elbepack.elbexml import (ElbeXML, NoInitvmNode,
>                                 ValidationError, ValidationMode)
> @@@ -334,10 -326,9 +326,11 @@@ class ElbeProject (object)
>                   try:
>                       cache.mark_install(p, None)
>                   except KeyError:
> -                     self.log.printo("No Package " + p)
> -                 except SystemError as e:
> -                     self.log.printo("Error: Unable to correct problems "
> -                                     "in package %s (%s)" % (p, str(e)))
> +                     logging.exception("No Package %s", p)
> +                 except SystemError:
>  -                    logging.exception("Unable to correct problems in package %s", p)
> ++                    logging.exception("Unable to correct problems in "
> ++                                      "package %s",
> ++                                      p)
>   
>               try:
>                   cache.commit()
> @@@ -613,31 -589,32 +591,32 @@@
>               os.remove(os.path.join(self.builddir, "licence.xml"))
>   
>           # Use some handwaving to determine grub version
>  -        # jessie and wheezy grubs are 2.0 but differ in behaviour
>           #
>           # We might also want support for legacy grub
>  -        if (self.get_rpcaptcache().is_installed('grub-pc') and
>  -                self.get_rpcaptcache().is_installed('grub-efi-amd64-bin')):
>  +        grub_arch = "ia32" if self.arch == "i386" else self.arch
>  +        grub_fw_type = []
>  +        grub_version = 0
>  +        if self.get_rpcaptcache().is_installed('grub-pc'):
>               grub_version = 202
>  -            grub_fw_type = "hybrid"
>  -        elif self.get_rpcaptcache().is_installed('grub-pc'):
>  -            if self.codename == "wheezy":
>  -                grub_version = 199
>  -            else:
>  -                grub_version = 202
>  -            grub_fw_type = "bios"
>  -        elif self.get_rpcaptcache().is_installed('grub-efi-amd64'):
>  +            grub_fw_type.append("bios")
>  +        if self.get_rpcaptcache().is_installed('grub-efi-%s-bin' % grub_arch):
>  +            grub_version = 202
>  +            grub_tgt = "x86_64" if self.arch == "amd64" else self.arch
>  +            grub_fw_type.extend(["efi", grub_tgt + "-efi"])
>  +        if (self.get_rpcaptcache().is_installed('shim-signed') and
>  +                self.get_rpcaptcache().is_installed(
>  +                    'grub-efi-%s-signed' % grub_arch)):
>               grub_version = 202
>  -            grub_fw_type = "efi"
>  -        elif self.get_rpcaptcache().is_installed('grub-legacy'):
>  +            grub_fw_type.append("shimfix")
>  +        if self.get_rpcaptcache().is_installed('grub-legacy'):
> -             self.log.printo("package grub-legacy is installed, "
> +             logging.warning("package grub-legacy is installed, "
>                               "this is obsolete, skipping grub")
>  -            grub_version = 0
>  -            grub_fw_type = ""
>  -        else:
>  -            logging.warning("package grub-pc is not installed, skipping grub")
>  -            # version 0 == skip_grub
>  -            grub_version = 0
>  -            grub_fw_type = ""
>  +            grub_fw_type = []
>  +        elif not grub_fw_type:
> -             self.log.printo("neither package grub-pc nor grub-efi-%s-bin "
> -                             "are installed, skipping grub" % grub_arch)
> ++            logging.warning("neither package grub-pc nor grub-efi-%s-bin "
> ++                            "are installed, skipping grub",
> ++                            grub_arch)
>  +
>           self.targetfs.part_target(self.builddir, grub_version, grub_fw_type)
>   
>           self.build_cdroms(build_bin, build_sources, cdrom_size)
> @@@ -747,44 -712,28 +714,28 @@@
>   
>       def create_pbuilder(self):
>           # Remove old pbuilder directory, if it exists
> -         self.log.do('rm -rf "%s"' % os.path.join(self.builddir, "pbuilder"))
> +         do('rm -rf "%s"' % os.path.join(self.builddir, "pbuilder"))
>   
>           # make hooks.d and pbuilder directory
> -         self.log.do(
> -             'mkdir -p "%s"' %
> -             os.path.join(
> -                 self.builddir,
> -                 "pbuilder",
> -                 "hooks.d"))
> -         self.log.do(
> -             'mkdir -p "%s"' %
> -             os.path.join(
> -                 self.builddir,
> -                 "pbuilder",
> -                 "aptcache"))
> -         self.log.do(
> -             'mkdir -p "%s"' %
> -             os.path.join(
> -                 self.builddir,
> -                 "aptconfdir",
> -                 "apt.conf.d"))
> +         do('mkdir -p "%s"' %
> +            os.path.join(self.builddir, "pbuilder", "hooks.d"))
> +         do('mkdir -p "%s"' %
> +            os.path.join(self.builddir, "pbuilder", "aptcache"))
> +         do('mkdir -p "%s"' %
> +            os.path.join(self.builddir, "aptconfdir", "apt.conf.d"))
>   
>           # write config files
> -         pbuilder_write_config(self.builddir, self.xml, self.log)
> +         pbuilder_write_config(self.builddir, self.xml)
>           pbuilder_write_apt_conf(self.builddir, self.xml)
>           pbuilder_write_repo_hook(self.builddir, self.xml)
> -         self.log.do(
> -             'chmod -R 755 "%s"' %
> -             os.path.join(
> -                 self.builddir,
> -                 "pbuilder",
> -                 "hooks.d"))
> +         do('chmod -R 755 "%s"' %
> +            os.path.join(self.builddir, "pbuilder", "hooks.d"))
>   
>           # Run pbuilder --create
> -         self.log.do('pbuilder --create --configfile "%s" --aptconfdir "%s" '
> -                     '--debootstrapopts --include="git gnupg"' % (
> -                         os.path.join(self.builddir, "pbuilderrc"),
> -                         os.path.join(self.builddir, "aptconfdir")))
> +         do('pbuilder --create --configfile "%s" --aptconfdir "%s" '
>  -           '--debootstrapopts --include="git gnupg2"' %
> ++           '--debootstrapopts --include="git gnupg"' %
> +            (os.path.join(self.builddir, "pbuilderrc"),
> +             os.path.join(self.builddir, "aptconfdir")))
>   
>       def sync_xml_to_disk(self):
>           try:
> diff --cc elbepack/filesystem.py
> index d7ed4b21c,a8bb6b5c0..3dac75ff6
> --- a/elbepack/filesystem.py
> +++ b/elbepack/filesystem.py
> @@@ -12,8 -12,9 +12,10 @@@ import shuti
>   from glob import glob
>   from tempfile import mkdtemp
>   from string import digits
>  +import gzip
>   
> + from elbepack.shellhelper import do
> + 
>   def size_to_int(size):
>       if size[-1] in digits:
>           return int(size)
> diff --cc elbepack/finetuning.py
> index 20d2e6612,18d9a948c..404ec771a
> --- a/elbepack/finetuning.py
> +++ b/elbepack/finetuning.py
> @@@ -9,8 -9,7 +9,9 @@@
>   from __future__ import print_function
>   
>   import os
>  +import errno
>  +import base64
> + import logging
>   
>   from shutil import rmtree
>   from gpg import core
> @@@ -23,7 -22,7 +24,8 @@@ from elbepack.shellhelper import Comman
>   from elbepack.filesystem import ImgMountFilesystem
>   from elbepack.packers import default_packer, packers
>   from elbepack.egpg import unlock_key
>  +from elbepack.junit import TestSuite, TestException
> + from elbepack.shellhelper import chroot, do, get_command_out
>   
>   
>   class FinetuningException(Exception):
> @@@ -52,16 -44,17 +54,16 @@@ class FinetuningAction(object)
>       def __init__(self, node):
>           self.node = node
>   
> -     def execute(self, _log, _buildenv, _target):
> +     def execute(self, _buildenv, _target):
>           raise NotImplementedError('execute() not implemented')
>   
> -     def execute_prj(self, log, buildenv, target, _builddir):
> -         self.execute(log, buildenv, target)
> +     def execute_prj(self, buildenv, target, _builddir):
> +         self.execute(buildenv, target)
>   
>   
>  + at FinetuningAction.register('image_finetuning', False)
>   class ImageFinetuningAction(FinetuningAction):
>   
>  -    tag = 'image_finetuning'
>  -
>       def __init__(self, node):
>           FinetuningAction.__init__(self, node)
>   
> @@@ -91,93 -85,128 +93,94 @@@ class RmAction(FinetuningAction)
>               if os.path.basename(f) in exclude:
>                   continue
>   
> -             log.do("rm -rvf '%s'" % f)
> +             do("rm -rvf '%s'" % f)
>   
>   
>  -FinetuningAction.register(RmAction)
>  -
>  -
>  + at FinetuningAction.register('mkdir')
>   class MkdirAction(FinetuningAction):
>   
>  -    tag = 'mkdir'
>  -
>       def __init__(self, node):
>           FinetuningAction.__init__(self, node)
>   
> -     def execute(self, log, _buildenv, target):
> -         log.do("mkdir -p " + target.fname(self.node.et.text))
> +     def execute(self, _buildenv, target):
> +         do("mkdir -p %s" % target.fname(self.node.et.text))
>   
>   
>  -FinetuningAction.register(MkdirAction)
>  -
>  -
>  + at FinetuningAction.register('mknod')
>   class MknodAction(FinetuningAction):
>   
>  -    tag = 'mknod'
>  -
>       def __init__(self, node):
>           FinetuningAction.__init__(self, node)
>   
> -     def execute(self, log, _buildenv, target):
> -         log.do(
> -             "mknod " +
> -             target.fname(
> -                 self.node.et.text) +
> -             " " +
> -             self.node.et.attrib['opts'])
> +     def execute(self, _buildenv, target):
> +         cmd = "mknod %s %s" % (target.fname(self.node.et.text),
> +                                self.node.et.attrib['opts'])
> +         do(cmd)
>   
>  -
>  -FinetuningAction.register(MknodAction)
>  -
>  -
>  + at FinetuningAction.register('buildenv_mkdir')
>   class BuildenvMkdirAction(FinetuningAction):
>   
>  -    tag = 'buildenv_mkdir'
>  -
>       def __init__(self, node):
>           FinetuningAction.__init__(self, node)
>   
> -     def execute(self, log, buildenv, _target):
> -         log.do("mkdir -p " + buildenv.rfs.fname(self.node.et.text))
> +     def execute(self, buildenv, _target):
> +         do("mkdir -p %s" % buildenv.rfs.fname(self.node.et.text))
>   
>   
>  -FinetuningAction.register(BuildenvMkdirAction)
>  -
>  -
>  + at FinetuningAction.register('cp')
>   class CpAction(FinetuningAction):
>   
>  -    tag = 'cp'
>  -
>       def __init__(self, node):
>           FinetuningAction.__init__(self, node)
>   
> -     def execute(self, log, _buildenv, target):
> +     def execute(self, _buildenv, target):
>           src = target.glob(self.node.et.attrib['path'])
> +         cmd = "cp -av %s {}".format(target.fname(self.node.et.text))
>           for f in src:
> -             log.do("cp -av " + f + " " + target.fname(self.node.et.text))
> +             do(cmd % f)
>   
>   
>  -FinetuningAction.register(CpAction)
>  -
>  -
>  + at FinetuningAction.register('buildenv_cp')
>   class BuildenvCpAction(FinetuningAction):
>   
>  -    tag = 'buildenv_cp'
>  -
>       def __init__(self, node):
>           FinetuningAction.__init__(self, node)
>   
> -     def execute(self, log, buildenv, _target):
> +     def execute(self, buildenv, _target):
>           src = buildenv.glob(self.node.et.attrib['path'])
> +         cmd = "cp -av %s {}".format(buildenv.rfs.fname(self.node.et.text))
>           for f in src:
> -             log.do("cp -av " + f + " " + buildenv.rfs.fname(self.node.et.text))
> +             do(cmd % f)
>   
>   
>  -FinetuningAction.register(BuildenvCpAction)
>  -
>  -
>  + at FinetuningAction.register('b2t_cp')
>   class B2TCpAction(FinetuningAction):
>   
>  -    tag = 'b2t_cp'
>  -
>       def __init__(self, node):
>           FinetuningAction.__init__(self, node)
>   
> -     def execute(self, log, buildenv, target):
> +     def execute(self, buildenv, target):
>           src = buildenv.rfs.glob(self.node.et.attrib['path'])
> +         cmd = "cp -av %s {}".format(target.fname(self.node.et.text))
>           for f in src:
> -             log.do("cp -av " + f + " " + target.fname(self.node.et.text))
> +             do(cmd % f)
>   
>   
>  -FinetuningAction.register(B2TCpAction)
>  -
>  -
>  + at FinetuningAction.register('t2b_cp')
>   class T2BCpAction(FinetuningAction):
>   
>  -    tag = 't2b_cp'
>  -
>       def __init__(self, node):
>           FinetuningAction.__init__(self, node)
>   
> -     def execute(self, log, buildenv, target):
> +     def execute(self, buildenv, target):
>           src = target.glob(self.node.et.attrib['path'])
> +         cmd = "cp -av %s {}".format(buildenv.rfs.fname(self.node.et.text))
>           for f in src:
> -             log.do("cp -av " + f + " " + buildenv.rfs.fname(self.node.et.text))
> +             do(cmd % f)
>   
>  -
>  -FinetuningAction.register(T2BCpAction)
>  -
>  -
>  + at FinetuningAction.register('t2p_mv')
>   class T2PMvAction(FinetuningAction):
>   
>  -    tag = 't2p_mv'
>  -
>       def __init__(self, node):
>           FinetuningAction.__init__(self, node)
>   
> @@@ -189,51 -218,67 +192,54 @@@
>           dest = os.path.join('..', dest)
>   
>           src = target.glob(self.node.et.attrib['path'])
> +         cmd = "mv -v %s {}".format(dest)
>           for f in src:
> -             log.do("mv -v " + f + " " + dest)
> +             do(cmd % f)
>   
>   
>  -FinetuningAction.register(T2PMvAction)
>  -
>  -
>  + at FinetuningAction.register('mv')
>   class MvAction(FinetuningAction):
>   
>  -    tag = 'mv'
>  -
>       def __init__(self, node):
>           FinetuningAction.__init__(self, node)
>   
> -     def execute(self, log, _buildenv, target):
> +     def execute(self, _buildenv, target):
>           src = target.glob(self.node.et.attrib['path'])
> +         cmd = "mv -v %s {}".format(target.fname(self.node.et.text))
>           for f in src:
> -             log.do("mv -v " + f + " " + target.fname(self.node.et.text))
> +             do(cmd % f)
>   
>   
>  -FinetuningAction.register(MvAction)
>  -
>  -
>  + at FinetuningAction.register('ln')
>   class LnAction(FinetuningAction):
>   
>  -    tag = 'ln'
>  -
>       def __init__(self, node):
>           FinetuningAction.__init__(self, node)
>   
> -     def execute(self, log, _buildenv, target):
> +     def execute(self, _buildenv, target):
>  -        with target:
>  -            cmd = """/bin/sh -c 'ln -s %s "%s"' """ % (self.node.et.attrib['path'],
>  -                                                       self.node.et.text)
>  -            chroot(target.path, cmd)
>  -
>  -FinetuningAction.register(LnAction)
>  +        target_name = self.node.et.attrib['path']
>  +        link_name = self.node.et.text
>  +        with target.protect({link_name}):
> -             log.chroot(
> -                 target.path, """/bin/sh -c 'ln -sf %s "%s"' """ %
> -                 (target_name, link_name))
> ++            chroot(target.path,
> ++                   """/bin/sh -c 'ln -sf %s "%s"' """ %
> ++                   (target_name, link_name))
>   
>   
>  + at FinetuningAction.register('buildenv_mv')
>   class BuildenvMvAction(FinetuningAction):
>   
>  -    tag = 'buildenv_mv'
>  -
>       def __init__(self, node):
>           FinetuningAction.__init__(self, node)
>   
> -     def execute(self, log, buildenv, _target):
> +     def execute(self, buildenv, _target):
>           src = buildenv.rfs.glob(self.node.et.attrib['path'])
> +         cmd = "mv -v %s {}".format(buildenv.rfs.fname(self.node.et.text))
>           for f in src:
> -             log.do("mv -v " + f + " " + buildenv.rfs.fname(self.node.et.text))
> +             do(cmd % f)
>   
>  -FinetuningAction.register(BuildenvMvAction)
>  -
>  -
>  + at FinetuningAction.register('adduser')
>   class AddUserAction(FinetuningAction):
>   
>  -    tag = 'adduser'
>  -
>       def __init__(self, node):
>           FinetuningAction.__init__(self, node)
>   
> @@@ -262,23 -307,23 +268,19 @@@
>               else:
>                   options += '-U '
>   
> -             log.chroot(
> -                 target.path,
> -                 '/usr/sbin/useradd %s "%s"' %
> -                 (options,
> -                  self.node.et.text))
> +             cmd =  '/usr/sbin/useradd %s "%s"' % (options,
> +                                                   self.node.et.text)
> +             chroot(target.path, cmd)
>   
>               if 'passwd' in att:
> -                 log.chroot(target.path,
> -                            """/bin/sh -c 'echo "%s\\n%s\\n" | passwd %s'""" % (
> -                                att['passwd'],
> -                                att['passwd'],
> -                                self.node.et.text))
> +                 cmd = "passwd %s" % self.node.et.text
> +                 stdin = "%s\n%s\n" % (att["passwd"], att["passwd"])
> +                 chroot(target.path, cmd, stdin=stdin)
>   
>   
>  -FinetuningAction.register(AddUserAction)
>  -
>  -
>  + at FinetuningAction.register('addgroup')
>   class AddGroupAction(FinetuningAction):
>   
>  -    tag = 'addgroup'
>  -
>       def __init__(self, node):
>           FinetuningAction.__init__(self, node)
>   
> @@@ -291,118 -336,78 +293,118 @@@
>                   options += '-g "%s" ' % att['gid']
>               if 'system' in att and att['system'] == 'True':
>                   options += '-r'
> -             log.chroot(target.path, '/usr/sbin/groupadd %s "%s"' % (
> -                 options,
> -                 self.node.et.text))
> +             cmd = '/usr/sbin/groupadd %s "%s"' % (options,
> +                                                   self.node.et.text)
> +             chroot(target.path, cmd)
>   
>   
>  -FinetuningAction.register(AddGroupAction)
>  + at FinetuningAction.register('file')
>  +class AddFileAction(FinetuningAction):
>   
>  +    def __init__(self, node):
>  +        FinetuningAction.__init__(self, node)
>   
>  -class RawCmdAction(FinetuningAction):
>  +    @staticmethod
>  +    def decode(text, encoding):
>  +        if encoding == "plain":
>  +            msg = "\n".join([line.lstrip(" \t") for line in text.splitlines()[1:-1]])
>  +        elif encoding == "raw":
>  +            msg = "\n".join(text.splitlines()[1:-1])
>  +        elif encoding == "base64":
>  +            msg = base64.standard_b64decode(text)
>  +        else:
>  +            raise FinetuningException("Invalid encoding %s" % encoding)
>  +        return msg
>  +
>  +    def execute(self, log, _buildenv, target):
>  +
>  +        att = self.node.et.attrib
>  +        dst = att["dst"]
>  +        content = self.node.et.text
>  +        encoding = "plain"
>  +        owner = None
>  +        group = None
>  +        mode = None
>  +
>  +        if "encoding" in att:
>  +            encoding = att["encoding"]
>  +        if "owner" in att:
>  +            owner = att["owner"]
>  +        if "group" in att:
>  +            group = att["group"]
>  +        if "mode" in att:
>  +            mode  = att["mode"]
>  +
>  +        try:
>  +            target.mkdir_p(os.path.dirname(dst))
>  +        except OSError as E:
>  +            if E.errno is not errno.EEXIST:
>  +                raise
>   
>  -    tag = 'raw_cmd'
>  +        content = AddFileAction.decode(content, encoding)
>  +
>  +        if "append" in att and att["append"] == "true":
>  +            target.append_file(dst, content)
>  +        else:
>  +            target.write_file(dst, None, content)
>  +
>  +        if owner is not None:
>  +            log.chroot(target.path, 'chown "%s" "%s"' % (owner, dst))
>  +
>  +        if group is not None:
>  +            log.chroot(target.path, 'chgrp "%s" "%s"' % (group, dst))
>  +
>  +        if mode is not None:
>  +            log.chroot(target.path, 'chmod "%s" "%s"' % (mode, dst))
>  +
>  +
>  + at FinetuningAction.register('raw_cmd')
>  +class RawCmdAction(FinetuningAction):
>   
>       def __init__(self, node):
>           FinetuningAction.__init__(self, node)
>   
> -     def execute(self, log, _buildenv, target):
> +     def execute(self, _buildenv, target):
>           with target:
> -             log.chroot(target.path, self.node.et.text)
> +             chroot(target.path, self.node.et.text)
>   
>   
>  -FinetuningAction.register(RawCmdAction)
>  -
>  -
>  + at FinetuningAction.register('command')
>   class CmdAction(FinetuningAction):
>   
>  -    tag = 'command'
>  -
>       def __init__(self, node):
>           FinetuningAction.__init__(self, node)
>   
> -     def execute(self, log, _buildenv, target):
> +     def execute(self, _buildenv, target):
>           with target:
> -             log.chroot(target.path, "/bin/sh", stdin=self.node.et.text)
> +             chroot(target.path, "/bin/sh", stdin=self.node.et.text)
>   
>   
>  -FinetuningAction.register(CmdAction)
>  -
>  -
>  + at FinetuningAction.register('buildenv_command')
>   class BuildenvCmdAction(FinetuningAction):
>   
>  -    tag = 'buildenv_command'
>  -
>       def __init__(self, node):
>           FinetuningAction.__init__(self, node)
>   
> -     def execute(self, log, buildenv, _target):
> +     def execute(self, buildenv, _target):
>           with buildenv:
> -             log.chroot(buildenv.path, "/bin/sh", stdin=self.node.et.text)
> +             chroot(buildenv.path, "/bin/sh", stdin=self.node.et.text)
>   
>   
>  -FinetuningAction.register(BuildenvCmdAction)
>  -
>  -
>  + at FinetuningAction.register('purge')
>   class PurgeAction(FinetuningAction):
>   
>  -    tag = 'purge'
>  -
>       def __init__(self, node):
>           FinetuningAction.__init__(self, node)
>   
> -     def execute(self, log, _buildenv, target):
> +     def execute(self, _buildenv, target):
>           with target:
> -             log.chroot(target.path, "dpkg --purge " + self.node.et.text)
> +             chroot(target.path, "dpkg --purge %s" % (self.node.et.text))
>   
>   
>  -FinetuningAction.register(PurgeAction)
>  -
>  -
>  + at FinetuningAction.register('updated')
>   class UpdatedAction(FinetuningAction):
>   
>  -    tag = 'updated'
>  -
>       def __init__(self, node):
>           FinetuningAction.__init__(self, node)
>   
> @@@ -513,17 -515,17 +504,17 @@@ class RmArtifactAction(FinetuningAction
>           raise NotImplementedError("<rm_artifact> may only be "
>                                     "used in <project-finetuning>")
>   
> -     def execute_prj(self, _log, _buildenv, target, _builddir):
> +     def execute_prj(self, _buildenv, target, _builddir):
>  -        target.images.remove(self.node.et.text)
>  -
>  -
>  -FinetuningAction.register(ArtifactAction)
>  +        try:
>  +            target.images.remove(self.node.et.text)
>  +        except ValueError:
>  +            raise FinetuningException("Artifact %s doesn't exist" %
>  +                                      self.node.et.text)
>   
>   
>  + at FinetuningAction.register('losetup')
>   class LosetupAction(FinetuningAction):
>   
>  -    tag = 'losetup'
>  -
>       def __init__(self, node):
>           FinetuningAction.__init__(self, node)
>   
> @@@ -540,15 -542,19 +531,15 @@@
>           try:
>               for i in self.node:
>                   action = ImageFinetuningAction(i)
> -                 action.execute_img(log, buildenv, target, builddir, loop_dev)
> +                 action.execute_img(buildenv, target, builddir, loop_dev)
>           finally:
>               cmd = 'losetup --detach "%s"' % loop_dev
> -             log.do(cmd)
> +             do(cmd)
>   
>   
>  -FinetuningAction.register(LosetupAction)
>  -
>  -
>  + at FinetuningAction.register('img_convert')
>   class ImgConvertAction(FinetuningAction):
>   
>  -    tag = 'img_convert'
>  -
>       def __init__(self, node):
>           FinetuningAction.__init__(self, node)
>   
> @@@ -676,34 -696,16 +665,33 @@@ class CopyToPartition(ImageFinetuningAc
>           img_mnt = os.path.join(builddir, 'imagemnt')
>           device = "%sp%s" % (loop_dev, part_nr)
>   
> -         with ImgMountFilesystem(img_mnt, device, log) as mnt_fs:
> +         with ImgMountFilesystem(img_mnt, device) as mnt_fs:
>               fname = mnt_fs.fname(self.node.et.text)
> - 
>               cmd = 'cp "%s" "%s"' % (os.path.join(builddir, aname), fname)
> -             log.do(cmd)
> +             do(cmd)
>   
>   
>  -FinetuningAction.register(CopyToPartition)
>  + at FinetuningAction.register("unit-tests")
>  +class TestSuites(FinetuningAction):
>  +
>  +    elbe_junit = "elbe-junit.xml"
>  +
> -     def execute_prj(self, log, buildenv, target, builddir):
> ++    def execute_prj(self, buildenv, target, builddir):
>  +
>  +        tss = []
>  +        output = os.path.join(builddir, elbe_junit)
>  +        target.images.append(elbe_junit)
>  +
>  +        for test_suite in self.node:
>  +            ts = TestSuite(test_suite, target)
>  +            try:
>  +                tss.append(ts())
>  +            except TestException as E:
> -                 log.printo(str(E))
> ++                logging.exception(str(E))
>   
>  +        TestSuite.to_file(output, tss)
>   
> - def do_finetuning(xml, log, buildenv, target):
> + def do_finetuning(xml, buildenv, target):
>   
>       if not xml.has('target/finetuning'):
>           return
> @@@ -729,12 -731,12 +717,15 @@@ def do_prj_finetuning(xml, buildenv, ta
>       for i in xml.node('target/project-finetuning'):
>           try:
>               action = FinetuningAction(i)
> -             action.execute_prj(log, buildenv, target, builddir)
> +             action.execute_prj(buildenv, target, builddir)
> +         except KeyError:
> +             logging.exception("Unimplemented project-finetuning action '%s'",
> +                               i.et.tag)
>           except CommandError:
> -             log.printo("ProjectFinetuning Error, trying to continue anyways")
> -         except FinetuningException as e:
> -             log.printo("ProjectFinetuning Error: %s" % e)
> -             log.printo("trying to continue anyways")
> +             logging.exception("ProjectFinetuning Error, trying to continue anyways")
> +         except FinetuningException:
> +             logging.exception("Finetuning Error\n"
> +                               "Trying to continue anyways")
>  +        except Exception as e:
> -             log.printo(str(e))
> ++            logging.exception(str(e))
>  +            raise
> diff --cc elbepack/fstab.py
> index 0cd569c6a,bd6d9a180..8c938e4f7
> --- a/elbepack/fstab.py
> +++ b/elbepack/fstab.py
> @@@ -139,10 -139,6 +140,10 @@@ class fstabentry(object)
>           self.partnum = ppart.number
>           self.number = '{}{}'.format(disk.type, ppart.number)
>   
> -     def losetup(self, outf, loopdev):
> -         outf.do('losetup -o%d --sizelimit %d /dev/%s "%s"' %
> -                 (self.offset, self.size, loopdev, self.filename))
> +     def losetup(self, loopdev):
> +         do('losetup -o%d --sizelimit %d /dev/%s "%s"' %
> +            (self.offset, self.size, loopdev, self.filename))
>  +
>  +    def tuning(self, loopdev):
>  +        if self.tune:
> -             system('tune2fs "%s" %s' % (self.tune, loopdev))
> ++            do('tune2fs "%s" %s' % (self.tune, loopdev))
> diff --cc elbepack/hdimg.py
> index 58052e5aa,340934235..5c8ef6d84
> --- a/elbepack/hdimg.py
> +++ b/elbepack/hdimg.py
> @@@ -15,11 -15,11 +15,11 @@@ import parte
>   import _ped
>   
>   from elbepack.fstab import fstabentry, mountpoint_dict
> - from elbepack.asciidoclog import CommandError
>  -from elbepack.filesystem import size_to_int
>  +from elbepack.filesystem import Filesystem, size_to_int
> + from elbepack.shellhelper import do, CommandError, chroot
>   
>   
> - def mkfs_mtd(outf, mtd, fslabel, target):
> + def mkfs_mtd(mtd, fslabel, target):
>   
>       # generated files
>       img_files = []
> @@@ -144,13 -145,21 +145,12 @@@ def build_image_mtd(mtd, target)
>   
>   
>   class grubinstaller_base(object):
> -     def __init__(self, outf, fw_type=None):
> -         self.outf = outf
> +     def __init__(self, fw_type=None):
>  -        self.root = None
>  -        self.boot = None
>  -        self.boot_efi = None
>  -        self.fw_type = fw_type
>  +        self.fs = mountpoint_dict()
>  +        self.fw_type = fw_type if fw_type else []
>   
>  -    def set_boot_entry(self, entry):
>  -        print("setting boot entry")
>  -        self.boot = entry
>  -
>  -    def set_boot_efi_entry(self, entry):
>  -        self.boot_efi = entry
>  -
>  -    def set_root_entry(self, entry):
>  -        self.root = entry
>  +    def add_fs_entry(self, entry):
>  +        self.fs[entry.mountpoint] = entry
>   
>       def install(self, target):
>           pass
> @@@ -163,78 -172,121 +163,62 @@@ class grubinstaller202(grubinstaller_ba
>               return
>   
>           imagemnt = os.path.join(target, "imagemnt")
>  +        imagemntfs = Filesystem(imagemnt)
>           try:
> -             self.outf.do('cp -a /dev/loop0 /dev/poop0')
> +             do('cp -a /dev/loop0 /dev/poop0')
>  -            do('losetup /dev/poop0 "%s"' % self.root.filename)
>  +
> -             self.outf.do('losetup /dev/poop0 "%s"' % self.fs['/'].filename)
> -             self.outf.do('kpartx -as /dev/poop0')
> ++            do('losetup /dev/poop0 "%s"' % self.fs['/'].filename)
> +             do('kpartx -as /dev/poop0')
>  -            do('mount /dev/mapper/poop0p%d %s' %
>  -               (self.root.partnum, imagemnt))
>   
>  -            if self.boot:
>  +            for entry in self.fs.depthlist():
> -                 self.outf.do(
> -                     'mount /dev/mapper/poop0p%d %s' %
> -                     (entry.partnum, imagemntfs.fname(entry.mountpoint)))
> - 
> -             self.outf.do(
> -                 "mount --bind /dev %s" %
> -                 imagemntfs.fname("dev"))
> -             self.outf.do(
> -                 "mount --bind /proc %s" %
> -                 imagemntfs.fname("proc"))
> -             self.outf.do(
> -                 "mount --bind /sys %s" %
> -                 imagemntfs.fname("sys"))
> - 
> -             self.outf.do('mkdir -p "%s"' % imagemntfs.fname("boot/grub"))
> +                 do('mount /dev/mapper/poop0p%d %s' %
>  -                   (self.boot.partnum, os.path.join(imagemnt, "boot")))
> ++                   (entry.partnum, imagemntfs.fname(entry.mountpoint)))
> + 
>  -            if self.boot_efi:
>  -                do('mount /dev/mapper/poop0p%d %s' %
>  -                   (self.boot_efi.partnum, os.path.join(imagemnt, "boot/efi")))
> ++            do("mount --bind /dev %s" % imagemntfs.fname("dev"))
> ++            do("mount --bind /proc %s" % imagemntfs.fname("proc"))
> ++            do("mount --bind /sys %s" % imagemntfs.fname("sys"))
> + 
>  -            do("mount --bind /dev %s" % os.path.join(imagemnt, "dev"))
>  -            do("mount --bind /proc %s" % os.path.join(imagemnt, "proc"))
>  -            do("mount --bind /sys %s" % os.path.join(imagemnt, "sys"))
>  -            do('mkdir -p "%s"' % os.path.join(imagemnt, "boot/grub"))
> ++            do('mkdir -p "%s"' % imagemntfs.fname("boot/grub"))
>   
>  -            devmap = open(os.path.join(imagemnt, "boot/grub/device.map"), "w")
>  +            devmap = open(imagemntfs.fname("boot/grub/device.map"), "w")
>               devmap.write("(hd0) /dev/poop0\n")
>               devmap.close()
>   
> -             self.outf.do("chroot %s  update-initramfs -u -k all" % imagemnt)
> -             self.outf.do("chroot %s  update-grub2" % imagemnt)
> +             chroot(imagemnt, "update-initramfs -u -k all")
> +             chroot(imagemnt, "update-grub2")
>   
>  -            if self.fw_type == "efi" or self.fw_type == "hybrid":
>  -                chroot(imagemnt, "grub-install --target=x86_64-efi --removable "
>  -                       "--no-floppy /dev/poop0")
>  -
>  -            if self.fw_type == "hybrid" or self.fw_type is None:
>  -                # when we are in hybrid mode, install grub also into MBR
>  -                chroot(imagemnt, "grub-install --no-floppy /dev/poop0")
>  +            if "efi" in self.fw_type:
>  +                grub_tgt = next(t for t in self.fw_type if t.endswith("-efi"))
> -                 self.outf.do(
> -                     "chroot %s grub-install --target=%s --removable "
> -                     "--no-floppy /dev/poop0" %
> -                     (imagemnt, grub_tgt))
> ++                do("chroot %s grub-install --target=%s --removable "
> ++                   "--no-floppy /dev/poop0" %
> ++                   (imagemnt, grub_tgt))
>  +            if "shimfix" in self.fw_type:
>  +                # grub-install is heavily dependent on the running system having
>  +                # a BIOS or EFI.  The initvm is BIOS-based, so fix the resulting
>  +                # shim installation.
> -                 self.outf.do("chroot %s  /bin/bash -c '"
> -                              "cp -r /boot/efi/EFI/BOOT /boot/efi/EFI/debian && "
> -                              "cd /usr/lib/shim && f=( shim*.efi.signed ) && cp "
> -                              "${f[0]} /boot/efi/EFI/debian/${f[0]%%.signed}'"  %
> -                              imagemnt)
> ++                do("chroot %s  /bin/bash -c '"
> ++                   "cp -r /boot/efi/EFI/BOOT /boot/efi/EFI/debian && "
> ++                   "cd /usr/lib/shim && f=( shim*.efi.signed ) && cp "
> ++                   "${f[0]} /boot/efi/EFI/debian/${f[0]%%.signed}'"  %
> ++                   imagemnt)
>  +            if not self.fw_type or "bios" in self.fw_type:
> -                 self.outf.do(
> -                     "chroot %s grub-install --no-floppy /dev/poop0" %
> -                     (imagemnt))
> ++                do("chroot %s grub-install --no-floppy /dev/poop0" %
> ++                   (imagemnt))
>   
>           finally:
>  -            os.unlink(os.path.join(imagemnt, "boot/grub/device.map"))
>  +            os.unlink(imagemntfs.fname("boot/grub/device.map"))
> -             self.outf.do(
> -                 "umount %s" % imagemntfs.fname("dev"),
> -                 allow_fail=True)
> -             self.outf.do(
> -                 "umount %s" % imagemntfs.fname("proc"),
> -                 allow_fail=True)
> -             self.outf.do(
> -                 "umount %s" % imagemntfs.fname("sys"),
> -                 allow_fail=True)
> ++            do("umount %s" % imagemntfs.fname("dev"), allow_fail=True)
> ++            do("umount %s" % imagemntfs.fname("proc"), allow_fail=True)
> ++            do("umount %s" % imagemntfs.fname("sys"), allow_fail=True)
>   
>  -            do("umount %s" % os.path.join(imagemnt, "dev"), allow_fail=True)
>  -            do("umount %s" % os.path.join(imagemnt, "proc"), allow_fail=True)
>  -            do("umount %s" % os.path.join(imagemnt, "sys"), allow_fail=True)
>  -
>  -            if self.boot_efi:
>  -                do('umount /dev/mapper/poop0p%d' %
>  -                   self.boot_efi.partnum, allow_fail=True)
>  -
>  -            if self.boot:
>  -                do('umount /dev/mapper/poop0p%d' %
>  -                   self.boot.partnum, allow_fail=True)
>  -
>  -            do('umount /dev/mapper/poop0p%d' % self.root.partnum,
>  -               allow_fail=True)
>  +            for entry in reversed(self.fs.depthlist()):
> -                 self.outf.do(
> -                     'umount /dev/mapper/poop0p%d' %
> -                     entry.partnum, allow_fail=True)
> ++                do('umount /dev/mapper/poop0p%d' % entry.partnum,
> ++                   allow_fail=True)
>   
> -             self.outf.do('kpartx -d /dev/poop0', allow_fail=True)
> -             self.outf.do("losetup -d /dev/poop0", allow_fail=True)
> +             do('kpartx -d /dev/poop0', allow_fail=True)
> +             do("losetup -d /dev/poop0", allow_fail=True)
>   
>   
>  -class grubinstaller199(grubinstaller_base):
>  -
>  -    def install(self, target):
>  -        if not self.root:
>  -            return
>  -
>  -        imagemnt = os.path.join(target, "imagemnt")
>  -        try:
>  -            do('cp -a /dev/loop0 /dev/poop0')
>  -            do('cp -a /dev/loop1 /dev/poop1')
>  -            do('cp -a /dev/loop2 /dev/poop2')
>  -
>  -            do('losetup /dev/poop0 "%s"' % self.root.filename)
>  -            self.root.losetup("poop1")
>  -            do('mount /dev/poop1 %s' % imagemnt)
>  -
>  -            if self.boot:
>  -                self.boot.losetup("poop2")
>  -                do('mount /dev/poop2 %s' %
>  -                             (os.path.join(imagemnt, "boot")))
>  -
>  -            devmap = open(os.path.join(imagemnt, "boot/grub/device.map"), "w")
>  -            devmap.write("(hd0) /dev/poop0\n")
>  -            devmap.write("(hd0,%s) /dev/poop1\n" % self.root.number)
>  -            if self.boot:
>  -                devmap.write("(hd0,%s) /dev/poop2\n" % self.boot.number)
>  -
>  -            devmap.close()
>  -
>  -            do("mount --bind /dev %s" % os.path.join(imagemnt, "dev"))
>  -            do("mount --bind /proc %s" % os.path.join(imagemnt, "proc"))
>  -            do("mount --bind /sys %s" % os.path.join(imagemnt, "sys"))
>  -            chroot(imagemnt, "update-initramfs -u -k all")
>  -            chroot(imagemnt, "update-grub2")
>  -            chroot(imagemnt, "grub-install --no-floppy /dev/loop0")
>  -
>  -        finally:
>  -            os.unlink(os.path.join(imagemnt, "boot/grub/device.map"))
>  -
>  -            do("umount -l %s" % os.path.join(imagemnt, "dev"),
>  -               allow_fail=True)
>  -
>  -            do("umount -l %s" % os.path.join(imagemnt, "proc"),
>  -               allow_fail=True)
>  -
>  -            do("umount -l %s" % os.path.join(imagemnt, "sys"),
>  -               allow_fail=True)
>  -
>  -            do("losetup -d /dev/poop0", allow_fail=True)
>  -
>  -            if self.boot:
>  -                do('umount /dev/poop2', allow_fail=True)
>  -                do('losetup -d /dev/poop2', allow_fail=True)
>  -
>  -            do('umount /dev/poop1', allow_fail=True)
>  -            do('losetup -d /dev/poop1', allow_fail=True)
>  -
>  -
>   class simple_fstype(object):
>       def __init__(self, typ):
>           self.type = typ
> @@@ -289,24 -341,27 +273,22 @@@ def create_label(disk, part, ppart, fsl
>       entry = fslabel[part.text("label")]
>       entry.set_geometry(ppart, disk)
>   
>  -    if entry.mountpoint == "/":
>  -        grub.set_root_entry(entry)
>  -    elif entry.mountpoint == "/boot":
>  -        grub.set_boot_entry(entry)
>  -    elif entry.mountpoint == "/boot/efi":
>  -        grub.set_boot_efi_entry(entry)
>  +    grub.add_fs_entry(entry)
>   
> -     entry.losetup(outf, "loop0")
> -     outf.do(
> -         'mkfs.%s %s %s /dev/loop0' %
> -         (entry.fstype,
> -          entry.mkfsopt,
> -          entry.get_label_opt()))
> - 
> -     outf.do('mount /dev/loop0 %s' % os.path.join(target, "imagemnt"))
> -     outf.do(
> -         'cp -a "%s/." "%s/"' %
> -         (os.path.join(
> -             target, "filesystems", entry.id), os.path.join(
> -             target, "imagemnt")), allow_fail=True)
> +     entry.losetup("loop0")
>  -
> +     do('mkfs.%s %s %s /dev/loop0' %
> +        (entry.fstype,
> +         entry.mkfsopt,
> +         entry.get_label_opt()))
> + 
> +     do('mount /dev/loop0 %s' % os.path.join(target, "imagemnt"))
> +     do('cp -a "%s/." "%s/"' %
> +        (os.path.join(target, "filesystems", entry.id),
> +         os.path.join(target, "imagemnt")),
> +        allow_fail=True)
>  +    entry.tuning("/dev/loop0")
> -     outf.do('umount /dev/loop0')
> -     outf.do('losetup -d /dev/loop0')
> +     do('umount /dev/loop0')
> +     do('losetup -d /dev/loop0')
>   
>       return ppart
>   
> @@@ -365,10 -418,16 +345,10 @@@ def do_image_hd(hd, fslabel, target, gr
>       else:
>           disk = parted.freshDisk(imag, "msdos")
>   
>  -    if grub_version == 199:
>  -        grub = grubinstaller199()
>  -    elif grub_version == 202 and grub_fw_type == "efi":
>  -        grub = grubinstaller202("efi")
>  -    elif grub_version == 202 and grub_fw_type == "hybrid":
>  -        grub = grubinstaller202("hybrid")
>  -    elif grub_version == 202:
>  -        grub = grubinstaller202()
>  +    if grub_version == 202:
> -         grub = grubinstaller202(outf, grub_fw_type)
> ++        grub = grubinstaller202(grub_fw_type)
>       else:
> -         grub = grubinstaller_base(outf)
> +         grub = grubinstaller_base()
>   
>       current_sector = 2048
>       for part in hd:
> diff --cc elbepack/pkgutils.py
> index 595ecc318,e639a8315..155cc050e
> --- a/elbepack/pkgutils.py
> +++ b/elbepack/pkgutils.py
> @@@ -8,12 -8,12 +8,14 @@@
>   from __future__ import print_function
>   
>   import os
>  +import re
> + import logging
>   
>   from apt_pkg import TagFile
> - 
> + from elbepack.shellhelper import CommandError, system, do
> + from elbepack.virtapt import get_virtaptcache
> + from elbepack.hashes import validate_sha256, HashValidationFailed
>  +from elbepack.filesystem import TmpdirFilesystem
> - from elbepack.shellhelper import system
>   
>   
>   class NoPackageException(Exception):
> diff --cc elbepack/repomanager.py
> index 18fa6926f,c2d455024..005bcea92
> --- a/elbepack/repomanager.py
> +++ b/elbepack/repomanager.py
> @@@ -309,16 -290,15 +285,15 @@@ class RepoBase(object)
>           files = []
>           if self.volume_count == 0:
>               new_path = '"' + self.fs.path + '"'
> -             self.log.do("genisoimage %s -o %s -J -joliet-long -R %s" %
> -                         (options, fname, new_path))
>  -            do("genisoimage -o %s -J -joliet-long -R %s" %
>  -               (fname, new_path))
> ++            do("genisoimage %s -o %s -J -joliet-long -R %s" %
> ++               (options, fname, new_path))
>               files.append(fname)
>           else:
>               for i in range(self.volume_count + 1):
>                   volfs = self.get_volume_fs(i)
>                   newname = fname + ("%02d" % i)
> -                 self.log.do(
> -                     "genisoimage %s -o %s -J -joliet-long -R %s" %
> -                     (options, newname, volfs.path))
>  -                do("genisoimage -o %s -J -joliet-long -R %s" %
>  -                   (newname, volfs.path))
> ++                do("genisoimage %s -o %s -J -joliet-long -R %s" %
> ++                   (options, newname, volfs.path))
>                   files.append(newname)
>   
>           return files
> diff --cc elbepack/rfs.py
> index e12051e0f,b3c86344e..0f33eaae0
> --- a/elbepack/rfs.py
> +++ b/elbepack/rfs.py
> @@@ -14,47 -15,9 +15,47 @@@ import loggin
>   from elbepack.efilesystem import BuildImgFs
>   from elbepack.templates import (write_pack_template, get_preseed,
>                                   preseed_to_text)
> - from elbepack.shellhelper import CommandError
> + from elbepack.shellhelper import CommandError, do, chroot, get_command_out
>   
>   
>  +def create_apt_prefs(xml, rfs):
>  +
>  +    filename =  "etc/apt/preferences"
>  +
>  +    if rfs.lexists(filename):
>  +        rfs.remove(filename)
>  +
>  +    rfs.mkdir_p("/etc/apt")
>  +
>  +    pinned_origins = []
>  +    if xml.has('project/mirror/url-list'):
>  +        for url in xml.node('project/mirror/url-list'):
>  +            if not url.has('binary'):
>  +                continue
>  +
>  +            repo = url.node('binary')
>  +            if 'pin' not in repo.et.attrib:
>  +                continue
>  +
>  +            origin = urlparse.urlsplit(repo.et.text.strip()).hostname
>  +            pin = repo.et.attrib['pin']
>  +            if 'package' in repo.et.attrib:
>  +                package = repo.et.attrib['package']
>  +            else:
>  +                package = '*'
>  +            pinning = {'pin': pin,
>  +                       'origin': origin,
>  +                       'package': package}
>  +            pinned_origins.append(pinning)
>  +
>  +    d = {"xml": xml,
>  +         "prj": xml.node("/project"),
>  +         "pkgs": xml.node("/target/pkg-list"),
>  +         "porgs": pinned_origins}
>  +
>  +    write_pack_template(rfs.fname(filename), "preferences.mako", d)
>  +
>  +
>   class DebootstrapException (Exception):
>       def __init__(self):
>           Exception.__init__(self, "Debootstrap Failed")
> @@@ -308,10 -263,46 +306,10 @@@ class BuildEnv (object)
>           preseed_txt = preseed_to_text(preseed)
>           self.rfs.write_file("var/cache/elbe/preseed.txt", 0o644, preseed_txt)
>           with self.rfs:
> -             self.log.chroot(
> -                 self.rfs.path, 'debconf-set-selections < %s' %
> -                 self.rfs.fname("var/cache/elbe/preseed.txt"))
> +             cmd = ('debconf-set-selections < %s' %
> +                    self.rfs.fname("var/cache/elbe/preseed.txt"))
> +             chroot(self.rfs.path, cmd)
>   
>  -    def create_apt_prefs(self):
>  -
>  -        filename = self.rfs.path + "/etc/apt/preferences"
>  -
>  -        if os.path.exists(filename):
>  -            os.remove(filename)
>  -
>  -        self.rfs.mkdir_p("/etc/apt")
>  -
>  -        pinned_origins = []
>  -        if self.xml.has('project/mirror/url-list'):
>  -            for url in self.xml.node('project/mirror/url-list'):
>  -                if not url.has('binary'):
>  -                    continue
>  -
>  -                repo = url.node('binary')
>  -                if 'pin' not in repo.et.attrib:
>  -                    continue
>  -
>  -                origin = urlparse.urlsplit(repo.et.text.strip()).hostname
>  -                pin = repo.et.attrib['pin']
>  -                if 'package' in repo.et.attrib:
>  -                    package = repo.et.attrib['package']
>  -                else:
>  -                    package = '*'
>  -                pinning = {'pin': pin,
>  -                           'origin': origin,
>  -                           'package': package}
>  -                pinned_origins.append(pinning)
>  -
>  -        d = {"xml": self.xml,
>  -             "prj": self.xml.node("/project"),
>  -             "pkgs": self.xml.node("/target/pkg-list"),
>  -             "porgs": pinned_origins}
>  -
>  -        write_pack_template(filename, "preferences.mako", d)
>   
>       def seed_etc(self):
>           passwd = self.xml.text("target/passwd")
> diff --cc elbepack/updatepkg.py
> index 4c848a55c,6e3735642..74ce2243f
> --- a/elbepack/updatepkg.py
> +++ b/elbepack/updatepkg.py
> @@@ -14,7 -13,7 +13,7 @@@ from elbepack.elbexml import ElbeXM
>   from elbepack.dump import dump_fullpkgs
>   from elbepack.ziparchives import create_zip_archive
>   from elbepack.repomanager import UpdateRepo
> - from elbepack.shellhelper import system
>  -from elbepack.shellhelper import do
> ++from elbepack.shellhelper import system, do
>   
>   
>   class MissingData(Exception):
> -----------------------------------------------------------------------------------------
> 



More information about the elbe-devel mailing list