diff options
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | docs/mock.1 | 37 | ||||
-rwxr-xr-x | docs/releasetests.sh | 1 | ||||
-rwxr-xr-x | py/mock.py | 53 | ||||
-rw-r--r-- | py/mock/backend.py | 58 | ||||
-rw-r--r-- | py/mock/plugins/bind_mount.py | 6 | ||||
-rw-r--r-- | py/mock/plugins/ccache.py | 7 | ||||
-rw-r--r-- | py/mock/plugins/yum_cache.py | 7 |
8 files changed, 124 insertions, 47 deletions
diff --git a/configure.ac b/configure.ac index 99bca21..f1d16af 100644 --- a/configure.ac +++ b/configure.ac @@ -9,7 +9,7 @@ AC_INIT([mock],[0.9.2]) temp_RELEASE_NAME=mock temp_RELEASE_MAJOR=0 temp_RELEASE_MINOR=9 -temp_RELEASE_SUBLEVEL=2 +temp_RELEASE_SUBLEVEL=3jcw temp_RELEASE_EXTRALEVEL= #################################### diff --git a/docs/mock.1 b/docs/mock.1 index ac295e6..4afde95 100644 --- a/docs/mock.1 +++ b/docs/mock.1 @@ -17,6 +17,10 @@ mock [options] \fB\-\-install\fR PACKAGE mock [options] \fB\-\-update\fR .LP mock [options] \fB\-\-orphanskill\fR +.LP +mock [options] \fB\-\-copyin\fR \fIpath [\fIpath...\fR] \fIdestination\fR +.LP +mock [options] \fB\-\-copyout\fR \fIpath [\fIpath...\fR] \fIdestination\fR .SH "DESCRIPTION" .LP @@ -97,24 +101,41 @@ Show version number and exit. .SH "COMMANDS" .LP .TP -\fB\-\-clean\fR \- purge the chroot tree +\fB\-\-clean\fP +Purge the chroot tree .TP -\fB\-\-init\fR \- initialize a chroot (clean, install chroot packages, etc.) +\fB\-\-init\fP +Initialize a chroot (clean, install chroot packages, etc.) .TP -\fB\-\-rebuild\fR \- If no command is specified, rebuild is assumed. Rebuilds the specified SRPM(s). The buildroot is cleaned first, unless --no-clean is specified. +\fB\-\-rebuild\fP +If no command is specified, rebuild is assumed. Rebuilds the specified SRPM(s). The buildroot is cleaned first, unless --no-clean is specified. .TP -\fB\-\-shell\fR \- run the specified command interactively within the chroot (which must already be initialized -- no 'clean' is performed). If no command specified, /bin/sh is run. +\fB\-\-shell\fP +Run the specified command interactively within the chroot (which must already be initialized -- no 'clean' is performed). If no command specified, /bin/sh is run. .TP -\fB\-\-chroot\fR \- run the specified command non-interactively within the chroot (which must already be initialized -- no 'clean' is performed). Command output will be sent to the log files. +\fB\-\-chroot\fP +Run the specified command non-interactively within the chroot (which must already be initialized -- no 'clean' is performed). Command output will be sent to the log files. .TP -\fB\-\-installdeps\fR \- find out deps for SRPM or RPM, and do a yum install to put them in the buildroot. Buildroot must already be initialized -- no 'clean' is performed +\fB\-\-installdeps\fP +Find out deps for SRPM or RPM, and do a yum install to put them in the buildroot. Buildroot must already be initialized -- no 'clean' is performed .TP -\fB\-\-install\fR \- Do a yum install PACKAGE inside the buildroot. Buildroot must already be initialized -- no 'clean' is performed +\fB\-\-install\fP +Do a yum install PACKAGE inside the buildroot. Buildroot must already be initialized -- no 'clean' is performed .TP -\fB\-\-update\fR \- Do a yum update inside the buildroot. Buildroot must already be initialized -- no 'clean' is performed +\fB\-\-update\fP +Do a yum update inside the buildroot. Buildroot must already be initialized -- no 'clean' is performed .TP \fB\-\-orphanskill\fP Noop mode that simply checks that no stray processes are running in the chroot. Kills any processes that it finds using specified root. +.TP +\fB\-\-copyin\fP +Copies the source paths (files or directory trees) into the chroot at +the specified destination path. +.TP +\fB\-\-copyout\fP +Copies the source paths (files or directory trees) from the chroot to +the specified destination path. + .SH "FILES" .LP \fI/etc/mock/\fP \- default configuration directory diff --git a/docs/releasetests.sh b/docs/releasetests.sh index 0c1727c..ba29c20 100755 --- a/docs/releasetests.sh +++ b/docs/releasetests.sh @@ -27,5 +27,4 @@ make distclean ||: ./configure make distcheck make srpm - make check @@ -25,6 +25,8 @@ mock [options] {--shell|--chroot} <cmd> mock [options] --installdeps {SRPM|RPM} mock [options] --install PACKAGE + mock [options] --copyin path [..path] destination + mock [options] --copyout path [..path] destination """ # library imports @@ -65,6 +67,8 @@ import mock.util def command_parse(config_opts): """return options and args from parsing the command line""" parser = OptionParser(usage=__doc__, version=__VERSION__) + + # modes (basic commands) parser.add_option("--rebuild", action="store_const", const="rebuild", dest="mode", default='rebuild', help="rebuild the specified SRPM(s)") @@ -93,6 +97,15 @@ def command_parse(config_opts): dest="mode", help="Kill all processes using specified buildroot.") + parser.add_option("--copyin", action="store_const", const="copyin", + dest="mode", + help="Copy file(s) into the specified chroot") + + parser.add_option("--copyout", action="store_const", const="copyout", + dest="mode", + help="Copy file(s) from the specified chroot") + + # options parser.add_option("-r", action="store", type="string", dest="chroot", help="chroot name/config file name default: %default", default='default') @@ -528,7 +541,45 @@ def main(ret): elif options.mode == 'orphanskill': mock.util.orphansKill(chroot.rootdir) - + elif options.mode == 'copyin': + chroot.tryLockBuildRoot() + chroot._resetLogging() + uidManager.dropPrivsForever() + if len(args) < 2: + log.critical("Must have source and destinations for copyin") + sys.exit(50) + dest = chroot.makeChrootPath(args[-1]) + if len(args) > 2 and not os.path.isdir(dest): + log.critical("multiple source files and %s is not a directory!" % dest) + sys.exit(50) + args = args[:-1] + import shutil + for src in args: + log.debug("copying %s to %s" % (src, dest)) + if os.path.isdir(src): + shutil.copytree(src, dest) + else: + shutil.copy(src, dest) + elif options.mode == 'copyout': + chroot.tryLockBuildRoot() + chroot._resetLogging() + uidManager.dropPrivsForever() + if len(args) < 2: + log.critical("Must have source and destinations for copyout") + sys.exit(50) + dest = args[-1] + if len(args) > 2 and not os.path.isdir(dest): + log.critical("multiple source files and %s is not a directory!" % dest) + sys.exit(50) + args = args[:-1] + import shutil + for f in args: + src = chroot.makeChrootPath(f) + log.debug("copying %s to %s" % (src, dest)) + if os.path.isdir(src): + shutil.copytree(src, dest) + else: + shutil.copy(src, dest) if __name__ == '__main__': # fix for python 2.4 logging module bug: diff --git a/py/mock/backend.py b/py/mock/backend.py index 4593357..c850118 100644 --- a/py/mock/backend.py +++ b/py/mock/backend.py @@ -142,6 +142,14 @@ class Root(object): return 1 decorate(traceLog()) + def makeChrootPath(self, *args): + '''For safety reasons, self.rootdir should not be used directly. Instead + use this handy helper function anytime you want to reference a path in + relation to the chroot.''' + tmp = self.rootdir + "/" + "/".join(args) + return tmp.replace("//", "/") + + decorate(traceLog()) def init(self): self.state("init") @@ -188,41 +196,41 @@ class Root(object): 'proc', 'sys', ]: - mock.util.mkdirIfAbsent(os.path.join(self.rootdir, item)) + mock.util.mkdirIfAbsent(self.makeChrootPath(item)) # touch files self.root_log.debug('touch required files') - for item in [os.path.join(self.rootdir, 'etc', 'mtab'), - os.path.join(self.rootdir, 'etc', 'fstab'), - os.path.join(self.rootdir, 'var', 'log', 'yum.log')]: + for item in [self.makeChrootPath('etc', 'mtab'), + self.makeChrootPath('etc', 'fstab'), + self.makeChrootPath('var', 'log', 'yum.log')]: mock.util.touch(item) # write in yum.conf into chroot # always truncate and overwrite (w+) self.root_log.debug('configure yum') - yumconf = os.path.join(self.rootdir, 'etc', 'yum', 'yum.conf') + yumconf = self.makeChrootPath('etc', 'yum', 'yum.conf') yumconf_fo = open(yumconf, 'w+') yumconf_fo.write(self.yum_conf_content) yumconf_fo.close() # symlink /etc/yum.conf to /etc/yum/yum.conf (FC6 requires) try: - os.unlink(os.path.join(self.rootdir, "etc", "yum.conf")) + os.unlink(self.makeChrootPath("etc", "yum.conf")) except OSError: pass - os.symlink('yum/yum.conf', os.path.join(self.rootdir, "etc", "yum.conf")) + os.symlink('yum/yum.conf', self.makeChrootPath("etc", "yum.conf")) # set up resolv.conf if self.use_host_resolv: - resolvdir = os.path.join(self.rootdir, 'etc') - resolvpath = os.path.join(self.rootdir, 'etc', 'resolv.conf') + resolvdir = self.makeChrootPath('etc') + resolvpath = self.makeChrootPath('etc', 'resolv.conf') if os.path.exists(resolvpath): os.remove(resolvpath) shutil.copy2('/etc/resolv.conf', resolvdir) # files in /etc that need doing for key in self.chroot_file_contents: - p = os.path.join(self.rootdir, *key.split('/')) + p = self.makeChrootPath(key) if not os.path.exists(p): # write file fo = open(p, 'w+') @@ -254,8 +262,8 @@ class Root(object): decorate(traceLog()) def _setupDev(self): # files in /dev - mock.util.rmtree(os.path.join(self.rootdir, "dev")) - mock.util.mkdirIfAbsent(os.path.join(self.rootdir, "dev", "pts")) + mock.util.rmtree(self.makeChrootPath("dev")) + mock.util.mkdirIfAbsent(self.makeChrootPath("dev", "pts")) prevMask = os.umask(0000) devFiles = ( (stat.S_IFCHR | 0666, os.makedev(1, 3), "dev/null"), @@ -268,23 +276,23 @@ class Root(object): ) for i in devFiles: # create node - os.mknod( os.path.join(self.rootdir, i[2]), i[0], i[1] ) + os.mknod( self.makeChrootPath(i[2]), i[0], i[1]) # set context. (only necessary if host running selinux enabled.) # fails gracefully if chcon not installed. mock.util.do("chcon --reference=/%s %s" % - (i[2], os.path.join(self.rootdir, i[2])), raiseExc=0) + (i[2], self.makeChrootPath(i[2])), raiseExc=0) - os.symlink("/proc/self/fd/0", os.path.join(self.rootdir, "dev/stdin")) - os.symlink("/proc/self/fd/1", os.path.join(self.rootdir, "dev/stdout")) - os.symlink("/proc/self/fd/2", os.path.join(self.rootdir, "dev/stderr")) + os.symlink("/proc/self/fd/0", self.makeChrootPath("dev/stdin")) + os.symlink("/proc/self/fd/1", self.makeChrootPath("dev/stdout")) + os.symlink("/proc/self/fd/2", self.makeChrootPath("dev/stderr")) os.umask(prevMask) # mount/umount - umntCmd = 'umount -n %s/dev/pts' % self.rootdir + umntCmd = 'umount -n %s' % self.makeChrootPath('/dev/pts') if umntCmd not in self.umountCmds: self.umountCmds.append(umntCmd) - mntCmd = 'mount -n -t devpts mock_chroot_devpts %s/dev/pts' % self.rootdir + mntCmd = 'mount -n -t devpts mock_chroot_devpts %s' % self.makeChrootPath('/dev/pts') if mntCmd not in self.mountCmds: self.mountCmds.append(mntCmd) @@ -405,7 +413,7 @@ class Root(object): gid=self.chrootgid, ) - bd_out = self.rootdir + self.builddir + bd_out = self.makeChrootPath(self.builddir) rpms = glob.glob(bd_out + '/RPMS/*.rpm') srpms = glob.glob(bd_out + '/SRPMS/*.rpm') packages = rpms + srpms @@ -482,11 +490,11 @@ class Root(object): decorate(traceLog()) def _makeBuildUser(self): - if not os.path.exists(os.path.join(self.rootdir, 'usr/sbin/useradd')): + if not os.path.exists(self.makeChrootPath('usr/sbin/useradd')): raise mock.exception.RootError, "Could not find useradd in chroot, maybe the install failed?" # safe and easy. blow away existing /builddir and completely re-create. - mock.util.rmtree(os.path.join(self.rootdir, self.homedir)) + mock.util.rmtree(self.makeChrootPath(self.homedir)) dets = { 'uid': self.chrootuid, 'gid': self.chrootgid, 'user': self.chrootuser, 'group': self.chrootgroup, 'home': self.homedir } self.doChroot('/usr/sbin/userdel -r %(user)s' % dets, raiseExc=False) @@ -533,7 +541,7 @@ class Root(object): self.uidManager.becomeUser(self.chrootuid, self.chrootgid) try: # create dir structure - for subdir in ["%s/%s/%s" % (self.rootdir, self.builddir, s) for s in ('RPMS', 'SRPMS', 'SOURCES', 'SPECS', 'BUILD', 'originals')]: + for subdir in [self.makeChrootPath(self.builddir, s) for s in ('RPMS', 'SRPMS', 'SOURCES', 'SPECS', 'BUILD', 'originals')]: mock.util.mkdirIfAbsent(subdir) # change ownership so we can write to build home dir @@ -543,7 +551,7 @@ class Root(object): os.chmod(os.path.join(dirpath, path), 0755) # rpmmacros default - macrofile_out = '%s%s/.rpmmacros' % (self.rootdir, self.homedir) + macrofile_out = self.makeChrootPath(self.homedir, ".rpmmacros") rpmmacros = open(macrofile_out, 'w+') for key, value in self.macros.items(): rpmmacros.write( "%s %s\n" % (key, value) ) @@ -559,7 +567,7 @@ class Root(object): decorate(traceLog()) def _copySrpmIntoChroot(self, srpm): srpmFilename = os.path.basename(srpm) - dest = self.rootdir + '/' + self.builddir + '/' + 'originals' + dest = self.makeChrootPath(self.builddir, 'originals') shutil.copy2(srpm, dest) return os.path.join(self.builddir, 'originals', srpmFilename) diff --git a/py/mock/plugins/bind_mount.py b/py/mock/plugins/bind_mount.py index 60f0f8b..df5e215 100644 --- a/py/mock/plugins/bind_mount.py +++ b/py/mock/plugins/bind_mount.py @@ -29,10 +29,10 @@ class BindMount(object): rootObj.bindMountObj = self rootObj.addHook("preinit", self._bindMountPreInitHook) for srcdir, destdir in self.bind_opts['dirs']: - rootObj.umountCmds.append('umount -n %s/%s' % (rootObj.rootdir, destdir)) - rootObj.mountCmds.append('mount -n --bind %s %s/%s' % (srcdir, rootObj.rootdir, destdir)) + rootObj.umountCmds.append('umount -n %s' % rootObj.makeChrootPath(destdir)) + rootObj.mountCmds.append('mount -n --bind %s %s' % (srcdir, rootObj.makeChrootPath(destdir))) decorate(traceLog()) def _bindMountPreInitHook(self): for srcdir, destdir in self.bind_opts['dirs']: - mock.util.mkdirIfAbsent("%s/%s" % (self.rootObj.rootdir, destdir)) + mock.util.mkdirIfAbsent(self.rootObj.makeChrootPath(destdir)) diff --git a/py/mock/plugins/ccache.py b/py/mock/plugins/ccache.py index 7974b1f..77a9130 100644 --- a/py/mock/plugins/ccache.py +++ b/py/mock/plugins/ccache.py @@ -25,13 +25,12 @@ class CCache(object): self.rootObj = rootObj self.ccache_opts = conf self.ccachePath = self.ccache_opts['dir'] % self.ccache_opts - self.rootdir = rootObj.rootdir rootObj.ccacheObj = self rootObj.preExistingDeps = rootObj.preExistingDeps + " ccache " rootObj.addHook("prebuild", self._ccacheBuildHook) rootObj.addHook("preinit", self._ccachePreInitHook) - rootObj.umountCmds.append('umount -n %s/tmp/ccache' % rootObj.rootdir) - rootObj.mountCmds.append('mount -n --bind %s %s/tmp/ccache' % (self.ccachePath, rootObj.rootdir)) + rootObj.umountCmds.append('umount -n %s' % rootObj.makeChrootPath("/tmp/ccache")) + rootObj.mountCmds.append('mount -n --bind %s %s' % (self.ccachePath, rootObj.makeChrootPath("/tmp/ccache"))) # ============= # 'Private' API @@ -49,7 +48,7 @@ class CCache(object): # cache. decorate(traceLog()) def _ccachePreInitHook(self): - mock.util.mkdirIfAbsent(os.path.join(self.rootdir, 'tmp/ccache')) + mock.util.mkdirIfAbsent(self.rootObj.makeChrootPath('/tmp/ccache')) mock.util.mkdirIfAbsent(self.ccachePath) os.environ['PATH'] = "/tmp/ccache:%s" % (os.environ['PATH']) os.environ['CCACHE_DIR'] = "/tmp/ccache" diff --git a/py/mock/plugins/yum_cache.py b/py/mock/plugins/yum_cache.py index 5b371bb..bcdf465 100644 --- a/py/mock/plugins/yum_cache.py +++ b/py/mock/plugins/yum_cache.py @@ -30,14 +30,13 @@ class YumCache(object): self.yum_cache_opts = conf self.yumSharedCachePath = self.yum_cache_opts['dir'] % self.yum_cache_opts self.state = rootObj.state - self.rootdir = rootObj.rootdir self.online = rootObj.online rootObj.yum_cacheObj = self rootObj.addHook("preyum", self._yumCachePreYumHook) rootObj.addHook("postyum", self._yumCachePostYumHook) rootObj.addHook("preinit", self._yumCachePreInitHook) - rootObj.umountCmds.append('umount -n %s/var/cache/yum' % rootObj.rootdir) - rootObj.mountCmds.append('mount -n --bind %s %s/var/cache/yum' % (self.yumSharedCachePath, rootObj.rootdir)) + rootObj.umountCmds.append('umount -n %s' % rootObj.makeChrootPath('/var/cache/yum')) + rootObj.mountCmds.append('mount -n --bind %s %s' % (self.yumSharedCachePath, rootObj.makeChrootPath('/var/cache/yum'))) mock.util.mkdirIfAbsent(self.yumSharedCachePath) self.yumCacheLock = open(os.path.join(self.yumSharedCachePath, "yumcache.lock"), "a+") @@ -65,7 +64,7 @@ class YumCache(object): decorate(traceLog()) def _yumCachePreInitHook(self): getLog().info("enabled yum cache") - mock.util.mkdirIfAbsent(os.path.join(self.rootdir, 'var/cache/yum')) + mock.util.mkdirIfAbsent(self.rootObj.makeChrootPath('/var/cache/yum')) # lock so others dont accidentally use yum cache while we operate on it. self._yumCachePreYumHook() |