tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

hardlink.py (3106B)


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