summaryrefslogtreecommitdiff
path: root/lib/types.nix
diff options
context:
space:
mode:
authorJeremy Fleischman <jeremyfleischman@gmail.com>2025-01-12 12:21:10 -0800
committerJeremy Fleischman <jeremyfleischman@gmail.com>2025-02-15 16:14:06 +0700
commit6d7f6a92cc5830f28dc56e4de8a4dc18c7ceda69 (patch)
tree82e184b505fb4689047b9f79746554fafd585203 /lib/types.nix
parentpython312Packages.open-hypergraphs: init at 0.1.2 (#380798) (diff)
downloadnixpkgs-6d7f6a92cc5830f28dc56e4de8a4dc18c7ceda69.tar.gz
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.
Diffstat (limited to 'lib/types.nix')
-rw-r--r--lib/types.nix49
1 files changed, 38 insertions, 11 deletions
diff --git a/lib/types.nix b/lib/types.nix
index 5226609822f1..07d8a28d1394 100644
--- a/lib/types.nix
+++ b/lib/types.nix
@@ -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}";