Merge remote-tracking branch 'upstream/master' into ca-floating-upstream

This commit is contained in:
John Ericson 2020-09-17 16:33:10 +00:00
commit b7df353f27
59 changed files with 662 additions and 491 deletions

9
.gitignore vendored
View file

@ -12,15 +12,6 @@ perl/Makefile.config
/svn-revision /svn-revision
/libtool /libtool
/corepkgs/config.nix
# /corepkgs/channels/
/corepkgs/channels/unpack.sh
# /corepkgs/nar/
/corepkgs/nar/nar.sh
/corepkgs/nar/unnar.sh
# /doc/manual/ # /doc/manual/
/doc/manual/*.1 /doc/manual/*.1
/doc/manual/*.5 /doc/manual/*.5

View file

@ -1,13 +0,0 @@
# FIXME: remove this file?
let
fromEnv = var: def:
let val = builtins.getEnv var; in
if val != "" then val else def;
in rec {
nixBinDir = fromEnv "NIX_BIN_DIR" "@bindir@";
nixPrefix = "@prefix@";
nixLibexecDir = fromEnv "NIX_LIBEXEC_DIR" "@libexecdir@";
nixLocalstateDir = "@localstatedir@";
nixSysconfDir = "@sysconfdir@";
nixStoreDir = fromEnv "NIX_STORE_DIR" "@storedir@";
}

View file

@ -1,8 +1,4 @@
corepkgs_FILES = \ corepkgs_FILES = \
unpack-channel.nix \
derivation.nix \
fetchurl.nix fetchurl.nix
$(foreach file,config.nix $(corepkgs_FILES),$(eval $(call install-data-in,$(d)/$(file),$(datadir)/nix/corepkgs))) $(foreach file,$(corepkgs_FILES),$(eval $(call install-data-in,$(d)/$(file),$(datadir)/nix/corepkgs)))
template-files += $(d)/config.nix

View file

@ -1,6 +0,0 @@
. | to_entries | sort_by(.key) | map(
" - `builtins." + .key + "` "
+ (.value.args | map("*" + . + "*") | join(" "))
+ " \n\n"
+ (.value.doc | split("\n") | map(" " + . + "\n") | join("")) + "\n\n"
) | join("")

View file

@ -0,0 +1,14 @@
with builtins;
with import ./utils.nix;
builtins:
concatStrings (map
(name:
let builtin = builtins.${name}; in
" - `builtins.${name}` " + concatStringsSep " " (map (s: "*${s}*") builtin.args)
+ " \n\n"
+ concatStrings (map (s: " ${s}\n") (splitLines builtin.doc)) + "\n\n"
)
(attrNames builtins))

View file

@ -1,44 +0,0 @@
def show_flags:
.flags
| map_values(select(.category != "config"))
| to_entries
| map(
" - `--" + .key + "`"
+ (if .value.shortName then " / `" + .value.shortName + "`" else "" end)
+ (if .value.labels then " " + (.value.labels | map("*" + . + "*") | join(" ")) else "" end)
+ " \n"
+ " " + .value.description + "\n\n")
| join("")
;
def show_synopsis:
"`" + .command + "` [*flags*...] " + (.args | map("*" + .label + "*" + (if has("arity") then "" else "..." end)) | join(" ")) + "\n\n"
;
def show_command:
. as $top |
.section + " Name\n\n"
+ "`" + .command + "` - " + .def.description + "\n\n"
+ .section + " Synopsis\n\n"
+ ({"command": .command, "args": .def.args} | show_synopsis)
+ (if .def | has("doc")
then .section + " Description\n\n" + .def.doc + "\n\n"
else ""
end)
+ (if (.def.flags | length) > 0 then
.section + " Flags\n\n"
+ (.def | show_flags)
else "" end)
+ (if (.def.examples | length) > 0 then
.section + " Examples\n\n"
+ (.def.examples | map(.description + "\n\n```console\n" + .command + "\n```\n" ) | join("\n"))
+ "\n"
else "" end)
+ (if .def.commands then .def.commands | to_entries | map(
"# Subcommand `" + ($top.command + " " + .key) + "`\n\n"
+ ({"command": ($top.command + " " + .key), "section": "##", "def": .value} | show_command)
) | join("") else "" end)
;
"Title: nix\n\n"
+ ({"command": "nix", "section": "#", "def": .} | show_command)

View file

@ -0,0 +1,56 @@
with builtins;
with import ./utils.nix;
let
showCommand =
{ command, section, def }:
"${section} Name\n\n"
+ "`${command}` - ${def.description}\n\n"
+ "${section} Synopsis\n\n"
+ showSynopsis { inherit command; args = def.args; }
+ (if def ? doc
then "${section} Description\n\n" + def.doc + "\n\n"
else "")
+ (let s = showFlags def.flags; in
if s != ""
then "${section} Flags\n\n${s}"
else "")
+ (if def.examples or [] != []
then
"${section} Examples\n\n"
+ concatStrings (map ({ description, command }: "${description}\n\n```console\n${command}\n```\n\n") def.examples)
else "")
+ (if def.commands or [] != []
then concatStrings (
map (name:
"# Subcommand `${command} ${name}`\n\n"
+ showCommand { command = command + " " + name; section = "##"; def = def.commands.${name}; })
(attrNames def.commands))
else "");
showFlags = flags:
concatStrings
(map (longName:
let flag = flags.${longName}; in
if flag.category or "" != "config"
then
" - `--${longName}`"
+ (if flag ? shortName then " / `${flag.shortName}`" else "")
+ (if flag ? labels then " " + (concatStringsSep " " (map (s: "*${s}*") flag.labels)) else "")
+ " \n"
+ " " + flag.description + "\n\n"
else "")
(attrNames flags));
showSynopsis =
{ command, args }:
"`${command}` [*flags*...] ${concatStringsSep " "
(map (arg: "*${arg.label}*" + (if arg ? arity then "" else "...")) args)}\n\n";
in
command:
"Title: nix\n\n"
+ showCommand { command = "nix"; section = "#"; def = command; }

View file

@ -1,16 +0,0 @@
. | to_entries | sort_by(.key) | map(
" - `" + .key + "` \n\n"
+ (.value.description | split("\n") | map(" " + . + "\n") | join("")) + "\n\n"
+ " **Default:** " + (
if .value.value == "" or .value.value == []
then "*empty*"
elif (.value.value | type) == "array"
then "`" + (.value.value | join(" ")) + "`"
else "`" + (.value.value | tostring) + "`"
end)
+ "\n\n"
+ (if (.value.aliases | length) > 0
then " **Deprecated alias:** " + (.value.aliases | map("`" + . + "`") | join(", ")) + "\n\n"
else ""
end)
) | join("")

View file

@ -0,0 +1,21 @@
with builtins;
with import ./utils.nix;
options:
concatStrings (map
(name:
let option = options.${name}; in
" - `${name}` \n\n"
+ concatStrings (map (s: " ${s}\n") (splitLines option.description)) + "\n\n"
+ " **Default:** " + (
if option.value == "" || option.value == []
then "*empty*"
else if isBool option.value
then (if option.value then "`true`" else "`false`")
else "`" + toString option.value + "`") + "\n\n"
+ (if option.aliases != []
then " **Deprecated alias:** " + (concatStringsSep ", " (map (s: "`${s}`") option.aliases)) + "\n\n"
else "")
)
(attrNames options))

View file

@ -15,6 +15,8 @@ clean-files += $(d)/*.1 $(d)/*.5 $(d)/*.8
dist-files += $(man-pages) dist-files += $(man-pages)
nix-eval = $(bindir)/nix eval --experimental-features nix-command -I nix/corepkgs=corepkgs --store dummy:// --impure --raw --expr
$(d)/%.1: $(d)/src/command-ref/%.md $(d)/%.1: $(d)/src/command-ref/%.md
$(trace-gen) lowdown -sT man $^ -o $@ $(trace-gen) lowdown -sT man $^ -o $@
@ -24,25 +26,31 @@ $(d)/%.8: $(d)/src/command-ref/%.md
$(d)/nix.conf.5: $(d)/src/command-ref/conf-file.md $(d)/nix.conf.5: $(d)/src/command-ref/conf-file.md
$(trace-gen) lowdown -sT man $^ -o $@ $(trace-gen) lowdown -sT man $^ -o $@
$(d)/src/command-ref/nix.md: $(d)/nix.json $(d)/generate-manpage.jq $(d)/src/command-ref/nix.md: $(d)/nix.json $(d)/generate-manpage.nix $(bindir)/nix
jq -r -f doc/manual/generate-manpage.jq $< > $@ $(trace-gen) $(nix-eval) 'import doc/manual/generate-manpage.nix (builtins.fromJSON (builtins.readFile $<))' > $@.tmp
@mv $@.tmp $@
$(d)/src/command-ref/conf-file.md: $(d)/conf-file.json $(d)/generate-options.jq $(d)/src/command-ref/conf-file-prefix.md $(d)/src/command-ref/conf-file.md: $(d)/conf-file.json $(d)/generate-options.nix $(d)/src/command-ref/conf-file-prefix.md $(bindir)/nix
cat doc/manual/src/command-ref/conf-file-prefix.md > $@ @cat doc/manual/src/command-ref/conf-file-prefix.md > $@.tmp
jq -r -f doc/manual/generate-options.jq $< >> $@ $(trace-gen) $(nix-eval) 'import doc/manual/generate-options.nix (builtins.fromJSON (builtins.readFile $<))' >> $@.tmp
@mv $@.tmp $@
$(d)/nix.json: $(bindir)/nix $(d)/nix.json: $(bindir)/nix
$(trace-gen) $(bindir)/nix __dump-args > $@ $(trace-gen) $(bindir)/nix __dump-args > $@.tmp
@mv $@.tmp $@
$(d)/conf-file.json: $(bindir)/nix $(d)/conf-file.json: $(bindir)/nix
$(trace-gen) env -i NIX_CONF_DIR=/dummy HOME=/dummy $(bindir)/nix show-config --json --experimental-features nix-command > $@ $(trace-gen) env -i NIX_CONF_DIR=/dummy HOME=/dummy $(bindir)/nix show-config --json --experimental-features nix-command > $@.tmp
@mv $@.tmp $@
$(d)/src/expressions/builtins.md: $(d)/builtins.json $(d)/generate-builtins.jq $(d)/src/expressions/builtins-prefix.md $(d)/src/expressions/builtins.md: $(d)/builtins.json $(d)/generate-builtins.nix $(d)/src/expressions/builtins-prefix.md $(bindir)/nix
cat doc/manual/src/expressions/builtins-prefix.md > $@ @cat doc/manual/src/expressions/builtins-prefix.md > $@.tmp
jq -r -f doc/manual/generate-builtins.jq $< >> $@ $(trace-gen) $(nix-eval) 'import doc/manual/generate-builtins.nix (builtins.fromJSON (builtins.readFile $<))' >> $@.tmp
@mv $@.tmp $@
$(d)/builtins.json: $(bindir)/nix $(d)/builtins.json: $(bindir)/nix
$(trace-gen) $(bindir)/nix __dump-builtins > $@ $(trace-gen) NIX_PATH=nix/corepkgs=corepkgs $(bindir)/nix __dump-builtins > $@.tmp
mv $@.tmp $@
# Generate the HTML manual. # Generate the HTML manual.
install: $(docdir)/manual/index.html install: $(docdir)/manual/index.html

7
doc/manual/utils.nix Normal file
View file

@ -0,0 +1,7 @@
with builtins;
{
splitLines = s: filter (x: !isList x) (split "\n" s);
concatStrings = concatStringsSep "";
}

View file

@ -70,19 +70,6 @@ PKG_CHECK_MODULES([NIX], [nix-store])
NEED_PROG([NIX], [nix]) NEED_PROG([NIX], [nix])
# Get nix configure values
export NIX_REMOTE=daemon
nixbindir=$("$NIX" --experimental-features nix-command eval --raw -f '<nix/config.nix>' nixBinDir)
nixlibexecdir=$("$NIX" --experimental-features nix-command eval --raw -f '<nix/config.nix>' nixLibexecDir)
nixlocalstatedir=$("$NIX" --experimental-features nix-command eval --raw -f '<nix/config.nix>' nixLocalstateDir)
nixsysconfdir=$("$NIX" --experimental-features nix-command eval --raw -f '<nix/config.nix>' nixSysconfDir)
nixstoredir=$("$NIX" --experimental-features nix-command eval --raw -f '<nix/config.nix>' nixStoreDir)
AC_SUBST(nixbindir)
AC_SUBST(nixlibexecdir)
AC_SUBST(nixlocalstatedir)
AC_SUBST(nixsysconfdir)
AC_SUBST(nixstoredir)
# Expand all variables in config.status. # Expand all variables in config.status.
test "$prefix" = NONE && prefix=$ac_default_prefix test "$prefix" = NONE && prefix=$ac_default_prefix
test "$exec_prefix" = NONE && exec_prefix='${prefix}' test "$exec_prefix" = NONE && exec_prefix='${prefix}'

View file

@ -4,14 +4,8 @@ use MIME::Base64;
$version = "@PACKAGE_VERSION@"; $version = "@PACKAGE_VERSION@";
$binDir = $ENV{"NIX_BIN_DIR"} || "@nixbindir@"; $binDir = Nix::Store::getBinDir;
$libexecDir = $ENV{"NIX_LIBEXEC_DIR"} || "@nixlibexecdir@"; $storeDir = Nix::Store::getStoreDir;
$stateDir = $ENV{"NIX_STATE_DIR"} || "@nixlocalstatedir@/nix";
$logDir = $ENV{"NIX_LOG_DIR"} || "@nixlocalstatedir@/log/nix";
$confDir = $ENV{"NIX_CONF_DIR"} || "@nixsysconfdir@/nix";
$storeDir = $ENV{"NIX_STORE_DIR"} || "@nixstoredir@";
$useBindings = 1;
%config = (); %config = ();

View file

@ -2,7 +2,6 @@ package Nix::Store;
use strict; use strict;
use warnings; use warnings;
use Nix::Config;
require Exporter; require Exporter;
@ -22,6 +21,7 @@ our @EXPORT = qw(
addToStore makeFixedOutputPath addToStore makeFixedOutputPath
derivationFromPath derivationFromPath
addTempRoot addTempRoot
getBinDir getStoreDir
); );
our $VERSION = '0.15'; our $VERSION = '0.15';
@ -34,62 +34,8 @@ sub backtick {
return $res; return $res;
} }
if ($Nix::Config::useBindings) { require XSLoader;
require XSLoader; XSLoader::load('Nix::Store', $VERSION);
XSLoader::load('Nix::Store', $VERSION);
} else {
# Provide slow fallbacks of some functions on platforms that don't
# support the Perl bindings.
use File::Temp;
use Fcntl qw/F_SETFD/;
*hashFile = sub {
my ($algo, $base32, $path) = @_;
my $res = backtick("$Nix::Config::binDir/nix-hash", "--flat", $path, "--type", $algo, $base32 ? "--base32" : ());
chomp $res;
return $res;
};
*hashPath = sub {
my ($algo, $base32, $path) = @_;
my $res = backtick("$Nix::Config::binDir/nix-hash", $path, "--type", $algo, $base32 ? "--base32" : ());
chomp $res;
return $res;
};
*hashString = sub {
my ($algo, $base32, $s) = @_;
my $fh = File::Temp->new();
print $fh $s;
my $res = backtick("$Nix::Config::binDir/nix-hash", $fh->filename, "--type", $algo, $base32 ? "--base32" : ());
chomp $res;
return $res;
};
*addToStore = sub {
my ($srcPath, $recursive, $algo) = @_;
die "not implemented" if $recursive || $algo ne "sha256";
my $res = backtick("$Nix::Config::binDir/nix-store", "--add", $srcPath);
chomp $res;
return $res;
};
*isValidPath = sub {
my ($path) = @_;
my $res = backtick("$Nix::Config::binDir/nix-store", "--check-validity", "--print-invalid", $path);
chomp $res;
return $res ne $path;
};
*queryPathHash = sub {
my ($path) = @_;
my $res = backtick("$Nix::Config::binDir/nix-store", "--query", "--hash", $path);
chomp $res;
return $res;
};
}
1; 1;
__END__ __END__

View file

@ -351,3 +351,13 @@ void addTempRoot(char * storePath)
} catch (Error & e) { } catch (Error & e) {
croak("%s", e.what()); croak("%s", e.what());
} }
SV * getBinDir()
PPCODE:
XPUSHs(sv_2mortal(newSVpv(settings.nixBinDir.c_str(), 0)));
SV * getStoreDir()
PPCODE:
XPUSHs(sv_2mortal(newSVpv(settings.nixStore.c_str(), 0)));

View file

@ -370,7 +370,11 @@ EvalState::EvalState(const Strings & _searchPath, ref<Store> store)
for (auto & i : _searchPath) addToSearchPath(i); for (auto & i : _searchPath) addToSearchPath(i);
for (auto & i : evalSettings.nixPath.get()) addToSearchPath(i); for (auto & i : evalSettings.nixPath.get()) addToSearchPath(i);
} }
try {
addToSearchPath("nix=" + canonPath(settings.nixDataDir + "/nix/corepkgs", true)); addToSearchPath("nix=" + canonPath(settings.nixDataDir + "/nix/corepkgs", true));
} catch (Error &) {
}
if (evalSettings.restrictEval || evalSettings.pureEval) { if (evalSettings.restrictEval || evalSettings.pureEval) {
allowedPaths = PathSet(); allowedPaths = PathSet();

View file

@ -6,7 +6,7 @@
namespace nix { namespace nix {
class Store; class Store;
struct StorePath; class StorePath;
} }
namespace nix::flake { namespace nix::flake {

View file

@ -42,6 +42,6 @@ $(eval $(call install-file-in, $(d)/nix-expr.pc, $(prefix)/lib/pkgconfig, 0644))
$(foreach i, $(wildcard src/libexpr/flake/*.hh), \ $(foreach i, $(wildcard src/libexpr/flake/*.hh), \
$(eval $(call install-file-in, $(i), $(includedir)/nix/flake, 0644))) $(eval $(call install-file-in, $(i), $(includedir)/nix/flake, 0644)))
$(d)/primops.cc: $(d)/imported-drv-to-derivation.nix.gen.hh $(d)/primops.cc: $(d)/imported-drv-to-derivation.nix.gen.hh $(d)/primops/derivation.nix.gen.hh
$(d)/flake/flake.cc: $(d)/flake/call-flake.nix.gen.hh $(d)/flake/flake.cc: $(d)/flake/call-flake.nix.gen.hh

View file

@ -3565,9 +3565,10 @@ void EvalState::createBaseEnv()
/* Add a wrapper around the derivation primop that computes the /* Add a wrapper around the derivation primop that computes the
`drvPath' and `outPath' attributes lazily. */ `drvPath' and `outPath' attributes lazily. */
string path = canonPath(settings.nixDataDir + "/nix/corepkgs/derivation.nix", true); sDerivationNix = symbols.create("//builtin/derivation.nix");
sDerivationNix = symbols.create(path); eval(parse(
evalFile(path, v); #include "primops/derivation.nix.gen.hh"
, foFile, sDerivationNix, "/", staticBaseEnv), v);
addConstant("derivation", v); addConstant("derivation", v);
/* Now that we've added all primops, sort the `builtins' set, /* Now that we've added all primops, sort the `builtins' set,

View file

@ -23,7 +23,7 @@ struct InputScheme;
struct Input struct Input
{ {
friend class InputScheme; friend struct InputScheme;
std::shared_ptr<InputScheme> scheme; // note: can be null std::shared_ptr<InputScheme> scheme; // note: can be null
Attrs attrs; Attrs attrs;

View file

@ -22,7 +22,8 @@
namespace nix { namespace nix {
BinaryCacheStore::BinaryCacheStore(const Params & params) BinaryCacheStore::BinaryCacheStore(const Params & params)
: Store(params) : BinaryCacheStoreConfig(params)
, Store(params)
{ {
if (secretKeyFile != "") if (secretKeyFile != "")
secretKey = std::unique_ptr<SecretKey>(new SecretKey(readFile(secretKeyFile))); secretKey = std::unique_ptr<SecretKey>(new SecretKey(readFile(secretKeyFile)));

View file

@ -11,17 +11,21 @@ namespace nix {
struct NarInfo; struct NarInfo;
class BinaryCacheStore : public Store struct BinaryCacheStoreConfig : virtual StoreConfig
{ {
public: using StoreConfig::StoreConfig;
const Setting<std::string> compression{this, "xz", "compression", "NAR compression method ('xz', 'bzip2', or 'none')"}; const Setting<std::string> compression{(StoreConfig*) this, "xz", "compression", "NAR compression method ('xz', 'bzip2', or 'none')"};
const Setting<bool> writeNARListing{this, false, "write-nar-listing", "whether to write a JSON file listing the files in each NAR"}; const Setting<bool> writeNARListing{(StoreConfig*) this, false, "write-nar-listing", "whether to write a JSON file listing the files in each NAR"};
const Setting<bool> writeDebugInfo{this, false, "index-debug-info", "whether to index DWARF debug info files by build ID"}; const Setting<bool> writeDebugInfo{(StoreConfig*) this, false, "index-debug-info", "whether to index DWARF debug info files by build ID"};
const Setting<Path> secretKeyFile{this, "", "secret-key", "path to secret key used to sign the binary cache"}; const Setting<Path> secretKeyFile{(StoreConfig*) this, "", "secret-key", "path to secret key used to sign the binary cache"};
const Setting<Path> localNarCache{this, "", "local-nar-cache", "path to a local cache of NARs"}; const Setting<Path> localNarCache{(StoreConfig*) this, "", "local-nar-cache", "path to a local cache of NARs"};
const Setting<bool> parallelCompression{this, false, "parallel-compression", const Setting<bool> parallelCompression{(StoreConfig*) this, false, "parallel-compression",
"enable multi-threading compression, available for xz only currently"}; "enable multi-threading compression, available for xz only currently"};
};
class BinaryCacheStore : public Store, public virtual BinaryCacheStoreConfig
{
private: private:
@ -58,7 +62,7 @@ public:
public: public:
virtual void init(); virtual void init() override;
private: private:

View file

@ -2910,18 +2910,23 @@ void DerivationGoal::writeStructuredAttrs()
chownToBuilder(tmpDir + "/.attrs.sh"); chownToBuilder(tmpDir + "/.attrs.sh");
} }
struct RestrictedStoreConfig : LocalFSStoreConfig
{
using LocalFSStoreConfig::LocalFSStoreConfig;
const std::string name() { return "Restricted Store"; }
};
/* A wrapper around LocalStore that only allows building/querying of /* A wrapper around LocalStore that only allows building/querying of
paths that are in the input closures of the build or were added via paths that are in the input closures of the build or were added via
recursive Nix calls. */ recursive Nix calls. */
struct RestrictedStore : public LocalFSStore struct RestrictedStore : public LocalFSStore, public virtual RestrictedStoreConfig
{ {
ref<LocalStore> next; ref<LocalStore> next;
DerivationGoal & goal; DerivationGoal & goal;
RestrictedStore(const Params & params, ref<LocalStore> next, DerivationGoal & goal) RestrictedStore(const Params & params, ref<LocalStore> next, DerivationGoal & goal)
: Store(params), LocalFSStore(params), next(next), goal(goal) : StoreConfig(params), Store(params), LocalFSStore(params), next(next), goal(goal)
{ } { }
Path getRealStoreDir() override Path getRealStoreDir() override

View file

@ -2,17 +2,27 @@
namespace nix { namespace nix {
static std::string uriScheme = "dummy://"; struct DummyStoreConfig : virtual StoreConfig {
using StoreConfig::StoreConfig;
struct DummyStore : public Store const std::string name() override { return "Dummy Store"; }
};
struct DummyStore : public Store, public virtual DummyStoreConfig
{ {
DummyStore(const Params & params) DummyStore(const std::string scheme, const std::string uri, const Params & params)
: Store(params) : DummyStore(params)
{ } { }
DummyStore(const Params & params)
: StoreConfig(params)
, Store(params)
{
}
string getUri() override string getUri() override
{ {
return uriScheme; return *uriSchemes().begin();
} }
void queryPathInfoUncached(const StorePath & path, void queryPathInfoUncached(const StorePath & path,
@ -21,6 +31,10 @@ struct DummyStore : public Store
callback(nullptr); callback(nullptr);
} }
static std::set<std::string> uriSchemes() {
return {"dummy"};
}
std::optional<StorePath> queryPathFromHashPart(const std::string & hashPart) override std::optional<StorePath> queryPathFromHashPart(const std::string & hashPart) override
{ unsupported("queryPathFromHashPart"); } { unsupported("queryPathFromHashPart"); }
@ -48,12 +62,6 @@ struct DummyStore : public Store
{ unsupported("buildDerivation"); } { unsupported("buildDerivation"); }
}; };
static RegisterStoreImplementation regStore([]( static RegisterStoreImplementation<DummyStore, DummyStoreConfig> regStore;
const std::string & uri, const Store::Params & params)
-> std::shared_ptr<Store>
{
if (uri != uriScheme) return nullptr;
return std::make_shared<DummyStore>(params);
});
} }

View file

@ -574,9 +574,12 @@ bool LocalStore::canReachRoot(GCState & state, StorePathSet & visited, const Sto
/* If keep-derivations is set and this is a derivation, then /* If keep-derivations is set and this is a derivation, then
don't delete the derivation if any of the outputs are alive. */ don't delete the derivation if any of the outputs are alive. */
if (state.gcKeepDerivations && path.isDerivation()) { if (state.gcKeepDerivations && path.isDerivation()) {
for (auto & i : queryDerivationOutputs(path)) for (auto & [name, maybeOutPath] : queryPartialDerivationOutputMap(path))
if (isValidPath(i) && queryPathInfo(i)->deriver == path) if (maybeOutPath &&
incoming.insert(i); isValidPath(*maybeOutPath) &&
queryPathInfo(*maybeOutPath)->deriver == path
)
incoming.insert(*maybeOutPath);
} }
/* If keep-outputs is set, then don't delete this path if there /* If keep-outputs is set, then don't delete this path if there

View file

@ -162,11 +162,6 @@ template<> std::string BaseSetting<SandboxMode>::to_string() const
else abort(); else abort();
} }
template<> nlohmann::json BaseSetting<SandboxMode>::toJSON()
{
return AbstractSetting::toJSON();
}
template<> void BaseSetting<SandboxMode>::convertToArg(Args & args, const std::string & category) template<> void BaseSetting<SandboxMode>::convertToArg(Args & args, const std::string & category)
{ {
args.addFlag({ args.addFlag({

View file

@ -2,6 +2,7 @@
#include "types.hh" #include "types.hh"
#include "config.hh" #include "config.hh"
#include "abstractsettingtojson.hh"
#include "util.hh" #include "util.hh"
#include <map> #include <map>

View file

@ -7,7 +7,14 @@ namespace nix {
MakeError(UploadToHTTP, Error); MakeError(UploadToHTTP, Error);
class HttpBinaryCacheStore : public BinaryCacheStore struct HttpBinaryCacheStoreConfig : virtual BinaryCacheStoreConfig
{
using BinaryCacheStoreConfig::BinaryCacheStoreConfig;
const std::string name() override { return "Http Binary Cache Store"; }
};
class HttpBinaryCacheStore : public BinaryCacheStore, public HttpBinaryCacheStoreConfig
{ {
private: private:
@ -24,9 +31,12 @@ private:
public: public:
HttpBinaryCacheStore( HttpBinaryCacheStore(
const Params & params, const Path & _cacheUri) const std::string & scheme,
: BinaryCacheStore(params) const Path & _cacheUri,
, cacheUri(_cacheUri) const Params & params)
: StoreConfig(params)
, BinaryCacheStore(params)
, cacheUri(scheme + "://" + _cacheUri)
{ {
if (cacheUri.back() == '/') if (cacheUri.back() == '/')
cacheUri.pop_back(); cacheUri.pop_back();
@ -55,6 +65,13 @@ public:
} }
} }
static std::set<std::string> uriSchemes()
{
static bool forceHttp = getEnv("_NIX_FORCE_HTTP") == "1";
auto ret = std::set<std::string>({"http", "https"});
if (forceHttp) ret.insert("file");
return ret;
}
protected: protected:
void maybeDisable() void maybeDisable()
@ -162,18 +179,6 @@ protected:
}; };
static RegisterStoreImplementation regStore([]( static RegisterStoreImplementation<HttpBinaryCacheStore, HttpBinaryCacheStoreConfig> regStore;
const std::string & uri, const Store::Params & params)
-> std::shared_ptr<Store>
{
static bool forceHttp = getEnv("_NIX_FORCE_HTTP") == "1";
if (std::string(uri, 0, 7) != "http://" &&
std::string(uri, 0, 8) != "https://" &&
(!forceHttp || std::string(uri, 0, 7) != "file://"))
return 0;
auto store = std::make_shared<HttpBinaryCacheStore>(params, uri);
store->init();
return store;
});
} }

View file

@ -9,18 +9,24 @@
namespace nix { namespace nix {
static std::string uriScheme = "ssh://"; struct LegacySSHStoreConfig : virtual StoreConfig
struct LegacySSHStore : public Store
{ {
const Setting<int> maxConnections{this, 1, "max-connections", "maximum number of concurrent SSH connections"}; using StoreConfig::StoreConfig;
const Setting<Path> sshKey{this, "", "ssh-key", "path to an SSH private key"}; const Setting<int> maxConnections{(StoreConfig*) this, 1, "max-connections", "maximum number of concurrent SSH connections"};
const Setting<bool> compress{this, false, "compress", "whether to compress the connection"}; const Setting<Path> sshKey{(StoreConfig*) this, "", "ssh-key", "path to an SSH private key"};
const Setting<Path> remoteProgram{this, "nix-store", "remote-program", "path to the nix-store executable on the remote system"}; const Setting<bool> compress{(StoreConfig*) this, false, "compress", "whether to compress the connection"};
const Setting<std::string> remoteStore{this, "", "remote-store", "URI of the store on the remote system"}; const Setting<Path> remoteProgram{(StoreConfig*) this, "nix-store", "remote-program", "path to the nix-store executable on the remote system"};
const Setting<std::string> remoteStore{(StoreConfig*) this, "", "remote-store", "URI of the store on the remote system"};
const std::string name() override { return "Legacy SSH Store"; }
};
struct LegacySSHStore : public Store, public virtual LegacySSHStoreConfig
{
// Hack for getting remote build log output. // Hack for getting remote build log output.
const Setting<int> logFD{this, -1, "log-fd", "file descriptor to which SSH's stderr is connected"}; // Intentionally not in `LegacySSHStoreConfig` so that it doesn't appear in
// the documentation
const Setting<int> logFD{(StoreConfig*) this, -1, "log-fd", "file descriptor to which SSH's stderr is connected"};
struct Connection struct Connection
{ {
@ -37,8 +43,11 @@ struct LegacySSHStore : public Store
SSHMaster master; SSHMaster master;
LegacySSHStore(const string & host, const Params & params) static std::set<std::string> uriSchemes() { return {"ssh"}; }
: Store(params)
LegacySSHStore(const string & scheme, const string & host, const Params & params)
: StoreConfig(params)
, Store(params)
, host(host) , host(host)
, connections(make_ref<Pool<Connection>>( , connections(make_ref<Pool<Connection>>(
std::max(1, (int) maxConnections), std::max(1, (int) maxConnections),
@ -84,7 +93,7 @@ struct LegacySSHStore : public Store
string getUri() override string getUri() override
{ {
return uriScheme + host; return *uriSchemes().begin() + "://" + host;
} }
void queryPathInfoUncached(const StorePath & path, void queryPathInfoUncached(const StorePath & path,
@ -325,12 +334,6 @@ public:
} }
}; };
static RegisterStoreImplementation regStore([]( static RegisterStoreImplementation<LegacySSHStore, LegacySSHStoreConfig> regStore;
const std::string & uri, const Store::Params & params)
-> std::shared_ptr<Store>
{
if (std::string(uri, 0, uriScheme.size()) != uriScheme) return 0;
return std::make_shared<LegacySSHStore>(std::string(uri, uriScheme.size()), params);
});
} }

View file

@ -4,7 +4,14 @@
namespace nix { namespace nix {
class LocalBinaryCacheStore : public BinaryCacheStore struct LocalBinaryCacheStoreConfig : virtual BinaryCacheStoreConfig
{
using BinaryCacheStoreConfig::BinaryCacheStoreConfig;
const std::string name() override { return "Local Binary Cache Store"; }
};
class LocalBinaryCacheStore : public BinaryCacheStore, public virtual LocalBinaryCacheStoreConfig
{ {
private: private:
@ -13,8 +20,11 @@ private:
public: public:
LocalBinaryCacheStore( LocalBinaryCacheStore(
const Params & params, const Path & binaryCacheDir) const std::string scheme,
: BinaryCacheStore(params) const Path & binaryCacheDir,
const Params & params)
: StoreConfig(params)
, BinaryCacheStore(params)
, binaryCacheDir(binaryCacheDir) , binaryCacheDir(binaryCacheDir)
{ {
} }
@ -26,6 +36,8 @@ public:
return "file://" + binaryCacheDir; return "file://" + binaryCacheDir;
} }
static std::set<std::string> uriSchemes();
protected: protected:
bool fileExists(const std::string & path) override; bool fileExists(const std::string & path) override;
@ -85,16 +97,14 @@ bool LocalBinaryCacheStore::fileExists(const std::string & path)
return pathExists(binaryCacheDir + "/" + path); return pathExists(binaryCacheDir + "/" + path);
} }
static RegisterStoreImplementation regStore([]( std::set<std::string> LocalBinaryCacheStore::uriSchemes()
const std::string & uri, const Store::Params & params)
-> std::shared_ptr<Store>
{ {
if (getEnv("_NIX_FORCE_HTTP_BINARY_CACHE_STORE") == "1" || if (getEnv("_NIX_FORCE_HTTP_BINARY_CACHE_STORE") == "1")
std::string(uri, 0, 7) != "file://") return {};
return 0; else
auto store = std::make_shared<LocalBinaryCacheStore>(params, std::string(uri, 7)); return {"file"};
store->init(); }
return store;
}); static RegisterStoreImplementation<LocalBinaryCacheStore, LocalBinaryCacheStoreConfig> regStore;
} }

View file

@ -42,7 +42,8 @@ namespace nix {
LocalStore::LocalStore(const Params & params) LocalStore::LocalStore(const Params & params)
: Store(params) : StoreConfig(params)
, Store(params)
, LocalFSStore(params) , LocalFSStore(params)
, realStoreDir_{this, false, rootDir != "" ? rootDir + "/nix/store" : storeDir, "real", , realStoreDir_{this, false, rootDir != "" ? rootDir + "/nix/store" : storeDir, "real",
"physical path to the Nix store"} "physical path to the Nix store"}

View file

@ -30,8 +30,19 @@ struct OptimiseStats
uint64_t blocksFreed = 0; uint64_t blocksFreed = 0;
}; };
struct LocalStoreConfig : virtual LocalFSStoreConfig
{
using LocalFSStoreConfig::LocalFSStoreConfig;
class LocalStore : public LocalFSStore Setting<bool> requireSigs{(StoreConfig*) this,
settings.requireSigs,
"require-sigs", "whether store paths should have a trusted signature on import"};
const std::string name() override { return "Local Store"; }
};
class LocalStore : public LocalFSStore, public virtual LocalStoreConfig
{ {
private: private:
@ -95,10 +106,6 @@ public:
private: private:
Setting<bool> requireSigs{(Store*) this,
settings.requireSigs,
"require-sigs", "whether store paths should have a trusted signature on import"};
const PublicKeys & getPublicKeys(); const PublicKeys & getPublicKeys();
public: public:

View file

@ -94,9 +94,19 @@ void write(const Store & store, Sink & out, const std::optional<StorePath> & sto
/* TODO: Separate these store impls into different files, give them better names */ /* TODO: Separate these store impls into different files, give them better names */
RemoteStore::RemoteStore(const Params & params) RemoteStore::RemoteStore(const Params & params)
: Store(params) : Store(params)
, RemoteStoreConfig(params)
, connections(make_ref<Pool<Connection>>( , connections(make_ref<Pool<Connection>>(
std::max(1, (int) maxConnections), std::max(1, (int) maxConnections),
[this]() { return openConnectionWrapper(); }, [this]() {
auto conn = openConnectionWrapper();
try {
initConnection(*conn);
} catch (...) {
failed = true;
throw;
}
return conn;
},
[this](const ref<Connection> & r) { [this](const ref<Connection> & r) {
return return
r->to.good() r->to.good()
@ -123,19 +133,21 @@ ref<RemoteStore::Connection> RemoteStore::openConnectionWrapper()
UDSRemoteStore::UDSRemoteStore(const Params & params) UDSRemoteStore::UDSRemoteStore(const Params & params)
: Store(params) : StoreConfig(params)
, Store(params)
, LocalFSStore(params) , LocalFSStore(params)
, RemoteStore(params) , RemoteStore(params)
{ {
} }
UDSRemoteStore::UDSRemoteStore(std::string socket_path, const Params & params) UDSRemoteStore::UDSRemoteStore(
: Store(params) const std::string scheme,
, LocalFSStore(params) std::string socket_path,
, RemoteStore(params) const Params & params)
, path(socket_path) : UDSRemoteStore(params)
{ {
path.emplace(socket_path);
} }
@ -179,8 +191,6 @@ ref<RemoteStore::Connection> UDSRemoteStore::openConnection()
conn->startTime = std::chrono::steady_clock::now(); conn->startTime = std::chrono::steady_clock::now();
initConnection(*conn);
return conn; return conn;
} }
@ -982,14 +992,6 @@ std::exception_ptr RemoteStore::Connection::processStderr(Sink * sink, Source *
return nullptr; return nullptr;
} }
static std::string uriScheme = "unix://"; static RegisterStoreImplementation<UDSRemoteStore, UDSRemoteStoreConfig> regStore;
static RegisterStoreImplementation regStore([](
const std::string & uri, const Store::Params & params)
-> std::shared_ptr<Store>
{
if (std::string(uri, 0, uriScheme.size()) != uriScheme) return 0;
return std::make_shared<UDSRemoteStore>(std::string(uri, uriScheme.size()), params);
});
} }

View file

@ -16,19 +16,23 @@ struct FdSource;
template<typename T> class Pool; template<typename T> class Pool;
struct ConnectionHandle; struct ConnectionHandle;
struct RemoteStoreConfig : virtual StoreConfig
{
using StoreConfig::StoreConfig;
const Setting<int> maxConnections{(StoreConfig*) this, 1,
"max-connections", "maximum number of concurrent connections to the Nix daemon"};
const Setting<unsigned int> maxConnectionAge{(StoreConfig*) this, std::numeric_limits<unsigned int>::max(),
"max-connection-age", "number of seconds to reuse a connection"};
};
/* FIXME: RemoteStore is a misnomer - should be something like /* FIXME: RemoteStore is a misnomer - should be something like
DaemonStore. */ DaemonStore. */
class RemoteStore : public virtual Store class RemoteStore : public virtual Store, public virtual RemoteStoreConfig
{ {
public: public:
const Setting<int> maxConnections{(Store*) this, 1,
"max-connections", "maximum number of concurrent connections to the Nix daemon"};
const Setting<unsigned int> maxConnectionAge{(Store*) this, std::numeric_limits<unsigned int>::max(),
"max-connection-age", "number of seconds to reuse a connection"};
virtual bool sameMachine() = 0; virtual bool sameMachine() = 0;
RemoteStore(const Params & params); RemoteStore(const Params & params);
@ -102,8 +106,6 @@ public:
void flushBadConnections(); void flushBadConnections();
protected:
struct Connection struct Connection
{ {
AutoCloseFD fd; AutoCloseFD fd;
@ -119,6 +121,8 @@ protected:
ref<Connection> openConnectionWrapper(); ref<Connection> openConnectionWrapper();
protected:
virtual ref<Connection> openConnection() = 0; virtual ref<Connection> openConnection() = 0;
void initConnection(Connection & conn); void initConnection(Connection & conn);
@ -141,15 +145,35 @@ private:
}; };
class UDSRemoteStore : public LocalFSStore, public RemoteStore struct UDSRemoteStoreConfig : virtual LocalFSStoreConfig, virtual RemoteStoreConfig
{
UDSRemoteStoreConfig(const Store::Params & params)
: StoreConfig(params)
, LocalFSStoreConfig(params)
, RemoteStoreConfig(params)
{
}
UDSRemoteStoreConfig()
: UDSRemoteStoreConfig(Store::Params({}))
{
}
const std::string name() override { return "Local Daemon Store"; }
};
class UDSRemoteStore : public LocalFSStore, public RemoteStore, public virtual UDSRemoteStoreConfig
{ {
public: public:
UDSRemoteStore(const Params & params); UDSRemoteStore(const Params & params);
UDSRemoteStore(std::string path, const Params & params); UDSRemoteStore(const std::string scheme, std::string path, const Params & params);
std::string getUri() override; std::string getUri() override;
static std::set<std::string> uriSchemes()
{ return {"unix"}; }
bool sameMachine() override bool sameMachine() override
{ return true; } { return true; }

View file

@ -172,20 +172,26 @@ S3Helper::FileTransferResult S3Helper::getObject(
return res; return res;
} }
struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore struct S3BinaryCacheStoreConfig : virtual BinaryCacheStoreConfig
{ {
const Setting<std::string> profile{this, "", "profile", "The name of the AWS configuration profile to use."}; using BinaryCacheStoreConfig::BinaryCacheStoreConfig;
const Setting<std::string> region{this, Aws::Region::US_EAST_1, "region", {"aws-region"}}; const Setting<std::string> profile{(StoreConfig*) this, "", "profile", "The name of the AWS configuration profile to use."};
const Setting<std::string> scheme{this, "", "scheme", "The scheme to use for S3 requests, https by default."}; const Setting<std::string> region{(StoreConfig*) this, Aws::Region::US_EAST_1, "region", {"aws-region"}};
const Setting<std::string> endpoint{this, "", "endpoint", "An optional override of the endpoint to use when talking to S3."}; const Setting<std::string> scheme{(StoreConfig*) this, "", "scheme", "The scheme to use for S3 requests, https by default."};
const Setting<std::string> narinfoCompression{this, "", "narinfo-compression", "compression method for .narinfo files"}; const Setting<std::string> endpoint{(StoreConfig*) this, "", "endpoint", "An optional override of the endpoint to use when talking to S3."};
const Setting<std::string> lsCompression{this, "", "ls-compression", "compression method for .ls files"}; const Setting<std::string> narinfoCompression{(StoreConfig*) this, "", "narinfo-compression", "compression method for .narinfo files"};
const Setting<std::string> logCompression{this, "", "log-compression", "compression method for log/* files"}; const Setting<std::string> lsCompression{(StoreConfig*) this, "", "ls-compression", "compression method for .ls files"};
const Setting<std::string> logCompression{(StoreConfig*) this, "", "log-compression", "compression method for log/* files"};
const Setting<bool> multipartUpload{ const Setting<bool> multipartUpload{
this, false, "multipart-upload", "whether to use multi-part uploads"}; (StoreConfig*) this, false, "multipart-upload", "whether to use multi-part uploads"};
const Setting<uint64_t> bufferSize{ const Setting<uint64_t> bufferSize{
this, 5 * 1024 * 1024, "buffer-size", "size (in bytes) of each part in multi-part uploads"}; (StoreConfig*) this, 5 * 1024 * 1024, "buffer-size", "size (in bytes) of each part in multi-part uploads"};
const std::string name() override { return "S3 Binary Cache Store"; }
};
struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore, virtual S3BinaryCacheStoreConfig
{
std::string bucketName; std::string bucketName;
Stats stats; Stats stats;
@ -193,8 +199,11 @@ struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore
S3Helper s3Helper; S3Helper s3Helper;
S3BinaryCacheStoreImpl( S3BinaryCacheStoreImpl(
const Params & params, const std::string & bucketName) const std::string & scheme,
: S3BinaryCacheStore(params) const std::string & bucketName,
const Params & params)
: StoreConfig(params)
, S3BinaryCacheStore(params)
, bucketName(bucketName) , bucketName(bucketName)
, s3Helper(profile, region, scheme, endpoint) , s3Helper(profile, region, scheme, endpoint)
{ {
@ -426,17 +435,11 @@ struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore
return paths; return paths;
} }
static std::set<std::string> uriSchemes() { return {"s3"}; }
}; };
static RegisterStoreImplementation regStore([]( static RegisterStoreImplementation<S3BinaryCacheStoreImpl, S3BinaryCacheStoreConfig> regStore;
const std::string & uri, const Store::Params & params)
-> std::shared_ptr<Store>
{
if (std::string(uri, 0, 5) != "s3://") return 0;
auto store = std::make_shared<S3BinaryCacheStoreImpl>(params, std::string(uri, 5));
store->init();
return store;
});
} }

View file

@ -8,19 +8,25 @@
namespace nix { namespace nix {
static std::string uriScheme = "ssh-ng://"; struct SSHStoreConfig : virtual RemoteStoreConfig
{
using RemoteStoreConfig::RemoteStoreConfig;
class SSHStore : public RemoteStore const Setting<Path> sshKey{(StoreConfig*) this, "", "ssh-key", "path to an SSH private key"};
const Setting<bool> compress{(StoreConfig*) this, false, "compress", "whether to compress the connection"};
const Setting<Path> remoteProgram{(StoreConfig*) this, "nix-daemon", "remote-program", "path to the nix-daemon executable on the remote system"};
const Setting<std::string> remoteStore{(StoreConfig*) this, "", "remote-store", "URI of the store on the remote system"};
const std::string name() override { return "SSH Store"; }
};
class SSHStore : public virtual RemoteStore, public virtual SSHStoreConfig
{ {
public: public:
const Setting<Path> sshKey{(Store*) this, "", "ssh-key", "path to an SSH private key"}; SSHStore(const std::string & scheme, const std::string & host, const Params & params)
const Setting<bool> compress{(Store*) this, false, "compress", "whether to compress the connection"}; : StoreConfig(params)
const Setting<Path> remoteProgram{(Store*) this, "nix-daemon", "remote-program", "path to the nix-daemon executable on the remote system"}; , Store(params)
const Setting<std::string> remoteStore{(Store*) this, "", "remote-store", "URI of the store on the remote system"};
SSHStore(const std::string & host, const Params & params)
: Store(params)
, RemoteStore(params) , RemoteStore(params)
, host(host) , host(host)
, master( , master(
@ -32,9 +38,11 @@ public:
{ {
} }
static std::set<std::string> uriSchemes() { return {"ssh-ng"}; }
std::string getUri() override std::string getUri() override
{ {
return uriScheme + host; return *uriSchemes().begin() + "://" + host;
} }
bool sameMachine() override bool sameMachine() override
@ -72,16 +80,9 @@ ref<RemoteStore::Connection> SSHStore::openConnection()
+ (remoteStore.get() == "" ? "" : " --store " + shellEscape(remoteStore.get()))); + (remoteStore.get() == "" ? "" : " --store " + shellEscape(remoteStore.get())));
conn->to = FdSink(conn->sshConn->in.get()); conn->to = FdSink(conn->sshConn->in.get());
conn->from = FdSource(conn->sshConn->out.get()); conn->from = FdSource(conn->sshConn->out.get());
initConnection(*conn);
return conn; return conn;
} }
static RegisterStoreImplementation regStore([]( static RegisterStoreImplementation<SSHStore, SSHStoreConfig> regStore;
const std::string & uri, const Store::Params & params)
-> std::shared_ptr<Store>
{
if (std::string(uri, 0, uriScheme.size()) != uriScheme) return 0;
return std::make_shared<SSHStore>(std::string(uri, uriScheme.size()), params);
});
} }

View file

@ -346,7 +346,7 @@ ValidPathInfo Store::addToStoreSlow(std::string_view name, const Path & srcPath,
Store::Store(const Params & params) Store::Store(const Params & params)
: Config(params) : StoreConfig(params)
, state({(size_t) pathInfoCacheSize}) , state({(size_t) pathInfoCacheSize})
{ {
} }
@ -1009,7 +1009,6 @@ Derivation Store::readDerivation(const StorePath & drvPath)
} }
} }
} }
@ -1019,9 +1018,6 @@ Derivation Store::readDerivation(const StorePath & drvPath)
namespace nix { namespace nix {
RegisterStoreImplementation::Implementations * RegisterStoreImplementation::implementations = 0;
/* Split URI into protocol+hierarchy part and its parameter set. */ /* Split URI into protocol+hierarchy part and its parameter set. */
std::pair<std::string, Store::Params> splitUriAndParams(const std::string & uri_) std::pair<std::string, Store::Params> splitUriAndParams(const std::string & uri_)
{ {
@ -1035,24 +1031,6 @@ std::pair<std::string, Store::Params> splitUriAndParams(const std::string & uri_
return {uri, params}; return {uri, params};
} }
ref<Store> openStore(const std::string & uri_,
const Store::Params & extraParams)
{
auto [uri, uriParams] = splitUriAndParams(uri_);
auto params = extraParams;
params.insert(uriParams.begin(), uriParams.end());
for (auto fun : *RegisterStoreImplementation::implementations) {
auto store = fun(uri, params);
if (store) {
store->warnUnknownSettings();
return ref<Store>(store);
}
}
throw Error("don't know how to open Nix store '%s'", uri);
}
static bool isNonUriPath(const std::string & spec) { static bool isNonUriPath(const std::string & spec) {
return return
// is not a URL // is not a URL
@ -1062,44 +1040,62 @@ static bool isNonUriPath(const std::string & spec) {
&& spec.find("/") != std::string::npos; && spec.find("/") != std::string::npos;
} }
StoreType getStoreType(const std::string & uri, const std::string & stateDir) std::shared_ptr<Store> openFromNonUri(const std::string & uri, const Store::Params & params)
{ {
if (uri == "daemon") { if (uri == "" || uri == "auto") {
return tDaemon; auto stateDir = get(params, "state").value_or(settings.nixStateDir);
} else if (uri == "local" || isNonUriPath(uri)) {
return tLocal;
} else if (uri == "" || uri == "auto") {
if (access(stateDir.c_str(), R_OK | W_OK) == 0) if (access(stateDir.c_str(), R_OK | W_OK) == 0)
return tLocal; return std::make_shared<LocalStore>(params);
else if (pathExists(settings.nixDaemonSocketFile)) else if (pathExists(settings.nixDaemonSocketFile))
return tDaemon; return std::make_shared<UDSRemoteStore>(params);
else else
return tLocal; 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)) {
Store::Params params2 = params;
params2["root"] = absPath(uri);
return std::make_shared<LocalStore>(params2);
} else { } else {
return tOther; return nullptr;
} }
} }
ref<Store> openStore(const std::string & uri_,
static RegisterStoreImplementation regStore([]( const Store::Params & extraParams)
const std::string & uri, const Store::Params & params)
-> std::shared_ptr<Store>
{ {
switch (getStoreType(uri, get(params, "state").value_or(settings.nixStateDir))) { auto params = extraParams;
case tDaemon: try {
return std::shared_ptr<Store>(std::make_shared<UDSRemoteStore>(params)); auto parsedUri = parseURL(uri_);
case tLocal: { params.insert(parsedUri.query.begin(), parsedUri.query.end());
Store::Params params2 = params;
if (isNonUriPath(uri)) {
params2["root"] = absPath(uri);
}
return std::shared_ptr<Store>(std::make_shared<LocalStore>(params2));
}
default:
return nullptr;
}
});
auto baseURI = parsedUri.authority.value_or("") + parsedUri.path;
for (auto implem : *Implementations::registered) {
if (implem.uriSchemes.count(parsedUri.scheme)) {
auto store = implem.create(parsedUri.scheme, baseURI, params);
if (store) {
store->init();
store->warnUnknownSettings();
return ref<Store>(store);
}
}
}
}
catch (BadURL &) {
auto [uri, uriParams] = splitUriAndParams(uri_);
params.insert(uriParams.begin(), uriParams.end());
if (auto store = openFromNonUri(uri, params)) {
store->warnUnknownSettings();
return ref<Store>(store);
}
}
throw Error("don't know how to open Nix store '%s'", uri_);
}
std::list<ref<Store>> getDefaultSubstituters() std::list<ref<Store>> getDefaultSubstituters()
{ {
@ -1133,5 +1129,6 @@ std::list<ref<Store>> getDefaultSubstituters()
return stores; return stores;
} }
std::vector<StoreFactory> * Implementations::registered = 0;
} }

View file

@ -24,6 +24,31 @@
namespace nix { namespace nix {
/**
* About the class hierarchy of the store implementations:
*
* Each store type `Foo` consists of two classes:
*
* 1. A class `FooConfig : virtual StoreConfig` that contains the configuration
* for the store
*
* It should only contain members of type `const Setting<T>` (or subclasses
* of it) and inherit the constructors of `StoreConfig`
* (`using StoreConfig::StoreConfig`).
*
* 2. A class `Foo : virtual Store, virtual FooConfig` that contains the
* implementation of the store.
*
* This class is expected to have a constructor `Foo(const Params & params)`
* that calls `StoreConfig(params)` (otherwise you're gonna encounter an
* `assertion failure` when trying to instantiate it).
*
* You can then register the new store using:
*
* ```
* cpp static RegisterStoreImplementation<Foo, FooConfig> regStore;
* ```
*/
MakeError(SubstError, Error); MakeError(SubstError, Error);
MakeError(BuildError, Error); // denotes a permanent build failure MakeError(BuildError, Error); // denotes a permanent build failure
@ -33,6 +58,7 @@ MakeError(SubstituteGone, Error);
MakeError(SubstituterDisabled, Error); MakeError(SubstituterDisabled, Error);
MakeError(BadStorePath, Error); MakeError(BadStorePath, Error);
MakeError(InvalidStoreURI, Error);
class FSAccessor; class FSAccessor;
class NarInfoDiskCache; class NarInfoDiskCache;
@ -144,12 +170,31 @@ struct BuildResult
} }
}; };
struct StoreConfig : public Config
class Store : public std::enable_shared_from_this<Store>, public Config
{ {
public: using Config::Config;
typedef std::map<std::string, std::string> Params; /**
* When constructing a store implementation, we pass in a map `params` of
* parameters that's supposed to initialize the associated config.
* To do that, we must use the `StoreConfig(StringMap & params)`
* constructor, so we'd like to `delete` its default constructor to enforce
* it.
*
* However, actually deleting it means that all the subclasses of
* `StoreConfig` will have their default constructor deleted (because it's
* supposed to call the deleted default constructor of `StoreConfig`). But
* because we're always using virtual inheritance, the constructors of
* child classes will never implicitely call this one, so deleting it will
* be more painful than anything else.
*
* So we `assert(false)` here to ensure at runtime that the right
* constructor is always called without having to redefine a custom
* constructor for each `*Config` class.
*/
StoreConfig() { assert(false); }
virtual const std::string name() = 0;
const PathSetting storeDir_{this, false, settings.nixStore, const PathSetting storeDir_{this, false, settings.nixStore,
"store", "path to the Nix store"}; "store", "path to the Nix store"};
@ -167,6 +212,14 @@ public:
"system-features", "system-features",
"Optional features that the system this store builds on implements (like \"kvm\")."}; "Optional features that the system this store builds on implements (like \"kvm\")."};
};
class Store : public std::enable_shared_from_this<Store>, public virtual StoreConfig
{
public:
typedef std::map<std::string, std::string> Params;
protected: protected:
struct PathInfoCacheValue { struct PathInfoCacheValue {
@ -200,6 +253,11 @@ protected:
Store(const Params & params); Store(const Params & params);
public: public:
/**
* Perform any necessary effectful operation to make the store up and
* running
*/
virtual void init() {};
virtual ~Store() { } virtual ~Store() { }
@ -626,22 +684,25 @@ protected:
}; };
struct LocalFSStoreConfig : virtual StoreConfig
class LocalFSStore : public virtual Store
{ {
public: using StoreConfig::StoreConfig;
// FIXME: the (StoreConfig*) cast works around a bug in gcc that causes
// FIXME: the (Store*) cast works around a bug in gcc that causes
// it to omit the call to the Setting constructor. Clang works fine // it to omit the call to the Setting constructor. Clang works fine
// either way. // either way.
const PathSetting rootDir{(Store*) this, true, "", const PathSetting rootDir{(StoreConfig*) this, true, "",
"root", "directory prefixed to all other paths"}; "root", "directory prefixed to all other paths"};
const PathSetting stateDir{(Store*) this, false, const PathSetting stateDir{(StoreConfig*) this, false,
rootDir != "" ? rootDir + "/nix/var/nix" : settings.nixStateDir, rootDir != "" ? rootDir + "/nix/var/nix" : settings.nixStateDir,
"state", "directory where Nix will store state"}; "state", "directory where Nix will store state"};
const PathSetting logDir{(Store*) this, false, const PathSetting logDir{(StoreConfig*) this, false,
rootDir != "" ? rootDir + "/nix/var/log/nix" : settings.nixLogDir, rootDir != "" ? rootDir + "/nix/var/log/nix" : settings.nixLogDir,
"log", "directory where Nix will store state"}; "log", "directory where Nix will store state"};
};
class LocalFSStore : public virtual Store, public virtual LocalFSStoreConfig
{
public:
const static string drvsLogDir; const static string drvsLogDir;
@ -730,37 +791,47 @@ ref<Store> openStore(const std::string & uri = settings.storeUri.get(),
const Store::Params & extraParams = Store::Params()); const Store::Params & extraParams = Store::Params());
enum StoreType {
tDaemon,
tLocal,
tOther
};
StoreType getStoreType(const std::string & uri = settings.storeUri.get(),
const std::string & stateDir = settings.nixStateDir);
/* Return the default substituter stores, defined by the /* Return the default substituter stores, defined by the
substituters option and various legacy options. */ substituters option and various legacy options. */
std::list<ref<Store>> getDefaultSubstituters(); std::list<ref<Store>> getDefaultSubstituters();
struct StoreFactory
/* Store implementation registration. */
typedef std::function<std::shared_ptr<Store>(
const std::string & uri, const Store::Params & params)> OpenStore;
struct RegisterStoreImplementation
{ {
typedef std::vector<OpenStore> Implementations; std::set<std::string> uriSchemes;
static Implementations * implementations; std::function<std::shared_ptr<Store> (const std::string & scheme, const std::string & uri, const Store::Params & params)> create;
std::function<std::shared_ptr<StoreConfig> ()> getConfig;
};
struct Implementations
{
static std::vector<StoreFactory> * registered;
RegisterStoreImplementation(OpenStore fun) template<typename T, typename TConfig>
static void add()
{ {
if (!implementations) implementations = new Implementations; if (!registered) registered = new std::vector<StoreFactory>();
implementations->push_back(fun); StoreFactory factory{
.uriSchemes = T::uriSchemes(),
.create =
([](const std::string & scheme, const std::string & uri, const Store::Params & params)
-> std::shared_ptr<Store>
{ return std::make_shared<T>(scheme, uri, params); }),
.getConfig =
([]()
-> std::shared_ptr<StoreConfig>
{ return std::make_shared<TConfig>(StringMap({})); })
};
registered->push_back(factory);
} }
}; };
template<typename T, typename TConfig>
struct RegisterStoreImplementation
{
RegisterStoreImplementation()
{
Implementations::add<T, TConfig>();
}
};
/* Display a set of paths in human-readable form (i.e., between quotes /* Display a set of paths in human-readable form (i.e., between quotes

View file

@ -0,0 +1,15 @@
#pragma once
#include <nlohmann/json.hpp>
#include "config.hh"
namespace nix {
template<typename T>
std::map<std::string, nlohmann::json> BaseSetting<T>::toJSONObject()
{
auto obj = AbstractSetting::toJSONObject();
obj.emplace("value", value);
obj.emplace("defaultValue", defaultValue);
return obj;
}
}

View file

@ -1,5 +1,6 @@
#include "config.hh" #include "config.hh"
#include "args.hh" #include "args.hh"
#include "abstractsettingtojson.hh"
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
@ -137,11 +138,7 @@ nlohmann::json Config::toJSON()
auto res = nlohmann::json::object(); auto res = nlohmann::json::object();
for (auto & s : _settings) for (auto & s : _settings)
if (!s.second.isAlias) { if (!s.second.isAlias) {
auto obj = nlohmann::json::object(); res.emplace(s.first, s.second.setting->toJSON());
obj.emplace("description", s.second.setting->description);
obj.emplace("aliases", s.second.setting->aliases);
obj.emplace("value", s.second.setting->toJSON());
res.emplace(s.first, obj);
} }
return res; return res;
} }
@ -168,19 +165,21 @@ void AbstractSetting::setDefault(const std::string & str)
nlohmann::json AbstractSetting::toJSON() nlohmann::json AbstractSetting::toJSON()
{ {
return to_string(); return nlohmann::json(toJSONObject());
}
std::map<std::string, nlohmann::json> AbstractSetting::toJSONObject()
{
std::map<std::string, nlohmann::json> obj;
obj.emplace("description", description);
obj.emplace("aliases", aliases);
return obj;
} }
void AbstractSetting::convertToArg(Args & args, const std::string & category) void AbstractSetting::convertToArg(Args & args, const std::string & category)
{ {
} }
template<typename T>
nlohmann::json BaseSetting<T>::toJSON()
{
return value;
}
template<typename T> template<typename T>
void BaseSetting<T>::convertToArg(Args & args, const std::string & category) void BaseSetting<T>::convertToArg(Args & args, const std::string & category)
{ {
@ -259,11 +258,6 @@ template<> std::string BaseSetting<Strings>::to_string() const
return concatStringsSep(" ", value); return concatStringsSep(" ", value);
} }
template<> nlohmann::json BaseSetting<Strings>::toJSON()
{
return value;
}
template<> void BaseSetting<StringSet>::set(const std::string & str) template<> void BaseSetting<StringSet>::set(const std::string & str)
{ {
value = tokenizeString<StringSet>(str); value = tokenizeString<StringSet>(str);
@ -274,11 +268,6 @@ template<> std::string BaseSetting<StringSet>::to_string() const
return concatStringsSep(" ", value); return concatStringsSep(" ", value);
} }
template<> nlohmann::json BaseSetting<StringSet>::toJSON()
{
return value;
}
template class BaseSetting<int>; template class BaseSetting<int>;
template class BaseSetting<unsigned int>; template class BaseSetting<unsigned int>;
template class BaseSetting<long>; template class BaseSetting<long>;

View file

@ -206,7 +206,9 @@ protected:
virtual std::string to_string() const = 0; virtual std::string to_string() const = 0;
virtual nlohmann::json toJSON(); nlohmann::json toJSON();
virtual std::map<std::string, nlohmann::json> toJSONObject();
virtual void convertToArg(Args & args, const std::string & category); virtual void convertToArg(Args & args, const std::string & category);
@ -220,6 +222,7 @@ class BaseSetting : public AbstractSetting
protected: protected:
T value; T value;
const T defaultValue;
public: public:
@ -229,6 +232,7 @@ public:
const std::set<std::string> & aliases = {}) const std::set<std::string> & aliases = {})
: AbstractSetting(name, description, aliases) : AbstractSetting(name, description, aliases)
, value(def) , value(def)
, defaultValue(def)
{ } { }
operator const T &() const { return value; } operator const T &() const { return value; }
@ -251,7 +255,7 @@ public:
void convertToArg(Args & args, const std::string & category) override; void convertToArg(Args & args, const std::string & category) override;
nlohmann::json toJSON() override; std::map<std::string, nlohmann::json> toJSONObject() override;
}; };
template<typename T> template<typename T>

View file

@ -161,7 +161,7 @@ namespace nix {
Setting<std::string> setting{&config, "", "name-of-the-setting", "description"}; Setting<std::string> setting{&config, "", "name-of-the-setting", "description"};
setting.assign("value"); setting.assign("value");
ASSERT_EQ(config.toJSON().dump(), R"#({"name-of-the-setting":{"aliases":[],"description":"description\n","value":"value"}})#"); ASSERT_EQ(config.toJSON().dump(), R"#({"name-of-the-setting":{"aliases":[],"defaultValue":"","description":"description\n","value":"value"}})#");
} }
TEST(Config, setSettingAlias) { TEST(Config, setSettingAlias) {

View file

@ -31,7 +31,7 @@ ParsedURL parseURL(const std::string & url);
// URI stuff. // URI stuff.
const static std::string pctEncoded = "(?:%[0-9a-fA-F][0-9a-fA-F])"; const static std::string pctEncoded = "(?:%[0-9a-fA-F][0-9a-fA-F])";
const static std::string schemeRegex = "(?:[a-z+]+)"; const static std::string schemeRegex = "(?:[a-z+.-]+)";
const static std::string ipv6AddressRegex = "(?:\\[[0-9a-fA-F:]+\\])"; const static std::string ipv6AddressRegex = "(?:\\[[0-9a-fA-F:]+\\])";
const static std::string unreservedRegex = "(?:[a-zA-Z0-9-._~])"; const static std::string unreservedRegex = "(?:[a-zA-Z0-9-._~])";
const static std::string subdelimsRegex = "(?:[!$&'\"()*+,;=])"; const static std::string subdelimsRegex = "(?:[!$&'\"()*+,;=])";

View file

@ -76,6 +76,13 @@ static void update(const StringSet & channelNames)
auto store = openStore(); auto store = openStore();
auto [fd, unpackChannelPath] = createTempFile();
writeFull(fd.get(),
#include "unpack-channel.nix.gen.hh"
);
fd = -1;
AutoDelete del(unpackChannelPath, false);
// Download each channel. // Download each channel.
Strings exprs; Strings exprs;
for (const auto & channel : channels) { for (const auto & channel : channels) {
@ -104,7 +111,7 @@ static void update(const StringSet & channelNames)
bool unpacked = false; bool unpacked = false;
if (std::regex_search(filename, std::regex("\\.tar\\.(gz|bz2|xz)$"))) { if (std::regex_search(filename, std::regex("\\.tar\\.(gz|bz2|xz)$"))) {
runProgram(settings.nixBinDir + "/nix-build", false, { "--no-out-link", "--expr", "import <nix/unpack-channel.nix> " runProgram(settings.nixBinDir + "/nix-build", false, { "--no-out-link", "--expr", "import " + unpackChannelPath +
"{ name = \"" + cname + "\"; channelName = \"" + name + "\"; src = builtins.storePath \"" + filename + "\"; }" }); "{ name = \"" + cname + "\"; channelName = \"" + name + "\"; src = builtins.storePath \"" + filename + "\"; }" });
unpacked = true; unpacked = true;
} }
@ -125,7 +132,7 @@ static void update(const StringSet & channelNames)
// Unpack the channel tarballs into the Nix store and install them // Unpack the channel tarballs into the Nix store and install them
// into the channels profile. // into the channels profile.
std::cerr << "unpacking channels...\n"; std::cerr << "unpacking channels...\n";
Strings envArgs{ "--profile", profile, "--file", "<nix/unpack-channel.nix>", "--install", "--from-expression" }; Strings envArgs{ "--profile", profile, "--file", unpackChannelPath, "--install", "--from-expression" };
for (auto & expr : exprs) for (auto & expr : exprs)
envArgs.push_back(std::move(expr)); envArgs.push_back(std::move(expr));
envArgs.push_back("--quiet"); envArgs.push_back("--quiet");

View file

@ -1,5 +1,6 @@
#include "shared.hh" #include "shared.hh"
#include "local-store.hh" #include "local-store.hh"
#include "remote-store.hh"
#include "util.hh" #include "util.hh"
#include "serialise.hh" #include "serialise.hh"
#include "archive.hh" #include "archive.hh"
@ -285,44 +286,28 @@ static int _main(int argc, char * * argv)
initPlugins(); initPlugins();
if (stdio) { if (stdio) {
if (getStoreType() == tDaemon) { if (auto store = openUncachedStore().dynamic_pointer_cast<RemoteStore>()) {
// Forward on this connection to the real daemon auto conn = store->openConnectionWrapper();
auto socketPath = settings.nixDaemonSocketFile; int from = conn->from.fd;
auto s = socket(PF_UNIX, SOCK_STREAM, 0); int to = conn->to.fd;
if (s == -1)
throw SysError("creating Unix domain socket");
auto socketDir = dirOf(socketPath); auto nfds = std::max(from, STDIN_FILENO) + 1;
if (chdir(socketDir.c_str()) == -1)
throw SysError("changing to socket directory '%1%'", socketDir);
auto socketName = std::string(baseNameOf(socketPath));
auto addr = sockaddr_un{};
addr.sun_family = AF_UNIX;
if (socketName.size() + 1 >= sizeof(addr.sun_path))
throw Error("socket name %1% is too long", socketName);
strcpy(addr.sun_path, socketName.c_str());
if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) == -1)
throw SysError("cannot connect to daemon at %1%", socketPath);
auto nfds = (s > STDIN_FILENO ? s : STDIN_FILENO) + 1;
while (true) { while (true) {
fd_set fds; fd_set fds;
FD_ZERO(&fds); FD_ZERO(&fds);
FD_SET(s, &fds); FD_SET(from, &fds);
FD_SET(STDIN_FILENO, &fds); FD_SET(STDIN_FILENO, &fds);
if (select(nfds, &fds, nullptr, nullptr, nullptr) == -1) if (select(nfds, &fds, nullptr, nullptr, nullptr) == -1)
throw SysError("waiting for data from client or server"); throw SysError("waiting for data from client or server");
if (FD_ISSET(s, &fds)) { if (FD_ISSET(from, &fds)) {
auto res = splice(s, nullptr, STDOUT_FILENO, nullptr, SSIZE_MAX, SPLICE_F_MOVE); auto res = splice(from, nullptr, STDOUT_FILENO, nullptr, SSIZE_MAX, SPLICE_F_MOVE);
if (res == -1) if (res == -1)
throw SysError("splicing data from daemon socket to stdout"); throw SysError("splicing data from daemon socket to stdout");
else if (res == 0) else if (res == 0)
throw EndOfFile("unexpected EOF from daemon socket"); throw EndOfFile("unexpected EOF from daemon socket");
} }
if (FD_ISSET(STDIN_FILENO, &fds)) { if (FD_ISSET(STDIN_FILENO, &fds)) {
auto res = splice(STDIN_FILENO, nullptr, s, nullptr, SSIZE_MAX, SPLICE_F_MOVE); auto res = splice(STDIN_FILENO, nullptr, to, nullptr, SSIZE_MAX, SPLICE_F_MOVE);
if (res == -1) if (res == -1)
throw SysError("splicing data from stdin to daemon socket"); throw SysError("splicing data from stdin to daemon socket");
else if (res == 0) else if (res == 0)

View file

@ -0,0 +1,44 @@
#include "command.hh"
#include "common-args.hh"
#include "shared.hh"
#include "store-api.hh"
#include <nlohmann/json.hpp>
using namespace nix;
struct CmdDescribeStores : Command, MixJSON
{
std::string description() override
{
return "show registered store types and their available options";
}
Category category() override { return catUtility; }
void run() override
{
auto res = nlohmann::json::object();
for (auto & implem : *Implementations::registered) {
auto storeConfig = implem.getConfig();
auto storeName = storeConfig->name();
res[storeName] = storeConfig->toJSON();
}
if (json) {
std::cout << res;
} else {
for (auto & [storeName, storeConfig] : res.items()) {
std::cout << "## " << storeName << std::endl << std::endl;
for (auto & [optionName, optionDesc] : storeConfig.items()) {
std::cout << "### " << optionName << std::endl << std::endl;
std::cout << optionDesc["description"].get<std::string>() << std::endl;
std::cout << "default: " << optionDesc["defaultValue"] << std::endl <<std::endl;
if (!optionDesc["aliases"].empty())
std::cout << "aliases: " << optionDesc["aliases"] << std::endl << std::endl;
}
}
}
}
};
static auto r1 = registerCommand<CmdDescribeStores>("describe-stores");

View file

@ -392,7 +392,7 @@ struct CmdDevelop : Common, MixEnvironment
auto bashInstallable = std::make_shared<InstallableFlake>( auto bashInstallable = std::make_shared<InstallableFlake>(
state, state,
std::move(installable->nixpkgsFlakeRef()), installable->nixpkgsFlakeRef(),
Strings{"bashInteractive"}, Strings{"bashInteractive"},
Strings{"legacyPackages." + settings.thisSystem.get() + "."}, Strings{"legacyPackages." + settings.thisSystem.get() + "."},
lockFlags); lockFlags);

View file

@ -81,7 +81,7 @@ void printClosureDiff(
auto beforeSize = totalSize(beforeVersions); auto beforeSize = totalSize(beforeVersions);
auto afterSize = totalSize(afterVersions); auto afterSize = totalSize(afterVersions);
auto sizeDelta = (int64_t) afterSize - (int64_t) beforeSize; auto sizeDelta = (int64_t) afterSize - (int64_t) beforeSize;
auto showDelta = abs(sizeDelta) >= 8 * 1024; auto showDelta = std::abs(sizeDelta) >= 8 * 1024;
std::set<std::string> removed, unchanged; std::set<std::string> removed, unchanged;
for (auto & [version, _] : beforeVersions) for (auto & [version, _] : beforeVersions)

View file

@ -49,9 +49,7 @@ struct CmdDoctor : StoreCommand
{ {
logger->log("Running checks against store uri: " + store->getUri()); logger->log("Running checks against store uri: " + store->getUri());
auto type = getStoreType(); if (store.dynamic_pointer_cast<LocalFSStore>()) {
if (type < tOther) {
success &= checkNixInPath(); success &= checkNixInPath();
success &= checkProfileRoots(store); success &= checkProfileRoots(store);
} }

View file

@ -69,7 +69,7 @@ struct Installable
virtual FlakeRef nixpkgsFlakeRef() const virtual FlakeRef nixpkgsFlakeRef() const
{ {
return std::move(FlakeRef::fromAttrs({{"type","indirect"}, {"id", "nixpkgs"}})); return FlakeRef::fromAttrs({{"type","indirect"}, {"id", "nixpkgs"}});
} }
}; };

View file

@ -29,3 +29,5 @@ $(eval $(call install-symlink, $(bindir)/nix, $(libexecdir)/nix/build-remote))
src/nix-env/user-env.cc: src/nix-env/buildenv.nix.gen.hh src/nix-env/user-env.cc: src/nix-env/buildenv.nix.gen.hh
src/nix/develop.cc: src/nix/get-env.sh.gen.hh src/nix/develop.cc: src/nix/get-env.sh.gen.hh
src/nix-channel/nix-channel.cc: src/nix-channel/unpack-channel.nix.gen.hh

View file

@ -185,6 +185,7 @@ void mainWrapped(int argc, char * * argv)
} }
if (argc == 2 && std::string(argv[1]) == "__dump-builtins") { if (argc == 2 && std::string(argv[1]) == "__dump-builtins") {
evalSettings.pureEval = false;
EvalState state({}, openStore("dummy://")); EvalState state({}, openStore("dummy://"));
auto res = nlohmann::json::object(); auto res = nlohmann::json::object();
auto builtins = state.baseEnv.values[0]->attrs; auto builtins = state.baseEnv.values[0]->attrs;

View file

@ -22,3 +22,6 @@ secondSeedArgs=(-j0)
# dependent derivations always being already built. # dependent derivations always being already built.
#testDerivation dependentCA #testDerivation dependentCA
testDerivation transitivelyDependentCA testDerivation transitivelyDependentCA
nix-instantiate --experimental-features ca-derivations ./content-addressed.nix -A rootCA --arg seed 5
nix-collect-garbage --experimental-features ca-derivations --option keep-derivations true

8
tests/describe-stores.sh Normal file
View file

@ -0,0 +1,8 @@
source common.sh
# Query an arbitrary value in `nix describe-stores --json`'s output just to
# check that it has the right structure
[[ $(nix --experimental-features 'nix-command flakes' describe-stores --json | jq '.["SSH Store"]["compress"]["defaultValue"]') == false ]]
# Ensure that the output of `nix describe-stores` isn't empty
[[ -n $(nix --experimental-features 'nix-command flakes' describe-stores) ]]

View file

@ -15,6 +15,7 @@ nix_tests = \
linux-sandbox.sh \ linux-sandbox.sh \
build-dry.sh \ build-dry.sh \
build-remote-input-addressed.sh \ build-remote-input-addressed.sh \
ssh-relay.sh \
nar-access.sh \ nar-access.sh \
structured-attrs.sh \ structured-attrs.sh \
fetchGit.sh \ fetchGit.sh \
@ -32,6 +33,7 @@ nix_tests = \
post-hook.sh \ post-hook.sh \
function-trace.sh \ function-trace.sh \
recursive.sh \ recursive.sh \
describe-stores.sh \
flakes.sh \ flakes.sh \
content-addressed.sh content-addressed.sh
# parallel.sh # parallel.sh

View file

@ -9,9 +9,8 @@ rm -f $TEST_ROOT/result
export unreachable=$(nix add-to-store ./recursive.sh) export unreachable=$(nix add-to-store ./recursive.sh)
nix --experimental-features 'nix-command recursive-nix' build -o $TEST_ROOT/result -L --impure --expr ' NIX_BIN_DIR=$(dirname $(type -p nix)) nix --experimental-features 'nix-command recursive-nix' build -o $TEST_ROOT/result -L --impure --expr '
with import ./config.nix; with import ./config.nix;
with import <nix/config.nix>;
mkDerivation { mkDerivation {
name = "recursive"; name = "recursive";
dummy = builtins.toFile "dummy" "bla bla"; dummy = builtins.toFile "dummy" "bla bla";
@ -24,9 +23,10 @@ nix --experimental-features 'nix-command recursive-nix' build -o $TEST_ROOT/resu
buildCommand = '\'\'' buildCommand = '\'\''
mkdir $out mkdir $out
PATH=${nixBinDir}:$PATH
opts="--experimental-features nix-command" opts="--experimental-features nix-command"
PATH=${builtins.getEnv "NIX_BIN_DIR"}:$PATH
# Check that we can query/build paths in our input closure. # Check that we can query/build paths in our input closure.
nix $opts path-info $dummy nix $opts path-info $dummy
nix $opts build $dummy nix $opts build $dummy

16
tests/ssh-relay.sh Normal file
View file

@ -0,0 +1,16 @@
source common.sh
echo foo > $TEST_ROOT/hello.sh
ssh_localhost=ssh://localhost
remote_store=?remote-store=$ssh_localhost
store=$ssh_localhost
store+=$remote_store
store+=$remote_store
store+=$remote_store
out=$(nix add-to-store --store "$store" $TEST_ROOT/hello.sh)
[ foo = $(< $out) ]