# vi: syntax=python:et:ts=4 from SCons.Action import ActionFactory from shutil import copy2 from SCons.Script import Flatten, Dir, Entry, Builder, AlwaysBuild import os from SCons.Node import FS def install_filtered_hook(target, source, env): copy_filter = env["copy_filter"] target = Flatten(target) if len(target) != len(source): raise ValueError("Number of targets doesn't match number of sources") def do_copy(target, source): if copy_filter(source): if os.path.isfile(source): if env["verbose"]: print("cp %s %s" % (source, target)) copy2(source, target) else: if not os.path.exists(target): if env["verbose"]: print("Make directory {}".format(target)) os.makedirs(target) for file in os.listdir(source): do_copy(os.path.join(target, file), os.path.join(source, file)) for target_dir, source_dir in zip(target, source): target_path = str(target_dir) source_path = str(source_dir) if not os.path.exists(target_path): os.makedirs(target_path) for d in (target_path, source_path): if not os.path.isdir(d): raise ValueError("%s is not a directory" % d) do_copy(target_path, source_path) def hard_link(dest, src, symlink=False): try: if symlink: os.symlink(src, dest) else: os.link(src, dest) except OSError as e: if e.errno == 18: hard_link(dest, src, True) else: os.remove(dest) os.link(src, dest) except AttributeError: copy2(src, dest) HardLink = ActionFactory(hard_link, lambda dest, src: f"Hardlinking {src} to {dest}") def install_binary(env, source): if not source: return source binary = source[0].name binary = binary.split("-")[0] install_dir = env.subst(os.path.join(env["destdir"], env["bindir"].lstrip("/"))) env.Alias("install-" + binary, env.InstallAs(os.path.join(install_dir, binary + env["program_suffix"]), source)) def install_data(env, datadir, component, source, subdir="", **kwargs): install_dir = Dir(env.subst(os.path.join(env["destdir"], env[datadir].lstrip("/"), subdir))) sources = map(Entry, Flatten([source])) dirs = [] for source in sources: if isinstance(source, FS.Dir) or source.isdir(): dirs.append(source) else: env.Alias( "install-" + component, env.Install(install_dir, source, **kwargs) ) if dirs: if len(dirs) == 1: install = env.InstallFiltered(install_dir.path, dirs[0].path, **kwargs) else: install = [env.InstallFiltered(os.path.join(install_dir.path, x.name, **kwargs), x.path) for x in dirs] AlwaysBuild(install) env.Alias("install-" + component, install) def generate(env): env.AddMethod(install_binary) env.AddMethod(install_data) env.Append(BUILDERS={"InstallFiltered": Builder(action=install_filtered_hook, target_factory=Dir, source_factory=Dir)}) def exists(): return True