1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
# 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 os
import time
from glob import glob
# our imports
from mock.trace_decorator import decorate, traceLog, getLog
import mock.util
requires_api_version = "1.0"
# plugin entry point
decorate(traceLog())
def init(rootObj, conf):
RootCache(rootObj, conf)
# classes
class RootCache(object):
"""caches root environment in a tarball"""
decorate(traceLog())
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")
self.rootCacheLock = None
self.compressProgram = self.root_cache_opts['compress_program']
if self.compressProgram:
self.compressArgs = ['--use-compress-program', self.compressProgram]
self.rootCacheFile = self.rootCacheFile + self.root_cache_opts['extension']
else:
self.compressArgs = []
self.state = rootObj.state
rootObj.rootCacheObj = self
rootObj.addHook("preinit", self._rootCachePreInitHook)
rootObj.addHook("postinit", self._rootCachePostInitHook)
# =============
# 'Private' API
# =============
decorate(traceLog())
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)
decorate(traceLog())
def _rootCacheUnlock(self):
fcntl.lockf(self.rootCacheLock.fileno(), fcntl.LOCK_UN)
decorate(traceLog())
def _rootCachePreInitHook(self):
getLog().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 status
try:
# see if it aged out
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']:
getLog().info("root cache aged out! cache will be rebuilt")
os.unlink(self.rootCacheFile)
else:
# make sure no config file is newer than the cache file
for cfg in self.rootObj.configs:
if os.stat(cfg).st_mtime > statinfo.st_mtime:
getLog().info("%s newer than root cache; cache will be rebuilt" % cfg)
os.unlink(self.rootCacheFile)
break
except OSError:
pass
# optimization: don't unpack root cache if chroot was not cleaned
if os.path.exists(self.rootCacheFile) and self.rootObj.chrootWasCleaned:
self.state("unpacking root cache")
self._rootCacheLock()
mock.util.do(
["tar"] + self.compressArgs + ["-xf", self.rootCacheFile, "-C", self.rootObj.makeChrootPath()],
shell=False
)
self._rootCacheUnlock()
self.rootObj.chrootWasCleaned = False
self.rootObj.chrootWasCached = True
decorate(traceLog())
def _rootCachePostInitHook(self):
try:
self._rootCacheLock(shared=0)
# nuke any rpmdb tmp files
for tmp in glob(self.rootObj.makeChrootPath('var/lib/rpm/__db*')):
os.unlink(tmp)
# never rebuild cache unless it was a clean build.
if self.rootObj.chrootWasCleaned:
mock.util.do(["sync"], shell=False)
self.state("creating cache")
try:
mock.util.do(
["tar"] + self.compressArgs + ["-cf", self.rootCacheFile,
"-C", self.rootObj.makeChrootPath(),
"--exclude=./proc",
"--exclude=./sys",
"--exclude=./dev",
"--exclude=./tmp/ccache",
"--exclude=./var/cache/yum",
"."],
shell=False
)
except:
if os.path.exists(self.rootCacheFile):
os.remove(self.rootCacheFile)
raise
finally:
self._rootCacheUnlock()
|