tvl-depot/nix/writeTree/default.nix
sterni 756e96499c fix(nix/writeTree): also shell escape path nodes
We allow strings with context that represent paths (since they qualify
as `pathLike`). While store path (names) may not contain any characters
that are meaningful in shell, they may contain directories and/or files
with such names since it's permissible in POSIX.

To fix this, we convert the given value `v` to a shell argument in two
stages:

1. Use `${v}` to coerce the value to a string while importing any
   necessary paths to store.
2. Escape the resulting string for use as an argument.

Change-Id: Ib989b50df2a921c2abcd1ebc7ca0ff6e2bb79088
Reviewed-on: https://cl.tvl.fyi/c/depot/+/12898
Reviewed-by: sterni <sternenseemann@systemli.org>
Tested-by: BuildkiteCI
Autosubmit: sterni <sternenseemann@systemli.org>
2024-12-20 23:38:05 +00:00

43 lines
1.3 KiB
Nix

{ depot, lib, pkgs, ... }:
let
inherit (lib) fix pipe mapAttrsToList isAttrs concatLines isString isDerivation isPath;
# TODO(sterni): move to //nix/utils with clearer naming and alternative similar to lib.types.path
isPathLike = value:
isPath value
|| isDerivation value
|| (isString value && builtins.hasContext value);
esc = s: lib.escapeShellArg /* ensure paths import into store */ "${s}";
writeTreeAtPath = path: tree:
''
mkdir -p "$out/"${esc path}
''
+ pipe tree [
(mapAttrsToList (k: v:
if isPathLike v then
"cp -R --reflink=auto ${esc "${v}"} \"$out/\"${esc path}/${esc k}"
else if lib.isAttrs v then
writeTreeAtPath (path + "/" + k) v
else
throw "invalid type (expected path, derivation, string with context, or attrs)"))
concatLines
];
/* Create a directory tree specified by a Nix attribute set structure.
Each value in `tree` should either be a file, a directory, or another tree
attribute set. Those paths will be written to a directory tree
corresponding to the structure of the attribute set.
Type: string -> attrSet -> derivation
*/
writeTree = name: tree:
pkgs.runCommandLocal name { } (writeTreeAtPath "" tree);
in
# __functor trick so readTree can add the tests attribute
{
__functor = _: writeTree;
}