diff options
author | Eelco Dolstra <edolstra@gmail.com> | 2020-04-27 22:53:11 +0200 |
---|---|---|
committer | Eelco Dolstra <edolstra@gmail.com> | 2020-04-27 22:53:11 +0200 |
commit | 6521c92ce8289a5f9e959c6789ab24dacdad082e (patch) | |
tree | 659c7ce34b0cb970aa7d99bcda991de50e8d27ac /src/libexpr/flake | |
parent | 829dcb35d52443636d7c6df0d54270b9995bc71a (diff) |
Improve path:// handling
In particular, doing 'nix build /path/to/dir' now works if
/path/to/dir is not a Git tree (it only has to contain a flake.nix
file).
Also, 'nix flake init' no longer requires a Git tree (but it will do a
'git add flake.nix' if it's a Git tree)
Diffstat (limited to 'src/libexpr/flake')
-rw-r--r-- | src/libexpr/flake/flake.cc | 4 | ||||
-rw-r--r-- | src/libexpr/flake/flakeref.cc | 64 | ||||
-rw-r--r-- | src/libexpr/flake/flakeref.hh | 4 |
3 files changed, 40 insertions, 32 deletions
diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc index 55a4fe65b..0f5770019 100644 --- a/src/libexpr/flake/flake.cc +++ b/src/libexpr/flake/flake.cc @@ -176,7 +176,7 @@ static FlakeInput parseFlakeInput(EvalState & state, if (!attrs.empty()) throw Error("unexpected flake input attribute '%s', at %s", attrs.begin()->first, pos); if (url) - input.ref = parseFlakeRef(*url); + input.ref = parseFlakeRef(*url, {}, true); } return input; @@ -630,7 +630,7 @@ void callFlake(EvalState & state, static void prim_getFlake(EvalState & state, const Pos & pos, Value * * args, Value & v) { auto flakeRefS = state.forceStringNoCtx(*args[0], pos); - auto flakeRef = parseFlakeRef(flakeRefS); + auto flakeRef = parseFlakeRef(flakeRefS, {}, true); if (evalSettings.pureEval && !flakeRef.input->isImmutable()) throw Error("cannot call 'getFlake' on mutable flake reference '%s', at %s (use --impure to override)", flakeRefS, pos); diff --git a/src/libexpr/flake/flakeref.cc b/src/libexpr/flake/flakeref.cc index de91f2eed..a70261a41 100644 --- a/src/libexpr/flake/flakeref.cc +++ b/src/libexpr/flake/flakeref.cc @@ -47,9 +47,9 @@ FlakeRef FlakeRef::resolve(ref<Store> store) const } FlakeRef parseFlakeRef( - const std::string & url, const std::optional<Path> & baseDir) + const std::string & url, const std::optional<Path> & baseDir, bool allowMissing) { - auto [flakeRef, fragment] = parseFlakeRefWithFragment(url, baseDir); + auto [flakeRef, fragment] = parseFlakeRefWithFragment(url, baseDir, allowMissing); if (fragment != "") throw Error("unexpected fragment '%s' in flake reference '%s'", fragment, url); return flakeRef; @@ -66,7 +66,7 @@ std::optional<FlakeRef> maybeParseFlakeRef( } std::pair<FlakeRef, std::string> parseFlakeRefWithFragment( - const std::string & url, const std::optional<Path> & baseDir) + const std::string & url, const std::optional<Path> & baseDir, bool allowMissing) { using namespace fetchers; @@ -115,39 +115,47 @@ std::pair<FlakeRef, std::string> parseFlakeRefWithFragment( if (!S_ISDIR(lstat(path).st_mode)) throw BadURL("path '%s' is not a flake (because it's not a directory)", path); + if (!allowMissing && !pathExists(path + "/flake.nix")) + throw BadURL("path '%s' is not a flake (because it doesn't contain a 'flake.nix' file)", path); + + auto fragment = percentDecode(std::string(match[3])); + auto flakeRoot = path; std::string subdir; - while (true) { - if (pathExists(flakeRoot + "/.git")) break; + while (flakeRoot != "/") { + if (pathExists(flakeRoot + "/.git")) { + auto base = std::string("git+file://") + flakeRoot; + + auto parsedURL = ParsedURL{ + .url = base, // FIXME + .base = base, + .scheme = "git+file", + .authority = "", + .path = flakeRoot, + .query = decodeQuery(match[2]), + }; + + if (subdir != "") { + if (parsedURL.query.count("dir")) + throw Error("flake URL '%s' has an inconsistent 'dir' parameter", url); + parsedURL.query.insert_or_assign("dir", subdir); + } + + return std::make_pair( + FlakeRef(inputFromURL(parsedURL), get(parsedURL.query, "dir").value_or("")), + fragment); + } + subdir = std::string(baseNameOf(flakeRoot)) + (subdir.empty() ? "" : "/" + subdir); flakeRoot = dirOf(flakeRoot); - if (flakeRoot == "/") - throw BadURL("path '%s' is not a flake (because it does not reference a Git repository)", path); } - auto base = std::string("git+file://") + flakeRoot; + fetchers::Attrs attrs; + attrs.insert_or_assign("type", "path"); + attrs.insert_or_assign("path", path); - auto parsedURL = ParsedURL{ - .url = base, // FIXME - .base = base, - .scheme = "git+file", - .authority = "", - .path = flakeRoot, - .query = decodeQuery(match[2]), - }; - - auto fragment = percentDecode(std::string(match[3])); - - if (subdir != "") { - if (parsedURL.query.count("dir")) - throw Error("flake URL '%s' has an inconsistent 'dir' parameter", url); - parsedURL.query.insert_or_assign("dir", subdir); - } - - return std::make_pair( - FlakeRef(inputFromURL(parsedURL), get(parsedURL.query, "dir").value_or("")), - fragment); + return std::make_pair(FlakeRef(inputFromAttrs(attrs), ""), fragment); } else { diff --git a/src/libexpr/flake/flakeref.hh b/src/libexpr/flake/flakeref.hh index 1dbb6e54d..72cbb2908 100644 --- a/src/libexpr/flake/flakeref.hh +++ b/src/libexpr/flake/flakeref.hh @@ -41,13 +41,13 @@ struct FlakeRef std::ostream & operator << (std::ostream & str, const FlakeRef & flakeRef); FlakeRef parseFlakeRef( - const std::string & url, const std::optional<Path> & baseDir = {}); + const std::string & url, const std::optional<Path> & baseDir = {}, bool allowMissing = false); std::optional<FlakeRef> maybeParseFlake( const std::string & url, const std::optional<Path> & baseDir = {}); std::pair<FlakeRef, std::string> parseFlakeRefWithFragment( - const std::string & url, const std::optional<Path> & baseDir = {}); + const std::string & url, const std::optional<Path> & baseDir = {}, bool allowMissing = false); std::optional<std::pair<FlakeRef, std::string>> maybeParseFlakeRefWithFragment( const std::string & url, const std::optional<Path> & baseDir = {}); |