summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTristan Van Berkom <tristan.van.berkom@gmail.com>2018-08-12 07:00:17 +0000
committerTristan Van Berkom <tristan.van.berkom@gmail.com>2018-08-12 07:00:17 +0000
commite5dfbb54626323b11f78fb2cebbbc615e0221a2b (patch)
tree1d6c5bbdc063d7d9fefd29bb7b5a709e755fd44c
parent37742ac7a2b1b6aaaa460da0be30495c3c1a60db (diff)
parentb7b4b71800f04b19b17de2298cf1fa96b544acd5 (diff)
downloadbuildstream-e5dfbb54626323b11f78fb2cebbbc615e0221a2b.tar.gz
Merge branch 'valentindavid/deterministic-source-1.2' into 'bst-1.2'
Deterministic staging See merge request BuildStream/buildstream!634
-rw-r--r--buildstream/_versions.py3
-rw-r--r--buildstream/plugins/sources/local.py26
-rw-r--r--buildstream/plugins/sources/remote.py2
-rw-r--r--buildstream/plugins/sources/zip.py32
-rw-r--r--buildstream/utils.py11
-rw-r--r--tests/cachekey/project/elements/build1.expected2
-rw-r--r--tests/cachekey/project/elements/build2.expected2
-rw-r--r--tests/cachekey/project/elements/compose1.expected2
-rw-r--r--tests/cachekey/project/elements/compose2.expected2
-rw-r--r--tests/cachekey/project/elements/compose3.expected2
-rw-r--r--tests/cachekey/project/elements/compose4.expected2
-rw-r--r--tests/cachekey/project/elements/compose5.expected2
-rw-r--r--tests/cachekey/project/elements/import1.expected2
-rw-r--r--tests/cachekey/project/elements/import2.expected2
-rw-r--r--tests/cachekey/project/elements/import3.expected2
-rw-r--r--tests/cachekey/project/elements/script1.expected2
-rw-r--r--tests/cachekey/project/sources/bzr1.expected2
-rw-r--r--tests/cachekey/project/sources/git1.expected2
-rw-r--r--tests/cachekey/project/sources/git2.expected2
-rw-r--r--tests/cachekey/project/sources/local1.expected2
-rw-r--r--tests/cachekey/project/sources/local2.expected2
-rw-r--r--tests/cachekey/project/sources/ostree1.expected2
-rw-r--r--tests/cachekey/project/sources/patch1.expected2
-rw-r--r--tests/cachekey/project/sources/patch2.expected2
-rw-r--r--tests/cachekey/project/sources/patch3.expected2
-rw-r--r--tests/cachekey/project/sources/tar1.expected2
-rw-r--r--tests/cachekey/project/sources/tar2.expected2
-rw-r--r--tests/cachekey/project/sources/zip1.expected2
-rw-r--r--tests/cachekey/project/sources/zip2.expected2
-rw-r--r--tests/cachekey/project/target.expected2
-rw-r--r--tests/integration/source-determinism.py155
31 files changed, 249 insertions, 30 deletions
diff --git a/buildstream/_versions.py b/buildstream/_versions.py
index ff85d2443..eddb34fc6 100644
--- a/buildstream/_versions.py
+++ b/buildstream/_versions.py
@@ -33,4 +33,5 @@ BST_FORMAT_VERSION = 12
# or if buildstream was changed in a way which can cause
# the same cache key to produce something that is no longer
# the same.
-BST_CORE_ARTIFACT_VERSION = 2
+
+BST_CORE_ARTIFACT_VERSION = ('bst-1.2', 3)
diff --git a/buildstream/plugins/sources/local.py b/buildstream/plugins/sources/local.py
index 058553424..7c19e1f90 100644
--- a/buildstream/plugins/sources/local.py
+++ b/buildstream/plugins/sources/local.py
@@ -37,6 +37,7 @@ local - stage local files and directories
"""
import os
+import stat
from buildstream import Source, Consistency
from buildstream import utils
@@ -94,12 +95,35 @@ class LocalSource(Source):
# Dont use hardlinks to stage sources, they are not write protected
# in the sandbox.
with self.timed_activity("Staging local files at {}".format(self.path)):
+
if os.path.isdir(self.fullpath):
- utils.copy_files(self.fullpath, directory)
+ files = list(utils.list_relative_paths(self.fullpath, list_dirs=True))
+ utils.copy_files(self.fullpath, directory, files=files)
else:
destfile = os.path.join(directory, os.path.basename(self.path))
+ files = [os.path.basename(self.path)]
utils.safe_copy(self.fullpath, destfile)
+ for f in files:
+ # Non empty directories are not listed by list_relative_paths
+ dirs = f.split(os.sep)
+ for i in range(1, len(dirs)):
+ d = os.path.join(directory, *(dirs[:i]))
+ assert os.path.isdir(d) and not os.path.islink(d)
+ os.chmod(d, stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH)
+
+ path = os.path.join(directory, f)
+ if os.path.islink(path):
+ pass
+ elif os.path.isdir(path):
+ os.chmod(path, stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH)
+ else:
+ st = os.stat(path)
+ if st.st_mode & stat.S_IXUSR:
+ os.chmod(path, stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH)
+ else:
+ os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH)
+
# Create a unique key for a file
def unique_key(filename):
diff --git a/buildstream/plugins/sources/remote.py b/buildstream/plugins/sources/remote.py
index ad4cdab8b..ea0e612c2 100644
--- a/buildstream/plugins/sources/remote.py
+++ b/buildstream/plugins/sources/remote.py
@@ -49,6 +49,7 @@ remote - stage files from remote urls
"""
import os
+import stat
from buildstream import SourceError, utils
from ._downloadablefilesource import DownloadableFileSource
@@ -75,6 +76,7 @@ class RemoteSource(DownloadableFileSource):
dest = os.path.join(directory, self.filename)
with self.timed_activity("Staging remote file to {}".format(dest)):
utils.safe_copy(self._get_mirror_file(), dest)
+ os.chmod(dest, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH)
def setup():
diff --git a/buildstream/plugins/sources/zip.py b/buildstream/plugins/sources/zip.py
index 9b47d7f78..d3ce0f16d 100644
--- a/buildstream/plugins/sources/zip.py
+++ b/buildstream/plugins/sources/zip.py
@@ -49,10 +49,17 @@ zip - stage files from zip archives
# To extract the root of the archive directly, this can be set
# to an empty string.
base-dir: '*'
+
+.. attention::
+
+ File permissions are not preserved. All extracted directories have
+ permissions 0755 and all extracted files have permissions 0644.
+
"""
import os
import zipfile
+import stat
from buildstream import SourceError
from buildstream import utils
@@ -74,6 +81,9 @@ class ZipSource(DownloadableFileSource):
return super().get_unique_key() + [self.base_dir]
def stage(self, directory):
+ exec_rights = (stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) & ~(stat.S_IWGRP | stat.S_IWOTH)
+ noexec_rights = exec_rights & ~(stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
+
try:
with zipfile.ZipFile(self._get_mirror_file()) as archive:
base_dir = None
@@ -81,9 +91,27 @@ class ZipSource(DownloadableFileSource):
base_dir = self._find_base_dir(archive, self.base_dir)
if base_dir:
- archive.extractall(path=directory, members=self._extract_members(archive, base_dir))
+ members = self._extract_members(archive, base_dir)
else:
- archive.extractall(path=directory)
+ members = archive.namelist()
+
+ for member in members:
+ written = archive.extract(member, path=directory)
+
+ # zipfile.extract might create missing directories
+ rel = os.path.relpath(written, start=directory)
+ assert not os.path.isabs(rel)
+ rel = os.path.dirname(rel)
+ while rel:
+ os.chmod(os.path.join(directory, rel), exec_rights)
+ rel = os.path.dirname(rel)
+
+ if os.path.islink(written):
+ pass
+ elif os.path.isdir(written):
+ os.chmod(written, exec_rights)
+ else:
+ os.chmod(written, noexec_rights)
except (zipfile.BadZipFile, zipfile.LargeZipFile, OSError) as e:
raise SourceError("{}: Error staging source: {}".format(self, e)) from e
diff --git a/buildstream/utils.py b/buildstream/utils.py
index 68f99b9a3..9546f13cd 100644
--- a/buildstream/utils.py
+++ b/buildstream/utils.py
@@ -1010,6 +1010,15 @@ def _call(*popenargs, terminate=False, **kwargs):
process = None
+ old_preexec_fn = kwargs.get('preexec_fn')
+ if 'preexec_fn' in kwargs:
+ del kwargs['preexec_fn']
+
+ def preexec_fn():
+ os.umask(stat.S_IWGRP | stat.S_IWOTH)
+ if old_preexec_fn is not None:
+ old_preexec_fn()
+
# Handle termination, suspend and resume
def kill_proc():
if process:
@@ -1054,7 +1063,7 @@ def _call(*popenargs, terminate=False, **kwargs):
os.killpg(group_id, signal.SIGCONT)
with _signals.suspendable(suspend_proc, resume_proc), _signals.terminator(kill_proc):
- process = subprocess.Popen(*popenargs, **kwargs)
+ process = subprocess.Popen(*popenargs, preexec_fn=preexec_fn, **kwargs)
output, _ = process.communicate()
exit_code = process.poll()
diff --git a/tests/cachekey/project/elements/build1.expected b/tests/cachekey/project/elements/build1.expected
index 7c5af6054..cc4bf4229 100644
--- a/tests/cachekey/project/elements/build1.expected
+++ b/tests/cachekey/project/elements/build1.expected
@@ -1 +1 @@
-3db51572837956b28ffbc4aabdce659b4a1d91dcbb8b75954210346959ed5fa9 \ No newline at end of file
+e7de3dd12a1e5307e07859ddf2192443a0ccb1ff48e0adcc6c18f9edc2bd0d7d \ No newline at end of file
diff --git a/tests/cachekey/project/elements/build2.expected b/tests/cachekey/project/elements/build2.expected
index e1bd91218..3cb726dde 100644
--- a/tests/cachekey/project/elements/build2.expected
+++ b/tests/cachekey/project/elements/build2.expected
@@ -1 +1 @@
-bcde6fc389b7d8bb7788989b68f68653ab8ed658117012c0611f218f4a585d38 \ No newline at end of file
+d74957e0f20a7664e9ceed6cc2ba6c140bd8d8d0712d02066feb442638e8e6ed \ No newline at end of file
diff --git a/tests/cachekey/project/elements/compose1.expected b/tests/cachekey/project/elements/compose1.expected
index 86a2a2f2a..7289d9919 100644
--- a/tests/cachekey/project/elements/compose1.expected
+++ b/tests/cachekey/project/elements/compose1.expected
@@ -1 +1 @@
-6736bbcc055e1801a19288d3a64b622e0b9223164f8ad2ce842b18a4eaa0cfb9 \ No newline at end of file
+f8b69ac5ce84a8e8db30f9ae58d7560054d41da311176f74047694ec1203d7e8 \ No newline at end of file
diff --git a/tests/cachekey/project/elements/compose2.expected b/tests/cachekey/project/elements/compose2.expected
index a811cc421..f80f6fb1e 100644
--- a/tests/cachekey/project/elements/compose2.expected
+++ b/tests/cachekey/project/elements/compose2.expected
@@ -1 +1 @@
-9294428a0b5c0d44fdb3ab0f883ee87f9e62d51f96c7de1e5e81ed5e3934d403 \ No newline at end of file
+4f542af0ebf3136b0affe42cb5574b7cf1034db6fb60d272ab2304e1c99b0d6f \ No newline at end of file
diff --git a/tests/cachekey/project/elements/compose3.expected b/tests/cachekey/project/elements/compose3.expected
index ce28c853a..7b9d23ed4 100644
--- a/tests/cachekey/project/elements/compose3.expected
+++ b/tests/cachekey/project/elements/compose3.expected
@@ -1 +1 @@
-4f1569b9a6317280e6299f9f7f706a6adcc89603030cde51d529dd6dfe2851be \ No newline at end of file
+93863a5513f3b59a107a3ba23a6e47b38738e7c99ac462d2379308dab9910d8f \ No newline at end of file
diff --git a/tests/cachekey/project/elements/compose4.expected b/tests/cachekey/project/elements/compose4.expected
index 8d95a3d87..7feb88917 100644
--- a/tests/cachekey/project/elements/compose4.expected
+++ b/tests/cachekey/project/elements/compose4.expected
@@ -1 +1 @@
-4c83744bec21c8c38bce2d48396b8df1eb4df7b2f155424016bd012743efd808 \ No newline at end of file
+e66827c4f0beffbb9eff52522539b10945ad108bd5ad722107e5dfbce7d064ef \ No newline at end of file
diff --git a/tests/cachekey/project/elements/compose5.expected b/tests/cachekey/project/elements/compose5.expected
index 183534aa4..d99aa675f 100644
--- a/tests/cachekey/project/elements/compose5.expected
+++ b/tests/cachekey/project/elements/compose5.expected
@@ -1 +1 @@
-97385aa2192ef0295dd2601e78491d8bdf6b74e98938d0f8011747c2caf3a5c6 \ No newline at end of file
+74a1fcb3c1c7829962398cc104a30d52aeb38af9fe8631a6b77112a1fe99b653 \ No newline at end of file
diff --git a/tests/cachekey/project/elements/import1.expected b/tests/cachekey/project/elements/import1.expected
index 387da88b7..b9020e2d0 100644
--- a/tests/cachekey/project/elements/import1.expected
+++ b/tests/cachekey/project/elements/import1.expected
@@ -1 +1 @@
-99c8f61d415de3a6c96e48299fda5554bf4bbaf56bb4b5acd85861ab37ede0c3 \ No newline at end of file
+619692c94c9b499eaa23358b45fd75b4526d9f5b6d3a6061faad9b6726510db3 \ No newline at end of file
diff --git a/tests/cachekey/project/elements/import2.expected b/tests/cachekey/project/elements/import2.expected
index 0893dde2a..27a365a64 100644
--- a/tests/cachekey/project/elements/import2.expected
+++ b/tests/cachekey/project/elements/import2.expected
@@ -1 +1 @@
-5f5884c5e4bb7066eede3a135e49753ec06b757a30983513a7a4e0cdd2a8f402 \ No newline at end of file
+8e1ee1f99738be5162e97194d9aa72aef0a9d3458218747f9721102f2d7104d7 \ No newline at end of file
diff --git a/tests/cachekey/project/elements/import3.expected b/tests/cachekey/project/elements/import3.expected
index 6d0fe864a..8e8eed096 100644
--- a/tests/cachekey/project/elements/import3.expected
+++ b/tests/cachekey/project/elements/import3.expected
@@ -1 +1 @@
-e11f93ec629bc3556e15bd374e67a0b5e34350e1e9b1d1f98f8de984a27bbead \ No newline at end of file
+5d9cfb59d10bb98ca17c52cf8862b84a39202b1d83074a8b8dd3da83a0303c19 \ No newline at end of file
diff --git a/tests/cachekey/project/elements/script1.expected b/tests/cachekey/project/elements/script1.expected
index e8d5b24c4..3613c35d7 100644
--- a/tests/cachekey/project/elements/script1.expected
+++ b/tests/cachekey/project/elements/script1.expected
@@ -1 +1 @@
-d8388b756de5c8441375ba32cedd9560a65a8f9a85e41038837d342c8fb10004 \ No newline at end of file
+7df04616b29ee538ec5e290dcfd7fdfce9cacdbaf224597856272aec3939d5c8 \ No newline at end of file
diff --git a/tests/cachekey/project/sources/bzr1.expected b/tests/cachekey/project/sources/bzr1.expected
index ca11c959a..cb276c4c2 100644
--- a/tests/cachekey/project/sources/bzr1.expected
+++ b/tests/cachekey/project/sources/bzr1.expected
@@ -1 +1 @@
-519ee88fcca7fea091245713ec68baa048e3d876ea22559d4b2035d3d2ab2494 \ No newline at end of file
+a2682d5e230ea207054fef05eecc1bb8ebc856ae12984ca5ab187d648551e917 \ No newline at end of file
diff --git a/tests/cachekey/project/sources/git1.expected b/tests/cachekey/project/sources/git1.expected
index 85dc88500..427db1397 100644
--- a/tests/cachekey/project/sources/git1.expected
+++ b/tests/cachekey/project/sources/git1.expected
@@ -1 +1 @@
-a5424aa7cc25f0ada9ac1245b33d55d078559ae6c50b10bea3db9acb964b058c \ No newline at end of file
+572276304251917e3ce611b19a6c95cb984d989274405344d307e463c53c6b41 \ No newline at end of file
diff --git a/tests/cachekey/project/sources/git2.expected b/tests/cachekey/project/sources/git2.expected
index 9a643c000..a481139d9 100644
--- a/tests/cachekey/project/sources/git2.expected
+++ b/tests/cachekey/project/sources/git2.expected
@@ -1 +1 @@
-93bf7344c118664f0d7f2b8e5a6731b2a95de6df83ba7fa2a2ab28227b0b3e8b \ No newline at end of file
+e1c86b2e7a5e87f01a7ea10beacff0c9d2771b39e295729e76db42f2133ad478 \ No newline at end of file
diff --git a/tests/cachekey/project/sources/local1.expected b/tests/cachekey/project/sources/local1.expected
index 387da88b7..b9020e2d0 100644
--- a/tests/cachekey/project/sources/local1.expected
+++ b/tests/cachekey/project/sources/local1.expected
@@ -1 +1 @@
-99c8f61d415de3a6c96e48299fda5554bf4bbaf56bb4b5acd85861ab37ede0c3 \ No newline at end of file
+619692c94c9b499eaa23358b45fd75b4526d9f5b6d3a6061faad9b6726510db3 \ No newline at end of file
diff --git a/tests/cachekey/project/sources/local2.expected b/tests/cachekey/project/sources/local2.expected
index 598fe73ba..7a5a9fcc7 100644
--- a/tests/cachekey/project/sources/local2.expected
+++ b/tests/cachekey/project/sources/local2.expected
@@ -1 +1 @@
-780a7e62bbe5bc0f975ec6cd749de6a85f9080d3628f16f881605801597916a7 \ No newline at end of file
+080e7416809ccc1a433e28263f6d719c2ac18047ea6def5991ef0dbd049a76f7 \ No newline at end of file
diff --git a/tests/cachekey/project/sources/ostree1.expected b/tests/cachekey/project/sources/ostree1.expected
index 0e8e83014..b318f5051 100644
--- a/tests/cachekey/project/sources/ostree1.expected
+++ b/tests/cachekey/project/sources/ostree1.expected
@@ -1 +1 @@
-9b06b6e0c213a5475d2b0fcfee537c41dbec579e6109e95f7e7aeb0488f079f6 \ No newline at end of file
+9ea532e5911bae30f07910a5da05190c74477e4b5038e8aa43e0178c48d85f92 \ No newline at end of file
diff --git a/tests/cachekey/project/sources/patch1.expected b/tests/cachekey/project/sources/patch1.expected
index d7cf73c34..8887de99d 100644
--- a/tests/cachekey/project/sources/patch1.expected
+++ b/tests/cachekey/project/sources/patch1.expected
@@ -1 +1 @@
-d5b0f1fa5b4e3e7aa617de303125268c7a7461e415ecf1eccc8aee2cda56897e \ No newline at end of file
+11cab57689dcbb0afd4ee70d589d41d641e1f103427df51fd1d944ec66edc21b \ No newline at end of file
diff --git a/tests/cachekey/project/sources/patch2.expected b/tests/cachekey/project/sources/patch2.expected
index 56a92dc8e..196bfedf4 100644
--- a/tests/cachekey/project/sources/patch2.expected
+++ b/tests/cachekey/project/sources/patch2.expected
@@ -1 +1 @@
-6decb6b49e48a5869b2a438254c911423275662aff73348cd95e64148011c097 \ No newline at end of file
+4ab69bc0ecbe926e5659a11bb3b82ac0e5155f1571923b1a57668ce93f27cb46 \ No newline at end of file
diff --git a/tests/cachekey/project/sources/patch3.expected b/tests/cachekey/project/sources/patch3.expected
index f1257bb31..abac783cd 100644
--- a/tests/cachekey/project/sources/patch3.expected
+++ b/tests/cachekey/project/sources/patch3.expected
@@ -1 +1 @@
-ab91e0ab9e167c4e9d31480c96a6a91a47ff27246f4eeff4ce6b671cbd865901 \ No newline at end of file
+d2d943fa7e0bc7188eaa461d9b92c23aee43361c279106d92dd5f2260ebf8110 \ No newline at end of file
diff --git a/tests/cachekey/project/sources/tar1.expected b/tests/cachekey/project/sources/tar1.expected
index ab0bd56ea..0e657b4a7 100644
--- a/tests/cachekey/project/sources/tar1.expected
+++ b/tests/cachekey/project/sources/tar1.expected
@@ -1 +1 @@
-ccb35d04789b0d83fd93a6c2f8688c4abfe20f5bc77420f63054893450b2a832 \ No newline at end of file
+a284396dae1e98302c98b150d1bb04b576d3039bea138fe0244c3cde6d5ccea5 \ No newline at end of file
diff --git a/tests/cachekey/project/sources/tar2.expected b/tests/cachekey/project/sources/tar2.expected
index 03241f460..720ea6cfd 100644
--- a/tests/cachekey/project/sources/tar2.expected
+++ b/tests/cachekey/project/sources/tar2.expected
@@ -1 +1 @@
-441c80ed92c77df8247344337f470ac7ab7fe91d2fe3900b498708b0faeac4b5 \ No newline at end of file
+db0d89c04aa964931ee65c456ae91aa2cb784c189f03f2ad36c3ba91381c2005 \ No newline at end of file
diff --git a/tests/cachekey/project/sources/zip1.expected b/tests/cachekey/project/sources/zip1.expected
index a3ac93ecf..799277681 100644
--- a/tests/cachekey/project/sources/zip1.expected
+++ b/tests/cachekey/project/sources/zip1.expected
@@ -1 +1 @@
-be47de64162c9cce0322d0af327092c7afc3a890ba9d6ef92eef016dcced5bae \ No newline at end of file
+d106ec29cbd3d04f54d6416edb2300d3e7acb5cb21b231efa6e9f251384d7bc0 \ No newline at end of file
diff --git a/tests/cachekey/project/sources/zip2.expected b/tests/cachekey/project/sources/zip2.expected
index 49bd45fd0..82ea3c545 100644
--- a/tests/cachekey/project/sources/zip2.expected
+++ b/tests/cachekey/project/sources/zip2.expected
@@ -1 +1 @@
-bedd330938f9405e2febcf1de8428b7180eb62ab73f8e31e49871874ae351735 \ No newline at end of file
+5085978ab2f7f228a6d58ddad945d146d353be6f313e9e13981b7f3a88819d72 \ No newline at end of file
diff --git a/tests/cachekey/project/target.expected b/tests/cachekey/project/target.expected
index 4f4c7c1f8..e2e2e665a 100644
--- a/tests/cachekey/project/target.expected
+++ b/tests/cachekey/project/target.expected
@@ -1 +1 @@
-a408b3e4b6ba4d6a6338bd3153728be89a18b74b13bde554411a4371fda487bc \ No newline at end of file
+01f611e61e948f32035b659d33cdae662d863c99051d0e6746f9c5626138655f \ No newline at end of file
diff --git a/tests/integration/source-determinism.py b/tests/integration/source-determinism.py
new file mode 100644
index 000000000..b60bc25f7
--- /dev/null
+++ b/tests/integration/source-determinism.py
@@ -0,0 +1,155 @@
+import os
+import pytest
+
+from buildstream import _yaml, utils
+from tests.testutils import cli, create_repo, ALL_REPO_KINDS
+
+
+DATA_DIR = os.path.join(
+ os.path.dirname(os.path.realpath(__file__)),
+ "project"
+)
+
+
+def create_test_file(*path, mode=0o644, content='content\n'):
+ path = os.path.join(*path)
+ os.makedirs(os.path.dirname(path), exist_ok=True)
+ with open(path, 'w') as f:
+ f.write(content)
+ os.fchmod(f.fileno(), mode)
+
+
+def create_test_directory(*path, mode=0o644):
+ create_test_file(*path, '.keep', content='')
+ path = os.path.join(*path)
+ os.chmod(path, mode)
+
+
+@pytest.mark.integration
+@pytest.mark.datafiles(DATA_DIR)
+@pytest.mark.parametrize("kind", [(kind) for kind in ALL_REPO_KINDS] + ['local'])
+def test_deterministic_source_umask(cli, tmpdir, datafiles, kind):
+ project = str(datafiles)
+ element_name = 'list'
+ element_path = os.path.join(project, 'elements', element_name)
+ repodir = os.path.join(str(tmpdir), 'repo')
+ sourcedir = os.path.join(project, 'source')
+
+ create_test_file(sourcedir, 'a.txt', mode=0o700)
+ create_test_file(sourcedir, 'b.txt', mode=0o755)
+ create_test_file(sourcedir, 'c.txt', mode=0o600)
+ create_test_file(sourcedir, 'd.txt', mode=0o400)
+ create_test_file(sourcedir, 'e.txt', mode=0o644)
+ create_test_file(sourcedir, 'f.txt', mode=0o4755)
+ create_test_file(sourcedir, 'g.txt', mode=0o2755)
+ create_test_file(sourcedir, 'h.txt', mode=0o1755)
+ create_test_directory(sourcedir, 'dir-a', mode=0o0700)
+ create_test_directory(sourcedir, 'dir-c', mode=0o0755)
+ create_test_directory(sourcedir, 'dir-d', mode=0o4755)
+ create_test_directory(sourcedir, 'dir-e', mode=0o2755)
+ create_test_directory(sourcedir, 'dir-f', mode=0o1755)
+
+ if kind == 'local':
+ source = {'kind': 'local',
+ 'path': 'source'}
+ else:
+ repo = create_repo(kind, repodir)
+ ref = repo.create(sourcedir)
+ source = repo.source_config(ref=ref)
+ element = {
+ 'kind': 'manual',
+ 'depends': [
+ {
+ 'filename': 'base.bst',
+ 'type': 'build'
+ }
+ ],
+ 'sources': [
+ source
+ ],
+ 'config': {
+ 'install-commands': [
+ 'ls -l >"%{install-root}/ls-l"'
+ ]
+ }
+ }
+ _yaml.dump(element, element_path)
+
+ def get_value_for_umask(umask):
+ checkoutdir = os.path.join(str(tmpdir), 'checkout-{}'.format(umask))
+
+ old_umask = os.umask(umask)
+
+ try:
+ result = cli.run(project=project, args=['build', element_name])
+ result.assert_success()
+
+ result = cli.run(project=project, args=['checkout', element_name, checkoutdir])
+ result.assert_success()
+
+ with open(os.path.join(checkoutdir, 'ls-l'), 'r') as f:
+ return f.read()
+ finally:
+ os.umask(old_umask)
+ cli.remove_artifact_from_cache(project, element_name)
+
+ assert get_value_for_umask(0o022) == get_value_for_umask(0o077)
+
+
+@pytest.mark.integration
+@pytest.mark.datafiles(DATA_DIR)
+def test_deterministic_source_local(cli, tmpdir, datafiles):
+ """Only user rights should be considered for local source.
+ """
+ project = str(datafiles)
+ element_name = 'test'
+ element_path = os.path.join(project, 'elements', element_name)
+ sourcedir = os.path.join(project, 'source')
+
+ element = {
+ 'kind': 'manual',
+ 'depends': [
+ {
+ 'filename': 'base.bst',
+ 'type': 'build'
+ }
+ ],
+ 'sources': [
+ {
+ 'kind': 'local',
+ 'path': 'source'
+ }
+ ],
+ 'config': {
+ 'install-commands': [
+ 'ls -l >"%{install-root}/ls-l"'
+ ]
+ }
+ }
+ _yaml.dump(element, element_path)
+
+ def get_value_for_mask(mask):
+ checkoutdir = os.path.join(str(tmpdir), 'checkout-{}'.format(mask))
+
+ create_test_file(sourcedir, 'a.txt', mode=0o644 & mask)
+ create_test_file(sourcedir, 'b.txt', mode=0o755 & mask)
+ create_test_file(sourcedir, 'c.txt', mode=0o4755 & mask)
+ create_test_file(sourcedir, 'd.txt', mode=0o2755 & mask)
+ create_test_file(sourcedir, 'e.txt', mode=0o1755 & mask)
+ create_test_directory(sourcedir, 'dir-a', mode=0o0755 & mask)
+ create_test_directory(sourcedir, 'dir-b', mode=0o4755 & mask)
+ create_test_directory(sourcedir, 'dir-c', mode=0o2755 & mask)
+ create_test_directory(sourcedir, 'dir-d', mode=0o1755 & mask)
+ try:
+ result = cli.run(project=project, args=['build', element_name])
+ result.assert_success()
+
+ result = cli.run(project=project, args=['checkout', element_name, checkoutdir])
+ result.assert_success()
+
+ with open(os.path.join(checkoutdir, 'ls-l'), 'r') as f:
+ return f.read()
+ finally:
+ cli.remove_artifact_from_cache(project, element_name)
+
+ assert get_value_for_mask(0o7777) == get_value_for_mask(0o0700)