aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Ameen <alex.ameen.tx@gmail.com>2023-07-25 12:43:33 -0500
committerGitHub <noreply@github.com>2023-07-25 17:43:33 +0000
commit2d1d81114d72ace89ce08cd3bc93f4eb27a2975d (patch)
tree68134064a86a69ecb65a698cd0a5e71aa12cc5d2
parent484c820c481ce1aabf0fe51e478eb0187bc68fb6 (diff)
Add `parseFlakeRef` and `flakeRefToString` builtins (#8670)
Over the last year or so I've run into several use cases where I need to parse and/or serialize URLs for use by `builtins.fetchTree` or `builtins.getFlake`, largely in order to produce _lockfile-like_ files for lang2nix frameworks or tools which use `nix` internally to drive builds. I've gone through the painstaking process of emulating `nix::FlakeRef::fromAttrs` and `nix::parseFlakeRef` several times with mixed success; but these are difficult to create and even harder to maintain if I hope to stay aligned with changes to the real parser/serializer. I understand why adding new `builtins` isn't something we want to do flagrantly. I'm recommending this addition simply because I keep encountering use cases where I need to parse/serialize these URIs in `nix` expressions, and I want a reliable solution. Co-authored-by: Eelco Dolstra <edolstra@gmail.com> Co-authored-by: John Ericson <git@JohnEricson.me>
-rw-r--r--doc/manual/src/release-notes/rl-next.md7
-rw-r--r--src/libexpr/flake/flake.cc95
-rw-r--r--tests/lang/eval-okay-flake-ref-to-string.exp1
-rw-r--r--tests/lang/eval-okay-flake-ref-to-string.nix7
-rw-r--r--tests/lang/eval-okay-parse-flake-ref.exp1
-rw-r--r--tests/lang/eval-okay-parse-flake-ref.nix1
6 files changed, 112 insertions, 0 deletions
diff --git a/doc/manual/src/release-notes/rl-next.md b/doc/manual/src/release-notes/rl-next.md
index c869b5e2f..065364453 100644
--- a/doc/manual/src/release-notes/rl-next.md
+++ b/doc/manual/src/release-notes/rl-next.md
@@ -1 +1,8 @@
# Release X.Y (202?-??-??)
+
+- Two new builtin functions,
+ [`builtins.parseFlakeRef`](@docroot@/language/builtins.md#builtins-parseFlakeRef)
+ and
+ [`builtins.flakeRefToString`](@docroot@/language/builtins.md#builtins-flakeRefToString),
+ have been added.
+ These functions are useful for converting between flake references encoded as attribute sets and URLs.
diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc
index 5aa44d6a1..9112becff 100644
--- a/src/libexpr/flake/flake.cc
+++ b/src/libexpr/flake/flake.cc
@@ -793,6 +793,101 @@ static RegisterPrimOp r2({
.experimentalFeature = Xp::Flakes,
});
+static void prim_parseFlakeRef(
+ EvalState & state,
+ const PosIdx pos,
+ Value * * args,
+ Value & v)
+{
+ std::string flakeRefS(state.forceStringNoCtx(*args[0], pos,
+ "while evaluating the argument passed to builtins.parseFlakeRef"));
+ auto attrs = parseFlakeRef(flakeRefS, {}, true).toAttrs();
+ auto binds = state.buildBindings(attrs.size());
+ for (const auto & [key, value] : attrs) {
+ auto s = state.symbols.create(key);
+ auto & vv = binds.alloc(s);
+ std::visit(overloaded {
+ [&vv](const std::string & value) { vv.mkString(value); },
+ [&vv](const uint64_t & value) { vv.mkInt(value); },
+ [&vv](const Explicit<bool> & value) { vv.mkBool(value.t); }
+ }, value);
+ }
+ v.mkAttrs(binds);
+}
+
+static RegisterPrimOp r3({
+ .name = "__parseFlakeRef",
+ .args = {"flake-ref"},
+ .doc = R"(
+ Parse a flake reference, and return its exploded form.
+
+ For example:
+ ```nix
+ builtins.parseFlakeRef "github:NixOS/nixpkgs/23.05?dir=lib"
+ ```
+ evaluates to:
+ ```nix
+ { dir = "lib"; owner = "NixOS"; ref = "23.05"; repo = "nixpkgs"; type = "github"; }
+ ```
+ )",
+ .fun = prim_parseFlakeRef,
+ .experimentalFeature = Xp::Flakes,
+});
+
+
+static void prim_flakeRefToString(
+ EvalState & state,
+ const PosIdx pos,
+ Value * * args,
+ Value & v)
+{
+ state.forceAttrs(*args[0], noPos,
+ "while evaluating the argument passed to builtins.flakeRefToString");
+ fetchers::Attrs attrs;
+ for (const auto & attr : *args[0]->attrs) {
+ auto t = attr.value->type();
+ if (t == nInt) {
+ attrs.emplace(state.symbols[attr.name],
+ (uint64_t) attr.value->integer);
+ } else if (t == nBool) {
+ attrs.emplace(state.symbols[attr.name],
+ Explicit<bool> { attr.value->boolean });
+ } else if (t == nString) {
+ attrs.emplace(state.symbols[attr.name],
+ std::string(attr.value->str()));
+ } else {
+ state.error(
+ "flake reference attribute sets may only contain integers, Booleans, "
+ "and strings, but attribute '%s' is %s",
+ state.symbols[attr.name],
+ showType(*attr.value)).debugThrow<EvalError>();
+ }
+ }
+ auto flakeRef = FlakeRef::fromAttrs(attrs);
+ v.mkString(flakeRef.to_string());
+}
+
+static RegisterPrimOp r4({
+ .name = "__flakeRefToString",
+ .args = {"attrs"},
+ .doc = R"(
+ Convert a flake reference from attribute set format to URL format.
+
+ For example:
+ ```nix
+ builtins.flakeRefToString {
+ dir = "lib"; owner = "NixOS"; ref = "23.05"; repo = "nixpkgs"; type = "github";
+ }
+ ```
+ evaluates to
+ ```nix
+ "github:NixOS/nixpkgs/23.05?dir=lib"
+ ```
+ )",
+ .fun = prim_flakeRefToString,
+ .experimentalFeature = Xp::Flakes,
+});
+
}
Fingerprint LockedFlake::getFingerprint() const
diff --git a/tests/lang/eval-okay-flake-ref-to-string.exp b/tests/lang/eval-okay-flake-ref-to-string.exp
new file mode 100644
index 000000000..110f8442d
--- /dev/null
+++ b/tests/lang/eval-okay-flake-ref-to-string.exp
@@ -0,0 +1 @@
+"github:NixOS/nixpkgs/23.05?dir=lib"
diff --git a/tests/lang/eval-okay-flake-ref-to-string.nix b/tests/lang/eval-okay-flake-ref-to-string.nix
new file mode 100644
index 000000000..dbb4e5b2a
--- /dev/null
+++ b/tests/lang/eval-okay-flake-ref-to-string.nix
@@ -0,0 +1,7 @@
+builtins.flakeRefToString {
+ type = "github";
+ owner = "NixOS";
+ repo = "nixpkgs";
+ ref = "23.05";
+ dir = "lib";
+}
diff --git a/tests/lang/eval-okay-parse-flake-ref.exp b/tests/lang/eval-okay-parse-flake-ref.exp
new file mode 100644
index 000000000..fc17ba085
--- /dev/null
+++ b/tests/lang/eval-okay-parse-flake-ref.exp
@@ -0,0 +1 @@
+{ dir = "lib"; owner = "NixOS"; ref = "23.05"; repo = "nixpkgs"; type = "github"; }
diff --git a/tests/lang/eval-okay-parse-flake-ref.nix b/tests/lang/eval-okay-parse-flake-ref.nix
new file mode 100644
index 000000000..db4ed2742
--- /dev/null
+++ b/tests/lang/eval-okay-parse-flake-ref.nix
@@ -0,0 +1 @@
+ builtins.parseFlakeRef "github:NixOS/nixpkgs/23.05?dir=lib"