25
26
_fake_machine = None
29
""" A file-like object that optionally mimics tee functionality.
31
By default, output will go to both stdout and the file specified.
32
Optionally, quiet=True can be used to mute the output to stdout.
34
def __init__(self, *args, **kwargs):
36
self.quiet = kwargs.pop('quiet')
39
super(Tee, self).__init__(*args, **kwargs)
41
def write(self, data):
42
super(Tee, self).write(data)
43
if self.quiet is False:
44
sys.stdout.write(data)
47
29
def geturl(url, path=""):
48
30
urlpath = urlparse.urlsplit(url).path
49
31
filename = os.path.basename(urlpath)
142
108
if _fake_machine is None:
143
109
return os.uname()[-1]
144
110
return _fake_machine
113
def mkdir_p(dirname):
114
if not os.path.exists(dirname):
118
@contextlib.contextmanager
119
def changed_directory(dirname, make_if_needed=True):
121
A context manager for running a piece of code in another
122
directory. The directory is created if needed (by default, can
123
be changed with make_if_needed).
125
orig_dir = os.getcwd()
128
logging.info("Changing directory to %r", dirname)
133
logging.info("Changing directory to %r", orig_dir)
137
def merge_dict(merge_into, merge_from):
139
Merge two dictionaries recursively:
141
1) Simple values are overwritten with a logging.warning() message
142
2) Lists are appended
143
3) Dictionaries are merged recursively
145
assert isinstance(merge_into, dict)
146
assert isinstance(merge_from, dict)
147
for key in merge_from.iterkeys():
148
if key in merge_into:
149
if (isinstance(merge_from[key], dict)
150
and isinstance(merge_into[key], dict)):
151
merge_dict(merge_into[key], merge_from[key])
152
elif (isinstance(merge_from[key], list)
153
and isinstance(merge_into[key], list)):
154
merge_into[key].extend(merge_from[key])
157
"Overwriting existing value of %r:"
158
"%r overwritten with %r",
159
key, merge_into[key], merge_from[key])
160
merge_into[key] = merge_from[key]
162
merge_into[key] = merge_from[key]
167
Simple open-cached-URL class
173
home = os.environ.get('HOME', '/')
174
basecache = os.environ.get('XDG_CACHE_HOME',
175
os.path.join(home, '.cache'))
176
self.cache_dir = os.path.join(basecache, 'lava_test')
179
def get_instance(cls):
180
if cls._instance is None:
181
cls._instance = cls()
184
def open_cached(self, key, mode="r"):
186
Acts like open() but the pathname is relative to the
187
lava_test-specific cache directory.
189
if "w" in mode and not os.path.exists(self.cache_dir):
190
os.makedirs(self.cache_dir)
191
if os.path.isabs(key):
192
raise ValueError("key cannot be an absolute path")
194
stream = open(os.path.join(self.cache_dir, key), mode)
199
def _key_for_url(self, url):
200
return hashlib.sha1(url).hexdigest()
202
def _refresh_url_cache(self, key, url):
203
with contextlib.nested(
204
contextlib.closing(urllib2.urlopen(url)),
205
self.open_cached(key, "wb")) as (in_stream, out_stream):
206
out_stream.write(in_stream.read())
208
@contextlib.contextmanager
209
def open_cached_url(self, url):
211
Like urlopen.open() but the content may be cached.
213
# Do not cache local files, this is not what users would expect
215
# workaround - not using cache at all.
216
# TODO: fix this and use the cache
217
# if url.startswith("file://"):
219
stream = urllib2.urlopen(url)
221
key = self._key_for_url(url)
223
stream = self.open_cached(key, "rb")
225
self._refresh_url_cache(key, url)
226
stream = self.open_cached(key, "rb")