diff --git a/src/libexpr/flake/flakeref.cc b/src/libexpr/flake/flakeref.cc index 7631cd53a..253442566 100644 --- a/src/libexpr/flake/flakeref.cc +++ b/src/libexpr/flake/flakeref.cc @@ -145,10 +145,10 @@ FlakeRef::FlakeRef(const std::string & uri_, bool allowRelative) d.path = absPath(uri); try { if (!S_ISDIR(lstat(d.path).st_mode)) - throw BadFlakeRef("path '%s' is not a flake (sub)directory"); + throw MissingFlake("path '%s' is not a flake (sub)directory", d.path); } catch (SysError & e) { if (e.errNo == ENOENT || e.errNo == EISDIR) - throw BadFlakeRef("flake '%s' does not exist"); + throw MissingFlake("flake '%s' does not exist", d.path); throw; } while (true) { @@ -156,7 +156,7 @@ FlakeRef::FlakeRef(const std::string & uri_, bool allowRelative) subdir = baseNameOf(d.path) + (subdir.empty() ? "" : "/" + subdir); d.path = dirOf(d.path); if (d.path == "/") - throw BadFlakeRef("path '%s' does not reference a Git repository", uri); + throw MissingFlake("path '%s' is not a flake (because it does not reference a Git repository)", uri); } } else d.path = canonPath(uri); diff --git a/src/libexpr/flake/flakeref.hh b/src/libexpr/flake/flakeref.hh index 082dd8c26..9ddc227bb 100644 --- a/src/libexpr/flake/flakeref.hh +++ b/src/libexpr/flake/flakeref.hh @@ -187,6 +187,7 @@ struct FlakeRef std::ostream & operator << (std::ostream & str, const FlakeRef & flakeRef); MakeError(BadFlakeRef, Error); +MakeError(MissingFlake, BadFlakeRef); std::optional parseFlakeRef( const std::string & uri, bool allowRelative = false); diff --git a/src/nix/installables.cc b/src/nix/installables.cc index dbbf58861..a4726a59e 100644 --- a/src/nix/installables.cc +++ b/src/nix/installables.cc @@ -417,25 +417,43 @@ std::vector> SourceExprCommand::parseInstallables( Strings{"legacyPackages." + std::string(s, 8)})); } - else if (auto flakeRef = parseFlakeRef(s, true)) - result.push_back(std::make_shared(*this, std::move(*flakeRef), - getDefaultFlakeAttrPaths())); + else { - else if ((colon = s.rfind(':')) != std::string::npos) { - auto flakeRef = std::string(s, 0, colon); - auto attrPath = std::string(s, colon + 1); - result.push_back(std::make_shared( - *this, - FlakeRef(flakeRef, true), - attrPath, - getDefaultFlakeAttrPathPrefixes())); + std::exception_ptr flakeEx; + + try { + auto flakeRef = FlakeRef(s, true); + result.push_back(std::make_shared( + *this, std::move(flakeRef), getDefaultFlakeAttrPaths())); + continue; + } catch (MissingFlake &) { + /* 's' could be parsed as a flakeref, but it + references a local path that is not a flake. So + take note of that. */ + flakeEx = std::current_exception(); + } catch (BadFlakeRef &) { + } + + if ((colon = s.rfind(':')) != std::string::npos) { + auto flakeRef = std::string(s, 0, colon); + auto attrPath = std::string(s, colon + 1); + result.push_back(std::make_shared( + *this, + FlakeRef(flakeRef, true), + attrPath, + getDefaultFlakeAttrPathPrefixes())); + } + + else if (s.find('/') != std::string::npos && (storePath = follow(s))) + result.push_back(std::make_shared(*storePath)); + + else { + if (flakeEx) + std::rethrow_exception(flakeEx); + else + throw Error("unsupported argument '%s'", s); + } } - - else if (s.find('/') != std::string::npos && (storePath = follow(s))) - result.push_back(std::make_shared(*storePath)); - - else - throw Error("unsupported argument '%s'", s); } }