8 def clear_tmpdir(path=None):
10 Ensure the given directory (or TASK_TMPDIR if none given)
14 path = current_task().tmpdir
15 if os.path.exists(path):
16 p = subprocess.Popen(['rm', '-rf', path])
17 stdout, stderr = p.communicate(None)
19 raise Exception('rm -rf %s: %s' % (path, stderr))
22 def run_command(execargs, **kwargs):
23 kwargs.setdefault('stdin', subprocess.PIPE)
24 kwargs.setdefault('stdout', subprocess.PIPE)
25 kwargs.setdefault('stderr', sys.stderr)
26 kwargs.setdefault('close_fds', True)
27 kwargs.setdefault('shell', False)
28 p = subprocess.Popen(execargs, **kwargs)
29 stdoutdata, stderrdata = p.communicate(None)
31 raise errors.CommandFailedError(
32 "run_command %s exit %d:\n%s" %
33 (execargs, p.returncode, stderrdata))
34 return stdoutdata, stderrdata
36 def git_checkout(url, version, path):
37 if not re.search('^/', path):
38 path = os.path.join(current_job().tmpdir, path)
39 if not os.path.exists(path):
40 util.run_command(["git", "clone", url, path],
41 cwd=os.path.dirname(path))
42 util.run_command(["git", "checkout", version],
46 def tar_extractor(path, decompress_flag):
47 return subprocess.Popen(["tar",
49 ("-x%sf" % decompress_flag),
52 stdin=subprocess.PIPE, stderr=sys.stderr,
53 shell=False, close_fds=True)
55 def tarball_extract(tarball, path):
56 """Retrieve a tarball from Keep and extract it to a local
57 directory. Return the absolute path where the tarball was
58 extracted. If the top level of the tarball contained just one
59 file or directory, return the absolute path of that single
62 tarball -- collection locator
63 path -- where to extract the tarball: absolute, or relative to job tmp
65 if not re.search('^/', path):
66 path = os.path.join(current_job().tmpdir, path)
67 lockfile = open(path + '.lock', 'w')
68 fcntl.flock(lockfile, fcntl.LOCK_EX)
73 already_have_it = False
75 if os.readlink(os.path.join(path, '.locator')) == tarball:
76 already_have_it = True
79 if not already_have_it:
81 # emulate "rm -f" (i.e., if the file does not exist, we win)
83 os.unlink(os.path.join(path, '.locator'))
85 if os.path.exists(os.path.join(path, '.locator')):
86 os.unlink(os.path.join(path, '.locator'))
88 for f in CollectionReader(tarball).all_files():
89 if re.search('\.(tbz|tar.bz2)$', f.name()):
90 p = util.tar_extractor(path, 'j')
91 elif re.search('\.(tgz|tar.gz)$', f.name()):
92 p = util.tar_extractor(path, 'z')
93 elif re.search('\.tar$', f.name()):
94 p = util.tar_extractor(path, '')
96 raise errors.AssertionError(
97 "tarball_extract cannot handle filename %s" % f.name())
105 if p.returncode != 0:
107 raise errors.CommandFailedError(
108 "tar exited %d" % p.returncode)
109 os.symlink(tarball, os.path.join(path, '.locator'))
110 tld_extracts = filter(lambda f: f != '.locator', os.listdir(path))
112 if len(tld_extracts) == 1:
113 return os.path.join(path, tld_extracts[0])
116 def zipball_extract(zipball, path):
117 """Retrieve a zip archive from Keep and extract it to a local
118 directory. Return the absolute path where the archive was
119 extracted. If the top level of the archive contained just one
120 file or directory, return the absolute path of that single
123 zipball -- collection locator
124 path -- where to extract the archive: absolute, or relative to job tmp
126 if not re.search('^/', path):
127 path = os.path.join(current_job().tmpdir, path)
128 lockfile = open(path + '.lock', 'w')
129 fcntl.flock(lockfile, fcntl.LOCK_EX)
134 already_have_it = False
136 if os.readlink(os.path.join(path, '.locator')) == zipball:
137 already_have_it = True
140 if not already_have_it:
142 # emulate "rm -f" (i.e., if the file does not exist, we win)
144 os.unlink(os.path.join(path, '.locator'))
146 if os.path.exists(os.path.join(path, '.locator')):
147 os.unlink(os.path.join(path, '.locator'))
149 for f in CollectionReader(zipball).all_files():
150 if not re.search('\.zip$', f.name()):
151 raise errors.NotImplementedError(
152 "zipball_extract cannot handle filename %s" % f.name())
153 zip_filename = os.path.join(path, os.path.basename(f.name()))
154 zip_file = open(zip_filename, 'wb')
162 p = subprocess.Popen(["unzip",
167 stdin=None, stderr=sys.stderr,
168 shell=False, close_fds=True)
170 if p.returncode != 0:
172 raise errors.CommandFailedError(
173 "unzip exited %d" % p.returncode)
174 os.unlink(zip_filename)
175 os.symlink(zipball, os.path.join(path, '.locator'))
176 tld_extracts = filter(lambda f: f != '.locator', os.listdir(path))
178 if len(tld_extracts) == 1:
179 return os.path.join(path, tld_extracts[0])
182 def collection_extract(collection, path, files=[], decompress=True):
183 """Retrieve a collection from Keep and extract it to a local
184 directory. Return the absolute path where the collection was
187 collection -- collection locator
188 path -- where to extract: absolute, or relative to job tmp
190 matches = re.search(r'^([0-9a-f]+)(\+[\w@]+)*$', collection)
192 collection_hash = matches.group(1)
194 collection_hash = hashlib.md5(collection).hexdigest()
195 if not re.search('^/', path):
196 path = os.path.join(current_job().tmpdir, path)
197 lockfile = open(path + '.lock', 'w')
198 fcntl.flock(lockfile, fcntl.LOCK_EX)
203 already_have_it = False
205 if os.readlink(os.path.join(path, '.locator')) == collection_hash:
206 already_have_it = True
210 # emulate "rm -f" (i.e., if the file does not exist, we win)
212 os.unlink(os.path.join(path, '.locator'))
214 if os.path.exists(os.path.join(path, '.locator')):
215 os.unlink(os.path.join(path, '.locator'))
218 for s in CollectionReader(collection).all_streams():
219 stream_name = s.name()
220 for f in s.all_files():
222 ((f.name() not in files_got) and
223 (f.name() in files or
224 (decompress and f.decompressed_name() in files)))):
225 outname = f.decompressed_name() if decompress else f.name()
226 files_got += [outname]
227 if os.path.exists(os.path.join(path, stream_name, outname)):
229 mkdir_dash_p(os.path.dirname(os.path.join(path, stream_name, outname)))
230 outfile = open(os.path.join(path, stream_name, outname), 'wb')
231 for buf in (f.readall_decompressed() if decompress
235 if len(files_got) < len(files):
236 raise errors.AssertionError(
237 "Wanted files %s but only got %s from %s" %
239 [z.name() for z in CollectionReader(collection).all_files()]))
240 os.symlink(collection_hash, os.path.join(path, '.locator'))
245 def mkdir_dash_p(path):
246 if not os.path.isdir(path):
250 if e.errno == errno.EEXIST and os.path.isdir(path):
251 # It is not an error if someone else creates the
252 # directory between our exists() and makedirs() calls.
257 def stream_extract(stream, path, files=[], decompress=True):
258 """Retrieve a stream from Keep and extract it to a local
259 directory. Return the absolute path where the stream was
262 stream -- StreamReader object
263 path -- where to extract: absolute, or relative to job tmp
265 if not re.search('^/', path):
266 path = os.path.join(current_job().tmpdir, path)
267 lockfile = open(path + '.lock', 'w')
268 fcntl.flock(lockfile, fcntl.LOCK_EX)
275 for f in stream.all_files():
277 ((f.name() not in files_got) and
278 (f.name() in files or
279 (decompress and f.decompressed_name() in files)))):
280 outname = f.decompressed_name() if decompress else f.name()
281 files_got += [outname]
282 if os.path.exists(os.path.join(path, outname)):
283 os.unlink(os.path.join(path, outname))
284 util.mkdir_dash_p(os.path.dirname(os.path.join(path, outname)))
285 outfile = open(os.path.join(path, outname), 'wb')
286 for buf in (f.readall_decompressed() if decompress
290 if len(files_got) < len(files):
291 raise errors.AssertionError(
292 "Wanted files %s but only got %s from %s" %
293 (files, files_got, [z.name() for z in stream.all_files()]))
297 def listdir_recursive(dirname, base=None):
299 for ent in sorted(os.listdir(dirname)):
300 ent_path = os.path.join(dirname, ent)
301 ent_base = os.path.join(base, ent) if base else ent
302 if os.path.isdir(ent_path):
303 allfiles += util.listdir_recursive(ent_path, ent_base)
305 allfiles += [ent_base]