nix profile: Support CA derivations

This commit is contained in:
Eelco Dolstra 2022-03-02 20:37:46 +01:00
parent 54888b92de
commit 161f798aa1
4 changed files with 66 additions and 53 deletions

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()
}; };

View file

@ -134,7 +134,6 @@ struct InstallableValue : Installable
struct DerivationInfo struct DerivationInfo
{ {
StorePath drvPath; StorePath drvPath;
std::optional<StorePath> outPath;
std::string outputName; std::string outputName;
}; };

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 = 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)); 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

@ -22,7 +22,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 +34,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/
@ -66,3 +71,17 @@ nix profile diff-closures | grep 'Version 3 -> 4'
# 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 --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: ]]