From 3ef3f525c35c84b90c5a0f4c07ffe53b2291973c Mon Sep 17 00:00:00 2001 From: Sergei Zimmerman Date: Sat, 30 Aug 2025 01:26:51 +0300 Subject: [PATCH] libflake: Fix flake id flake refs with revisions Starting from c436b7a32afaf01d62f828697ddf5c49d4f8678c this used to lead to assertion failures like: > std::string nix::ParsedURL::renderAuthorityAndPath() const: Assertion `path.empty() || path.front().empty()' failed. This has the bugfix for the issue and regressions tests so that this gets properly tested in the future. --- src/libflake-tests/flakeref.cc | 85 ++++++++++++++++++++++++++++++++++ src/libflake/flakeref.cc | 2 +- 2 files changed, 86 insertions(+), 1 deletion(-) diff --git a/src/libflake-tests/flakeref.cc b/src/libflake-tests/flakeref.cc index 404d7590a..3636d3e98 100644 --- a/src/libflake-tests/flakeref.cc +++ b/src/libflake-tests/flakeref.cc @@ -2,6 +2,7 @@ #include "nix/fetchers/fetch-settings.hh" #include "nix/flake/flakeref.hh" +#include "nix/fetchers/attrs.hh" namespace nix { @@ -90,6 +91,90 @@ TEST(parseFlakeRef, GitArchiveInput) } } +struct InputFromURLTestCase +{ + std::string url; + fetchers::Attrs attrs; + std::string description; + std::string expectedUrl = url; +}; + +class InputFromURLTest : public ::testing::WithParamInterface, public ::testing::Test +{}; + +TEST_P(InputFromURLTest, attrsAreCorrectAndRoundTrips) +{ + experimentalFeatureSettings.experimentalFeatures.get().insert(Xp::Flakes); + fetchers::Settings fetchSettings; + + const auto & testCase = GetParam(); + + auto flakeref = parseFlakeRef(fetchSettings, testCase.url); + + EXPECT_EQ(flakeref.toAttrs(), testCase.attrs); + EXPECT_EQ(flakeref.to_string(), testCase.expectedUrl); + + auto input = fetchers::Input::fromURL(fetchSettings, flakeref.to_string()); + + EXPECT_EQ(input.toURLString(), testCase.expectedUrl); + EXPECT_EQ(input.toAttrs(), testCase.attrs); + + // Round-trip check. + auto input2 = fetchers::Input::fromURL(fetchSettings, input.toURLString()); + EXPECT_EQ(input, input2); + EXPECT_EQ(input.toURLString(), input2.toURLString()); +} + +using fetchers::Attr; + +INSTANTIATE_TEST_SUITE_P( + InputFromURL, + InputFromURLTest, + ::testing::Values( + InputFromURLTestCase{ + .url = "flake:nixpkgs", + .attrs = + { + {"id", Attr("nixpkgs")}, + {"type", Attr("indirect")}, + }, + .description = "basic_indirect", + }, + InputFromURLTestCase{ + .url = "flake:nixpkgs/branch", + .attrs = + { + {"id", Attr("nixpkgs")}, + {"type", Attr("indirect")}, + {"ref", Attr("branch")}, + }, + .description = "basic_indirect_branch", + }, + InputFromURLTestCase{ + .url = "nixpkgs/branch", + .attrs = + { + {"id", Attr("nixpkgs")}, + {"type", Attr("indirect")}, + {"ref", Attr("branch")}, + }, + .description = "flake_id_ref_branch", + .expectedUrl = "flake:nixpkgs/branch", + }, + InputFromURLTestCase{ + .url = "nixpkgs/branch/2aae6c35c94fcfb415dbe95f408b9ce91ee846ed", + .attrs = + { + {"id", Attr("nixpkgs")}, + {"type", Attr("indirect")}, + {"ref", Attr("branch")}, + {"rev", Attr("2aae6c35c94fcfb415dbe95f408b9ce91ee846ed")}, + }, + .description = "flake_id_ref_branch_trailing_slash", + .expectedUrl = "flake:nixpkgs/branch/2aae6c35c94fcfb415dbe95f408b9ce91ee846ed", + }), + [](const ::testing::TestParamInfo & info) { return info.param.description; }); + TEST(to_string, doesntReencodeUrl) { fetchers::Settings fetchSettings; diff --git a/src/libflake/flakeref.cc b/src/libflake/flakeref.cc index cd176f14b..38979783d 100644 --- a/src/libflake/flakeref.cc +++ b/src/libflake/flakeref.cc @@ -198,7 +198,7 @@ parseFlakeIdRef(const fetchers::Settings & fetchSettings, const std::string & ur if (std::regex_match(url, match, flakeRegex)) { auto parsedURL = ParsedURL{ .scheme = "flake", - .authority = ParsedURL::Authority{}, + .authority = std::nullopt, .path = splitString>(match[1].str(), "/"), };