forked from OSchip/llvm-project
93 lines
3.0 KiB
Python
Executable File
93 lines
3.0 KiB
Python
Executable File
#!/bin/python3
|
|
|
|
# This file is licensed under the Apache License v2.0 with LLVM Exceptions.
|
|
# See https://llvm.org/LICENSE.txt for license information.
|
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
"""Overlays two directories into a target directory using symlinks.
|
|
|
|
Tries to minimize the number of symlinks created (that is, does not symlink
|
|
every single file). Symlinks every file in the overlay directory. Only symlinks
|
|
individual files in the source directory if their parent directory is also
|
|
contained in the overlay directory tree.
|
|
"""
|
|
|
|
import argparse
|
|
import errno
|
|
import os
|
|
import sys
|
|
|
|
|
|
def _check_python_version():
|
|
if sys.version_info[0] < 3:
|
|
raise RuntimeError(
|
|
"Must be invoked with a python 3 interpreter but was %s" %
|
|
sys.executable)
|
|
|
|
|
|
def _check_dir_exists(path):
|
|
if not os.path.isdir(path):
|
|
raise OSError(errno.ENOENT, os.strerror(errno.ENOENT), path)
|
|
|
|
|
|
def parse_arguments():
|
|
parser = argparse.ArgumentParser(description="""
|
|
Overlays two directories into a target directory using symlinks.
|
|
|
|
Tries to minimize the number of symlinks created (that is, does not symlink
|
|
every single file). Symlinks every file in the overlay directory. Only
|
|
symlinks individual files in the source directory if their parent directory
|
|
is also contained in the overlay directory tree.
|
|
""")
|
|
parser.add_argument(
|
|
"--src",
|
|
required=True,
|
|
help="Directory that contains most of the content to symlink.")
|
|
parser.add_argument(
|
|
"--overlay",
|
|
required=True,
|
|
help="Directory to overlay on top of the source directory.")
|
|
parser.add_argument(
|
|
"--target",
|
|
required=True,
|
|
help="Directory in which to place the fused symlink directories.")
|
|
|
|
args = parser.parse_args()
|
|
|
|
_check_dir_exists(args.target)
|
|
_check_dir_exists(args.overlay)
|
|
_check_dir_exists(args.src)
|
|
|
|
return args
|
|
|
|
|
|
def _symlink_abs(from_path, to_path):
|
|
os.symlink(os.path.abspath(from_path), os.path.abspath(to_path))
|
|
|
|
|
|
def main(args):
|
|
for root, dirs, files in os.walk(args.overlay):
|
|
# We could do something more intelligent here and only symlink individual
|
|
# files if the directory is present in both overlay and src. This could also
|
|
# be generalized to an arbitrary number of directories without any
|
|
# "src/overlay" distinction. In the current use case we only have two and
|
|
# the overlay directory is always small, so putting that off for now.
|
|
rel_root = os.path.relpath(root, start=args.overlay)
|
|
if rel_root != ".":
|
|
os.mkdir(os.path.join(args.target, rel_root))
|
|
|
|
for file in files:
|
|
relpath = os.path.join(rel_root, file)
|
|
_symlink_abs(os.path.join(args.overlay, relpath),
|
|
os.path.join(args.target, relpath))
|
|
|
|
for src_entry in os.listdir(os.path.join(args.src, rel_root)):
|
|
if src_entry not in dirs:
|
|
relpath = os.path.join(rel_root, src_entry)
|
|
_symlink_abs(os.path.join(args.src, relpath),
|
|
os.path.join(args.target, relpath))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
_check_python_version()
|
|
main(parse_arguments())
|