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:])