tvl-depot/nix/sparseTree/default.nix
Vincent Ambo aa122cbae7 style: format entire depot with nixpkgs-fmt
This CL can be used to compare the style of nixpkgs-fmt against other
formatters (nixpkgs, alejandra).

Change-Id: I87c6abff6bcb546b02ead15ad0405f81e01b6d9e
Reviewed-on: https://cl.tvl.fyi/c/depot/+/4397
Tested-by: BuildkiteCI
Reviewed-by: sterni <sternenseemann@systemli.org>
Reviewed-by: lukegb <lukegb@tvl.fyi>
Reviewed-by: wpcarro <wpcarro@gmail.com>
Reviewed-by: Profpatsch <mail@profpatsch.de>
Reviewed-by: kanepyork <rikingcoding@gmail.com>
Reviewed-by: tazjin <tazjin@tvl.su>
Reviewed-by: cynthia <cynthia@tvl.fyi>
Reviewed-by: edef <edef@edef.eu>
Reviewed-by: eta <tvl@eta.st>
Reviewed-by: grfn <grfn@gws.fyi>
2022-01-31 16:11:53 +00:00

74 lines
2.3 KiB
Nix

# Build a “sparse” version of a given directory, only including contained files
# and directories if they are listed in a supplied list:
#
# # A very minimal depot
# sparseTree ./depot [
# ./default.nix
# ./depot/nix/readTree/default.nix
# ./third_party/nixpkgs
# ./third_party/overlays
# ]
{ pkgs, lib, ... }:
# root path to use as a reference point
root:
# list of paths below `root` that should be
# included in the resulting directory
#
# If path, need to refer to the actual file / directory to be included.
# If a string, it is treated as a string relative to the root.
paths:
let
rootLength = builtins.stringLength (toString root);
# Count slashes in a path.
#
# Type: path -> int
depth = path: lib.pipe path [
toString
(builtins.split "/")
(builtins.filter builtins.isList)
builtins.length
];
# (Parent) directories will be created from deepest to shallowest
# which should mean no conflicts are caused unless both a child
# and its parent directory are in the list of paths.
# TODO(sterni): improve error messages in such cases
fromDeepest = lib.sort (a: b: depth a < depth b) paths;
# Create a set which contains the source path to copy / symlink and
# it's destination, so the path below the destination root including
# a leading slash. Additionally some sanity checking is done.
makeSymlink = path:
let
withLeading = p: if builtins.substring 0 1 p == "/" then p else "/" + p;
fullPath =
/**/
if builtins.isPath path then path
else if builtins.isString path then (root + withLeading path)
else builtins.throw "Unsupported path type ${builtins.typeOf path}";
strPath = toString fullPath;
contextPath = "${fullPath}";
belowRoot = builtins.substring rootLength (-1) strPath;
prefix = builtins.substring 0 rootLength strPath;
in
assert toString root == prefix; {
src = contextPath;
dst = belowRoot;
};
symlinks = builtins.map makeSymlink fromDeepest;
in
# TODO(sterni): teach readTree to also read symlinked directories,
# so we ln -sT instead of cp -aT.
pkgs.runCommandNoCC "sparse-${builtins.baseNameOf root}" { } (
lib.concatMapStrings
({ src, dst }: ''
mkdir -p "$(dirname "$out${dst}")"
cp -aT --reflink=auto "${src}" "$out${dst}"
'')
symlinks
)