Merge pull request #6197 from edolstra/nix-profile-ca

nix profile: Support CA derivations
This commit is contained in:
Eelco Dolstra 2022-03-02 23:48:52 +01:00 committed by GitHub
commit 3e3d0711d4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 170 additions and 152 deletions

View file

@ -28,7 +28,7 @@ run_test "$1"
# See https://github.com/NixOS/nix/issues/3605 for more info # See https://github.com/NixOS/nix/issues/3605 for more info
if [[ $status -ne 0 && $status -ne 99 && \ if [[ $status -ne 0 && $status -ne 99 && \
"$(uname)" == "Darwin" && \ "$(uname)" == "Darwin" && \
"$log" =~ "unexpected EOF reading a line" "$log" =~ "unexpected EOF reading a line" \
]]; then ]]; then
echo "$post_run_msg [${yellow}FAIL$normal] (possibly flaky, so will be retried)" echo "$post_run_msg [${yellow}FAIL$normal] (possibly flaky, so will be retried)"
echo "$log" | sed 's/^/ /' echo "$log" | sed 's/^/ /'

View file

@ -153,7 +153,7 @@ void BuiltPathsCommand::run(ref<Store> store)
for (auto & p : store->queryAllValidPaths()) for (auto & p : store->queryAllValidPaths())
paths.push_back(BuiltPath::Opaque{p}); paths.push_back(BuiltPath::Opaque{p});
} else { } else {
paths = toBuiltPaths(getEvalStore(), store, realiseMode, operateOn, installables); paths = Installable::toBuiltPaths(getEvalStore(), store, realiseMode, operateOn, installables);
if (recursive) { if (recursive) {
// XXX: This only computes the store path closure, ignoring // XXX: This only computes the store path closure, ignoring
// intermediate realisations // intermediate realisations

View file

@ -5,7 +5,6 @@
#include "common-eval-args.hh" #include "common-eval-args.hh"
#include "path.hh" #include "path.hh"
#include "flake/lockfile.hh" #include "flake/lockfile.hh"
#include "store-api.hh"
#include <optional> #include <optional>
@ -82,14 +81,6 @@ struct MixFlakeOptions : virtual Args, EvalCommand
{ return {}; } { return {}; }
}; };
/* How to handle derivations in commands that operate on store paths. */
enum class OperateOn {
/* Operate on the output path. */
Output,
/* Operate on the .drv path. */
Derivation
};
struct SourceExprCommand : virtual Args, MixFlakeOptions struct SourceExprCommand : virtual Args, MixFlakeOptions
{ {
std::optional<Path> file; std::optional<Path> file;
@ -113,19 +104,6 @@ struct SourceExprCommand : virtual Args, MixFlakeOptions
void completeInstallable(std::string_view prefix); void completeInstallable(std::string_view prefix);
}; };
enum class Realise {
/* Build the derivation. Postcondition: the
derivation outputs exist. */
Outputs,
/* Don't build the derivation. Postcondition: the store derivation
exists. */
Derivation,
/* Evaluate in dry-run mode. Postcondition: nothing. */
// FIXME: currently unused, but could be revived if we can
// evaluate derivations in-memory.
Nothing
};
/* A command that operates on a list of "installables", which can be /* A command that operates on a list of "installables", which can be
store paths, attribute paths, Nix expressions, etc. */ store paths, attribute paths, Nix expressions, etc. */
struct InstallablesCommand : virtual Args, SourceExprCommand struct InstallablesCommand : virtual Args, SourceExprCommand
@ -238,38 +216,6 @@ static RegisterCommand registerCommand2(std::vector<std::string> && name)
return RegisterCommand(std::move(name), [](){ return make_ref<T>(); }); return RegisterCommand(std::move(name), [](){ return make_ref<T>(); });
} }
BuiltPaths build(
ref<Store> evalStore,
ref<Store> store, Realise mode,
const std::vector<std::shared_ptr<Installable>> & installables,
BuildMode bMode = bmNormal);
std::set<StorePath> toStorePaths(
ref<Store> evalStore,
ref<Store> store,
Realise mode,
OperateOn operateOn,
const std::vector<std::shared_ptr<Installable>> & installables);
StorePath toStorePath(
ref<Store> evalStore,
ref<Store> store,
Realise mode,
OperateOn operateOn,
std::shared_ptr<Installable> installable);
std::set<StorePath> toDerivations(
ref<Store> store,
const std::vector<std::shared_ptr<Installable>> & installables,
bool useDeriver = false);
BuiltPaths toBuiltPaths(
ref<Store> evalStore,
ref<Store> store,
Realise mode,
OperateOn operateOn,
const std::vector<std::shared_ptr<Installable>> & installables);
/* Helper function to generate args that invoke $EDITOR on /* Helper function to generate args that invoke $EDITOR on
filename:lineno. */ filename:lineno. */
Strings editorFor(const Pos & pos); Strings editorFor(const Pos & pos);

View file

@ -470,7 +470,6 @@ std::vector<InstallableValue::DerivationInfo> InstallableAttrPath::toDerivations
for (auto & drvInfo : drvInfos) { for (auto & drvInfo : drvInfos) {
res.push_back({ res.push_back({
state->store->parseStorePath(drvInfo.queryDrvPath()), state->store->parseStorePath(drvInfo.queryDrvPath()),
state->store->maybeParseStorePath(drvInfo.queryOutPath()),
drvInfo.queryOutputName() drvInfo.queryOutputName()
}); });
} }
@ -584,9 +583,8 @@ std::tuple<std::string, FlakeRef, InstallableValue::DerivationInfo> InstallableF
auto drvPath = attr->forceDerivation(); auto drvPath = attr->forceDerivation();
auto drvInfo = DerivationInfo{ auto drvInfo = DerivationInfo {
std::move(drvPath), std::move(drvPath),
state->store->maybeParseStorePath(attr->getAttr(state->sOutPath)->getString()),
attr->getAttr(state->sOutputName)->getString() attr->getAttr(state->sOutputName)->getString()
}; };
@ -787,7 +785,7 @@ BuiltPaths getBuiltPaths(ref<Store> evalStore, ref<Store> store, const DerivedPa
return res; return res;
} }
BuiltPaths build( BuiltPaths Installable::build(
ref<Store> evalStore, ref<Store> evalStore,
ref<Store> store, ref<Store> store,
Realise mode, Realise mode,
@ -812,7 +810,7 @@ BuiltPaths build(
return getBuiltPaths(evalStore, store, pathsToBuild); return getBuiltPaths(evalStore, store, pathsToBuild);
} }
BuiltPaths toBuiltPaths( BuiltPaths Installable::toBuiltPaths(
ref<Store> evalStore, ref<Store> evalStore,
ref<Store> store, ref<Store> store,
Realise mode, Realise mode,
@ -820,19 +818,19 @@ BuiltPaths toBuiltPaths(
const std::vector<std::shared_ptr<Installable>> & installables) const std::vector<std::shared_ptr<Installable>> & installables)
{ {
if (operateOn == OperateOn::Output) if (operateOn == OperateOn::Output)
return build(evalStore, store, mode, installables); return Installable::build(evalStore, store, mode, installables);
else { else {
if (mode == Realise::Nothing) if (mode == Realise::Nothing)
settings.readOnlyMode = true; settings.readOnlyMode = true;
BuiltPaths res; BuiltPaths res;
for (auto & drvPath : toDerivations(store, installables, true)) for (auto & drvPath : Installable::toDerivations(store, installables, true))
res.push_back(BuiltPath::Opaque{drvPath}); res.push_back(BuiltPath::Opaque{drvPath});
return res; return res;
} }
} }
StorePathSet toStorePaths( StorePathSet Installable::toStorePaths(
ref<Store> evalStore, ref<Store> evalStore,
ref<Store> store, ref<Store> store,
Realise mode, OperateOn operateOn, Realise mode, OperateOn operateOn,
@ -846,7 +844,7 @@ StorePathSet toStorePaths(
return outPaths; return outPaths;
} }
StorePath toStorePath( StorePath Installable::toStorePath(
ref<Store> evalStore, ref<Store> evalStore,
ref<Store> store, ref<Store> store,
Realise mode, OperateOn operateOn, Realise mode, OperateOn operateOn,
@ -860,7 +858,7 @@ StorePath toStorePath(
return *paths.begin(); return *paths.begin();
} }
StorePathSet toDerivations( StorePathSet Installable::toDerivations(
ref<Store> store, ref<Store> store,
const std::vector<std::shared_ptr<Installable>> & installables, const std::vector<std::shared_ptr<Installable>> & installables,
bool useDeriver) bool useDeriver)

View file

@ -5,6 +5,7 @@
#include "path-with-outputs.hh" #include "path-with-outputs.hh"
#include "derived-path.hh" #include "derived-path.hh"
#include "eval.hh" #include "eval.hh"
#include "store-api.hh"
#include "flake/flake.hh" #include "flake/flake.hh"
#include <optional> #include <optional>
@ -29,6 +30,27 @@ struct UnresolvedApp
App resolve(ref<Store> evalStore, ref<Store> store); App resolve(ref<Store> evalStore, ref<Store> store);
}; };
enum class Realise {
/* Build the derivation. Postcondition: the
derivation outputs exist. */
Outputs,
/* Don't build the derivation. Postcondition: the store derivation
exists. */
Derivation,
/* Evaluate in dry-run mode. Postcondition: nothing. */
// FIXME: currently unused, but could be revived if we can
// evaluate derivations in-memory.
Nothing
};
/* How to handle derivations in commands that operate on store paths. */
enum class OperateOn {
/* Operate on the output path. */
Output,
/* Operate on the .drv path. */
Derivation
};
struct Installable struct Installable
{ {
virtual ~Installable() { } virtual ~Installable() { }
@ -68,6 +90,39 @@ struct Installable
{ {
return FlakeRef::fromAttrs({{"type","indirect"}, {"id", "nixpkgs"}}); return FlakeRef::fromAttrs({{"type","indirect"}, {"id", "nixpkgs"}});
} }
static BuiltPaths build(
ref<Store> evalStore,
ref<Store> store,
Realise mode,
const std::vector<std::shared_ptr<Installable>> & installables,
BuildMode bMode = bmNormal);
static std::set<StorePath> toStorePaths(
ref<Store> evalStore,
ref<Store> store,
Realise mode,
OperateOn operateOn,
const std::vector<std::shared_ptr<Installable>> & installables);
static StorePath toStorePath(
ref<Store> evalStore,
ref<Store> store,
Realise mode,
OperateOn operateOn,
std::shared_ptr<Installable> installable);
static std::set<StorePath> toDerivations(
ref<Store> store,
const std::vector<std::shared_ptr<Installable>> & installables,
bool useDeriver = false);
static BuiltPaths toBuiltPaths(
ref<Store> evalStore,
ref<Store> store,
Realise mode,
OperateOn operateOn,
const std::vector<std::shared_ptr<Installable>> & installables);
}; };
struct InstallableValue : Installable struct InstallableValue : Installable
@ -79,7 +134,6 @@ struct InstallableValue : Installable
struct DerivationInfo struct DerivationInfo
{ {
StorePath drvPath; StorePath drvPath;
std::optional<StorePath> outPath;
std::string outputName; std::string outputName;
}; };
@ -131,4 +185,9 @@ ref<eval_cache::EvalCache> openEvalCache(
EvalState & state, EvalState & state,
std::shared_ptr<flake::LockedFlake> lockedFlake); std::shared_ptr<flake::LockedFlake> lockedFlake);
BuiltPaths getBuiltPaths(
ref<Store> evalStore,
ref<Store> store,
const DerivedPaths & hopefullyBuiltPaths);
} }

View file

@ -114,7 +114,7 @@ App UnresolvedApp::resolve(ref<Store> evalStore, ref<Store> store)
installableContext.push_back( installableContext.push_back(
std::make_shared<InstallableDerivedPath>(store, ctxElt.toDerivedPath())); std::make_shared<InstallableDerivedPath>(store, ctxElt.toDerivedPath()));
auto builtContext = build(evalStore, store, Realise::Outputs, installableContext); auto builtContext = Installable::build(evalStore, store, Realise::Outputs, installableContext);
res.program = resolveString(*store, unresolved.program, builtContext); res.program = resolveString(*store, unresolved.program, builtContext);
if (!store->isInStore(res.program)) if (!store->isInStore(res.program))
throw Error("app program '%s' is not in the Nix store", res.program); throw Error("app program '%s' is not in the Nix store", res.program);

View file

@ -52,7 +52,7 @@ struct CmdBuild : InstallablesCommand, MixDryRun, MixJSON, MixProfile
void run(ref<Store> store) override void run(ref<Store> store) override
{ {
auto buildables = build( auto buildables = Installable::build(
getEvalStore(), store, getEvalStore(), store,
dryRun ? Realise::Derivation : Realise::Outputs, dryRun ? Realise::Derivation : Realise::Outputs,
installables, buildMode); installables, buildMode);

View file

@ -307,7 +307,7 @@ struct Common : InstallableCommand, MixProfile
for (auto & [installable_, dir_] : redirects) { for (auto & [installable_, dir_] : redirects) {
auto dir = absPath(dir_); auto dir = absPath(dir_);
auto installable = parseInstallable(store, installable_); auto installable = parseInstallable(store, installable_);
auto builtPaths = toStorePaths( auto builtPaths = Installable::toStorePaths(
getEvalStore(), store, Realise::Nothing, OperateOn::Output, {installable}); getEvalStore(), store, Realise::Nothing, OperateOn::Output, {installable});
for (auto & path: builtPaths) { for (auto & path: builtPaths) {
auto from = store->printStorePath(path); auto from = store->printStorePath(path);
@ -347,7 +347,7 @@ struct Common : InstallableCommand, MixProfile
if (path && hasSuffix(path->to_string(), "-env")) if (path && hasSuffix(path->to_string(), "-env"))
return *path; return *path;
else { else {
auto drvs = toDerivations(store, {installable}); auto drvs = Installable::toDerivations(store, {installable});
if (drvs.size() != 1) if (drvs.size() != 1)
throw Error("'%s' needs to evaluate to a single derivation, but it evaluated to %d derivations", throw Error("'%s' needs to evaluate to a single derivation, but it evaluated to %d derivations",
@ -511,7 +511,8 @@ struct CmdDevelop : Common, MixEnvironment
nixpkgsLockFlags); nixpkgsLockFlags);
shell = store->printStorePath( shell = store->printStorePath(
toStorePath(getEvalStore(), store, Realise::Outputs, OperateOn::Output, bashInstallable)) + "/bin/bash"; Installable::toStorePath(getEvalStore(), store, Realise::Outputs, OperateOn::Output, bashInstallable))
+ "/bin/bash";
} catch (Error &) { } catch (Error &) {
ignoreException(); ignoreException();
} }

View file

@ -131,9 +131,9 @@ struct CmdDiffClosures : SourceExprCommand
void run(ref<Store> store) override void run(ref<Store> store) override
{ {
auto before = parseInstallable(store, _before); auto before = parseInstallable(store, _before);
auto beforePath = toStorePath(getEvalStore(), store, Realise::Outputs, operateOn, before); auto beforePath = Installable::toStorePath(getEvalStore(), store, Realise::Outputs, operateOn, before);
auto after = parseInstallable(store, _after); auto after = parseInstallable(store, _after);
auto afterPath = toStorePath(getEvalStore(), store, Realise::Outputs, operateOn, after); auto afterPath = Installable::toStorePath(getEvalStore(), store, Realise::Outputs, operateOn, after);
printClosureDiff(store, beforePath, afterPath, ""); printClosureDiff(store, beforePath, afterPath, "");
} }
}; };

View file

@ -61,6 +61,27 @@ struct ProfileElement
{ {
return std::tuple(describe(), storePaths) < std::tuple(other.describe(), other.storePaths); return std::tuple(describe(), storePaths) < std::tuple(other.describe(), other.storePaths);
} }
void updateStorePaths(ref<Store> evalStore, ref<Store> store, Installable & installable)
{
// FIXME: respect meta.outputsToInstall
storePaths.clear();
for (auto & buildable : getBuiltPaths(evalStore, store, installable.toDerivedPaths())) {
std::visit(overloaded {
[&](const BuiltPath::Opaque & bo) {
storePaths.insert(bo.path);
},
[&](const BuiltPath::Built & bfd) {
// TODO: Why are we querying if we know the output
// names already? Is it just to figure out what the
// default one is?
for (auto & output : store->queryDerivationOutputMap(bfd.drvPath)) {
storePaths.insert(output.second);
}
},
}, buildable.raw());
}
}
}; };
struct ProfileManifest struct ProfileManifest
@ -232,53 +253,25 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile
{ {
ProfileManifest manifest(*getEvalState(), *profile); ProfileManifest manifest(*getEvalState(), *profile);
std::vector<DerivedPath> pathsToBuild; auto builtPaths = Installable::build(getEvalStore(), store, Realise::Outputs, installables, bmNormal);
for (auto & installable : installables) { for (auto & installable : installables) {
if (auto installable2 = std::dynamic_pointer_cast<InstallableFlake>(installable)) { ProfileElement element;
auto [attrPath, resolvedRef, drv] = installable2->toDerivation();
ProfileElement element; if (auto installable2 = std::dynamic_pointer_cast<InstallableFlake>(installable)) {
if (!drv.outPath) // FIXME: make build() return this?
throw UnimplementedError("CA derivations are not yet supported by 'nix profile'"); auto [attrPath, resolvedRef, drv] = installable2->toDerivation();
element.storePaths = {*drv.outPath}; // FIXME
element.source = ProfileElementSource{ element.source = ProfileElementSource{
installable2->flakeRef, installable2->flakeRef,
resolvedRef, resolvedRef,
attrPath, attrPath,
}; };
pathsToBuild.push_back(DerivedPath::Built{drv.drvPath, StringSet{drv.outputName}});
manifest.elements.emplace_back(std::move(element));
} else {
auto buildables = build(getEvalStore(), store, Realise::Outputs, {installable}, bmNormal);
for (auto & buildable : buildables) {
ProfileElement element;
std::visit(overloaded {
[&](const BuiltPath::Opaque & bo) {
pathsToBuild.push_back(bo);
element.storePaths.insert(bo.path);
},
[&](const BuiltPath::Built & bfd) {
// TODO: Why are we querying if we know the output
// names already? Is it just to figure out what the
// default one is?
for (auto & output : store->queryDerivationOutputMap(bfd.drvPath)) {
pathsToBuild.push_back(DerivedPath::Built{bfd.drvPath, {output.first}});
element.storePaths.insert(output.second);
}
},
}, buildable.raw());
manifest.elements.emplace_back(std::move(element));
}
} }
}
store->buildPaths(pathsToBuild); element.updateStorePaths(getEvalStore(), store, *installable);
manifest.elements.push_back(std::move(element));
}
updateProfile(manifest.build(store)); updateProfile(manifest.build(store));
} }
@ -407,8 +400,8 @@ struct CmdProfileUpgrade : virtual SourceExprCommand, MixDefaultProfile, MixProf
auto matchers = getMatchers(store); auto matchers = getMatchers(store);
// FIXME: code duplication std::vector<std::shared_ptr<Installable>> installables;
std::vector<DerivedPath> pathsToBuild; std::vector<size_t> indices;
auto upgradedCount = 0; auto upgradedCount = 0;
@ -423,32 +416,30 @@ struct CmdProfileUpgrade : virtual SourceExprCommand, MixDefaultProfile, MixProf
Activity act(*logger, lvlChatty, actUnknown, Activity act(*logger, lvlChatty, actUnknown,
fmt("checking '%s' for updates", element.source->attrPath)); fmt("checking '%s' for updates", element.source->attrPath));
InstallableFlake installable( auto installable = std::make_shared<InstallableFlake>(
this, this,
getEvalState(), getEvalState(),
FlakeRef(element.source->originalRef), FlakeRef(element.source->originalRef),
"", "",
{element.source->attrPath}, Strings{element.source->attrPath},
{}, Strings{},
lockFlags); lockFlags);
auto [attrPath, resolvedRef, drv] = installable.toDerivation(); auto [attrPath, resolvedRef, drv] = installable->toDerivation();
if (element.source->resolvedRef == resolvedRef) continue; if (element.source->resolvedRef == resolvedRef) continue;
printInfo("upgrading '%s' from flake '%s' to '%s'", printInfo("upgrading '%s' from flake '%s' to '%s'",
element.source->attrPath, element.source->resolvedRef, resolvedRef); element.source->attrPath, element.source->resolvedRef, resolvedRef);
if (!drv.outPath)
throw UnimplementedError("CA derivations are not yet supported by 'nix profile'");
element.storePaths = {*drv.outPath}; // FIXME
element.source = ProfileElementSource{ element.source = ProfileElementSource{
installable.flakeRef, installable->flakeRef,
resolvedRef, resolvedRef,
attrPath, attrPath,
}; };
pathsToBuild.push_back(DerivedPath::Built{drv.drvPath, {drv.outputName}}); installables.push_back(installable);
indices.push_back(i);
} }
} }
@ -465,7 +456,13 @@ struct CmdProfileUpgrade : virtual SourceExprCommand, MixDefaultProfile, MixProf
warn ("Use 'nix profile list' to see the current profile."); warn ("Use 'nix profile list' to see the current profile.");
} }
store->buildPaths(pathsToBuild); auto builtPaths = Installable::build(getEvalStore(), store, Realise::Outputs, installables, bmNormal);
for (size_t i = 0; i < installables.size(); ++i) {
auto & installable = installables.at(i);
auto & element = manifest.elements[indices.at(i)];
element.updateStorePaths(getEvalStore(), store, *installable);
}
updateProfile(manifest.build(store)); updateProfile(manifest.build(store));
} }

View file

@ -91,7 +91,7 @@ struct CmdShell : InstallablesCommand, MixEnvironment
void run(ref<Store> store) override void run(ref<Store> store) override
{ {
auto outPaths = toStorePaths(getEvalStore(), store, Realise::Outputs, OperateOn::Output, installables); auto outPaths = Installable::toStorePaths(getEvalStore(), store, Realise::Outputs, OperateOn::Output, installables);
auto accessor = store->getFSAccessor(); auto accessor = store->getFSAccessor();

View file

@ -40,7 +40,7 @@ struct CmdShowDerivation : InstallablesCommand
void run(ref<Store> store) override void run(ref<Store> store) override
{ {
auto drvPaths = toDerivations(store, installables, true); auto drvPaths = Installable::toDerivations(store, installables, true);
if (recursive) { if (recursive) {
StorePathSet closure; StorePathSet closure;

View file

@ -82,9 +82,9 @@ struct CmdWhyDepends : SourceExprCommand
void run(ref<Store> store) override void run(ref<Store> store) override
{ {
auto package = parseInstallable(store, _package); auto package = parseInstallable(store, _package);
auto packagePath = toStorePath(getEvalStore(), store, Realise::Outputs, operateOn, package); auto packagePath = Installable::toStorePath(getEvalStore(), store, Realise::Outputs, operateOn, package);
auto dependency = parseInstallable(store, _dependency); auto dependency = parseInstallable(store, _dependency);
auto dependencyPath = toStorePath(getEvalStore(), store, Realise::Derivation, operateOn, dependency); auto dependencyPath = Installable::toStorePath(getEvalStore(), store, Realise::Derivation, operateOn, dependency);
auto dependencyPathHash = dependencyPath.hashPart(); auto dependencyPathHash = dependencyPath.hashPart();
StorePathSet closure; StorePathSet closure;

View file

@ -2,7 +2,7 @@ source common.sh
file=build-hook-ca-floating.nix file=build-hook-ca-floating.nix
sed -i 's/experimental-features .*/& ca-derivations/' "$NIX_CONF_DIR"/nix.conf enableFeatures "ca-derivations ca-references"
CONTENT_ADDRESSED=true CONTENT_ADDRESSED=true

View file

@ -37,7 +37,7 @@ testCutoffFor () {
} }
testCutoff () { testCutoff () {
# Don't directly build depenentCA, that way we'll make sure we dodn't rely on # Don't directly build dependentCA, that way we'll make sure we don't rely on
# dependent derivations always being already built. # dependent derivations always being already built.
#testDerivation dependentCA #testDerivation dependentCA
testCutoffFor transitivelyDependentCA testCutoffFor transitivelyDependentCA

View file

@ -1,5 +1,5 @@
source ../common.sh source ../common.sh
sed -i 's/experimental-features .*/& ca-derivations ca-references/' "$NIX_CONF_DIR"/nix.conf enableFeatures "ca-derivations ca-references"
restartDaemon restartDaemon

View file

@ -2,8 +2,6 @@ source ./common.sh
requireDaemonNewerThan "2.4pre20210625" requireDaemonNewerThan "2.4pre20210625"
sed -i 's/experimental-features .*/& ca-derivations ca-references/' "$NIX_CONF_DIR"/nix.conf
export REMOTE_STORE_DIR="$TEST_ROOT/remote_store" export REMOTE_STORE_DIR="$TEST_ROOT/remote_store"
export REMOTE_STORE="file://$REMOTE_STORE_DIR" export REMOTE_STORE="file://$REMOTE_STORE_DIR"

View file

@ -2,9 +2,6 @@
source common.sh source common.sh
# Globally enable the ca derivations experimental flag
sed -i 's/experimental-features = .*/& ca-derivations ca-references/' "$NIX_CONF_DIR/nix.conf"
export REMOTE_STORE_DIR="$TEST_ROOT/remote_store" export REMOTE_STORE_DIR="$TEST_ROOT/remote_store"
export REMOTE_STORE="file://$REMOTE_STORE_DIR" export REMOTE_STORE="file://$REMOTE_STORE_DIR"

View file

@ -2,8 +2,6 @@
source common.sh source common.sh
sed -i 's/experimental-features .*/& ca-derivations ca-references nix-command flakes/' "$NIX_CONF_DIR"/nix.conf
FLAKE_PATH=path:$PWD FLAKE_PATH=path:$PWD
nix run --no-write-lock-file $FLAKE_PATH#runnable nix run --no-write-lock-file $FLAKE_PATH#runnable

View file

@ -2,8 +2,6 @@
source common.sh source common.sh
sed -i 's/experimental-features .*/& ca-derivations ca-references nix-command flakes/' "$NIX_CONF_DIR"/nix.conf
CONTENT_ADDRESSED=true CONTENT_ADDRESSED=true
cd .. cd ..
source ./nix-shell.sh source ./nix-shell.sh

View file

@ -4,8 +4,6 @@ source common.sh
requireDaemonNewerThan "2.4pre20210626" requireDaemonNewerThan "2.4pre20210626"
sed -i 's/experimental-features .*/& ca-derivations ca-references nix-command flakes/' "$NIX_CONF_DIR"/nix.conf
export NIX_TESTS_CA_BY_DEFAULT=1 export NIX_TESTS_CA_BY_DEFAULT=1
cd .. cd ..
source ./post-hook.sh source ./post-hook.sh

View file

@ -4,8 +4,6 @@ source common.sh
requireDaemonNewerThan "2.4pre20210623" requireDaemonNewerThan "2.4pre20210623"
sed -i 's/experimental-features .*/& ca-derivations ca-references nix-command flakes/' "$NIX_CONF_DIR"/nix.conf
export NIX_TESTS_CA_BY_DEFAULT=1 export NIX_TESTS_CA_BY_DEFAULT=1
cd .. cd ..
source ./recursive.sh source ./recursive.sh

View file

@ -1,8 +1,5 @@
source common.sh source common.sh
# Globally enable the ca derivations experimental flag
sed -i 's/experimental-features = .*/& ca-derivations ca-references/' "$NIX_CONF_DIR/nix.conf"
clearStore clearStore
clearCache clearCache

View file

@ -87,8 +87,7 @@ startDaemon() {
if [[ "$NIX_REMOTE" == daemon ]]; then if [[ "$NIX_REMOTE" == daemon ]]; then
return return
fi fi
# Start the daemon, wait for the socket to appear. !!! # Start the daemon, wait for the socket to appear.
# nix-daemon should have an option to fork into the background.
rm -f $NIX_DAEMON_SOCKET_PATH rm -f $NIX_DAEMON_SOCKET_PATH
PATH=$DAEMON_PATH nix-daemon& PATH=$DAEMON_PATH nix-daemon&
pidDaemon=$! pidDaemon=$!
@ -109,10 +108,10 @@ startDaemon() {
killDaemon() { killDaemon() {
kill $pidDaemon kill $pidDaemon
for i in {0..100}; do for i in {0..100}; do
kill -0 $pidDaemon || break kill -0 $pidDaemon 2> /dev/null || break
sleep 0.1 sleep 0.1
done done
kill -9 $pidDaemon || true kill -9 $pidDaemon 2> /dev/null || true
wait $pidDaemon || true wait $pidDaemon || true
trap "" EXIT trap "" EXIT
} }
@ -173,10 +172,15 @@ needLocalStore() {
} }
# Just to make it easy to find which tests should be fixed # Just to make it easy to find which tests should be fixed
buggyNeedLocalStore () { buggyNeedLocalStore() {
needLocalStore needLocalStore
} }
enableFeatures() {
local features="$1"
sed -i 's/experimental-features .*/& '"$features"'/' "$NIX_CONF_DIR"/nix.conf
}
set -x set -x
if [[ -n "${NIX_DAEMON_PACKAGE:-}" ]]; then if [[ -n "${NIX_DAEMON_PACKAGE:-}" ]]; then

View file

@ -3,6 +3,9 @@ source common.sh
clearStore clearStore
clearProfiles clearProfiles
enableFeatures "ca-derivations ca-references"
restartDaemon
# Make a flake. # Make a flake.
flake1Dir=$TEST_ROOT/flake1 flake1Dir=$TEST_ROOT/flake1
mkdir -p $flake1Dir mkdir -p $flake1Dir
@ -13,7 +16,7 @@ cat > $flake1Dir/flake.nix <<EOF
outputs = { self }: with import ./config.nix; rec { outputs = { self }: with import ./config.nix; rec {
packages.$system.default = mkDerivation { packages.$system.default = mkDerivation {
name = "simple-\${builtins.readFile ./version}"; name = "profile-test-\${builtins.readFile ./version}";
builder = builtins.toFile "builder.sh" builder = builtins.toFile "builder.sh"
'' ''
mkdir -p \$out/bin mkdir -p \$out/bin
@ -22,7 +25,11 @@ cat > $flake1Dir/flake.nix <<EOF
echo Hello \${builtins.readFile ./who} echo Hello \${builtins.readFile ./who}
EOF EOF
chmod +x \$out/bin/hello chmod +x \$out/bin/hello
echo DONE
''; '';
__contentAddressed = import ./ca.nix;
outputHashMode = "recursive";
outputHashAlgo = "sha256";
}; };
}; };
} }
@ -30,6 +37,7 @@ EOF
printf World > $flake1Dir/who printf World > $flake1Dir/who
printf 1.0 > $flake1Dir/version printf 1.0 > $flake1Dir/version
printf false > $flake1Dir/ca.nix
cp ./config.nix $flake1Dir/ cp ./config.nix $flake1Dir/
@ -63,6 +71,27 @@ nix profile remove 0
nix profile history | grep 'foo: 1.0 -> ∅' nix profile history | grep 'foo: 1.0 -> ∅'
nix profile diff-closures | grep 'Version 3 -> 4' nix profile diff-closures | grep 'Version 3 -> 4'
# Test installing a non-flake package.
nix profile install --file ./simple.nix ''
[[ $(cat $TEST_HOME/.nix-profile/hello) = "Hello World!" ]]
nix profile remove 1
nix profile install $(nix-build --no-out-link ./simple.nix)
[[ $(cat $TEST_HOME/.nix-profile/hello) = "Hello World!" ]]
# Test wipe-history. # Test wipe-history.
nix profile wipe-history nix profile wipe-history
[[ $(nix profile history | grep Version | wc -l) -eq 1 ]] [[ $(nix profile history | grep Version | wc -l) -eq 1 ]]
# Test upgrade to CA package.
printf true > $flake1Dir/ca.nix
printf 3.0 > $flake1Dir/version
nix profile upgrade 0
nix profile history | grep "packages.$system.default: 1.0 -> 3.0"
# Test new install of CA package.
nix profile remove 0
printf 4.0 > $flake1Dir/version
printf Utrecht > $flake1Dir/who
nix profile install $flake1Dir
[[ $($TEST_HOME/.nix-profile/bin/hello) = "Hello Utrecht" ]]
[[ $(nix path-info --json $(realpath $TEST_HOME/.nix-profile/bin/hello) | jq -r .[].ca) =~ fixed:r:sha256: ]]