summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWilliam Salmon <will.salmon@codethink.co.uk>2019-05-15 17:21:49 +0100
committerWilliam Salmon <will.salmon@codethink.co.uk>2019-07-25 10:08:18 +0100
commit43505dfd6da8b6eb3f4d4e544f3cdc0e2a31a947 (patch)
tree57c2c4e41df4c5c32b776818f83e5458a782b896
parent3e5790d151faaddbeb376eb8cb24178fa9899c17 (diff)
downloadbuildstream-43505dfd6da8b6eb3f4d4e544f3cdc0e2a31a947.tar.gz
Implmented export_to_tar for casbaseddirectory
-rw-r--r--src/buildstream/storage/_casbaseddirectory.py31
-rw-r--r--tests/frontend/buildcheckout.py43
-rw-r--r--tests/frontend/project/elements/import-links.bst4
-rw-r--r--tests/frontend/project/files/files-and-links/basicfile1
l---------tests/frontend/project/files/files-and-links/basicfolder/basicsymlink1
-rw-r--r--tests/frontend/project/files/files-and-links/basicfolder/subdir-file0
6 files changed, 79 insertions, 1 deletions
diff --git a/src/buildstream/storage/_casbaseddirectory.py b/src/buildstream/storage/_casbaseddirectory.py
index ea4862e50..7bd9ceea0 100644
--- a/src/buildstream/storage/_casbaseddirectory.py
+++ b/src/buildstream/storage/_casbaseddirectory.py
@@ -28,6 +28,9 @@ See also: :ref:`sandboxing`.
"""
import os
+import stat
+import tarfile as tarfilelib
+from io import StringIO
from .._protos.build.bazel.remote.execution.v2 import remote_execution_pb2
from .directory import Directory, VirtualDirectoryError, _FileType
@@ -413,7 +416,33 @@ class CasBasedDirectory(Directory):
self.cas_cache.checkout(to_directory, self._get_digest(), can_link=can_link)
def export_to_tar(self, tarfile, destination_dir, mtime=BST_ARBITRARY_TIMESTAMP):
- raise NotImplementedError()
+ for filename, entry in self.index.items():
+ arcname = os.path.join(destination_dir, filename)
+ if entry.type == _FileType.DIRECTORY:
+ tarinfo = tarfilelib.TarInfo(arcname)
+ tarinfo.mtime = mtime
+ tarinfo.type = tarfilelib.DIRTYPE
+ tarinfo.mode = 0o755
+ tarfile.addfile(tarinfo)
+ self.descend(filename).export_to_tar(tarfile, arcname, mtime)
+ elif entry.type == _FileType.REGULAR_FILE:
+ source_name = self.cas_cache.objpath(entry.digest)
+ tarinfo = tarfilelib.TarInfo(arcname)
+ tarinfo.mtime = mtime
+ tarinfo.mode |= entry.is_executable & stat.S_IXUSR
+ tarinfo.size = os.path.getsize(source_name)
+ with open(source_name, "rb") as f:
+ tarfile.addfile(tarinfo, f)
+ elif entry.type == _FileType.SYMLINK:
+ tarinfo = tarfilelib.TarInfo(arcname)
+ tarinfo.mtime = mtime
+ tarinfo.mode |= entry.is_executable & stat.S_IXUSR
+ tarinfo.linkname = entry.target
+ tarinfo.type = tarfilelib.SYMTYPE
+ f = StringIO(entry.target)
+ tarfile.addfile(tarinfo, f)
+ else:
+ raise VirtualDirectoryError("can not export file type {} to tar".format(entry.type))
def _mark_changed(self):
""" It should not be possible to externally modify a CAS-based
diff --git a/tests/frontend/buildcheckout.py b/tests/frontend/buildcheckout.py
index a3f68c031..dd4a461ea 100644
--- a/tests/frontend/buildcheckout.py
+++ b/tests/frontend/buildcheckout.py
@@ -425,6 +425,49 @@ def test_build_checkout_tarball_is_deterministic(datafiles, cli):
@pytest.mark.datafiles(DATA_DIR)
+def test_build_checkout_tarball_links(datafiles, cli):
+ project = str(datafiles)
+ checkout = os.path.join(cli.directory, 'checkout.tar')
+ extract = os.path.join(cli.directory, 'extract')
+
+ result = cli.run(project=project, args=['build', 'import-links.bst'])
+ result.assert_success()
+
+ builddir = os.path.join(cli.directory, 'build')
+ assert os.path.isdir(builddir)
+ assert not os.listdir(builddir)
+
+ checkout_args = ['artifact', 'checkout', '--tar', checkout, 'import-links.bst']
+
+ result = cli.run(project=project, args=checkout_args)
+ result.assert_success()
+
+ tar = tarfile.open(name=checkout, mode="r:")
+ tar.extractall(extract)
+ assert open(os.path.join(extract, 'basicfolder', 'basicsymlink')).read() == "file contents\n"
+
+
+@pytest.mark.datafiles(DATA_DIR)
+def test_build_checkout_links(datafiles, cli):
+ project = str(datafiles)
+ checkout = os.path.join(cli.directory, 'checkout')
+
+ result = cli.run(project=project, args=['build', 'import-links.bst'])
+ result.assert_success()
+
+ builddir = os.path.join(cli.directory, 'build')
+ assert os.path.isdir(builddir)
+ assert not os.listdir(builddir)
+
+ checkout_args = ['artifact', 'checkout', '--directory', checkout, 'import-links.bst']
+
+ result = cli.run(project=project, args=checkout_args)
+ result.assert_success()
+
+ assert open(os.path.join(checkout, 'basicfolder', 'basicsymlink')).read() == "file contents\n"
+
+
+@pytest.mark.datafiles(DATA_DIR)
@pytest.mark.parametrize("hardlinks", [("copies"), ("hardlinks")])
def test_build_checkout_nonempty(datafiles, cli, hardlinks):
project = str(datafiles)
diff --git a/tests/frontend/project/elements/import-links.bst b/tests/frontend/project/elements/import-links.bst
new file mode 100644
index 000000000..42b279ee2
--- /dev/null
+++ b/tests/frontend/project/elements/import-links.bst
@@ -0,0 +1,4 @@
+kind: import
+sources:
+- kind: local
+ path: files/files-and-links
diff --git a/tests/frontend/project/files/files-and-links/basicfile b/tests/frontend/project/files/files-and-links/basicfile
new file mode 100644
index 000000000..d03e2425c
--- /dev/null
+++ b/tests/frontend/project/files/files-and-links/basicfile
@@ -0,0 +1 @@
+file contents
diff --git a/tests/frontend/project/files/files-and-links/basicfolder/basicsymlink b/tests/frontend/project/files/files-and-links/basicfolder/basicsymlink
new file mode 120000
index 000000000..e2b4f7423
--- /dev/null
+++ b/tests/frontend/project/files/files-and-links/basicfolder/basicsymlink
@@ -0,0 +1 @@
+../basicfile \ No newline at end of file
diff --git a/tests/frontend/project/files/files-and-links/basicfolder/subdir-file b/tests/frontend/project/files/files-and-links/basicfolder/subdir-file
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/frontend/project/files/files-and-links/basicfolder/subdir-file