From 161f798aa13b56c5f71120a8cb5788409d9ab815 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 2 Mar 2022 20:37:46 +0100 Subject: [PATCH] nix profile: Support CA derivations --- src/libcmd/installables.cc | 4 +- src/libcmd/installables.hh | 1 - src/nix/profile.cc | 95 ++++++++++++++++++-------------------- tests/nix-profile.sh | 19 ++++++++ 4 files changed, 66 insertions(+), 53 deletions(-) diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc index b9afe5105..f18be5287 100644 --- a/src/libcmd/installables.cc +++ b/src/libcmd/installables.cc @@ -470,7 +470,6 @@ std::vector InstallableAttrPath::toDerivations for (auto & drvInfo : drvInfos) { res.push_back({ state->store->parseStorePath(drvInfo.queryDrvPath()), - state->store->maybeParseStorePath(drvInfo.queryOutPath()), drvInfo.queryOutputName() }); } @@ -584,9 +583,8 @@ std::tuple InstallableF auto drvPath = attr->forceDerivation(); - auto drvInfo = DerivationInfo{ + auto drvInfo = DerivationInfo { std::move(drvPath), - state->store->maybeParseStorePath(attr->getAttr(state->sOutPath)->getString()), attr->getAttr(state->sOutputName)->getString() }; diff --git a/src/libcmd/installables.hh b/src/libcmd/installables.hh index f296434c5..e172b71b0 100644 --- a/src/libcmd/installables.hh +++ b/src/libcmd/installables.hh @@ -134,7 +134,6 @@ struct InstallableValue : Installable struct DerivationInfo { StorePath drvPath; - std::optional outPath; std::string outputName; }; diff --git a/src/nix/profile.cc b/src/nix/profile.cc index c1bf62357..48834d15b 100644 --- a/src/nix/profile.cc +++ b/src/nix/profile.cc @@ -61,6 +61,27 @@ struct ProfileElement { return std::tuple(describe(), storePaths) < std::tuple(other.describe(), other.storePaths); } + + void updateStorePaths(ref evalStore, ref 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 @@ -232,53 +253,25 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile { ProfileManifest manifest(*getEvalState(), *profile); - std::vector pathsToBuild; + auto builtPaths = Installable::build(getEvalStore(), store, Realise::Outputs, installables, bmNormal); for (auto & installable : installables) { - if (auto installable2 = std::dynamic_pointer_cast(installable)) { - auto [attrPath, resolvedRef, drv] = installable2->toDerivation(); + ProfileElement element; - ProfileElement element; - if (!drv.outPath) - throw UnimplementedError("CA derivations are not yet supported by 'nix profile'"); - element.storePaths = {*drv.outPath}; // FIXME + if (auto installable2 = std::dynamic_pointer_cast(installable)) { + // FIXME: make build() return this? + auto [attrPath, resolvedRef, drv] = installable2->toDerivation(); element.source = ProfileElementSource{ installable2->flakeRef, resolvedRef, attrPath, }; - - pathsToBuild.push_back(DerivedPath::Built{drv.drvPath, StringSet{drv.outputName}}); - - manifest.elements.emplace_back(std::move(element)); - } else { - auto buildables = Installable::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)); } @@ -407,8 +400,8 @@ struct CmdProfileUpgrade : virtual SourceExprCommand, MixDefaultProfile, MixProf auto matchers = getMatchers(store); - // FIXME: code duplication - std::vector pathsToBuild; + std::vector> installables; + std::vector indices; auto upgradedCount = 0; @@ -423,32 +416,30 @@ struct CmdProfileUpgrade : virtual SourceExprCommand, MixDefaultProfile, MixProf Activity act(*logger, lvlChatty, actUnknown, fmt("checking '%s' for updates", element.source->attrPath)); - InstallableFlake installable( + auto installable = std::make_shared( this, getEvalState(), FlakeRef(element.source->originalRef), "", - {element.source->attrPath}, - {}, + Strings{element.source->attrPath}, + Strings{}, lockFlags); - auto [attrPath, resolvedRef, drv] = installable.toDerivation(); + auto [attrPath, resolvedRef, drv] = installable->toDerivation(); if (element.source->resolvedRef == resolvedRef) continue; printInfo("upgrading '%s' from flake '%s' to '%s'", 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{ - installable.flakeRef, + installable->flakeRef, resolvedRef, 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."); } - 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)); } diff --git a/tests/nix-profile.sh b/tests/nix-profile.sh index f134d70a4..0ab69db22 100644 --- a/tests/nix-profile.sh +++ b/tests/nix-profile.sh @@ -22,7 +22,11 @@ cat > $flake1Dir/flake.nix < $flake1Dir/who printf 1.0 > $flake1Dir/version +printf false > $flake1Dir/ca.nix cp ./config.nix $flake1Dir/ @@ -66,3 +71,17 @@ nix profile diff-closures | grep 'Version 3 -> 4' # Test wipe-history. nix profile wipe-history [[ $(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 --extra-experimental-features ca-derivations 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 --extra-experimental-features ca-derivations $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: ]]