From 32a62b0d25116ffe0d66ecaf6a479fbc915d196e Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 13 Dec 2021 20:54:43 +0100 Subject: [PATCH] Re-allow inputs.x.url = "/path/to/file" --- src/libexpr/flake/flake.cc | 8 ++-- src/libexpr/flake/flakeref.cc | 77 +++++++++++++++++++---------------- src/libexpr/flake/flakeref.hh | 10 ++++- tests/flakes.sh | 10 +++++ 4 files changed, 65 insertions(+), 40 deletions(-) diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc index 33d253eee..f598400fc 100644 --- a/src/libexpr/flake/flake.cc +++ b/src/libexpr/flake/flake.cc @@ -155,7 +155,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, baseDir, true); + input.ref = parseFlakeRef(*url, baseDir, true, input.isFlake); } if (!input.follows && !input.ref) @@ -194,8 +194,8 @@ static Flake getFlake( state, originalRef, allowLookup, flakeCache); // Guard against symlink attacks. - auto flakeDir = canonPath(sourceInfo.actualPath + "/" + lockedRef.subdir); - auto flakeFile = canonPath(flakeDir + "/flake.nix"); + auto flakeDir = canonPath(sourceInfo.actualPath + "/" + lockedRef.subdir, true); + auto flakeFile = canonPath(flakeDir + "/flake.nix", true); if (!isInDir(flakeFile, sourceInfo.actualPath)) throw Error("'flake.nix' file of flake '%s' escapes from '%s'", lockedRef, state.store->printStorePath(sourceInfo.storePath)); @@ -570,7 +570,7 @@ LockedFlake lockFlake( }; // Bring in the current ref for relative path resolution if we have it - auto parentPath = canonPath(flake.sourceInfo->actualPath + "/" + flake.lockedRef.subdir); + auto parentPath = canonPath(flake.sourceInfo->actualPath + "/" + flake.lockedRef.subdir, true); computeLocks( flake.inputs, newLockFile.root, {}, diff --git a/src/libexpr/flake/flakeref.cc b/src/libexpr/flake/flakeref.cc index 29128d789..c3b74e0fe 100644 --- a/src/libexpr/flake/flakeref.cc +++ b/src/libexpr/flake/flakeref.cc @@ -48,9 +48,12 @@ FlakeRef FlakeRef::resolve(ref store) const } FlakeRef parseFlakeRef( - const std::string & url, const std::optional & baseDir, bool allowMissing) + const std::string & url, + const std::optional & baseDir, + bool allowMissing, + bool isFlake) { - auto [flakeRef, fragment] = parseFlakeRefWithFragment(url, baseDir, allowMissing); + auto [flakeRef, fragment] = parseFlakeRefWithFragment(url, baseDir, allowMissing, isFlake); if (fragment != "") throw Error("unexpected fragment '%s' in flake reference '%s'", fragment, url); return flakeRef; @@ -67,7 +70,10 @@ std::optional maybeParseFlakeRef( } std::pair parseFlakeRefWithFragment( - const std::string & url, const std::optional & baseDir, bool allowMissing) + const std::string & url, + const std::optional & baseDir, + bool allowMissing, + bool isFlake) { using namespace fetchers; @@ -112,46 +118,49 @@ std::pair parseFlakeRefWithFragment( to 'baseDir'). If so, search upward to the root of the repo (i.e. the directory containing .git). */ - path = absPath(path, baseDir, true); + path = absPath(path, baseDir); - if (!S_ISDIR(lstat(path).st_mode)) - throw BadURL("path '%s' is not a flake (because it's not a directory)", path); + if (isFlake) { - if (!allowMissing && !pathExists(path + "/flake.nix")) - throw BadURL("path '%s' is not a flake (because it doesn't contain a 'flake.nix' file)", path); + if (!S_ISDIR(lstat(path).st_mode)) + throw BadURL("path '%s' is not a flake (because it's not a directory)", path); - auto flakeRoot = path; - std::string subdir; + if (!allowMissing && !pathExists(path + "/flake.nix")) + throw BadURL("path '%s' is not a flake (because it doesn't contain a 'flake.nix' file)", path); - while (flakeRoot != "/") { - if (pathExists(flakeRoot + "/.git")) { - auto base = std::string("git+file://") + flakeRoot; + auto flakeRoot = path; + std::string subdir; - auto parsedURL = ParsedURL{ - .url = base, // FIXME - .base = base, - .scheme = "git+file", - .authority = "", - .path = flakeRoot, - .query = decodeQuery(match[2]), - }; + while (flakeRoot != "/") { + if (pathExists(flakeRoot + "/.git")) { + auto base = std::string("git+file://") + flakeRoot; - 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); + 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); + } + + if (pathExists(flakeRoot + "/.git/shallow")) + parsedURL.query.insert_or_assign("shallow", "1"); + + return std::make_pair( + FlakeRef(Input::fromURL(parsedURL), get(parsedURL.query, "dir").value_or("")), + fragment); } - if (pathExists(flakeRoot + "/.git/shallow")) - parsedURL.query.insert_or_assign("shallow", "1"); - - return std::make_pair( - FlakeRef(Input::fromURL(parsedURL), get(parsedURL.query, "dir").value_or("")), - fragment); + subdir = std::string(baseNameOf(flakeRoot)) + (subdir.empty() ? "" : "/" + subdir); + flakeRoot = dirOf(flakeRoot); } - - subdir = std::string(baseNameOf(flakeRoot)) + (subdir.empty() ? "" : "/" + subdir); - flakeRoot = dirOf(flakeRoot); } } else { diff --git a/src/libexpr/flake/flakeref.hh b/src/libexpr/flake/flakeref.hh index 0292eb210..1fddfd9a0 100644 --- a/src/libexpr/flake/flakeref.hh +++ b/src/libexpr/flake/flakeref.hh @@ -62,13 +62,19 @@ struct FlakeRef std::ostream & operator << (std::ostream & str, const FlakeRef & flakeRef); FlakeRef parseFlakeRef( - const std::string & url, const std::optional & baseDir = {}, bool allowMissing = false); + const std::string & url, + const std::optional & baseDir = {}, + bool allowMissing = false, + bool isFlake = true); std::optional maybeParseFlake( const std::string & url, const std::optional & baseDir = {}); std::pair parseFlakeRefWithFragment( - const std::string & url, const std::optional & baseDir = {}, bool allowMissing = false); + const std::string & url, + const std::optional & baseDir = {}, + bool allowMissing = false, + bool isFlake = true); std::optional> maybeParseFlakeRefWithFragment( const std::string & url, const std::optional & baseDir = {}); diff --git a/tests/flakes.sh b/tests/flakes.sh index 20966ab2a..942d07010 100644 --- a/tests/flakes.sh +++ b/tests/flakes.sh @@ -249,6 +249,14 @@ cat > $flake3Dir/flake.nix < $flake3Dir/flake.nix < \$out + [[ \$(cat \${inputs.nonFlake}/README.md) = \$(cat \${inputs.nonFlakeFile}) ]] + [[ \${inputs.nonFlakeFile} = \${inputs.nonFlakeFile2} ]] ''; }; };