lib/types: add types.pathWith
This gives people some flexibility when they need a path type, and prevents a "combinatorial explosion" of various path stops. I've re-implemented our existing `path` and `pathInStore` types using `pathWith`. Our existing `package` type is potentially a candidate for similar treatment, but it's a little quirkier (there's some stuff with `builtins.hasContext` and `toDerivation` that I don't completely understand), and I didn't want to muddy this PR with that. As a happy side effect of this work, we get a new feature: the ability to create a type for paths *not* in the store. This is useful for when a module needs a path to a file, and wants to protect people from accidentally leaking that file into the nix store.
This commit is contained in:
@@ -566,21 +566,48 @@ rec {
|
||||
})
|
||||
(x: (x._type or null) == "pkgs");
|
||||
|
||||
path = mkOptionType {
|
||||
name = "path";
|
||||
descriptionClass = "noun";
|
||||
check = x: isStringLike x && builtins.substring 0 1 (toString x) == "/";
|
||||
merge = mergeEqualOption;
|
||||
path = pathWith {
|
||||
absolute = true;
|
||||
};
|
||||
|
||||
pathInStore = mkOptionType {
|
||||
name = "pathInStore";
|
||||
description = "path in the Nix store";
|
||||
descriptionClass = "noun";
|
||||
check = x: isStringLike x && builtins.match "${builtins.storeDir}/[^.].*" (toString x) != null;
|
||||
merge = mergeEqualOption;
|
||||
pathInStore = pathWith {
|
||||
inStore = true;
|
||||
};
|
||||
|
||||
pathWith = {
|
||||
inStore ? null,
|
||||
absolute ? null,
|
||||
}:
|
||||
throwIf (inStore != null && absolute != null && inStore && !absolute) "In pathWith, inStore means the path must be absolute" mkOptionType {
|
||||
name = "pathWith";
|
||||
description = (
|
||||
(if absolute == null then "" else (if absolute then "absolute " else "relative ")) +
|
||||
"path" +
|
||||
(if inStore == null then "" else (if inStore then " in the Nix store" else " not in the Nix store"))
|
||||
);
|
||||
descriptionClass = "noun";
|
||||
|
||||
merge = mergeEqualOption;
|
||||
functor = defaultFunctor "pathWith" // {
|
||||
type = pathWith;
|
||||
payload = {inherit inStore absolute; };
|
||||
binOp = lhs: rhs: if lhs == rhs then lhs else null;
|
||||
};
|
||||
|
||||
check = x:
|
||||
let
|
||||
isInStore = builtins.match "${builtins.storeDir}/[^.].*" (toString x) != null;
|
||||
isAbsolute = builtins.substring 0 1 (toString x) == "/";
|
||||
isExpectedType = (
|
||||
if inStore == null || inStore then
|
||||
isStringLike x
|
||||
else
|
||||
isString x # Do not allow a true path, which could be copied to the store later on.
|
||||
);
|
||||
in
|
||||
isExpectedType && (inStore == null || inStore == isInStore) && (absolute == null || absolute == isAbsolute);
|
||||
};
|
||||
|
||||
listOf = elemType: mkOptionType rec {
|
||||
name = "listOf";
|
||||
description = "list of ${optionDescriptionPhrase (class: class == "noun" || class == "composite") elemType}";
|
||||
|
||||
Reference in New Issue
Block a user