diff options
| author | Jeremy Fleischman <jeremyfleischman@gmail.com> | 2025-01-12 12:21:10 -0800 |
|---|---|---|
| committer | Jeremy Fleischman <jeremyfleischman@gmail.com> | 2025-02-15 16:14:06 +0700 |
| commit | 6d7f6a92cc5830f28dc56e4de8a4dc18c7ceda69 (patch) | |
| tree | 82e184b505fb4689047b9f79746554fafd585203 /lib/types.nix | |
| parent | python312Packages.open-hypergraphs: init at 0.1.2 (#380798) (diff) | |
| download | nixpkgs-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.nix | 49 |
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}"; |
