xref: /aosp_15_r20/external/angle/build/config/ios/hardlink.py (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1*8975f5c5SAndroid Build Coastguard Worker# Copyright 2017 The Chromium Authors
2*8975f5c5SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be
3*8975f5c5SAndroid Build Coastguard Worker# found in the LICENSE file.
4*8975f5c5SAndroid Build Coastguard Worker
5*8975f5c5SAndroid Build Coastguard Worker"""Recursively create hardlinks to targets at output."""
6*8975f5c5SAndroid Build Coastguard Worker
7*8975f5c5SAndroid Build Coastguard Worker
8*8975f5c5SAndroid Build Coastguard Workerimport argparse
9*8975f5c5SAndroid Build Coastguard Workerimport os
10*8975f5c5SAndroid Build Coastguard Workerimport shutil
11*8975f5c5SAndroid Build Coastguard Workerimport sys
12*8975f5c5SAndroid Build Coastguard Worker
13*8975f5c5SAndroid Build Coastguard Worker
14*8975f5c5SAndroid Build Coastguard Workerdef CreateHardlinkHelper(target, output):
15*8975f5c5SAndroid Build Coastguard Worker  """
16*8975f5c5SAndroid Build Coastguard Worker  Creates hardlink to `target` at `output`.
17*8975f5c5SAndroid Build Coastguard Worker
18*8975f5c5SAndroid Build Coastguard Worker  If `target` is a directory, the directory structure will be copied and
19*8975f5c5SAndroid Build Coastguard Worker  each file will be hardlinked independently. If `target` is a symlink,
20*8975f5c5SAndroid Build Coastguard Worker  a new symlink will be created.
21*8975f5c5SAndroid Build Coastguard Worker
22*8975f5c5SAndroid Build Coastguard Worker  The parent directory of `output` must exists or the function will fail.
23*8975f5c5SAndroid Build Coastguard Worker  """
24*8975f5c5SAndroid Build Coastguard Worker  if os.path.islink(target):
25*8975f5c5SAndroid Build Coastguard Worker    os.symlink(os.readlink(target), output)
26*8975f5c5SAndroid Build Coastguard Worker  elif os.path.isfile(target):
27*8975f5c5SAndroid Build Coastguard Worker    try:
28*8975f5c5SAndroid Build Coastguard Worker      os.link(target, output)
29*8975f5c5SAndroid Build Coastguard Worker    except:
30*8975f5c5SAndroid Build Coastguard Worker      shutil.copy(target, output)
31*8975f5c5SAndroid Build Coastguard Worker  else:
32*8975f5c5SAndroid Build Coastguard Worker    os.mkdir(output)
33*8975f5c5SAndroid Build Coastguard Worker    for name in os.listdir(target):
34*8975f5c5SAndroid Build Coastguard Worker      CreateHardlinkHelper(
35*8975f5c5SAndroid Build Coastguard Worker          os.path.join(target, name),
36*8975f5c5SAndroid Build Coastguard Worker          os.path.join(output, name))
37*8975f5c5SAndroid Build Coastguard Worker
38*8975f5c5SAndroid Build Coastguard Worker
39*8975f5c5SAndroid Build Coastguard Workerdef CreateHardlink(target, output):
40*8975f5c5SAndroid Build Coastguard Worker  """
41*8975f5c5SAndroid Build Coastguard Worker  Creates hardlink to `target` at `output`.
42*8975f5c5SAndroid Build Coastguard Worker
43*8975f5c5SAndroid Build Coastguard Worker  If `target` is a directory, the directory structure will be copied and
44*8975f5c5SAndroid Build Coastguard Worker  each file will be hardlinked independently. If `target` is a symlink,
45*8975f5c5SAndroid Build Coastguard Worker  a new symlink will be created.
46*8975f5c5SAndroid Build Coastguard Worker
47*8975f5c5SAndroid Build Coastguard Worker  If `output` already exists, it is first deleted. The parent directory
48*8975f5c5SAndroid Build Coastguard Worker  of `output` is created if it does not exists.
49*8975f5c5SAndroid Build Coastguard Worker  """
50*8975f5c5SAndroid Build Coastguard Worker  if os.path.exists(output):
51*8975f5c5SAndroid Build Coastguard Worker    if os.path.isdir(output):
52*8975f5c5SAndroid Build Coastguard Worker      shutil.rmtree(output)
53*8975f5c5SAndroid Build Coastguard Worker    else:
54*8975f5c5SAndroid Build Coastguard Worker      os.unlink(output)
55*8975f5c5SAndroid Build Coastguard Worker  dirname = os.path.dirname(output)
56*8975f5c5SAndroid Build Coastguard Worker  if not os.path.isdir(dirname):
57*8975f5c5SAndroid Build Coastguard Worker    os.makedirs(dirname)
58*8975f5c5SAndroid Build Coastguard Worker  CreateHardlinkHelper(target, output)
59*8975f5c5SAndroid Build Coastguard Worker
60*8975f5c5SAndroid Build Coastguard Worker
61*8975f5c5SAndroid Build Coastguard Workerdef CreateHardlinks(output_dir, relative_to, targets):
62*8975f5c5SAndroid Build Coastguard Worker  """
63*8975f5c5SAndroid Build Coastguard Worker  Creates hardlinks to `targets` in `output_dir`.
64*8975f5c5SAndroid Build Coastguard Worker
65*8975f5c5SAndroid Build Coastguard Worker  The `targets` should starts with `relative_to` and the hardlink will
66*8975f5c5SAndroid Build Coastguard Worker  be created at `{output_dir}/{os.path.relpath(sources, relative_to)}`.
67*8975f5c5SAndroid Build Coastguard Worker
68*8975f5c5SAndroid Build Coastguard Worker  Fails with an error if any file in `targets` not located inside the
69*8975f5c5SAndroid Build Coastguard Worker  `relative_to` directory or if creating any of the hardlinks fails.
70*8975f5c5SAndroid Build Coastguard Worker  """
71*8975f5c5SAndroid Build Coastguard Worker  for target in targets:
72*8975f5c5SAndroid Build Coastguard Worker    if not target.startswith(relative_to):
73*8975f5c5SAndroid Build Coastguard Worker      print(f'error: "{target}" not relative to "{relative_to}',
74*8975f5c5SAndroid Build Coastguard Worker            file=sys.stderr)
75*8975f5c5SAndroid Build Coastguard Worker      sys.exit(1)
76*8975f5c5SAndroid Build Coastguard Worker
77*8975f5c5SAndroid Build Coastguard Worker  for target in targets:
78*8975f5c5SAndroid Build Coastguard Worker    output = os.path.join(output_dir, os.path.relpath(target, relative_to))
79*8975f5c5SAndroid Build Coastguard Worker    CreateHardlink(target, output)
80*8975f5c5SAndroid Build Coastguard Worker
81*8975f5c5SAndroid Build Coastguard Worker
82*8975f5c5SAndroid Build Coastguard Workerdef main(args):
83*8975f5c5SAndroid Build Coastguard Worker  parser = argparse.ArgumentParser()
84*8975f5c5SAndroid Build Coastguard Worker
85*8975f5c5SAndroid Build Coastguard Worker  parser.add_argument('--output-dir',
86*8975f5c5SAndroid Build Coastguard Worker                      required=True,
87*8975f5c5SAndroid Build Coastguard Worker                      help='directory where the hardlinks should be created')
88*8975f5c5SAndroid Build Coastguard Worker
89*8975f5c5SAndroid Build Coastguard Worker  parser.add_argument('--relative-to',
90*8975f5c5SAndroid Build Coastguard Worker                      required=True,
91*8975f5c5SAndroid Build Coastguard Worker                      help='sources file will be rebased to this directory')
92*8975f5c5SAndroid Build Coastguard Worker
93*8975f5c5SAndroid Build Coastguard Worker  parser.add_argument(
94*8975f5c5SAndroid Build Coastguard Worker      'sources',
95*8975f5c5SAndroid Build Coastguard Worker      nargs='+',
96*8975f5c5SAndroid Build Coastguard Worker      help='files that should be hardlinked, must be below RELATIVE_TO')
97*8975f5c5SAndroid Build Coastguard Worker
98*8975f5c5SAndroid Build Coastguard Worker  parsed = parser.parse_args(args)
99*8975f5c5SAndroid Build Coastguard Worker  CreateHardlinks(os.path.normpath(parsed.output_dir),
100*8975f5c5SAndroid Build Coastguard Worker                  os.path.normpath(parsed.relative_to) + os.sep,
101*8975f5c5SAndroid Build Coastguard Worker                  [os.path.normpath(source) for source in parsed.sources])
102*8975f5c5SAndroid Build Coastguard Worker
103*8975f5c5SAndroid Build Coastguard Worker
104*8975f5c5SAndroid Build Coastguard Workerif __name__ == '__main__':
105*8975f5c5SAndroid Build Coastguard Worker  main(sys.argv[1:])
106