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