Jim MacArthur pushed to branch jmac/tempfile-extraction-bug at BuildStream / buildstream
Commits:
-
ddb2121e
by Jim MacArthur at 2018-08-23T17:39:06Z
-
4cc4b4c8
by James Ennis at 2018-08-23T17:39:06Z
-
74f5b158
by James Ennis at 2018-08-23T17:39:06Z
4 changed files:
- buildstream/element.py
- tests/sources/tar.py
- + tests/sources/tar/read-only/content/a.tar.gz
- + tests/sources/tar/read-only/target.bst
Changes:
... | ... | @@ -1361,8 +1361,12 @@ class Element(Plugin): |
1361 | 1361 |
if not vdirectory.is_empty():
|
1362 | 1362 |
raise ElementError("Staging directory '{}' is not empty".format(vdirectory))
|
1363 | 1363 |
|
1364 |
- with tempfile.TemporaryDirectory() as temp_staging_directory:
|
|
1364 |
+ # While mkdtemp is advertised as using the TMP environment variable, it
|
|
1365 |
+ # doesn't, so this explicit extraction is necesasry.
|
|
1366 |
+ tmp_prefix = os.environ.get("TMP", None)
|
|
1367 |
+ temp_staging_directory = tempfile.mkdtemp(prefix=tmp_prefix)
|
|
1365 | 1368 |
|
1369 |
+ try:
|
|
1366 | 1370 |
workspace = self._get_workspace()
|
1367 | 1371 |
if workspace:
|
1368 | 1372 |
# If mount_workspaces is set and we're doing incremental builds,
|
... | ... | @@ -1377,6 +1381,16 @@ class Element(Plugin): |
1377 | 1381 |
source._stage(temp_staging_directory)
|
1378 | 1382 |
|
1379 | 1383 |
vdirectory.import_files(temp_staging_directory)
|
1384 |
+ |
|
1385 |
+ finally:
|
|
1386 |
+ # Staging may produce directories with less than 'rwx' permissions
|
|
1387 |
+ # for the owner, which will break tempfile, so we need to use chmod
|
|
1388 |
+ # occasionally.
|
|
1389 |
+ def make_dir_writable(fn, path, excinfo):
|
|
1390 |
+ os.chmod(os.path.dirname(path), 0o777)
|
|
1391 |
+ os.remove(path)
|
|
1392 |
+ shutil.rmtree(temp_staging_directory, onerror=make_dir_writable)
|
|
1393 |
+ |
|
1380 | 1394 |
# Ensure deterministic mtime of sources at build time
|
1381 | 1395 |
vdirectory.set_deterministic_mtime()
|
1382 | 1396 |
# Ensure deterministic owners of sources at build time
|
... | ... | @@ -3,6 +3,7 @@ import pytest |
3 | 3 |
import tarfile
|
4 | 4 |
import tempfile
|
5 | 5 |
import subprocess
|
6 |
+from shutil import copyfile, rmtree
|
|
6 | 7 |
|
7 | 8 |
from buildstream._exceptions import ErrorDomain
|
8 | 9 |
from buildstream import _yaml
|
... | ... | @@ -257,3 +258,44 @@ def test_stage_default_basedir_lzip(cli, tmpdir, datafiles, srcdir): |
257 | 258 |
original_contents = list_dir_contents(original_dir)
|
258 | 259 |
checkout_contents = list_dir_contents(checkoutdir)
|
259 | 260 |
assert(checkout_contents == original_contents)
|
261 |
+ |
|
262 |
+ |
|
263 |
+# Test that a tarball that contains a read only dir works
|
|
264 |
+@pytest.mark.datafiles(os.path.join(DATA_DIR, 'read-only'))
|
|
265 |
+def test_read_only_dir(cli, tmpdir, datafiles):
|
|
266 |
+ try:
|
|
267 |
+ project = os.path.join(datafiles.dirname, datafiles.basename)
|
|
268 |
+ generate_project(project, tmpdir)
|
|
269 |
+ |
|
270 |
+ # Get the tarball in tests/sources/tar/read-only/content
|
|
271 |
+ #
|
|
272 |
+ # NOTE that we need to do this because tarfile.open and tar.add()
|
|
273 |
+ # are packing the tar up with writeable files and dirs
|
|
274 |
+ tarball = os.path.join(str(datafiles), 'content', 'a.tar.gz')
|
|
275 |
+ if not os.path.exists(tarball):
|
|
276 |
+ raise FileNotFoundError('{} does not exist'.format(tarball))
|
|
277 |
+ copyfile(tarball, os.path.join(tmpdir, 'a.tar.gz'))
|
|
278 |
+ |
|
279 |
+ # Because this test can potentially leave directories behind
|
|
280 |
+ # which are difficult to remove, ask buildstream to use
|
|
281 |
+ # our temp directory, so we can clean up.
|
|
282 |
+ tmpdir_str = str(tmpdir)
|
|
283 |
+ if not tmpdir_str.endswith(os.path.sep):
|
|
284 |
+ tmpdir_str += os.path.sep
|
|
285 |
+ env = {"TMP": tmpdir_str}
|
|
286 |
+ |
|
287 |
+ # Track, fetch, build, checkout
|
|
288 |
+ result = cli.run(project=project, args=['track', 'target.bst'], env=env)
|
|
289 |
+ result.assert_success()
|
|
290 |
+ result = cli.run(project=project, args=['fetch', 'target.bst'], env=env)
|
|
291 |
+ result.assert_success()
|
|
292 |
+ result = cli.run(project=project, args=['build', 'target.bst'], env=env)
|
|
293 |
+ result.assert_success()
|
|
294 |
+ |
|
295 |
+ finally:
|
|
296 |
+ |
|
297 |
+ # Make tmpdir deletable no matter what happens
|
|
298 |
+ def make_dir_writable(fn, path, excinfo):
|
|
299 |
+ os.chmod(os.path.dirname(path), 0o777)
|
|
300 |
+ os.remove(path)
|
|
301 |
+ rmtree(str(tmpdir), onerror=make_dir_writable)
|
No preview for this file type
1 |
+kind: import
|
|
2 |
+description: The kind of this element is irrelevant.
|
|
3 |
+sources:
|
|
4 |
+- kind: tar
|
|
5 |
+ url: tmpdir:/a.tar.gz
|
|
6 |
+ ref: foo
|