diff --git a/src/libexpr/flake/flakeref.cc b/src/libexpr/flake/flakeref.cc index 253442566..4ce326c0b 100644 --- a/src/libexpr/flake/flakeref.cc +++ b/src/libexpr/flake/flakeref.cc @@ -27,7 +27,7 @@ const static std::string ownerRegex = "[a-zA-Z][a-zA-Z0-9_-]*"; const static std::string repoRegex = "[a-zA-Z][a-zA-Z0-9_-]*"; // URI stuff. -const static std::string schemeRegex = "(?:http|https|ssh|git|file)"; +const static std::string schemeRegex = "[a-z+]+"; const static std::string authorityRegex = "[a-zA-Z0-9._~-]*"; const static std::string segmentRegex = "[a-zA-Z0-9._~-]+"; const static std::string pathRegex = "/?" + segmentRegex + "(?:/" + segmentRegex + ")*"; @@ -120,21 +120,29 @@ FlakeRef::FlakeRef(const std::string & uri_, bool allowRelative) data = d; } - else if (std::regex_match(uri.c_str(), match, uriRegex) - && (match[2] == "file" || hasSuffix(match[4], ".git"))) - { - IsGit d; - d.uri = match[1]; - for (auto & param : params) { - if (handleGitParams(param.first, param.second)) - ; - else - // FIXME: should probably pass through unknown parameters - throw BadFlakeRef("invalid Git flakeref parameter '%s', in '%s'", param.first, uri); - } - if (rev && !ref) - throw BadFlakeRef("flake URI '%s' lacks a Git ref", uri); - data = d; + else if (std::regex_match(uri.c_str(), match, uriRegex)) { + auto & scheme = match[2]; + if (scheme == "git" || + scheme == "git+http" || + scheme == "git+https" || + scheme == "git+ssh" || + scheme == "git+file" || + scheme == "file") + { + IsGit d; + d.uri = match[1]; + for (auto & param : params) { + if (handleGitParams(param.first, param.second)) + ; + else + // FIXME: should probably pass through unknown parameters + throw BadFlakeRef("invalid Git flakeref parameter '%s', in '%s'", param.first, uri); + } + if (rev && !ref) + throw BadFlakeRef("flake URI '%s' lacks a Git ref", uri); + data = d; + } else + throw BadFlakeRef("unsupported URI scheme '%s' in flake reference '%s'", scheme, uri); } else if ((hasPrefix(uri, "/") || (allowRelative && (hasPrefix(uri, "./") || hasPrefix(uri, "../") || uri == "."))) diff --git a/src/libexpr/flake/flakeref.hh b/src/libexpr/flake/flakeref.hh index 9ddc227bb..6b47330a7 100644 --- a/src/libexpr/flake/flakeref.hh +++ b/src/libexpr/flake/flakeref.hh @@ -52,28 +52,28 @@ namespace nix { github:edolstra/dwarffs/unstable github:edolstra/dwarffs/41c0c1bf292ea3ac3858ff393b49ca1123dbd553 - * https:///.git(\?attr(&attr)*)? - ssh:///.git(\?attr(&attr)*)? - git:///.git(\?attr(&attr)*)? + * git+https:///(\?attr(&attr)*)? + git+ssh:///(\?attr(&attr)*)? + git:///(\?attr(&attr)*)? file:///(\?attr(&attr)*)? where 'attr' is one of: rev= ref= - A Git repository fetched through https. Note that the path must - end in ".git". The default for "ref" is "master". + A Git repository fetched through https. The default for "ref" is + "master". Examples: - https://example.org/my/repo.git - https://example.org/my/repo.git?ref=release-1.2.3 - https://example.org/my/repo.git?rev=e72daba8250068216d79d2aeef40d4d95aff6666 + git+https://example.org/my/repo.git + git+https://example.org/my/repo.git?ref=release-1.2.3 + git+https://example.org/my/repo.git?rev=e72daba8250068216d79d2aeef40d4d95aff6666 git://github.com/edolstra/dwarffs.git?ref=flake&rev=2efca4bc9da70fb001b26c3dc858c6397d3c4817 - * /path.git(\?attr(&attr)*)? + * /path(\?attr(&attr)*)? - Like file://path.git, but if no "ref" or "rev" is specified, the + Like file://path, but if no "ref" or "rev" is specified, the (possibly dirty) working tree will be used. Using a working tree is not allowed in pure evaluation mode. diff --git a/src/libexpr/primops/fetchGit.cc b/src/libexpr/primops/fetchGit.cc index 931eac95f..48d84c4a1 100644 --- a/src/libexpr/primops/fetchGit.cc +++ b/src/libexpr/primops/fetchGit.cc @@ -25,6 +25,8 @@ GitInfo exportGit(ref store, std::string uri, { assert(!rev || rev->type == htSHA1); + if (hasPrefix(uri, "git+")) uri = std::string(uri, 4); + bool isLocal = hasPrefix(uri, "/") && pathExists(uri + "/.git"); // If this is a local directory (but not a file:// URI) and no ref