diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 21dd5a294..345c09e7e 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -406,7 +406,7 @@ void EvalState::checkURI(const std::string & uri) /* If the URI is a path, then check it against allowedPaths as well. */ - if (hasPrefix(uri, "/")) { + if (isAbsolute(uri)) { if (auto rootFS2 = rootFS.dynamic_pointer_cast()) rootFS2->checkAccess(CanonPath(uri)); return; diff --git a/src/libfetchers/path.cc b/src/libfetchers/path.cc index f628e042c..340e7f4fa 100644 --- a/src/libfetchers/path.cc +++ b/src/libfetchers/path.cc @@ -97,7 +97,7 @@ struct PathInputScheme : InputScheme std::optional isRelative(const Input & input) const { auto path = getStrAttr(input.attrs, "path"); - if (hasPrefix(path, "/")) + if (isAbsolute(path)) return std::nullopt; else return path; diff --git a/src/libfetchers/registry.cc b/src/libfetchers/registry.cc index 171afcea7..c18e12d23 100644 --- a/src/libfetchers/registry.cc +++ b/src/libfetchers/registry.cc @@ -153,7 +153,7 @@ static std::shared_ptr getGlobalRegistry(const Settings & settings, re return std::make_shared(settings, Registry::Global); // empty registry } - if (!hasPrefix(path, "/")) { + if (!isAbsolute(path)) { auto storePath = downloadFile(store, path, "flake-registry.json").storePath; if (auto store2 = store.dynamic_pointer_cast()) store2->addPermRoot(storePath, getCacheDir() + "/flake-registry.json"); diff --git a/src/libflake/flake/flakeref.cc b/src/libflake/flake/flakeref.cc index cdf0a40e8..b81eb1292 100644 --- a/src/libflake/flake/flakeref.cc +++ b/src/libflake/flake/flakeref.cc @@ -102,8 +102,8 @@ std::pair parsePathFlakeRefWithFragment( if (baseDir) { /* Check if 'url' is a path (either absolute or relative - to 'baseDir'). If so, search upward to the root of the - repo (i.e. the directory containing .git). */ + to 'baseDir'). If so, search upward to the root of the + repo (i.e. the directory containing .git). */ path = absPath(path, baseDir); @@ -178,7 +178,7 @@ std::pair parsePathFlakeRefWithFragment( } } else { - if (!hasPrefix(path, "/")) + if (!isAbsolute(path)) throw BadURL("flake reference '%s' is not an absolute path", url); path = canonPath(path + "/" + getOr(query, "dir", "")); } @@ -232,7 +232,12 @@ std::optional> parseURLFlakeRef( ) { try { - return fromParsedURL(fetchSettings, parseURL(url), isFlake); + auto parsed = parseURL(url); + if (baseDir + && (parsed.scheme == "path" || parsed.scheme == "git+file") + && !isAbsolute(parsed.path)) + parsed.path = absPath(parsed.path, *baseDir); + return fromParsedURL(fetchSettings, std::move(parsed), isFlake); } catch (BadURL &) { return std::nullopt; } diff --git a/src/libutil/file-system.cc b/src/libutil/file-system.cc index 923220fd0..a86f1ba4f 100644 --- a/src/libutil/file-system.cc +++ b/src/libutil/file-system.cc @@ -31,12 +31,7 @@ namespace nix { namespace fs { using namespace std::filesystem; } -/** - * Treat the string as possibly an absolute path, by inspecting the - * start of it. Return whether it was probably intended to be - * absolute. - */ -static bool isAbsolute(PathView path) +bool isAbsolute(PathView path) { return fs::path { path }.is_absolute(); } diff --git a/src/libutil/file-system.hh b/src/libutil/file-system.hh index 7fdaba811..204907339 100644 --- a/src/libutil/file-system.hh +++ b/src/libutil/file-system.hh @@ -42,6 +42,11 @@ namespace nix { struct Sink; struct Source; +/** + * Return whether the path denotes an absolute path. + */ +bool isAbsolute(PathView path); + /** * @return An absolutized path, resolving paths relative to the * specified directory, or the current directory otherwise. The path diff --git a/src/libutil/source-accessor.cc b/src/libutil/source-accessor.cc index aa8dcf9fd..78f038cf3 100644 --- a/src/libutil/source-accessor.cc +++ b/src/libutil/source-accessor.cc @@ -115,7 +115,7 @@ CanonPath SourceAccessor::resolveSymlinks( throw Error("infinite symlink recursion in path '%s'", showPath(path)); auto target = readLink(res); res.pop(); - if (hasPrefix(target, "/")) + if (isAbsolute(target)) res = CanonPath::root; todo.splice(todo.begin(), tokenizeString>(target, "/")); } diff --git a/tests/functional/flakes/flakes.sh b/tests/functional/flakes/flakes.sh index 995ca03b0..d8c9f254d 100755 --- a/tests/functional/flakes/flakes.sh +++ b/tests/functional/flakes/flakes.sh @@ -97,6 +97,9 @@ nix build -o "$TEST_ROOT/result" flake1 nix build -o "$TEST_ROOT/result" "$flake1Dir" nix build -o "$TEST_ROOT/result" "git+file://$flake1Dir" +(cd "$flake1Dir" && nix build -o "$TEST_ROOT/result" ".") +(cd "$flake1Dir" && nix build -o "$TEST_ROOT/result" "path:.") +(cd "$flake1Dir" && nix build -o "$TEST_ROOT/result" "git+file:.") # Test explicit packages.default. nix build -o "$TEST_ROOT/result" "$flake1Dir#default"