mirror of
https://github.com/privatevoid-net/nix-super.git
synced 2024-11-25 07:16:17 +02:00
Factor out abstract syntax for Store URIs
Need to decouple parsing from actually opening a store for Machine configs. Co-authored-by: Théophane Hufschmitt <7226587+thufschmitt@users.noreply.github.com> Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
This commit is contained in:
parent
1d6c2316a9
commit
c036d75f9e
4 changed files with 236 additions and 132 deletions
|
@ -8,7 +8,6 @@
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
#include "nar-info-disk-cache.hh"
|
#include "nar-info-disk-cache.hh"
|
||||||
#include "thread-pool.hh"
|
#include "thread-pool.hh"
|
||||||
#include "url.hh"
|
|
||||||
#include "references.hh"
|
#include "references.hh"
|
||||||
#include "archive.hh"
|
#include "archive.hh"
|
||||||
#include "callback.hh"
|
#include "callback.hh"
|
||||||
|
@ -1267,109 +1266,63 @@ Derivation Store::readInvalidDerivation(const StorePath & drvPath)
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
/* Split URI into protocol+hierarchy part and its parameter set. */
|
ref<Store> openStore(const std::string & uri,
|
||||||
std::pair<std::string, Store::Params> splitUriAndParams(const std::string & uri_)
|
|
||||||
{
|
|
||||||
auto uri(uri_);
|
|
||||||
Store::Params params;
|
|
||||||
auto q = uri.find('?');
|
|
||||||
if (q != std::string::npos) {
|
|
||||||
params = decodeQuery(uri.substr(q + 1));
|
|
||||||
uri = uri_.substr(0, q);
|
|
||||||
}
|
|
||||||
return {uri, params};
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isNonUriPath(const std::string & spec)
|
|
||||||
{
|
|
||||||
return
|
|
||||||
// is not a URL
|
|
||||||
spec.find("://") == std::string::npos
|
|
||||||
// Has at least one path separator, and so isn't a single word that
|
|
||||||
// might be special like "auto"
|
|
||||||
&& spec.find("/") != std::string::npos;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<Store> openFromNonUri(const std::string & uri, const Store::Params & params)
|
|
||||||
{
|
|
||||||
// TODO reenable on Windows once we have `LocalStore` and
|
|
||||||
// `UDSRemoteStore`.
|
|
||||||
if (uri == "" || uri == "auto") {
|
|
||||||
auto stateDir = getOr(params, "state", settings.nixStateDir);
|
|
||||||
if (access(stateDir.c_str(), R_OK | W_OK) == 0)
|
|
||||||
return std::make_shared<LocalStore>(params);
|
|
||||||
else if (pathExists(settings.nixDaemonSocketFile))
|
|
||||||
return std::make_shared<UDSRemoteStore>(params);
|
|
||||||
#if __linux__
|
|
||||||
else if (!pathExists(stateDir)
|
|
||||||
&& params.empty()
|
|
||||||
&& !isRootUser()
|
|
||||||
&& !getEnv("NIX_STORE_DIR").has_value()
|
|
||||||
&& !getEnv("NIX_STATE_DIR").has_value())
|
|
||||||
{
|
|
||||||
/* If /nix doesn't exist, there is no daemon socket, and
|
|
||||||
we're not root, then automatically set up a chroot
|
|
||||||
store in ~/.local/share/nix/root. */
|
|
||||||
auto chrootStore = getDataDir() + "/nix/root";
|
|
||||||
if (!pathExists(chrootStore)) {
|
|
||||||
try {
|
|
||||||
createDirs(chrootStore);
|
|
||||||
} catch (Error & e) {
|
|
||||||
return std::make_shared<LocalStore>(params);
|
|
||||||
}
|
|
||||||
warn("'%s' does not exist, so Nix will use '%s' as a chroot store", stateDir, chrootStore);
|
|
||||||
} else
|
|
||||||
debug("'%s' does not exist, so Nix will use '%s' as a chroot store", stateDir, chrootStore);
|
|
||||||
return std::make_shared<LocalStore>("local", chrootStore, params);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
else
|
|
||||||
return std::make_shared<LocalStore>(params);
|
|
||||||
} else if (uri == "daemon") {
|
|
||||||
return std::make_shared<UDSRemoteStore>(params);
|
|
||||||
} else if (uri == "local") {
|
|
||||||
return std::make_shared<LocalStore>(params);
|
|
||||||
} else if (isNonUriPath(uri)) {
|
|
||||||
return std::make_shared<LocalStore>("local", absPath(uri), params);
|
|
||||||
} else {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ref<Store> openStore(const std::string & uri_,
|
|
||||||
const Store::Params & extraParams)
|
const Store::Params & extraParams)
|
||||||
{
|
{
|
||||||
auto params = extraParams;
|
return openStore(StoreReference::parse(uri, extraParams));
|
||||||
try {
|
}
|
||||||
auto parsedUri = parseURL(uri_);
|
|
||||||
params.insert(parsedUri.query.begin(), parsedUri.query.end());
|
|
||||||
|
|
||||||
auto baseURI = parsedUri.authority.value_or("") + parsedUri.path;
|
ref<Store> openStore(StoreReference && storeURI)
|
||||||
|
{
|
||||||
|
auto & params = storeURI.params;
|
||||||
|
|
||||||
for (auto implem : *Implementations::registered) {
|
auto store = std::visit(overloaded {
|
||||||
if (implem.uriSchemes.count(parsedUri.scheme)) {
|
[&](const StoreReference::Auto &) -> std::shared_ptr<Store> {
|
||||||
auto store = implem.create(parsedUri.scheme, baseURI, params);
|
auto stateDir = getOr(params, "state", settings.nixStateDir);
|
||||||
if (store) {
|
if (access(stateDir.c_str(), R_OK | W_OK) == 0)
|
||||||
experimentalFeatureSettings.require(store->experimentalFeature());
|
return std::make_shared<LocalStore>(params);
|
||||||
store->init();
|
else if (pathExists(settings.nixDaemonSocketFile))
|
||||||
store->warnUnknownSettings();
|
return std::make_shared<UDSRemoteStore>(params);
|
||||||
return ref<Store>(store);
|
#if __linux__
|
||||||
}
|
else if (!pathExists(stateDir)
|
||||||
|
&& params.empty()
|
||||||
|
&& !isRootUser()
|
||||||
|
&& !getEnv("NIX_STORE_DIR").has_value()
|
||||||
|
&& !getEnv("NIX_STATE_DIR").has_value())
|
||||||
|
{
|
||||||
|
/* If /nix doesn't exist, there is no daemon socket, and
|
||||||
|
we're not root, then automatically set up a chroot
|
||||||
|
store in ~/.local/share/nix/root. */
|
||||||
|
auto chrootStore = getDataDir() + "/nix/root";
|
||||||
|
if (!pathExists(chrootStore)) {
|
||||||
|
try {
|
||||||
|
createDirs(chrootStore);
|
||||||
|
} catch (Error & e) {
|
||||||
|
return std::make_shared<LocalStore>(params);
|
||||||
|
}
|
||||||
|
warn("'%s' does not exist, so Nix will use '%s' as a chroot store", stateDir, chrootStore);
|
||||||
|
} else
|
||||||
|
debug("'%s' does not exist, so Nix will use '%s' as a chroot store", stateDir, chrootStore);
|
||||||
|
return std::make_shared<LocalStore>("local", chrootStore, params);
|
||||||
}
|
}
|
||||||
}
|
#endif
|
||||||
}
|
else
|
||||||
catch (BadURL &) {
|
return std::make_shared<LocalStore>(params);
|
||||||
auto [uri, uriParams] = splitUriAndParams(uri_);
|
},
|
||||||
params.insert(uriParams.begin(), uriParams.end());
|
[&](const StoreReference::Specified & g) {
|
||||||
|
for (auto implem : *Implementations::registered)
|
||||||
|
if (implem.uriSchemes.count(g.scheme))
|
||||||
|
return implem.create(g.scheme, g.authority, params);
|
||||||
|
|
||||||
if (auto store = openFromNonUri(uri, params)) {
|
throw Error("don't know how to open Nix store with scheme '%s'", g.scheme);
|
||||||
experimentalFeatureSettings.require(store->experimentalFeature());
|
},
|
||||||
store->warnUnknownSettings();
|
}, storeURI.variant);
|
||||||
return ref<Store>(store);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw Error("don't know how to open Nix store '%s'", uri_);
|
experimentalFeatureSettings.require(store->experimentalFeature());
|
||||||
|
store->warnUnknownSettings();
|
||||||
|
store->init();
|
||||||
|
|
||||||
|
return ref<Store> { store };
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<ref<Store>> getDefaultSubstituters()
|
std::list<ref<Store>> getDefaultSubstituters()
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "path-info.hh"
|
#include "path-info.hh"
|
||||||
#include "repair-flag.hh"
|
#include "repair-flag.hh"
|
||||||
#include "store-dir-config.hh"
|
#include "store-dir-config.hh"
|
||||||
|
#include "store-reference.hh"
|
||||||
#include "source-path.hh"
|
#include "source-path.hh"
|
||||||
|
|
||||||
#include <nlohmann/json_fwd.hpp>
|
#include <nlohmann/json_fwd.hpp>
|
||||||
|
@ -65,7 +66,7 @@ MakeError(Unsupported, Error);
|
||||||
MakeError(SubstituteGone, Error);
|
MakeError(SubstituteGone, Error);
|
||||||
MakeError(SubstituterDisabled, Error);
|
MakeError(SubstituterDisabled, Error);
|
||||||
|
|
||||||
MakeError(InvalidStoreURI, Error);
|
MakeError(InvalidStoreReference, Error);
|
||||||
|
|
||||||
struct Realisation;
|
struct Realisation;
|
||||||
struct RealisedPath;
|
struct RealisedPath;
|
||||||
|
@ -102,7 +103,7 @@ typedef std::map<StorePath, std::optional<ContentAddress>> StorePathCAMap;
|
||||||
|
|
||||||
struct StoreConfig : public StoreDirConfig
|
struct StoreConfig : public StoreDirConfig
|
||||||
{
|
{
|
||||||
typedef std::map<std::string, std::string> Params;
|
using Params = StoreReference::Params;
|
||||||
|
|
||||||
using StoreDirConfig::StoreDirConfig;
|
using StoreDirConfig::StoreDirConfig;
|
||||||
|
|
||||||
|
@ -859,34 +860,13 @@ OutputPathMap resolveDerivedPath(Store &, const DerivedPath::Built &, Store * ev
|
||||||
/**
|
/**
|
||||||
* @return a Store object to access the Nix store denoted by
|
* @return a Store object to access the Nix store denoted by
|
||||||
* ‘uri’ (slight misnomer...).
|
* ‘uri’ (slight misnomer...).
|
||||||
*
|
*/
|
||||||
* @param uri Supported values are:
|
ref<Store> openStore(StoreReference && storeURI);
|
||||||
*
|
|
||||||
* - ‘local’: The Nix store in /nix/store and database in
|
|
||||||
* /nix/var/nix/db, accessed directly.
|
/**
|
||||||
*
|
* Opens the store at `uri`, where `uri` is in the format expected by `StoreReference::parse`
|
||||||
* - ‘daemon’: The Nix store accessed via a Unix domain socket
|
|
||||||
* connection to nix-daemon.
|
|
||||||
*
|
|
||||||
* - ‘unix://<path>’: The Nix store accessed via a Unix domain socket
|
|
||||||
* connection to nix-daemon, with the socket located at <path>.
|
|
||||||
*
|
|
||||||
* - ‘auto’ or ‘’: Equivalent to ‘local’ or ‘daemon’ depending on
|
|
||||||
* whether the user has write access to the local Nix
|
|
||||||
* store/database.
|
|
||||||
*
|
|
||||||
* - ‘file://<path>’: A binary cache stored in <path>.
|
|
||||||
*
|
|
||||||
* - ‘https://<path>’: A binary cache accessed via HTTP.
|
|
||||||
*
|
|
||||||
* - ‘s3://<path>’: A writable binary cache stored on Amazon's Simple
|
|
||||||
* Storage Service.
|
|
||||||
*
|
|
||||||
* - ‘ssh://[user@]<host>’: A remote Nix store accessed by running
|
|
||||||
* ‘nix-store --serve’ via SSH.
|
|
||||||
*
|
|
||||||
* You can pass parameters to the store type by appending
|
|
||||||
* ‘?key=value&key=value&...’ to the URI.
|
|
||||||
*/
|
*/
|
||||||
ref<Store> openStore(const std::string & uri = settings.storeUri.get(),
|
ref<Store> openStore(const std::string & uri = settings.storeUri.get(),
|
||||||
const Store::Params & extraParams = Store::Params());
|
const Store::Params & extraParams = Store::Params());
|
||||||
|
@ -957,11 +937,6 @@ std::optional<ValidPathInfo> decodeValidPathInfo(
|
||||||
std::istream & str,
|
std::istream & str,
|
||||||
std::optional<HashResult> hashGiven = std::nullopt);
|
std::optional<HashResult> hashGiven = std::nullopt);
|
||||||
|
|
||||||
/**
|
|
||||||
* Split URI into protocol+hierarchy part and its parameter set.
|
|
||||||
*/
|
|
||||||
std::pair<std::string, Store::Params> splitUriAndParams(const std::string & uri);
|
|
||||||
|
|
||||||
const ContentAddress * getDerivationCA(const BasicDerivation & drv);
|
const ContentAddress * getDerivationCA(const BasicDerivation & drv);
|
||||||
|
|
||||||
std::map<DrvOutput, StorePath> drvOutputReferences(
|
std::map<DrvOutput, StorePath> drvOutputReferences(
|
||||||
|
|
92
src/libstore/store-reference.cc
Normal file
92
src/libstore/store-reference.cc
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
#include <regex>
|
||||||
|
|
||||||
|
#include "error.hh"
|
||||||
|
#include "url.hh"
|
||||||
|
#include "store-reference.hh"
|
||||||
|
#include "file-system.hh"
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
static bool isNonUriPath(const std::string & spec)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
// is not a URL
|
||||||
|
spec.find("://") == std::string::npos
|
||||||
|
// Has at least one path separator, and so isn't a single word that
|
||||||
|
// might be special like "auto"
|
||||||
|
&& spec.find("/") != std::string::npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
StoreReference StoreReference::parse(const std::string & uri, const StoreReference::Params & extraParams)
|
||||||
|
{
|
||||||
|
auto params = extraParams;
|
||||||
|
try {
|
||||||
|
auto parsedUri = parseURL(uri);
|
||||||
|
params.insert(parsedUri.query.begin(), parsedUri.query.end());
|
||||||
|
|
||||||
|
auto baseURI = parsedUri.authority.value_or("") + parsedUri.path;
|
||||||
|
|
||||||
|
return {
|
||||||
|
.variant =
|
||||||
|
Specified{
|
||||||
|
.scheme = std::move(parsedUri.scheme),
|
||||||
|
.authority = std::move(baseURI),
|
||||||
|
},
|
||||||
|
.params = std::move(params),
|
||||||
|
};
|
||||||
|
} catch (BadURL &) {
|
||||||
|
auto [baseURI, uriParams] = splitUriAndParams(uri);
|
||||||
|
params.insert(uriParams.begin(), uriParams.end());
|
||||||
|
|
||||||
|
if (baseURI == "" || baseURI == "auto") {
|
||||||
|
return {
|
||||||
|
.variant = Auto{},
|
||||||
|
.params = std::move(params),
|
||||||
|
};
|
||||||
|
} else if (baseURI == "daemon") {
|
||||||
|
return {
|
||||||
|
.variant =
|
||||||
|
Specified{
|
||||||
|
.scheme = "unix",
|
||||||
|
.authority = "",
|
||||||
|
},
|
||||||
|
.params = std::move(params),
|
||||||
|
};
|
||||||
|
} else if (baseURI == "local") {
|
||||||
|
return {
|
||||||
|
.variant =
|
||||||
|
Specified{
|
||||||
|
.scheme = "local",
|
||||||
|
.authority = "",
|
||||||
|
},
|
||||||
|
.params = std::move(params),
|
||||||
|
};
|
||||||
|
} else if (isNonUriPath(baseURI)) {
|
||||||
|
return {
|
||||||
|
.variant =
|
||||||
|
Specified{
|
||||||
|
.scheme = "local",
|
||||||
|
.authority = absPath(baseURI),
|
||||||
|
},
|
||||||
|
.params = std::move(params),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw UsageError("Cannot parse Nix store '%s'", uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Split URI into protocol+hierarchy part and its parameter set. */
|
||||||
|
std::pair<std::string, StoreReference::Params> splitUriAndParams(const std::string & uri_)
|
||||||
|
{
|
||||||
|
auto uri(uri_);
|
||||||
|
StoreReference::Params params;
|
||||||
|
auto q = uri.find('?');
|
||||||
|
if (q != std::string::npos) {
|
||||||
|
params = decodeQuery(uri.substr(q + 1));
|
||||||
|
uri = uri_.substr(0, q);
|
||||||
|
}
|
||||||
|
return {uri, params};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
84
src/libstore/store-reference.hh
Normal file
84
src/libstore/store-reference.hh
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
#pragma once
|
||||||
|
///@file
|
||||||
|
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
|
#include "types.hh"
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A parsed Store URI (URI is a slight misnomer...), parsed but not yet
|
||||||
|
* resolved to a specific instance and query parms validated.
|
||||||
|
*
|
||||||
|
* Supported values are:
|
||||||
|
*
|
||||||
|
* - ‘local’: The Nix store in /nix/store and database in
|
||||||
|
* /nix/var/nix/db, accessed directly.
|
||||||
|
*
|
||||||
|
* - ‘daemon’: The Nix store accessed via a Unix domain socket
|
||||||
|
* connection to nix-daemon.
|
||||||
|
*
|
||||||
|
* - ‘unix://<path>’: The Nix store accessed via a Unix domain socket
|
||||||
|
* connection to nix-daemon, with the socket located at <path>.
|
||||||
|
*
|
||||||
|
* - ‘auto’ or ‘’: Equivalent to ‘local’ or ‘daemon’ depending on
|
||||||
|
* whether the user has write access to the local Nix
|
||||||
|
* store/database.
|
||||||
|
*
|
||||||
|
* - ‘file://<path>’: A binary cache stored in <path>.
|
||||||
|
*
|
||||||
|
* - ‘https://<path>’: A binary cache accessed via HTTP.
|
||||||
|
*
|
||||||
|
* - ‘s3://<path>’: A writable binary cache stored on Amazon's Simple
|
||||||
|
* Storage Service.
|
||||||
|
*
|
||||||
|
* - ‘ssh://[user@]<host>’: A remote Nix store accessed by running
|
||||||
|
* ‘nix-store --serve’ via SSH.
|
||||||
|
*
|
||||||
|
* You can pass parameters to the store type by appending
|
||||||
|
* ‘?key=value&key=value&...’ to the URI.
|
||||||
|
*/
|
||||||
|
struct StoreReference
|
||||||
|
{
|
||||||
|
using Params = std::map<std::string, std::string>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Special store reference `""` or `"auto"`
|
||||||
|
*/
|
||||||
|
struct Auto
|
||||||
|
{
|
||||||
|
inline bool operator==(const Auto & rhs) const = default;
|
||||||
|
inline auto operator<=>(const Auto & rhs) const = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* General case, a regular `scheme://authority` URL.
|
||||||
|
*/
|
||||||
|
struct Specified
|
||||||
|
{
|
||||||
|
std::string scheme;
|
||||||
|
std::string authority;
|
||||||
|
|
||||||
|
bool operator==(const Specified & rhs) const = default;
|
||||||
|
auto operator<=>(const Specified & rhs) const = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::variant<Auto, Specified> Variant;
|
||||||
|
|
||||||
|
Variant variant;
|
||||||
|
|
||||||
|
Params params;
|
||||||
|
|
||||||
|
bool operator==(const StoreReference & rhs) const = default;
|
||||||
|
auto operator<=>(const StoreReference & rhs) const = default;
|
||||||
|
|
||||||
|
static StoreReference parse(const std::string & uri, const Params & extraParams = Params{});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Split URI into protocol+hierarchy part and its parameter set.
|
||||||
|
*/
|
||||||
|
std::pair<std::string, StoreReference::Params> splitUriAndParams(const std::string & uri);
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue