Merge pull request #15377 from obsidiansystems/fix-windows-url-paths

Fix windows url paths
This commit is contained in:
John Ericson
2026-03-02 18:38:17 +00:00
committed by GitHub
7 changed files with 20 additions and 7 deletions

View File

@@ -84,6 +84,8 @@ test(
this_exe,
env : {
'_NIX_TEST_UNIT_DATA' : meson.current_source_dir() / 'data',
'HOME' : meson.current_build_dir() / 'test-home',
'NIX_STORE' : '',
},
protocol : 'gtest',
)

View File

@@ -4,6 +4,7 @@
#include "nix/fetchers/fetch-settings.hh"
#include "nix/fetchers/fetchers.hh"
#include "nix/fetchers/git-utils.hh"
#include "nix/util/url.hh"
#include <git2.h>
#include <gtest/gtest.h>
@@ -190,7 +191,7 @@ TEST_F(GitTest, submodulePeriodSupport)
auto input = fetchers::Input::fromAttrs(
settings,
{
{"url", "file://" + repoPath.string()},
{"url", "file://" + encodeUrlPath(pathToUrlPath(repoPath))},
{"submodules", Explicit{true}},
{"type", "git"},
{"ref", "main"},

View File

@@ -66,6 +66,8 @@ test(
this_exe,
env : {
'_NIX_TEST_UNIT_DATA' : meson.current_source_dir() / 'data',
'HOME' : meson.current_build_dir() / 'test-home',
'NIX_STORE' : '',
},
protocol : 'gtest',
)

View File

@@ -95,7 +95,7 @@ struct PathInputScheme : InputScheme
query.erase("__final");
return ParsedURL{
.scheme = "path",
.path = splitString<std::vector<std::string>>(getStrAttr(input.attrs, "path"), "/"),
.path = pathToUrlPath(std::filesystem::path{getStrAttr(input.attrs, "path")}),
.query = query,
};
}

View File

@@ -62,6 +62,7 @@ test(
'_NIX_TEST_UNIT_DATA' : meson.current_source_dir() / 'data',
'NIX_CONFIG' : 'extra-experimental-features = flakes',
'HOME' : meson.current_build_dir() / 'test-home',
'NIX_STORE' : '',
},
protocol : 'gtest',
)

View File

@@ -146,7 +146,7 @@ std::pair<FlakeRef, std::string> parsePathFlakeRefWithFragment(
// Save device to detect filesystem boundary
dev_t device = lstat(path).st_dev;
bool found = false;
while (path != "/") {
while (path.parent_path() != path) {
if (pathExists(path / "flake.nix")) {
found = true;
break;
@@ -171,7 +171,7 @@ std::pair<FlakeRef, std::string> parsePathFlakeRefWithFragment(
auto flakeRoot = path;
std::string subdir;
while (flakeRoot != "/") {
while (flakeRoot.parent_path() != flakeRoot) {
if (pathExists(flakeRoot / ".git")) {
auto parsedURL = ParsedURL{
.scheme = "git+file",

View File

@@ -408,15 +408,22 @@ ParsedURL fixGitURL(std::string url)
url = std::regex_replace(url, scpRegex, "ssh://$1@$2/$3");
if (!hasPrefix(url, "file:") && !hasPrefix(url, "git+file:") && url.find("://") == std::string::npos) {
auto path = splitString<std::vector<std::string>>(url, "/");
#ifdef _WIN32
// Windows drive letters (e.g., "C:") look like SCP hosts but are local paths
bool hasDriveLetter = !path.empty() && path[0].size() == 2
&& std::isalpha(static_cast<unsigned char>(path[0][0])) && path[0][1] == ':';
#else
constexpr bool hasDriveLetter = false;
#endif
// Reject SCP-like URLs without user (e.g., "github.com:path") - colon in first component
if (!path.empty() && path[0].find(':') != std::string::npos)
if (!path.empty() && path[0].find(':') != std::string::npos && !hasDriveLetter)
throw BadURL("SCP-like URL '%s' is not supported; use SSH URL syntax instead (ssh://...)", url);
// Absolute paths get an empty authority (file:///path), relative paths get none (file:path)
if (hasPrefix(url, "/"))
if (hasPrefix(url, "/") || hasDriveLetter)
return ParsedURL{
.scheme = "file",
.authority = ParsedURL::Authority{},
.path = path,
.path = hasDriveLetter ? pathToUrlPath(std::filesystem::path(url)) : path,
};
else
return ParsedURL{