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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
build / config / ios / hardlink.py [blame]
# Copyright 2017 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Recursively create hardlinks to targets at output."""
import argparse
import os
import shutil
import sys
def CreateHardlinkHelper(target, output):
"""
Creates hardlink to `target` at `output`.
If `target` is a directory, the directory structure will be copied and
each file will be hardlinked independently. If `target` is a symlink,
a new symlink will be created.
The parent directory of `output` must exists or the function will fail.
"""
if os.path.islink(target):
os.symlink(os.readlink(target), output)
elif os.path.isfile(target):
try:
os.link(target, output)
except:
shutil.copy(target, output)
else:
os.mkdir(output)
for name in os.listdir(target):
CreateHardlinkHelper(
os.path.join(target, name),
os.path.join(output, name))
def CreateHardlink(target, output):
"""
Creates hardlink to `target` at `output`.
If `target` is a directory, the directory structure will be copied and
each file will be hardlinked independently. If `target` is a symlink,
a new symlink will be created.
If `output` already exists, it is first deleted. The parent directory
of `output` is created if it does not exists.
"""
if os.path.exists(output):
if os.path.isdir(output):
shutil.rmtree(output)
else:
os.unlink(output)
dirname = os.path.dirname(output)
if not os.path.isdir(dirname):
os.makedirs(dirname)
CreateHardlinkHelper(target, output)
def CreateHardlinks(output_dir, relative_to, targets):
"""
Creates hardlinks to `targets` in `output_dir`.
The `targets` should starts with `relative_to` and the hardlink will
be created at `{output_dir}/{os.path.relpath(sources, relative_to)}`.
Fails with an error if any file in `targets` not located inside the
`relative_to` directory or if creating any of the hardlinks fails.
"""
for target in targets:
if not target.startswith(relative_to):
print(f'error: "{target}" not relative to "{relative_to}',
file=sys.stderr)
sys.exit(1)
for target in targets:
output = os.path.join(output_dir, os.path.relpath(target, relative_to))
CreateHardlink(target, output)
def main(args):
parser = argparse.ArgumentParser()
parser.add_argument('--output-dir',
required=True,
help='directory where the hardlinks should be created')
parser.add_argument('--relative-to',
required=True,
help='sources file will be rebased to this directory')
parser.add_argument(
'sources',
nargs='+',
help='files that should be hardlinked, must be below RELATIVE_TO')
parsed = parser.parse_args(args)
CreateHardlinks(os.path.normpath(parsed.output_dir),
os.path.normpath(parsed.relative_to) + os.sep,
[os.path.normpath(source) for source in parsed.sources])
if __name__ == '__main__':
main(sys.argv[1:])