clean up command execution
Switch to using execWith* so that the command and its output can be logged. To capture the output setup a logger named "program" livemedia-creator captures all of this into program.log
This commit is contained in:
		
							parent
							
								
									994ff776c7
								
							
						
					
					
						commit
						134eec24d5
					
				| @ -30,7 +30,7 @@ import os | ||||
| import ConfigParser | ||||
| import tempfile | ||||
| import locale | ||||
| import subprocess | ||||
| from subprocess import CalledProcessError | ||||
| import selinux | ||||
| 
 | ||||
| from base import BaseLoraxClass, DataHolder | ||||
| @ -47,6 +47,7 @@ from treebuilder import RuntimeBuilder, TreeBuilder | ||||
| from buildstamp import BuildStamp | ||||
| from treeinfo import TreeInfo | ||||
| from discinfo import DiscInfo | ||||
| from executils import execWithRedirect | ||||
| 
 | ||||
| class ArchData(DataHolder): | ||||
|     lib64_arches = ("x86_64", "ppc64", "sparc64", "s390x", "ia64") | ||||
| @ -140,8 +141,8 @@ class Lorax(BaseLoraxClass): | ||||
| 
 | ||||
|         if domacboot: | ||||
|             try: | ||||
|                 subprocess.check_call(["rpm", "-q", "hfsplus-tools"]) | ||||
|             except subprocess.CalledProcessError: | ||||
|                 execWithRedirect("rpm", ["-q", "hfsplus-tools"]) | ||||
|             except CalledProcessError: | ||||
|                 logger.critical("you need to install hfsplus-tools to create mac images") | ||||
|                 sys.exit(1) | ||||
| 
 | ||||
|  | ||||
| @ -70,9 +70,11 @@ class tee(threading.Thread): | ||||
| # @param stdout The file descriptor to redirect stdout to. | ||||
| # @param stderr The file descriptor to redirect stderr to. | ||||
| # @param root The directory to chroot to before running command. | ||||
| # @param preexec_fn function to pass to Popen | ||||
| # @param cwd working directory to pass to Popen | ||||
| # @return The return code of command. | ||||
| def execWithRedirect(command, argv, stdin = None, stdout = None, | ||||
|                      stderr = None, root = '/'): | ||||
|                      stderr = None, root = None, preexec_fn=None, cwd=None): | ||||
|     def chroot (): | ||||
|         os.chroot(root) | ||||
| 
 | ||||
| @ -115,6 +117,13 @@ def execWithRedirect(command, argv, stdin = None, stdout = None, | ||||
|     env = os.environ.copy() | ||||
|     env.update({"LC_ALL": "C"}) | ||||
| 
 | ||||
|     if root: | ||||
|         preexec_fn = chroot | ||||
|         cwd = root | ||||
|         program_log.info("chrooting into %s" % (cwd,)) | ||||
|     elif cwd: | ||||
|         program_log.info("chdiring into %s" % (cwd,)) | ||||
| 
 | ||||
|     try: | ||||
|         #prepare tee proceses | ||||
|         proc_std = tee(pstdout, stdout, program_log.info, command) | ||||
| @ -127,7 +136,7 @@ def execWithRedirect(command, argv, stdin = None, stdout = None, | ||||
|         proc = subprocess.Popen([command] + argv, stdin=stdin, | ||||
|                                 stdout=pstdin, | ||||
|                                 stderr=perrin, | ||||
|                                 preexec_fn=chroot, cwd=root, | ||||
|                                 preexec_fn=preexec_fn, cwd=cwd, | ||||
|                                 env=env) | ||||
| 
 | ||||
|         proc.wait() | ||||
| @ -170,8 +179,10 @@ def execWithRedirect(command, argv, stdin = None, stdout = None, | ||||
| # @param stdin The file descriptor to read stdin from. | ||||
| # @param stderr The file descriptor to redirect stderr to. | ||||
| # @param root The directory to chroot to before running command. | ||||
| # @param preexec_fn function to pass to Popen | ||||
| # @param cwd working directory to pass to Popen | ||||
| # @return The output of command from stdout. | ||||
| def execWithCapture(command, argv, stdin = None, stderr = None, root='/'): | ||||
| def execWithCapture(command, argv, stdin = None, stderr = None, root=None, preexec_fn=None, cwd=None): | ||||
|     def chroot(): | ||||
|         os.chroot(root) | ||||
| 
 | ||||
| @ -207,11 +218,18 @@ def execWithCapture(command, argv, stdin = None, stderr = None, root='/'): | ||||
|     env = os.environ.copy() | ||||
|     env.update({"LC_ALL": "C"}) | ||||
| 
 | ||||
|     if root: | ||||
|         preexec_fn = chroot | ||||
|         cwd = root | ||||
|         program_log.info("chrooting into %s" % (cwd,)) | ||||
|     elif cwd: | ||||
|         program_log.info("chdiring into %s" % (cwd,)) | ||||
| 
 | ||||
|     try: | ||||
|         proc = subprocess.Popen([command] + argv, stdin=stdin, | ||||
|                                 stdout=subprocess.PIPE, | ||||
|                                 stderr=subprocess.PIPE, | ||||
|                                 preexec_fn=chroot, cwd=root, | ||||
|                                 preexec_fn=preexec_fn, cwd=cwd, | ||||
|                                 env=env) | ||||
| 
 | ||||
|         while True: | ||||
|  | ||||
| @ -22,12 +22,14 @@ logger = logging.getLogger("pylorax.imgutils") | ||||
| 
 | ||||
| import os, tempfile | ||||
| from os.path import join, dirname | ||||
| from pylorax.sysutils import cpfile | ||||
| from subprocess import * | ||||
| from subprocess import CalledProcessError | ||||
| import sys | ||||
| import traceback | ||||
| from time import sleep | ||||
| 
 | ||||
| from pylorax.sysutils import cpfile | ||||
| from pylorax.executils import execWithRedirect, execWithCapture | ||||
| 
 | ||||
| ######## Functions for making container images (cpio, squashfs) ########## | ||||
| 
 | ||||
| def mkcpio(rootdir, outfile, compression="xz", compressargs=["-9"]): | ||||
| @ -36,7 +38,6 @@ def mkcpio(rootdir, outfile, compression="xz", compressargs=["-9"]): | ||||
|     compressargs will be used on the compression commandline.''' | ||||
|     if compression not in (None, "xz", "gzip", "lzma"): | ||||
|         raise ValueError, "Unknown compression type %s" % compression | ||||
|     chdir = lambda: os.chdir(rootdir) | ||||
|     if compression == "xz": | ||||
|         compressargs.insert(0, "--check=crc32") | ||||
|     if compression is None: | ||||
| @ -44,9 +45,9 @@ def mkcpio(rootdir, outfile, compression="xz", compressargs=["-9"]): | ||||
|         compressargs = [] | ||||
|     logger.debug("mkcpio %s | %s %s > %s", rootdir, compression, | ||||
|                                         " ".join(compressargs), outfile) | ||||
|     find = Popen(["find", ".", "-print0"], stdout=PIPE, preexec_fn=chdir) | ||||
|     find = Popen(["find", ".", "-print0"], stdout=PIPE, cwd=rootdir) | ||||
|     cpio = Popen(["cpio", "--null", "--quiet", "-H", "newc", "-o"], | ||||
|                  stdin=find.stdout, stdout=PIPE, preexec_fn=chdir) | ||||
|                  stdin=find.stdout, stdout=PIPE, cwd=rootdir) | ||||
|     comp = Popen([compression] + compressargs, | ||||
|                  stdin=cpio.stdout, stdout=open(outfile, "wb")) | ||||
|     comp.wait() | ||||
| @ -56,9 +57,7 @@ def mksquashfs(rootdir, outfile, compression="default", compressargs=[]): | ||||
|     '''Make a squashfs image containing the given rootdir.''' | ||||
|     if compression != "default": | ||||
|         compressargs = ["-comp", compression] + compressargs | ||||
|     cmd = ["mksquashfs", rootdir, outfile] + compressargs | ||||
|     logger.debug(" ".join(cmd)) | ||||
|     return call(cmd) | ||||
|     return execWithRedirect("mksquashfs", [rootdir, outfile] + compressargs) | ||||
| 
 | ||||
| ######## Utility functions ############################################### | ||||
| 
 | ||||
| @ -70,17 +69,17 @@ def mksparse(outfile, size): | ||||
| def loop_attach(outfile): | ||||
|     '''Attach a loop device to the given file. Return the loop device name. | ||||
|     Raises CalledProcessError if losetup fails.''' | ||||
|     dev = check_output(["losetup", "--find", "--show", outfile], stderr=PIPE) | ||||
|     dev = execWithCapture("losetup", ["--find", "--show", outfile]) | ||||
|     return dev.strip() | ||||
| 
 | ||||
| def loop_detach(loopdev): | ||||
|     '''Detach the given loop device. Return False on failure.''' | ||||
|     return (call(["losetup", "--detach", loopdev]) == 0) | ||||
|     return (execWithRedirect("losetup", ["--detach", loopdev]) == 0) | ||||
| 
 | ||||
| def get_loop_name(path): | ||||
|     '''Return the loop device associated with the path. | ||||
|     Raises RuntimeError if more than one loop is associated''' | ||||
|     buf = check_output(["losetup", "-j", path], stderr=PIPE) | ||||
|     buf = execWithCapture("losetup", ["-j", path]) | ||||
|     if len(buf.splitlines()) > 1: | ||||
|         # there should never be more than one loop device listed | ||||
|         raise RuntimeError("multiple loops associated with %s" % path) | ||||
| @ -93,15 +92,14 @@ def dm_attach(dev, size, name=None): | ||||
|     raises CalledProcessError if dmsetup fails.''' | ||||
|     if name is None: | ||||
|         name = tempfile.mktemp(prefix="lorax.imgutils.", dir="") | ||||
|     check_call(["dmsetup", "create", name, "--table", | ||||
|                 "0 %i linear %s 0" % (size/512, dev)], | ||||
|                 stdout=PIPE, stderr=PIPE) | ||||
|     execWithRedirect("dmsetup", ["create", name, "--table", | ||||
|                                  "0 %i linear %s 0" % (size/512, dev)]) | ||||
|     return name | ||||
| 
 | ||||
| def dm_detach(dev): | ||||
|     '''Detach the named devicemapper device. Returns False if dmsetup fails.''' | ||||
|     dev = dev.replace("/dev/mapper/", "") # strip prefix, if it's there | ||||
|     return call(["dmsetup", "remove", dev], stdout=PIPE, stderr=PIPE) | ||||
|     return execWithRedirect("dmsetup", ["remove", dev]) | ||||
| 
 | ||||
| def mount(dev, opts="", mnt=None): | ||||
|     '''Mount the given device at the given mountpoint, using the given opts. | ||||
| @ -116,8 +114,7 @@ def mount(dev, opts="", mnt=None): | ||||
|     if opts: | ||||
|         mount += ["-o", opts] | ||||
|     mount += [dev, mnt] | ||||
|     logger.debug(" ".join(mount)) | ||||
|     check_call(mount) | ||||
|     execWithRedirect(mount[0], mount[1:]) | ||||
|     return mnt | ||||
| 
 | ||||
| def umount(mnt,  lazy=False, maxretry=3, retrysleep=1.0): | ||||
| @ -127,11 +124,10 @@ def umount(mnt,  lazy=False, maxretry=3, retrysleep=1.0): | ||||
|     umount = ["umount"] | ||||
|     if lazy: umount += ["-l"] | ||||
|     umount += [mnt] | ||||
|     logger.debug(" ".join(umount)) | ||||
|     count = 0 | ||||
|     while maxretry > 0: | ||||
|         try: | ||||
|             rv = check_call(umount) | ||||
|             rv = execWithRedirect(umount[0], umount[1:]) | ||||
|         except CalledProcessError: | ||||
|             count += 1 | ||||
|             if count == maxretry: | ||||
| @ -139,8 +135,7 @@ def umount(mnt,  lazy=False, maxretry=3, retrysleep=1.0): | ||||
|             logger.warn("failed to unmount %s. retrying (%d/%d)...", | ||||
|                          mnt, count, maxretry) | ||||
|             if logger.getEffectiveLevel() <= logging.DEBUG: | ||||
|                 fuser = check_output(["fuser", "-vm", mnt], | ||||
|                                      stderr=STDOUT) | ||||
|                 fuser = execWithCapture("fuser", ["-vm", mnt]) | ||||
|                 logger.debug("fuser -vm:\n%s\n", fuser) | ||||
|             sleep(retrysleep) | ||||
|         else: | ||||
| @ -155,9 +150,9 @@ def copytree(src, dest, preserve=True): | ||||
|     links, acls, sparse files, xattrs, selinux contexts, etc. | ||||
|     If preserve is False, uses cp -R (useful for modeless filesystems)''' | ||||
|     logger.debug("copytree %s %s", src, dest) | ||||
|     chdir = lambda: os.chdir(src) | ||||
|     cp = ["cp", "-a"] if preserve else ["cp", "-R", "-L"] | ||||
|     check_call(cp + [".", os.path.abspath(dest)], preexec_fn=chdir) | ||||
|     cp += [".", os.path.abspath(dest)] | ||||
|     execWithRedirect(cp[0], cp[1:], cwd=src) | ||||
| 
 | ||||
| def do_grafts(grafts, dest, preserve=True): | ||||
|     '''Copy each of the items listed in grafts into dest. | ||||
| @ -256,9 +251,7 @@ class PartitionMount(object): | ||||
|         # kpartx -p p -v -a /tmp/diskV2DiCW.im | ||||
|         # add map loop2p1 (253:2): 0 3481600 linear /dev/loop2 2048 | ||||
|         # add map loop2p2 (253:3): 0 614400 linear /dev/loop2 3483648 | ||||
|         cmd = [ "kpartx", "-v", "-p", "p", "-a", self.disk_img ] | ||||
|         logger.debug(cmd) | ||||
|         kpartx_output = check_output(cmd) | ||||
|         kpartx_output = execWithCapture("kpartx", ["-v", "-p", "p", "-a", self.disk_img]) | ||||
|         logger.debug(kpartx_output) | ||||
| 
 | ||||
|         # list of (deviceName, sizeInBytes) | ||||
| @ -296,7 +289,7 @@ class PartitionMount(object): | ||||
|             umount( self.mount_dir ) | ||||
|             os.rmdir(self.mount_dir) | ||||
|             self.mount_dir = None | ||||
|         call(["kpartx", "-d", self.disk_img]) | ||||
|         execWithRedirect("kpartx", ["-d", self.disk_img]) | ||||
| 
 | ||||
| 
 | ||||
| ######## Functions for making filesystem images ########################## | ||||
| @ -312,7 +305,7 @@ def mkfsimage(fstype, rootdir, outfile, size=None, mkfsargs=[], mountargs="", gr | ||||
|         size = estimate_size(rootdir, graft, fstype) | ||||
|     with LoopDev(outfile, size) as loopdev: | ||||
|         try: | ||||
|             check_output(["mkfs.%s" % fstype] + mkfsargs + [loopdev]) | ||||
|             execWithRedirect("mkfs.%s" % fstype, mkfsargs + [loopdev]) | ||||
|         except CalledProcessError as e: | ||||
|             logger.error("mkfs exited with a non-zero return code: %d" % e.returncode) | ||||
|             logger.error(e.output) | ||||
|  | ||||
| @ -25,11 +25,12 @@ logger = logging.getLogger("pylorax.ltmpl") | ||||
| 
 | ||||
| import os, re, glob, shlex, fnmatch | ||||
| from os.path import basename, isdir | ||||
| from subprocess import check_call, check_output, CalledProcessError, STDOUT | ||||
| from subprocess import CalledProcessError | ||||
| 
 | ||||
| from sysutils import joinpaths, cpfile, mvfile, replace, remove | ||||
| from yumhelper import * # Lorax*Callback classes | ||||
| from base import DataHolder | ||||
| from pylorax.executils import execWithRedirect, execWithCapture | ||||
| 
 | ||||
| from mako.lookup import TemplateLookup | ||||
| from mako.exceptions import text_error_template | ||||
| @ -368,9 +369,10 @@ class LoraxTemplateRunner(object): | ||||
|         ''' | ||||
|         if outfile is None: | ||||
|             outfile = self._out("etc/gconf/gconf.xml.defaults") | ||||
|         check_call(["gconftool-2", "--direct", | ||||
|         cmd = ["gconftool-2", "--direct", | ||||
|                     "--config-source=xml:readwrite:%s" % outfile, | ||||
|                     "--set", "--type", keytype, path, value]) | ||||
|                     "--set", "--type", keytype, path, value] | ||||
|         execWithRedirect(cmd[0], cmd[1:]) | ||||
| 
 | ||||
|     def log(self, msg): | ||||
|         ''' | ||||
| @ -404,16 +406,15 @@ class LoraxTemplateRunner(object): | ||||
|                 remove ${f} | ||||
|             %endfor | ||||
|         ''' | ||||
|         chdir = lambda: None | ||||
|         cwd = None | ||||
|         cmd = cmdlist | ||||
|         logger.debug('running command: %s', cmd) | ||||
|         if cmd[0].startswith("--chdir="): | ||||
|             dirname = cmd[0].split('=',1)[1] | ||||
|             chdir = lambda: os.chdir(dirname) | ||||
|             cwd = cmd[0].split('=',1)[1] | ||||
|             cmd = cmd[1:] | ||||
| 
 | ||||
|         try: | ||||
|             output = check_output(cmd, preexec_fn=chdir, stderr=STDOUT) | ||||
|             output = execWithCapture(cmd[0], cmd[1:], cwd=cwd) | ||||
|             if output: | ||||
|                 logger.debug('command output:\n%s', output) | ||||
|             logger.debug("command finished successfully") | ||||
| @ -550,6 +551,7 @@ class LoraxTemplateRunner(object): | ||||
|                      '--quiet', cmd) | ||||
|         # XXX for some reason 'systemctl enable/disable' always returns 1 | ||||
|         try: | ||||
|             check_call(systemctl + units) | ||||
|             cmd = systemctl + units | ||||
|             execWithRedirect(cmd[0], cmd[1:]) | ||||
|         except CalledProcessError: | ||||
|             pass | ||||
|  | ||||
| @ -32,6 +32,7 @@ import glob | ||||
| import shutil | ||||
| import subprocess | ||||
| 
 | ||||
| from pylorax.executils import execWithRedirect | ||||
| 
 | ||||
| def joinpaths(*args, **kwargs): | ||||
|     path = os.path.sep.join(args) | ||||
| @ -105,4 +106,5 @@ def remove(target): | ||||
|         os.unlink(target) | ||||
| 
 | ||||
| def linktree(src, dst): | ||||
|     subprocess.check_call(["/bin/cp", "-al", src, dst]) | ||||
|     execWithRedirect("/bin/cp", ["-al", src, dst]) | ||||
| 
 | ||||
|  | ||||
| @ -22,13 +22,13 @@ logger = logging.getLogger("pylorax.treebuilder") | ||||
| 
 | ||||
| import os, re | ||||
| from os.path import basename, isdir | ||||
| from subprocess import check_call, check_output | ||||
| 
 | ||||
| from sysutils import joinpaths, remove | ||||
| from shutil import copytree, copy2 | ||||
| from base import DataHolder | ||||
| from ltmpl import LoraxTemplateRunner | ||||
| import imgutils | ||||
| from pylorax.executils import execWithRedirect, execWithCapture | ||||
| 
 | ||||
| templatemap = { | ||||
|     'i386':    'x86.tmpl', | ||||
| @ -45,7 +45,8 @@ templatemap = { | ||||
| 
 | ||||
| def generate_module_info(moddir, outfile=None): | ||||
|     def module_desc(mod): | ||||
|         return check_output(["modinfo", "-F", "description", mod]).strip() | ||||
|         output = execWithCapture("modinfo", ["-F", "description", mod]) | ||||
|         return output.strip() | ||||
|     def read_module_set(name): | ||||
|         return set(l.strip() for l in open(joinpaths(moddir,name)) if ".ko" in l) | ||||
|     modsets = {'scsi':read_module_set("modules.block"), | ||||
| @ -148,7 +149,7 @@ class RuntimeBuilder(object): | ||||
|         for kver in os.listdir(moddir): | ||||
|             ksyms = joinpaths(root, "boot/System.map-%s" % kver) | ||||
|             logger.info("doing depmod and module-info for %s", kver) | ||||
|             check_call(["depmod", "-a", "-F", ksyms, "-b", root, kver]) | ||||
|             execWithRedirect("depmod", ["-a", "-F", ksyms, "-b", root, kver]) | ||||
|             generate_module_info(moddir+kver, outfile=moddir+"module-info") | ||||
| 
 | ||||
|     def create_runtime(self, outfile="/tmp/squashfs.img", compression="xz", compressargs=[], size=1): | ||||
| @ -165,8 +166,8 @@ class RuntimeBuilder(object): | ||||
|         # Reset selinux context on new rootfs | ||||
|         with imgutils.LoopDev( joinpaths(workdir, "LiveOS/rootfs.img") ) as loopdev: | ||||
|             with imgutils.Mount(loopdev) as mnt: | ||||
|                 cmd = ["chroot", mnt, "setfiles", "-e", "/proc", "-e", "/sys", "-e", "/dev", "-e", "/selinux", "/etc/selinux/targeted/contexts/files/file_contexts", "/"] | ||||
|                 check_call(cmd) | ||||
|                 cmd = [ "setfiles", "-e", "/proc", "-e", "/sys", "-e", "/dev", "-e", "/selinux", "/etc/selinux/targeted/contexts/files/file_contexts", "/"] | ||||
|                 execWithRedirect(cmd[0], cmd[1:], root=mnt) | ||||
| 
 | ||||
|         # squash the live rootfs and clean up workdir | ||||
|         imgutils.mksquashfs(workdir, outfile, compression, compressargs) | ||||
| @ -206,8 +207,8 @@ class TreeBuilder(object): | ||||
|             if backup: | ||||
|                 initrd = joinpaths(self.vars.inroot, kernel.initrd.path) | ||||
|                 os.rename(initrd, initrd + backup) | ||||
|             check_call(["chroot", self.vars.inroot] + \ | ||||
|                        dracut + [kernel.initrd.path, kernel.version]) | ||||
|             cmd = dracut + [kernel.initrd.path, kernel.version] | ||||
|             execWithRedirect(cmd[0], cmd[1:], root=self.vars.inroot) | ||||
|         os.unlink(joinpaths(self.vars.inroot,"/proc/modules")) | ||||
| 
 | ||||
|     def build(self): | ||||
| @ -220,7 +221,7 @@ class TreeBuilder(object): | ||||
|         for section, data in self.treeinfo_data.items(): | ||||
|             if 'boot.iso' in data: | ||||
|                 iso = joinpaths(self.vars.outroot, data['boot.iso']) | ||||
|                 check_call(["implantisomd5", iso]) | ||||
|                 execWithRedirect("implantisomd5", [iso]) | ||||
| 
 | ||||
|     @property | ||||
|     def dracut_hooks_path(self): | ||||
|  | ||||
| @ -178,8 +178,7 @@ class IsoMountpoint(object): | ||||
|         if not self.mount_dir: | ||||
|             raise Exception("Error creating temporary directory") | ||||
| 
 | ||||
|         cmd = ["mount","-o","loop",self.iso_path,self.mount_dir] | ||||
|         execWithRedirect( cmd[0], cmd[1:] ) | ||||
|         execWithRedirect("mount", ["-o", "loop", self.iso_path, self.mount_dir]) | ||||
| 
 | ||||
|         self.kernel = self.mount_dir+"/isolinux/vmlinuz" | ||||
|         self.initrd = self.mount_dir+"/isolinux/initrd.img" | ||||
| @ -201,16 +200,14 @@ class IsoMountpoint(object): | ||||
|         self.get_iso_label() | ||||
| 
 | ||||
|     def umount( self ): | ||||
|         cmd = ["umount", self.mount_dir] | ||||
|         execWithRedirect( cmd[0], cmd[1:] ) | ||||
|         execWithRedirect("umount", [self.mount_dir]) | ||||
|         os.rmdir( self.mount_dir ) | ||||
| 
 | ||||
|     def get_iso_label( self ): | ||||
|         """ | ||||
|         Get the iso's label using isoinfo | ||||
|         """ | ||||
|         cmd = [ "isoinfo", "-d", "-i", self.iso_path ] | ||||
|         isoinfo_output = execWithCapture( cmd[0], cmd[1:] ) | ||||
|         isoinfo_output = execWithCapture("isoinfo", ["-d", "-i", self.iso_path]) | ||||
|         log.debug( isoinfo_output ) | ||||
|         for line in isoinfo_output.splitlines(): | ||||
|             if line.startswith("Volume id: "): | ||||
| @ -491,9 +488,8 @@ def make_livecd( disk_img, squashfs_args="", templatedir=None, | ||||
|         # Link /images to work_dir/images to make the templates happy | ||||
|         if os.path.islink( joinpaths( installroot, "images" ) ): | ||||
|             os.unlink( joinpaths( installroot, "images" ) ) | ||||
|         cmd = ["/bin/ln", "-s", joinpaths(work_dir, "images"), | ||||
|                joinpaths(installroot, "images")] | ||||
|         execWithRedirect(cmd[0], cmd[1:]) | ||||
|         execWithRedirect("/bin/ln", ["-s", joinpaths(work_dir, "images"), | ||||
|                                      joinpaths(installroot, "images")]) | ||||
| 
 | ||||
|         isolabel = isolabel or "{0.name} {0.version} {1.basearch}".format(product, arch) | ||||
|         if len(isolabel) > 32: | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user