-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Expand file tree
/
Copy pathmaterialize_root.py
More file actions
executable file
·60 lines (47 loc) · 1.99 KB
/
Copy pathmaterialize_root.py
File metadata and controls
executable file
·60 lines (47 loc) · 1.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#!/usr/bin/env python3
"""Copies a pkg_install-materialized tree out of Bazel's sandbox symlink farm.
Usage: materialize_root.py <src_dir> <dst_dir>
Bazel presents a declare_directory() action input as a symlink farm: every
entry is (transitively) a symlink to its real, ephemeral location under the
sandbox/exec-root/cache. This walks that farm and, for each entry, resolves
symlinks one hop at a time until it finds either real content (a regular
file/directory) or another symlink -- the latter case means the payload
itself (via pkg_install's NativeInstaller) intentionally created that
symlink, e.g. for a pkg_mklink() entry, so its target text is preserved
verbatim rather than being flattened into a duplicate file.
File/directory modes are copied explicitly via shutil.copymode()/copystat()
so the result isn't affected by this process's umask.
"""
import os
import shutil
import sys
def _resolve_one_hop(path):
"""If path is a symlink, returns (resolved_path, target_is_symlink)."""
if not os.path.islink(path):
return path, False
target = os.readlink(path)
if os.path.isabs(target):
resolved = target
else:
resolved = os.path.join(os.path.dirname(path), target)
resolved = os.path.normpath(resolved)
return resolved, os.path.islink(resolved)
def materialize(src, dst):
real_src, is_intentional_symlink = _resolve_one_hop(src)
if is_intentional_symlink:
os.symlink(os.readlink(real_src), dst)
return
if os.path.isdir(real_src):
os.makedirs(dst, exist_ok=True)
for entry in os.listdir(real_src):
materialize(os.path.join(real_src, entry), os.path.join(dst, entry))
shutil.copystat(real_src, dst)
else:
shutil.copyfile(real_src, dst)
shutil.copymode(real_src, dst)
def main():
src_dir, dst_dir = sys.argv[1], sys.argv[2]
for entry in os.listdir(src_dir):
materialize(os.path.join(src_dir, entry), os.path.join(dst_dir, entry))
if __name__ == "__main__":
main()