diff --git a/src/libfetchers/git-utils.cc b/src/libfetchers/git-utils.cc index ffcc92fc7..1edafbf33 100644 --- a/src/libfetchers/git-utils.cc +++ b/src/libfetchers/git-utils.cc @@ -308,13 +308,21 @@ struct GitRepoImpl : GitRepo, std::enable_shared_from_this std::vector> getSubmodules(const Hash & rev) override; - std::string resolveSubmoduleUrl(const std::string & url) override + std::string resolveSubmoduleUrl( + const std::string & url, + const std::string & base) override { git_buf buf = GIT_BUF_INIT; if (git_submodule_resolve_url(&buf, *this, url.c_str())) throw Error("resolving Git submodule URL '%s'", url); Finally cleanup = [&]() { git_buf_dispose(&buf); }; - return buf.ptr; + + std::string res(buf.ptr); + + if (!hasPrefix(res, "/") && res.find("://") == res.npos) + res = parseURL(base + "/" + res).canonicalise().to_string(); + + return res; } bool hasObject(const Hash & oid_) override diff --git a/src/libfetchers/git-utils.hh b/src/libfetchers/git-utils.hh index 7efbdedce..e0cb2c34f 100644 --- a/src/libfetchers/git-utils.hh +++ b/src/libfetchers/git-utils.hh @@ -59,7 +59,9 @@ struct GitRepo */ virtual std::vector> getSubmodules(const Hash & rev) = 0; - virtual std::string resolveSubmoduleUrl(const std::string & url) = 0; + virtual std::string resolveSubmoduleUrl( + const std::string & url, + const std::string & base) = 0; struct TarballInfo { diff --git a/src/libfetchers/git.cc b/src/libfetchers/git.cc index 71ae74dde..177c8b66e 100644 --- a/src/libfetchers/git.cc +++ b/src/libfetchers/git.cc @@ -594,7 +594,7 @@ struct GitInputScheme : InputScheme std::map> mounts; for (auto & [submodule, submoduleRev] : repo->getSubmodules(rev)) { - auto resolved = repo->resolveSubmoduleUrl(submodule.url); + auto resolved = repo->resolveSubmoduleUrl(submodule.url, repoInfo.url); debug("Git submodule %s: %s %s %s -> %s", submodule.path, submodule.url, submodule.branch, submoduleRev.gitRev(), resolved); fetchers::Attrs attrs; diff --git a/src/libutil/url.cc b/src/libutil/url.cc index 9b438e6cd..57b64d607 100644 --- a/src/libutil/url.cc +++ b/src/libutil/url.cc @@ -2,6 +2,7 @@ #include "url-parts.hh" #include "util.hh" #include "split.hh" +#include "canon-path.hh" namespace nix { @@ -141,6 +142,13 @@ bool ParsedURL::operator ==(const ParsedURL & other) const && fragment == other.fragment; } +ParsedURL ParsedURL::canonicalise() +{ + ParsedURL res(*this); + res.path = CanonPath(res.path).abs(); + return res; +} + /** * Parse a URL scheme of the form '(applicationScheme\+)?transportScheme' * into a tuple '(applicationScheme, transportScheme)' diff --git a/src/libutil/url.hh b/src/libutil/url.hh index 26c2dcc28..833f54678 100644 --- a/src/libutil/url.hh +++ b/src/libutil/url.hh @@ -19,6 +19,11 @@ struct ParsedURL std::string to_string() const; bool operator ==(const ParsedURL & other) const; + + /** + * Remove `.` and `..` path elements. + */ + ParsedURL canonicalise(); }; MakeError(BadURL, Error);