Merge pull request #15280 from NixOS/local-store-filesystem
libstore: Fix pct-encoding issues in store references
This commit is contained in:
@@ -38,8 +38,7 @@ void HttpsBinaryCacheStoreTest::SetUp()
|
||||
delTmpDir = std::make_unique<AutoDelete>(tmpDir);
|
||||
|
||||
localCacheStore =
|
||||
make_ref<LocalBinaryCacheStoreConfig>("file", cacheDir.string(), LocalBinaryCacheStoreConfig::Params{})
|
||||
->openStore();
|
||||
make_ref<LocalBinaryCacheStoreConfig>(cacheDir, LocalBinaryCacheStoreConfig::Params{})->openStore();
|
||||
|
||||
caCert = tmpDir / "ca.crt";
|
||||
caKey = tmpDir / "ca.key";
|
||||
|
||||
@@ -7,24 +7,31 @@
|
||||
|
||||
namespace nix {
|
||||
|
||||
using Authority = ParsedURL::Authority;
|
||||
|
||||
TEST(HttpBinaryCacheStore, constructConfig)
|
||||
{
|
||||
HttpBinaryCacheStoreConfig config{"http", "foo.bar.baz", {}};
|
||||
HttpBinaryCacheStoreConfig config{
|
||||
{
|
||||
.scheme = "http",
|
||||
.authority = Authority{.host = "foo.bar.baz"},
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
EXPECT_EQ(config.cacheUri.to_string(), "http://foo.bar.baz");
|
||||
}
|
||||
|
||||
TEST(HttpBinaryCacheStore, constructConfigNoTrailingSlash)
|
||||
{
|
||||
HttpBinaryCacheStoreConfig config{"https", "foo.bar.baz/a/b/", {}};
|
||||
|
||||
HttpBinaryCacheStoreConfig config{parseURL("https://foo.bar.baz/a/b/"), {}};
|
||||
EXPECT_EQ(config.cacheUri.to_string(), "https://foo.bar.baz/a/b");
|
||||
}
|
||||
|
||||
TEST(HttpBinaryCacheStore, constructConfigWithParams)
|
||||
{
|
||||
StoreConfig::Params params{{"compression", "xz"}};
|
||||
HttpBinaryCacheStoreConfig config{"https", "foo.bar.baz/a/b/", params};
|
||||
HttpBinaryCacheStoreConfig config{parseURL("https://foo.bar.baz/a/b/"), params};
|
||||
EXPECT_EQ(config.cacheUri.to_string(), "https://foo.bar.baz/a/b");
|
||||
EXPECT_EQ(config.getReference().params, params);
|
||||
}
|
||||
@@ -32,7 +39,7 @@ TEST(HttpBinaryCacheStore, constructConfigWithParams)
|
||||
TEST(HttpBinaryCacheStore, constructConfigWithParamsAndUrlWithParams)
|
||||
{
|
||||
StoreConfig::Params params{{"compression", "xz"}};
|
||||
HttpBinaryCacheStoreConfig config{"https", "foo.bar.baz/a/b?some-param=some-value", params};
|
||||
HttpBinaryCacheStoreConfig config{parseURL("https://foo.bar.baz/a/b?some-param=some-value"), params};
|
||||
EXPECT_EQ(config.cacheUri.to_string(), "https://foo.bar.baz/a/b?some-param=some-value");
|
||||
EXPECT_EQ(config.getReference().params, params);
|
||||
}
|
||||
|
||||
@@ -7,8 +7,7 @@ namespace nix {
|
||||
TEST(LegacySSHStore, constructConfig)
|
||||
{
|
||||
LegacySSHStoreConfig config(
|
||||
"ssh",
|
||||
"me@localhost:2222",
|
||||
ParsedURL::Authority::parse("me@localhost:2222"),
|
||||
StoreConfig::Params{
|
||||
{
|
||||
"remote-program",
|
||||
|
||||
@@ -6,8 +6,7 @@ namespace nix {
|
||||
|
||||
TEST(LocalBinaryCacheStore, constructConfig)
|
||||
{
|
||||
LocalBinaryCacheStoreConfig config{"local", "/foo/bar/baz", {}};
|
||||
|
||||
LocalBinaryCacheStoreConfig config{std::filesystem::path("/foo/bar/baz"), {}};
|
||||
EXPECT_EQ(config.binaryCacheDir, "/foo/bar/baz");
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ namespace nix {
|
||||
TEST(LocalOverlayStore, constructConfig_rootQueryParam)
|
||||
{
|
||||
LocalOverlayStoreConfig config{
|
||||
"local-overlay",
|
||||
"",
|
||||
{
|
||||
{
|
||||
@@ -22,7 +21,7 @@ TEST(LocalOverlayStore, constructConfig_rootQueryParam)
|
||||
|
||||
TEST(LocalOverlayStore, constructConfig_rootPath)
|
||||
{
|
||||
LocalOverlayStoreConfig config{"local-overlay", "/foo/bar", {}};
|
||||
LocalOverlayStoreConfig config{"/foo/bar", {}};
|
||||
|
||||
EXPECT_EQ(config.rootDir.get(), std::optional{"/foo/bar"});
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ namespace nix {
|
||||
TEST(LocalStore, constructConfig_rootQueryParam)
|
||||
{
|
||||
LocalStoreConfig config{
|
||||
"local",
|
||||
"",
|
||||
{
|
||||
{
|
||||
@@ -28,14 +27,14 @@ TEST(LocalStore, constructConfig_rootQueryParam)
|
||||
|
||||
TEST(LocalStore, constructConfig_rootPath)
|
||||
{
|
||||
LocalStoreConfig config{"local", "/foo/bar", {}};
|
||||
LocalStoreConfig config{"/foo/bar", {}};
|
||||
|
||||
EXPECT_EQ(config.rootDir.get(), std::optional{"/foo/bar"});
|
||||
}
|
||||
|
||||
TEST(LocalStore, constructConfig_to_string)
|
||||
{
|
||||
LocalStoreConfig config{"local", "", {}};
|
||||
LocalStoreConfig config{"", {}};
|
||||
EXPECT_EQ(config.getReference().to_string(), "local");
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace nix {
|
||||
|
||||
TEST(S3BinaryCacheStore, constructConfig)
|
||||
{
|
||||
S3BinaryCacheStoreConfig config{"s3", "foobar", {}};
|
||||
S3BinaryCacheStoreConfig config{"foobar", {}};
|
||||
|
||||
// The bucket name is stored as the host part of the authority in cacheUri
|
||||
EXPECT_EQ(
|
||||
@@ -23,7 +23,7 @@ TEST(S3BinaryCacheStore, constructConfig)
|
||||
TEST(S3BinaryCacheStore, constructConfigWithRegion)
|
||||
{
|
||||
Store::Config::Params params{{"region", "eu-west-1"}};
|
||||
S3BinaryCacheStoreConfig config{"s3", "my-bucket", params};
|
||||
S3BinaryCacheStoreConfig config{"my-bucket", params};
|
||||
|
||||
EXPECT_EQ(
|
||||
config.cacheUri,
|
||||
@@ -37,7 +37,7 @@ TEST(S3BinaryCacheStore, constructConfigWithRegion)
|
||||
|
||||
TEST(S3BinaryCacheStore, defaultSettings)
|
||||
{
|
||||
S3BinaryCacheStoreConfig config{"s3", "test-bucket", {}};
|
||||
S3BinaryCacheStoreConfig config{"test-bucket", {}};
|
||||
|
||||
EXPECT_EQ(
|
||||
config.cacheUri,
|
||||
@@ -62,7 +62,7 @@ TEST(S3BinaryCacheStore, s3StoreConfigPreservesParameters)
|
||||
params["region"] = "eu-west-1";
|
||||
params["endpoint"] = "custom.s3.com";
|
||||
|
||||
S3BinaryCacheStoreConfig config("s3", "test-bucket", params);
|
||||
S3BinaryCacheStoreConfig config("test-bucket", params);
|
||||
|
||||
// The config should preserve S3-specific parameters
|
||||
EXPECT_EQ(
|
||||
@@ -99,7 +99,7 @@ TEST(S3BinaryCacheStore, parameterFiltering)
|
||||
params["want-mass-query"] = "true"; // Non-S3 store parameter
|
||||
params["priority"] = "10"; // Non-S3 store parameter
|
||||
|
||||
S3BinaryCacheStoreConfig config("s3", "test-bucket", params);
|
||||
S3BinaryCacheStoreConfig config("test-bucket", params);
|
||||
|
||||
// Only S3-specific params should be in cacheUri.query
|
||||
EXPECT_EQ(
|
||||
@@ -127,7 +127,7 @@ TEST(S3BinaryCacheStore, parameterFiltering)
|
||||
*/
|
||||
TEST(S3BinaryCacheStore, storageClassDefault)
|
||||
{
|
||||
S3BinaryCacheStoreConfig config{"s3", "test-bucket", {}};
|
||||
S3BinaryCacheStoreConfig config{"test-bucket", {}};
|
||||
EXPECT_EQ(config.storageClass.get(), std::nullopt);
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ TEST(S3BinaryCacheStore, storageClassConfiguration)
|
||||
StringMap params;
|
||||
params["storage-class"] = "GLACIER";
|
||||
|
||||
S3BinaryCacheStoreConfig config("s3", "test-bucket", params);
|
||||
S3BinaryCacheStoreConfig config("test-bucket", params);
|
||||
EXPECT_EQ(config.storageClass.get(), std::optional<std::string>("GLACIER"));
|
||||
}
|
||||
|
||||
|
||||
@@ -9,8 +9,7 @@ namespace nix {
|
||||
TEST(SSHStore, constructConfig)
|
||||
{
|
||||
SSHStoreConfig config{
|
||||
"ssh-ng",
|
||||
"me@localhost:2222",
|
||||
ParsedURL::Authority::parse("me@localhost:2222"),
|
||||
StoreConfig::Params{
|
||||
{
|
||||
"remote-program",
|
||||
@@ -35,8 +34,7 @@ TEST(SSHStore, constructConfig)
|
||||
TEST(MountedSSHStore, constructConfig)
|
||||
{
|
||||
MountedSSHStoreConfig config{
|
||||
"mounted-ssh",
|
||||
"localhost",
|
||||
{.host = "localhost"},
|
||||
StoreConfig::Params{
|
||||
{
|
||||
"remote-program",
|
||||
|
||||
@@ -6,26 +6,21 @@ namespace nix {
|
||||
|
||||
TEST(UDSRemoteStore, constructConfig)
|
||||
{
|
||||
UDSRemoteStoreConfig config{"unix", "/tmp/socket", {}};
|
||||
UDSRemoteStoreConfig config{"/tmp/socket", {}};
|
||||
|
||||
EXPECT_EQ(config.path, "/tmp/socket");
|
||||
}
|
||||
|
||||
TEST(UDSRemoteStore, constructConfigWrongScheme)
|
||||
{
|
||||
EXPECT_THROW(UDSRemoteStoreConfig("http", "/tmp/socket", {}), UsageError);
|
||||
}
|
||||
|
||||
TEST(UDSRemoteStore, constructConfig_to_string)
|
||||
{
|
||||
UDSRemoteStoreConfig config{"unix", "", {}};
|
||||
UDSRemoteStoreConfig config{"", {}};
|
||||
EXPECT_EQ(config.getReference().to_string(), "daemon");
|
||||
}
|
||||
|
||||
TEST(UDSRemoteStore, constructConfigWithParams)
|
||||
{
|
||||
StoreConfig::Params params{{"max-connections", "1"}};
|
||||
UDSRemoteStoreConfig config{"unix", "/tmp/socket", params};
|
||||
UDSRemoteStoreConfig config{"/tmp/socket", params};
|
||||
auto storeReference = config.getReference();
|
||||
EXPECT_EQ(storeReference.to_string(), "unix:///tmp/socket?max-connections=1");
|
||||
EXPECT_EQ(storeReference.render(/*withParams=*/false), "unix:///tmp/socket");
|
||||
@@ -35,7 +30,7 @@ TEST(UDSRemoteStore, constructConfigWithParams)
|
||||
TEST(UDSRemoteStore, constructConfigWithParamsNoPath)
|
||||
{
|
||||
StoreConfig::Params params{{"max-connections", "1"}};
|
||||
UDSRemoteStoreConfig config{"unix", "", params};
|
||||
UDSRemoteStoreConfig config{"", params};
|
||||
auto storeReference = config.getReference();
|
||||
EXPECT_EQ(storeReference.to_string(), "daemon?max-connections=1");
|
||||
EXPECT_EQ(storeReference.render(/*withParams=*/false), "daemon");
|
||||
|
||||
@@ -1,17 +1,9 @@
|
||||
#include <regex>
|
||||
|
||||
#include "nix/store/common-ssh-store-config.hh"
|
||||
#include "nix/store/ssh.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
CommonSSHStoreConfig::CommonSSHStoreConfig(std::string_view scheme, std::string_view authority, const Params & params)
|
||||
: CommonSSHStoreConfig(scheme, ParsedURL::Authority::parse(authority), params)
|
||||
{
|
||||
}
|
||||
|
||||
CommonSSHStoreConfig::CommonSSHStoreConfig(
|
||||
std::string_view scheme, const ParsedURL::Authority & authority, const Params & params)
|
||||
CommonSSHStoreConfig::CommonSSHStoreConfig(const ParsedURL::Authority & authority, const Params & params)
|
||||
: StoreConfig(params)
|
||||
, authority(authority)
|
||||
{
|
||||
|
||||
@@ -20,23 +20,13 @@ StringSet HttpBinaryCacheStoreConfig::uriSchemes()
|
||||
return ret;
|
||||
}
|
||||
|
||||
HttpBinaryCacheStoreConfig::HttpBinaryCacheStoreConfig(
|
||||
std::string_view scheme, std::string_view _cacheUri, const Params & params)
|
||||
: HttpBinaryCacheStoreConfig(
|
||||
parseURL(
|
||||
std::string{scheme} + "://"
|
||||
+ (!_cacheUri.empty()
|
||||
? _cacheUri
|
||||
: throw UsageError("`%s` Store requires a non-empty authority in Store URL", scheme))),
|
||||
params)
|
||||
{
|
||||
}
|
||||
|
||||
HttpBinaryCacheStoreConfig::HttpBinaryCacheStoreConfig(ParsedURL _cacheUri, const Params & params)
|
||||
: StoreConfig(params)
|
||||
, BinaryCacheStoreConfig(params)
|
||||
, cacheUri(std::move(_cacheUri))
|
||||
{
|
||||
if (!uriSchemes().contains("file") && (!cacheUri.authority || cacheUri.authority->host.empty()))
|
||||
throw UsageError("`%s` Store requires a non-empty authority in Store URL", cacheUri.scheme);
|
||||
while (!cacheUri.path.empty() && cacheUri.path.back() == "")
|
||||
cacheUri.path.pop_back();
|
||||
}
|
||||
|
||||
@@ -12,8 +12,7 @@ struct CommonSSHStoreConfig : virtual StoreConfig
|
||||
{
|
||||
using StoreConfig::StoreConfig;
|
||||
|
||||
CommonSSHStoreConfig(std::string_view scheme, const ParsedURL::Authority & authority, const Params & params);
|
||||
CommonSSHStoreConfig(std::string_view scheme, std::string_view authority, const Params & params);
|
||||
CommonSSHStoreConfig(const ParsedURL::Authority & authority, const Params & params);
|
||||
|
||||
Setting<std::filesystem::path> sshKey{
|
||||
this, "", "ssh-key", "Path to the SSH private key used to authenticate to the remote machine."};
|
||||
|
||||
@@ -16,9 +16,6 @@ struct HttpBinaryCacheStoreConfig : std::enable_shared_from_this<HttpBinaryCache
|
||||
{
|
||||
using BinaryCacheStoreConfig::BinaryCacheStoreConfig;
|
||||
|
||||
HttpBinaryCacheStoreConfig(
|
||||
std::string_view scheme, std::string_view cacheUri, const Store::Config::Params & params);
|
||||
|
||||
HttpBinaryCacheStoreConfig(ParsedURL cacheUri, const Store::Config::Params & params);
|
||||
|
||||
ParsedURL cacheUri;
|
||||
|
||||
@@ -14,7 +14,7 @@ struct LegacySSHStoreConfig : std::enable_shared_from_this<LegacySSHStoreConfig>
|
||||
{
|
||||
using CommonSSHStoreConfig::CommonSSHStoreConfig;
|
||||
|
||||
LegacySSHStoreConfig(std::string_view scheme, std::string_view authority, const Params & params);
|
||||
LegacySSHStoreConfig(const ParsedURL::Authority & authority, const Params & params);
|
||||
|
||||
#ifndef _WIN32
|
||||
// Hack for getting remote build log output.
|
||||
|
||||
@@ -12,7 +12,7 @@ struct LocalBinaryCacheStoreConfig : std::enable_shared_from_this<LocalBinaryCac
|
||||
* @param binaryCacheDir `file://` is a short-hand for `file:///`
|
||||
* for now.
|
||||
*/
|
||||
LocalBinaryCacheStoreConfig(std::string_view scheme, PathView binaryCacheDir, const Params & params);
|
||||
LocalBinaryCacheStoreConfig(const std::filesystem::path & binaryCacheDir, const Params & params);
|
||||
|
||||
std::filesystem::path binaryCacheDir;
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ public:
|
||||
*
|
||||
* @todo Make this less error-prone with new store settings system.
|
||||
*/
|
||||
LocalFSStoreConfig(PathView path, const Params & params);
|
||||
LocalFSStoreConfig(const std::filesystem::path & path, const Params & params);
|
||||
|
||||
Setting<std::optional<std::filesystem::path>> rootDir = makeRootDirSetting(*this, std::nullopt);
|
||||
|
||||
|
||||
@@ -8,14 +8,14 @@ namespace nix {
|
||||
struct LocalOverlayStoreConfig : virtual LocalStoreConfig
|
||||
{
|
||||
LocalOverlayStoreConfig(const StringMap & params)
|
||||
: LocalOverlayStoreConfig("local-overlay", "", params)
|
||||
: LocalOverlayStoreConfig("", params)
|
||||
{
|
||||
}
|
||||
|
||||
LocalOverlayStoreConfig(std::string_view scheme, PathView path, const Params & params)
|
||||
LocalOverlayStoreConfig(const std::filesystem::path & path, const Params & params)
|
||||
: StoreConfig(params)
|
||||
, LocalFSStoreConfig(path, params)
|
||||
, LocalStoreConfig(scheme, path, params)
|
||||
, LocalStoreConfig(path, params)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ struct LocalStoreConfig : std::enable_shared_from_this<LocalStoreConfig>,
|
||||
{
|
||||
using LocalFSStoreConfig::LocalFSStoreConfig;
|
||||
|
||||
LocalStoreConfig(std::string_view scheme, std::string_view authority, const Params & params);
|
||||
LocalStoreConfig(const std::filesystem::path & path, const Params & params);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
@@ -11,7 +11,9 @@ struct S3BinaryCacheStoreConfig : HttpBinaryCacheStoreConfig
|
||||
{
|
||||
using HttpBinaryCacheStoreConfig::HttpBinaryCacheStoreConfig;
|
||||
|
||||
S3BinaryCacheStoreConfig(std::string_view uriScheme, std::string_view bucketName, const Params & params);
|
||||
S3BinaryCacheStoreConfig(ParsedURL cacheUri, const Params & params);
|
||||
|
||||
S3BinaryCacheStoreConfig(std::string_view bucketName, const Params & params);
|
||||
|
||||
Setting<std::string> profile{
|
||||
this,
|
||||
|
||||
@@ -15,7 +15,7 @@ struct SSHStoreConfig : std::enable_shared_from_this<SSHStoreConfig>,
|
||||
using CommonSSHStoreConfig::CommonSSHStoreConfig;
|
||||
using RemoteStoreConfig::RemoteStoreConfig;
|
||||
|
||||
SSHStoreConfig(std::string_view scheme, std::string_view authority, const Params & params);
|
||||
SSHStoreConfig(const ParsedURL::Authority & authority, const Params & params);
|
||||
|
||||
Setting<Strings> remoteProgram{
|
||||
this, {"nix-daemon"}, "remote-program", "Path to the `nix-daemon` executable on the remote machine."};
|
||||
@@ -40,7 +40,7 @@ struct SSHStoreConfig : std::enable_shared_from_this<SSHStoreConfig>,
|
||||
struct MountedSSHStoreConfig : virtual SSHStoreConfig, virtual LocalFSStoreConfig
|
||||
{
|
||||
MountedSSHStoreConfig(StringMap params);
|
||||
MountedSSHStoreConfig(std::string_view scheme, std::string_view host, StringMap params);
|
||||
MountedSSHStoreConfig(const ParsedURL::Authority & authority, StringMap params);
|
||||
|
||||
static const std::string name()
|
||||
{
|
||||
|
||||
@@ -56,6 +56,7 @@ struct StoreReference
|
||||
|
||||
/**
|
||||
* General case, a regular `scheme://authority` URL.
|
||||
* @todo Consider making this pluggable instead of passing through the encoded authority + path.
|
||||
*/
|
||||
struct Specified
|
||||
{
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
*/
|
||||
|
||||
#include "nix/store/store-api.hh"
|
||||
#include "nix/util/url.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
@@ -65,7 +66,16 @@ struct Implementations
|
||||
.uriSchemes = TConfig::uriSchemes(),
|
||||
.experimentalFeature = TConfig::experimentalFeature(),
|
||||
.parseConfig = ([](auto scheme, auto uri, auto & params) -> ref<StoreConfig> {
|
||||
return make_ref<TConfig>(scheme, uri, params);
|
||||
if constexpr (std::is_constructible_v<TConfig, std::filesystem::path, StoreConfig::Params>) {
|
||||
std::filesystem::path path = percentDecode(uri);
|
||||
return make_ref<TConfig>(path.empty() ? std::filesystem::path{} : canonPath(path), params);
|
||||
} else if constexpr (std::is_constructible_v<TConfig, ParsedURL, StoreConfig::Params>) {
|
||||
return make_ref<TConfig>(parseURL(concatStrings(scheme, "://", uri)), params);
|
||||
} else if constexpr (std::is_constructible_v<TConfig, ParsedURL::Authority, StoreConfig::Params>) {
|
||||
return make_ref<TConfig>(ParsedURL::Authority::parse(uri), params);
|
||||
} else {
|
||||
return make_ref<TConfig>(scheme, uri, params);
|
||||
}
|
||||
}),
|
||||
.getConfig = ([]() -> ref<StoreConfig> { return make_ref<TConfig>(Store::Config::Params{}); }),
|
||||
};
|
||||
|
||||
@@ -11,15 +11,10 @@ struct UDSRemoteStoreConfig : std::enable_shared_from_this<UDSRemoteStoreConfig>
|
||||
virtual LocalFSStoreConfig,
|
||||
virtual RemoteStoreConfig
|
||||
{
|
||||
// TODO(fzakaria): Delete this constructor once moved over to the factory pattern
|
||||
// outlined in https://github.com/NixOS/nix/issues/10766
|
||||
using LocalFSStoreConfig::LocalFSStoreConfig;
|
||||
using RemoteStoreConfig::RemoteStoreConfig;
|
||||
|
||||
/**
|
||||
* @param authority is the socket path.
|
||||
*/
|
||||
UDSRemoteStoreConfig(std::string_view scheme, std::string_view authority, const Params & params);
|
||||
UDSRemoteStoreConfig(const std::filesystem::path & path, const Params & params);
|
||||
|
||||
UDSRemoteStoreConfig(const Params & params);
|
||||
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
|
||||
namespace nix {
|
||||
|
||||
LegacySSHStoreConfig::LegacySSHStoreConfig(std::string_view scheme, std::string_view authority, const Params & params)
|
||||
LegacySSHStoreConfig::LegacySSHStoreConfig(const ParsedURL::Authority & authority, const Params & params)
|
||||
: StoreConfig(params)
|
||||
, CommonSSHStoreConfig(scheme, ParsedURL::Authority::parse(authority), params)
|
||||
, CommonSSHStoreConfig(authority, params)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -8,8 +8,25 @@
|
||||
|
||||
namespace nix {
|
||||
|
||||
static std::filesystem::path checkBinaryCachePath(const std::filesystem::path & root, const std::string & path)
|
||||
{
|
||||
auto p = std::filesystem::path(requireCString(path));
|
||||
if (p.empty())
|
||||
throw Error("local binary cache path must not be empty");
|
||||
|
||||
if (p.is_absolute())
|
||||
throw Error("local binary cache path '%s' must not be absolute", path);
|
||||
|
||||
for (const auto & segment : p) {
|
||||
if (segment.native() == OS_STR("..") || segment.native() == OS_STR("."))
|
||||
throw Error("local binary cache path '%s' must not contain '..' or '.' segments", path);
|
||||
}
|
||||
|
||||
return root / p.relative_path();
|
||||
}
|
||||
|
||||
LocalBinaryCacheStoreConfig::LocalBinaryCacheStoreConfig(
|
||||
std::string_view scheme, PathView binaryCacheDir, const StoreReference::Params & params)
|
||||
const std::filesystem::path & binaryCacheDir, const StoreReference::Params & params)
|
||||
: Store::Config{params}
|
||||
, BinaryCacheStoreConfig{params}
|
||||
, binaryCacheDir(binaryCacheDir)
|
||||
@@ -29,7 +46,7 @@ StoreReference LocalBinaryCacheStoreConfig::getReference() const
|
||||
.variant =
|
||||
StoreReference::Specified{
|
||||
.scheme = "file",
|
||||
.authority = binaryCacheDir.string(),
|
||||
.authority = encodeUrlPath(pathToUrlPath(binaryCacheDir)),
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -56,23 +73,22 @@ protected:
|
||||
void upsertFile(
|
||||
const std::string & path, RestartableSource & source, const std::string & mimeType, uint64_t sizeHint) override
|
||||
{
|
||||
assert(!std::filesystem::path(path).is_absolute());
|
||||
auto path2 = config->binaryCacheDir / path;
|
||||
auto path2 = checkBinaryCachePath(config->binaryCacheDir, path);
|
||||
static std::atomic<int> counter{0};
|
||||
createDirs(path2.parent_path());
|
||||
auto tmp = path2;
|
||||
tmp += fmt(".tmp.%d.%d", getpid(), ++counter);
|
||||
AutoDelete del(tmp, false);
|
||||
writeFile(tmp, source);
|
||||
writeFile(tmp, source); /* TODO: Don't follow symlinks? */
|
||||
std::filesystem::rename(tmp, path2);
|
||||
del.cancel();
|
||||
}
|
||||
|
||||
void getFile(const std::string & path, Sink & sink) override
|
||||
{
|
||||
assert(!std::filesystem::path(path).is_absolute());
|
||||
try {
|
||||
readFile(config->binaryCacheDir / path, sink);
|
||||
/* TODO: Don't follow symlinks? */
|
||||
readFile(checkBinaryCachePath(config->binaryCacheDir, path), sink);
|
||||
} catch (SystemError & e) {
|
||||
if (e.is(std::errc::no_such_file_or_directory))
|
||||
throw NoSuchBinaryCacheFile("file '%s' does not exist in binary cache", path);
|
||||
@@ -113,8 +129,7 @@ void LocalBinaryCacheStore::init()
|
||||
|
||||
bool LocalBinaryCacheStore::fileExists(const std::string & path)
|
||||
{
|
||||
assert(!std::filesystem::path(path).is_absolute());
|
||||
return pathExists(config->binaryCacheDir / path);
|
||||
return pathExists(checkBinaryCachePath(config->binaryCacheDir, path));
|
||||
}
|
||||
|
||||
StringSet LocalBinaryCacheStoreConfig::uriSchemes()
|
||||
|
||||
@@ -18,7 +18,7 @@ std::filesystem::path LocalFSStoreConfig::getDefaultLogDir()
|
||||
return settings.getLogFileSettings().nixLogDir;
|
||||
}
|
||||
|
||||
LocalFSStoreConfig::LocalFSStoreConfig(PathView rootDir, const Params & params)
|
||||
LocalFSStoreConfig::LocalFSStoreConfig(const std::filesystem::path & rootDir, const Params & params)
|
||||
: StoreConfig(params)
|
||||
/* Default `?root` from `rootDir` if non set
|
||||
* NOTE: We would like to just do rootDir.set(...), which would take care of
|
||||
|
||||
@@ -56,9 +56,9 @@
|
||||
|
||||
namespace nix {
|
||||
|
||||
LocalStoreConfig::LocalStoreConfig(std::string_view scheme, std::string_view authority, const Params & params)
|
||||
LocalStoreConfig::LocalStoreConfig(const std::filesystem::path & path, const Params & params)
|
||||
: StoreConfig(params)
|
||||
, LocalFSStoreConfig(authority, params)
|
||||
, LocalFSStoreConfig(path, params)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -468,11 +468,13 @@ StoreReference LocalStoreConfig::getReference() const
|
||||
/* Back-compatibility kludge. Tools like nix-output-monitor expect 'local'
|
||||
and can't parse 'local://'. */
|
||||
if (params.empty())
|
||||
/* TODO: Add the rootDir here as the authority? */
|
||||
return {.variant = StoreReference::Local{}};
|
||||
return {
|
||||
.variant =
|
||||
StoreReference::Specified{
|
||||
.scheme = *uriSchemes().begin(),
|
||||
/* TODO: Add the rootDir here as the authority? */
|
||||
},
|
||||
.params = std::move(params),
|
||||
};
|
||||
|
||||
@@ -416,10 +416,9 @@ StringSet S3BinaryCacheStoreConfig::uriSchemes()
|
||||
return {"s3"};
|
||||
}
|
||||
|
||||
S3BinaryCacheStoreConfig::S3BinaryCacheStoreConfig(
|
||||
std::string_view scheme, std::string_view _cacheUri, const Params & params)
|
||||
S3BinaryCacheStoreConfig::S3BinaryCacheStoreConfig(ParsedURL cacheUri_, const Params & params)
|
||||
: StoreConfig(params)
|
||||
, HttpBinaryCacheStoreConfig(scheme, _cacheUri, params)
|
||||
, HttpBinaryCacheStoreConfig(std::move(cacheUri_), params)
|
||||
{
|
||||
assert(cacheUri.query.empty());
|
||||
assert(cacheUri.scheme == "s3");
|
||||
@@ -455,6 +454,12 @@ S3BinaryCacheStoreConfig::S3BinaryCacheStoreConfig(
|
||||
}
|
||||
}
|
||||
|
||||
S3BinaryCacheStoreConfig::S3BinaryCacheStoreConfig(std::string_view bucketName, const Params & params)
|
||||
: S3BinaryCacheStoreConfig(
|
||||
ParsedURL{.scheme = "s3", .authority = ParsedURL::Authority{.host = std::string(bucketName)}}, params)
|
||||
{
|
||||
}
|
||||
|
||||
std::string S3BinaryCacheStoreConfig::getHumanReadableURI() const
|
||||
{
|
||||
auto reference = getReference();
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
|
||||
namespace nix {
|
||||
|
||||
SSHStoreConfig::SSHStoreConfig(std::string_view scheme, std::string_view authority, const Params & params)
|
||||
SSHStoreConfig::SSHStoreConfig(const ParsedURL::Authority & authority, const Params & params)
|
||||
: Store::Config{params}
|
||||
, RemoteStore::Config{params}
|
||||
, CommonSSHStoreConfig{scheme, authority, params}
|
||||
, CommonSSHStoreConfig{authority, params}
|
||||
{
|
||||
}
|
||||
|
||||
@@ -97,11 +97,11 @@ MountedSSHStoreConfig::MountedSSHStoreConfig(StringMap params)
|
||||
{
|
||||
}
|
||||
|
||||
MountedSSHStoreConfig::MountedSSHStoreConfig(std::string_view scheme, std::string_view host, StringMap params)
|
||||
MountedSSHStoreConfig::MountedSSHStoreConfig(const ParsedURL::Authority & authority, StringMap params)
|
||||
: StoreConfig(params)
|
||||
, RemoteStoreConfig(params)
|
||||
, CommonSSHStoreConfig(scheme, host, params)
|
||||
, SSHStoreConfig(scheme, host, params)
|
||||
, CommonSSHStoreConfig(authority, params)
|
||||
, SSHStoreConfig(authority, params)
|
||||
, LocalFSStoreConfig(params)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ ref<StoreConfig> resolveStoreConfig(StoreReference && storeURI)
|
||||
} else
|
||||
debug(
|
||||
"%s does not exist, so Nix will use %s as a chroot store", stateDir, PathFmt(chrootStore));
|
||||
return make_ref<LocalStore::Config>("local", chrootStore.string(), params);
|
||||
return make_ref<LocalStore::Config>(std::filesystem::path(chrootStore), params);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
|
||||
@@ -19,16 +19,12 @@
|
||||
|
||||
namespace nix {
|
||||
|
||||
UDSRemoteStoreConfig::UDSRemoteStoreConfig(
|
||||
std::string_view scheme, std::string_view authority, const StoreReference::Params & params)
|
||||
UDSRemoteStoreConfig::UDSRemoteStoreConfig(const std::filesystem::path & path, const StoreReference::Params & params)
|
||||
: Store::Config{params}
|
||||
, LocalFSStore::Config{params}
|
||||
, RemoteStore::Config{params}
|
||||
, path{authority.empty() ? settings.nixDaemonSocketFile : std::filesystem::path{authority}}
|
||||
, path{path.empty() ? settings.nixDaemonSocketFile : path}
|
||||
{
|
||||
if (uriSchemes().count(scheme) == 0) {
|
||||
throw UsageError("Scheme must be 'unix'");
|
||||
}
|
||||
}
|
||||
|
||||
std::string UDSRemoteStoreConfig::doc()
|
||||
@@ -43,7 +39,7 @@ std::string UDSRemoteStoreConfig::doc()
|
||||
// don't we just wire it all through? I believe there are cases where it
|
||||
// will live reload so we want to continue to account for that.
|
||||
UDSRemoteStoreConfig::UDSRemoteStoreConfig(const Params & params)
|
||||
: UDSRemoteStoreConfig(*uriSchemes().begin(), "", params)
|
||||
: UDSRemoteStoreConfig("", params)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -69,7 +65,7 @@ StoreReference UDSRemoteStoreConfig::getReference() const
|
||||
.variant =
|
||||
StoreReference::Specified{
|
||||
.scheme = *uriSchemes().begin(),
|
||||
.authority = path.string(),
|
||||
.authority = encodeUrlPath(pathToUrlPath(path)),
|
||||
},
|
||||
.params = getQueryParams(),
|
||||
};
|
||||
|
||||
@@ -280,7 +280,7 @@ std::string encodeQuery(const StringMap & query);
|
||||
/**
|
||||
* Parse a URL into a ParsedURL.
|
||||
*
|
||||
* @parm lenient Also allow some long-supported Nix URIs that are not quite compliant with RFC3986.
|
||||
* @param lenient Also allow some long-supported Nix URIs that are not quite compliant with RFC3986.
|
||||
* Here are the deviations:
|
||||
* - Fragments can contain unescaped (not URL encoded) '^', '"' or space literals.
|
||||
* - Queries may contain unescaped '"' or spaces.
|
||||
|
||||
@@ -49,7 +49,11 @@ static int main_nix_copy_closure(int argc, char ** argv)
|
||||
if (sshHost.empty())
|
||||
throw UsageError("no host name specified");
|
||||
|
||||
auto remoteConfig = make_ref<LegacySSHStoreConfig>("ssh", sshHost, LegacySSHStoreConfig::Params{});
|
||||
auto remoteConfig =
|
||||
/* FIXME: This doesn't go through the back-compat machinery for IPv6 unbracketed URLs that
|
||||
is in StoreReference::parse. TODO: Maybe add a authority parsing function specifically
|
||||
for SSH reference parsing? */
|
||||
make_ref<LegacySSHStoreConfig>(ParsedURL::Authority::parse(sshHost), LegacySSHStoreConfig::Params{});
|
||||
remoteConfig->compress |= gzip;
|
||||
auto to = toMode ? remoteConfig->openStore() : openStore();
|
||||
auto from = toMode ? openStore() : remoteConfig->openStore();
|
||||
|
||||
@@ -38,6 +38,10 @@ nix log --substituters "file://$cacheDir" "$outPath" | grep FOO
|
||||
nix store copy-log --from "file://$cacheDir" "$(nix-store -qd "$outPath")"^'*'
|
||||
nix log "$outPath" | grep FOO
|
||||
|
||||
# Test that plus sign in the URL path is handled correctly.
|
||||
cacheDir2="$TEST_ROOT/binary+cache"
|
||||
nix copy --to "file://$cacheDir2" "$outPath" && [[ -d "$cacheDir2" ]]
|
||||
|
||||
basicDownloadTests() {
|
||||
# No uploading tests bcause upload with force HTTP doesn't work.
|
||||
|
||||
|
||||
@@ -42,6 +42,24 @@ PATH2=$(nix path-info --store "$TEST_ROOT/x" "$CORRECT_PATH")
|
||||
PATH3=$(nix path-info --store "local?root=$TEST_ROOT/x" "$CORRECT_PATH")
|
||||
[ "$CORRECT_PATH" == "$PATH3" ]
|
||||
|
||||
# Test chroot store path with + symbols in it to exercise pct-encoding issues.
|
||||
cp -r "$TEST_ROOT/x" "$TEST_ROOT/x+chroot"
|
||||
|
||||
PATH4=$(nix path-info --store "local://$TEST_ROOT/x+chroot" "$CORRECT_PATH")
|
||||
[ "$CORRECT_PATH" == "$PATH4" ]
|
||||
|
||||
PATH5=$(nix path-info --store "$TEST_ROOT/x+chroot" "$CORRECT_PATH")
|
||||
[ "$CORRECT_PATH" == "$PATH5" ]
|
||||
|
||||
# Params are pct-encoded.
|
||||
PATH6=$(nix path-info --store "local?root=$TEST_ROOT/x%2Bchroot" "$CORRECT_PATH")
|
||||
[ "$CORRECT_PATH" == "$PATH6" ]
|
||||
|
||||
PATH7=$(nix path-info --store "local://$TEST_ROOT/x%2Bchroot" "$CORRECT_PATH")
|
||||
[ "$CORRECT_PATH" == "$PATH7" ]
|
||||
# Path gets decoded.
|
||||
[[ ! -d "$TEST_ROOT/x%2Bchroot" ]]
|
||||
|
||||
# Ensure store info trusted works with local store
|
||||
nix --store "$TEST_ROOT/x" store info --json | jq -e '.trusted'
|
||||
|
||||
|
||||
Reference in New Issue
Block a user