Skip to content

Commit 2d9b213

Browse files
authored
Merge pull request #12157 from DeterminateSystems/fix-path-flakeref-query-without-fragment
parsePathFlakeRefWithFragment(): Handle 'path?query' without a fragment
2 parents 9b9e416 + 3ad0f45 commit 2d9b213

File tree

5 files changed

+78
-28
lines changed

5 files changed

+78
-28
lines changed

src/libflake-tests/flakeref.cc

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,60 @@ namespace nix {
77

88
/* ----------- tests for flake/flakeref.hh --------------------------------------------------*/
99

10-
/* ----------------------------------------------------------------------------
11-
* to_string
12-
* --------------------------------------------------------------------------*/
10+
TEST(parseFlakeRef, path) {
11+
experimentalFeatureSettings.experimentalFeatures.get().insert(Xp::Flakes);
12+
13+
fetchers::Settings fetchSettings;
14+
15+
{
16+
auto s = "/foo/bar";
17+
auto flakeref = parseFlakeRef(fetchSettings, s);
18+
ASSERT_EQ(flakeref.to_string(), "path:/foo/bar");
19+
}
20+
21+
{
22+
auto s = "/foo/bar?revCount=123&rev=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
23+
auto flakeref = parseFlakeRef(fetchSettings, s);
24+
ASSERT_EQ(flakeref.to_string(), "path:/foo/bar?rev=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&revCount=123");
25+
}
26+
27+
{
28+
auto s = "/foo/bar?xyzzy=123";
29+
EXPECT_THROW(
30+
parseFlakeRef(fetchSettings, s),
31+
Error);
32+
}
33+
34+
{
35+
auto s = "/foo/bar#bla";
36+
EXPECT_THROW(
37+
parseFlakeRef(fetchSettings, s),
38+
Error);
39+
}
40+
41+
{
42+
auto s = "/foo/bar#bla";
43+
auto [flakeref, fragment] = parseFlakeRefWithFragment(fetchSettings, s);
44+
ASSERT_EQ(flakeref.to_string(), "path:/foo/bar");
45+
ASSERT_EQ(fragment, "bla");
46+
}
47+
48+
{
49+
auto s = "/foo/bar?revCount=123#bla";
50+
auto [flakeref, fragment] = parseFlakeRefWithFragment(fetchSettings, s);
51+
ASSERT_EQ(flakeref.to_string(), "path:/foo/bar?revCount=123");
52+
ASSERT_EQ(fragment, "bla");
53+
}
54+
}
1355

1456
TEST(to_string, doesntReencodeUrl) {
1557
fetchers::Settings fetchSettings;
1658
auto s = "http://localhost:8181/test/+3d.tar.gz";
1759
auto flakeref = parseFlakeRef(fetchSettings, s);
18-
auto parsed = flakeref.to_string();
60+
auto unparsed = flakeref.to_string();
1961
auto expected = "http://localhost:8181/test/%2B3d.tar.gz";
2062

21-
ASSERT_EQ(parsed, expected);
63+
ASSERT_EQ(unparsed, expected);
2264
}
2365

2466
}

src/libflake/flake/flakeref.cc

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -89,23 +89,16 @@ std::pair<FlakeRef, std::string> parsePathFlakeRefWithFragment(
8989
bool allowMissing,
9090
bool isFlake)
9191
{
92-
std::string path = url;
93-
std::string fragment = "";
94-
std::map<std::string, std::string> query;
95-
auto pathEnd = url.find_first_of("#?");
96-
auto fragmentStart = pathEnd;
97-
if (pathEnd != std::string::npos && url[pathEnd] == '?') {
98-
fragmentStart = url.find("#");
99-
}
100-
if (pathEnd != std::string::npos) {
101-
path = url.substr(0, pathEnd);
102-
}
103-
if (fragmentStart != std::string::npos) {
104-
fragment = percentDecode(url.substr(fragmentStart+1));
105-
}
106-
if (pathEnd != std::string::npos && fragmentStart != std::string::npos && url[pathEnd] == '?') {
107-
query = decodeQuery(url.substr(pathEnd + 1, fragmentStart - pathEnd - 1));
108-
}
92+
static std::regex pathFlakeRegex(
93+
R"(([^?#]*)(\?([^#]*))?(#(.*))?)",
94+
std::regex::ECMAScript);
95+
96+
std::smatch match;
97+
auto succeeds = std::regex_match(url, match, pathFlakeRegex);
98+
assert(succeeds);
99+
auto path = match[1].str();
100+
auto query = decodeQuery(match[3]);
101+
auto fragment = percentDecode(match[5].str());
109102

110103
if (baseDir) {
111104
/* Check if 'url' is a path (either absolute or relative
@@ -190,11 +183,13 @@ std::pair<FlakeRef, std::string> parsePathFlakeRefWithFragment(
190183
path = canonPath(path + "/" + getOr(query, "dir", ""));
191184
}
192185

193-
fetchers::Attrs attrs;
194-
attrs.insert_or_assign("type", "path");
195-
attrs.insert_or_assign("path", path);
196-
197-
return std::make_pair(FlakeRef(fetchers::Input::fromAttrs(fetchSettings, std::move(attrs)), ""), fragment);
186+
return fromParsedURL(fetchSettings, {
187+
.scheme = "path",
188+
.authority = "",
189+
.path = path,
190+
.query = query,
191+
.fragment = fragment
192+
}, isFlake);
198193
}
199194

200195
/**

src/libutil/config.hh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ public:
262262
operator const T &() const { return value; }
263263
operator T &() { return value; }
264264
const T & get() const { return value; }
265+
T & get() { return value; }
265266
template<typename U>
266267
bool operator ==(const U & v2) const { return value == v2; }
267268
template<typename U>

src/libutil/url.cc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ ParsedURL parseURL(const std::string & url)
2222
std::smatch match;
2323

2424
if (std::regex_match(url, match, uriRegex)) {
25-
auto & base = match[1];
2625
std::string scheme = match[2];
2726
auto authority = match[3].matched
2827
? std::optional<std::string>(match[3]) : std::nullopt;

tests/functional/flakes/flake-in-submodule.sh

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,16 @@ flakeref=git+file://$rootRepo\?submodules=1\&dir=submodule
6363
echo '"foo"' > "$rootRepo"/submodule/sub.nix
6464
[[ $(nix eval --json "$flakeref#sub" ) = '"foo"' ]]
6565
[[ $(nix flake metadata --json "$flakeref" | jq -r .locked.rev) = null ]]
66+
67+
# Test that `nix flake metadata` parses `submodule` correctly.
68+
cat > "$rootRepo"/flake.nix <<EOF
69+
{
70+
outputs = { self }: {
71+
};
72+
}
73+
EOF
74+
git -C "$rootRepo" add flake.nix
75+
git -C "$rootRepo" commit -m "Add flake.nix"
76+
77+
storePath=$(nix flake metadata --json "$rootRepo?submodules=1" | jq -r .path)
78+
[[ -e "$storePath/submodule" ]]

0 commit comments

Comments
 (0)