diff options
| author | Michael E Brown <mebrown@michaels-house.net> | 2007-11-30 11:51:25 -0600 |
|---|---|---|
| committer | Michael E Brown <mebrown@michaels-house.net> | 2007-11-30 11:51:25 -0600 |
| commit | 97f06be255f9a20613c66510e05f68372af7215f (patch) | |
| tree | 2d57f70b6889bd351f3efac9f32ae806faa53aee /py/mock/plugins | |
| parent | 96dd05c47ed25102fe92a1c7810d12716083e05e (diff) | |
| download | mock-97f06be255f9a20613c66510e05f68372af7215f.tar.gz mock-97f06be255f9a20613c66510e05f68372af7215f.tar.xz mock-97f06be255f9a20613c66510e05f68372af7215f.zip | |
move things around so that we can run mock.py from the build tree instead of having to install it.
Diffstat (limited to 'py/mock/plugins')
| -rw-r--r-- | py/mock/plugins/bind_mount.py | 39 | ||||
| -rw-r--r-- | py/mock/plugins/ccache.py | 73 | ||||
| -rw-r--r-- | py/mock/plugins/root_cache.py | 93 | ||||
| -rw-r--r-- | py/mock/plugins/yum_cache.py | 94 |
4 files changed, 299 insertions, 0 deletions
diff --git a/py/mock/plugins/bind_mount.py b/py/mock/plugins/bind_mount.py new file mode 100644 index 0000000..e010f92 --- /dev/null +++ b/py/mock/plugins/bind_mount.py @@ -0,0 +1,39 @@ +# vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=python:textwidth=0: +# License: GPL2 or later see COPYING +# Written by Michael Brown +# Copyright (C) 2007 Michael E Brown <mebrown@michaels-house.net> + +# python library imports +import logging +import os + +# our imports +from mock.trace_decorator import traceLog +import mock.util + +# set up logging, module options +moduleLog = logging.getLogger("mock") +requires_api_version = "1.0" + +# plugin entry point +def init(rootObj, conf): + bind = BindMount(rootObj, conf) + +# classes +class BindMount(object): + """bind mount dirs from host into chroot""" + @traceLog(moduleLog) + def __init__(self, rootObj, conf): + self.rootObj = rootObj + self.bind_opts = conf + self.rootdir = rootObj.rootdir + 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)) + + @traceLog(moduleLog) + def _bindMountPreInitHook(self): + for srcdir, destdir in self.bind_opts['dirs']: + mock.util.mkdirIfAbsent("%s/%s" % (self.rootObj.rootdir, destdir)) diff --git a/py/mock/plugins/ccache.py b/py/mock/plugins/ccache.py new file mode 100644 index 0000000..27ec405 --- /dev/null +++ b/py/mock/plugins/ccache.py @@ -0,0 +1,73 @@ +# vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=python:textwidth=0: +# License: GPL2 or later see COPYING +# Written by Michael Brown +# Copyright (C) 2007 Michael E Brown <mebrown@michaels-house.net> + +# python library imports +import logging +import os + +# our imports +from mock.trace_decorator import traceLog +import mock.util + +# set up logging, module options +moduleLog = logging.getLogger("mock") +requires_api_version = "1.0" + +# plugin entry point +def init(rootObj, conf): + ccache = CCache(rootObj, conf) + +# classes +class CCache(object): + """enables ccache in buildroot/rpmbuild""" + @traceLog(moduleLog) + def __init__(self, rootObj, conf): + 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)) + + # ============= + # 'Private' API + # ============= + # set the max size before we actually use it during a build. + # ccache itself manages size and settings. + @traceLog(moduleLog) + def _ccacheBuildHook(self): + self.rootObj.doChroot("ccache -M %s" % self.ccache_opts['max_cache_size']) + + # basic idea here is that we add 'cc', 'gcc', 'g++' shell scripts to + # to /tmp/ccache, which is bind-mounted from a shared location. + # we then add this to the front of the path. + # we also set a few admin variables used by ccache to find the shared + # cache. + @traceLog(moduleLog) + def _ccachePreInitHook(self): + mock.util.mkdirIfAbsent(os.path.join(self.rootdir, 'tmp/ccache')) + mock.util.mkdirIfAbsent(self.ccachePath) + os.environ['PATH'] = "/tmp/ccache:%s" % (os.environ['PATH']) + os.environ['CCACHE_DIR'] = "/tmp/ccache" + os.environ['CCACHE_UMASK'] = "002" + for i in ("cc", "gcc", "gcc296", "gcc32", "gcc33", "gcc34", + "g++", "c++", "c++32", "c++33", "c++34", "g++296", "g++32", "g++33", "g++34", + "g++-libstdc++-so_7",): + forceLink("/usr/bin/ccache", os.path.join(self.ccachePath, "%s" % i)) + forceLink("/usr/bin/ccache", os.path.join(self.ccachePath, "x86_64-redhat-linux-%s" % i)) + forceLink("/usr/bin/ccache", os.path.join(self.ccachePath, "i386-redhat-linux-%s" % i)) + +@traceLog(moduleLog) +def forceLink( existing, linkname ): + try: + os.unlink(linkname) + except OSError: + pass + + os.symlink(existing, linkname) diff --git a/py/mock/plugins/root_cache.py b/py/mock/plugins/root_cache.py new file mode 100644 index 0000000..8ed2492 --- /dev/null +++ b/py/mock/plugins/root_cache.py @@ -0,0 +1,93 @@ +# vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=python:textwidth=0: +# License: GPL2 or later see COPYING +# Written by Michael Brown +# Copyright (C) 2007 Michael E Brown <mebrown@michaels-house.net> + +# python library imports +import fcntl +import logging +import os +import time + +# our imports +from mock.trace_decorator import traceLog +import mock.util + +# set up logging, module options +moduleLog = logging.getLogger("mock") +requires_api_version = "1.0" + +# plugin entry point +def init(rootObj, conf): + rootCache = RootCache(rootObj, conf) + +# classes +class RootCache(object): + """caches root environment in a tarball""" + @traceLog(moduleLog) + def __init__(self, rootObj, conf): + self.rootObj = rootObj + self.root_cache_opts = conf + self.rootSharedCachePath = self.root_cache_opts['dir'] % self.root_cache_opts + self.rootCacheFile = os.path.join(self.rootSharedCachePath, "cache.tar.gz") + self.rootCacheLock = None + self.state = rootObj.state + self.rootdir = rootObj.rootdir + rootObj.rootCacheObj = self + rootObj.addHook("preinit", self._rootCachePreInitHook) + rootObj.addHook("postinit", self._rootCachePostInitHook) + + # ============= + # 'Private' API + # ============= + @traceLog(moduleLog) + def _rootCacheLock(self, shared=1): + lockType = fcntl.LOCK_EX + if shared: lockType = fcntl.LOCK_SH + try: + fcntl.lockf(self.rootCacheLock.fileno(), lockType | fcntl.LOCK_NB) + except IOError, e: + oldState = self.state() + self.state("Waiting for rootcache lock") + fcntl.lockf(self.rootCacheLock.fileno(), lockType) + self.state(oldState) + + @traceLog(moduleLog) + def _rootCacheUnlock(self): + fcntl.lockf(self.rootCacheLock.fileno(), fcntl.LOCK_UN) + + @traceLog(moduleLog) + def _rootCachePreInitHook(self): + moduleLog.info("enabled root cache") + mock.util.mkdirIfAbsent(self.rootSharedCachePath) + # lock so others dont accidentally use root cache while we operate on it. + if self.rootCacheLock is None: + self.rootCacheLock = open(os.path.join(self.rootSharedCachePath, "rootcache.lock"), "a+") + + # check cache age: + try: + statinfo = os.stat(self.rootCacheFile) + file_age_days = (time.time() - statinfo.st_ctime) / (60 * 60 * 24) + if file_age_days > self.root_cache_opts['max_age_days']: + os.unlink(self.rootCacheFile) + except OSError: + pass + + # optimization: dont unpack root cache if chroot was not cleaned + if os.path.exists(self.rootCacheFile) and self.rootObj.chrootWasCleaned: + self.state("unpacking cache") + self._rootCacheLock() + mock.util.do("tar xzf %s -C %s" % (self.rootCacheFile, self.rootdir)) + self._rootCacheUnlock() + self.chroot_setup_cmd = "update" + self.rootObj.chrootWasCleaned = False + + @traceLog(moduleLog) + def _rootCachePostInitHook(self): + # never rebuild cache unless it was a clean build. + if self.rootObj.chrootWasCleaned: + self.state("creating cache") + self._rootCacheLock(shared=0) + mock.util.do("tar czf %s -C %s ." % (self.rootCacheFile, self.rootdir)) + self._rootCacheUnlock() + diff --git a/py/mock/plugins/yum_cache.py b/py/mock/plugins/yum_cache.py new file mode 100644 index 0000000..5a4abc3 --- /dev/null +++ b/py/mock/plugins/yum_cache.py @@ -0,0 +1,94 @@ +# vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=python:textwidth=0: +# License: GPL2 or later see COPYING +# Written by Michael Brown +# Copyright (C) 2007 Michael E Brown <mebrown@michaels-house.net> + +# python library imports +import logging +import fcntl +import time +import os + +# our imports +from mock.trace_decorator import traceLog +import mock.util + +# set up logging, module options +moduleLog = logging.getLogger("mock") +requires_api_version = "1.0" + +# plugin entry point +def init(rootObj, conf): + yumCache = YumCache(rootObj, conf) + +# classes +class YumCache(object): + """caches root environment in a tarball""" + @traceLog(moduleLog) + def __init__(self, rootObj, conf): + self.rootObj = rootObj + 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)) + + # ============= + # 'Private' API + # ============= + # lock the shared yum cache (when enabled) before any access + # by yum, and prior to cleaning it. This prevents simultaneous access from + # screwing things up. This can possibly happen, eg. when running multiple + # mock instances with --uniqueext= + @traceLog(moduleLog) + def _yumCachePreYumHook(self): + try: + fcntl.lockf(self.yumCacheLock.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB) + except IOError, e: + oldState = self.state() + self.state("Waiting for yumcache lock") + fcntl.lockf(self.yumCacheLock.fileno(), fcntl.LOCK_EX) + self.state(oldState) + + @traceLog(moduleLog) + def _yumCachePostYumHook(self): + fcntl.lockf(self.yumCacheLock.fileno(), fcntl.LOCK_UN) + + @traceLog(moduleLog) + def _yumCachePreInitHook(self): + moduleLog.info("enabled yum cache") + mock.util.mkdirIfAbsent(os.path.join(self.rootdir, 'var/cache/yum')) + mock.util.mkdirIfAbsent(self.yumSharedCachePath) + + # lock so others dont accidentally use yum cache while we operate on it. + self.yumCacheLock = open(os.path.join(self.yumSharedCachePath, "yumcache.lock"), "a+") + self._yumCachePreYumHook() + + if self.online: + self.state("cleaning yum metadata") + for (dirpath, dirnames, filenames) in os.walk(self.yumSharedCachePath): + for filename in filenames: + fullPath = os.path.join(dirpath, filename) + statinfo = os.stat(fullPath) + file_age_days = (time.time() - statinfo.st_ctime) / (60 * 60 * 24) + # prune repodata so yum redownloads. + # prevents certain errors where yum gets stuck due to bad metadata + for ext in (".sqllite", ".xml", ".bz2", ".gz"): + if filename.endswith(ext) and file_age_days > self.yum_cache_opts['max_metadata_age_days']: + os.unlink(fullPath) + fullPath = None + break + + if fullPath is None: continue + if file_age_days > self.yum_cache_opts['max_age_days']: + os.unlink(fullPath) + continue + + self._yumCachePostYumHook() + |
