mirror of
https://github.com/privatevoid-net/nix-super.git
synced 2024-12-02 02:16:15 +02:00
Allow non-CA derivations to depend on CA derivations
This commit is contained in:
parent
e0ca98c207
commit
c092fa4702
8 changed files with 124 additions and 23 deletions
|
@ -1089,8 +1089,9 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
|
||||||
|
|
||||||
// Regular, non-CA derivation should always return a single hash and not
|
// Regular, non-CA derivation should always return a single hash and not
|
||||||
// hash per output.
|
// hash per output.
|
||||||
Hash h = std::get<0>(hashDerivationModulo(*state.store, Derivation(drv), true));
|
auto hashModulo = hashDerivationModulo(*state.store, Derivation(drv), true);
|
||||||
|
std::visit(overloaded {
|
||||||
|
[&](Hash h) {
|
||||||
for (auto & i : outputs) {
|
for (auto & i : outputs) {
|
||||||
auto outPath = state.store->makeOutputPath(i, h, drvName);
|
auto outPath = state.store->makeOutputPath(i, h, drvName);
|
||||||
drv.env[i] = state.store->printStorePath(outPath);
|
drv.env[i] = state.store->printStorePath(outPath);
|
||||||
|
@ -1101,6 +1102,22 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
[&](CaOutputHashes) {
|
||||||
|
// Shouldn't happen as the toplevel derivation is not CA.
|
||||||
|
assert(false);
|
||||||
|
},
|
||||||
|
[&](UnknownHashes) {
|
||||||
|
for (auto & i : outputs) {
|
||||||
|
drv.outputs.insert_or_assign(i,
|
||||||
|
DerivationOutput {
|
||||||
|
.output = DerivationOutputDeferred{},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
hashModulo);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write the resulting term into the Nix store directory. */
|
/* Write the resulting term into the Nix store directory. */
|
||||||
|
|
|
@ -493,7 +493,8 @@ void DerivationGoal::inputsRealised()
|
||||||
if (useDerivation) {
|
if (useDerivation) {
|
||||||
auto & fullDrv = *dynamic_cast<Derivation *>(drv.get());
|
auto & fullDrv = *dynamic_cast<Derivation *>(drv.get());
|
||||||
|
|
||||||
if (!fullDrv.inputDrvs.empty() && fullDrv.type() == DerivationType::CAFloating) {
|
if ((!fullDrv.inputDrvs.empty() &&
|
||||||
|
fullDrv.type() == DerivationType::CAFloating) || fullDrv.type() == DerivationType::DeferredInputAddressed) {
|
||||||
/* We are be able to resolve this derivation based on the
|
/* We are be able to resolve this derivation based on the
|
||||||
now-known results of dependencies. If so, we become a stub goal
|
now-known results of dependencies. If so, we become a stub goal
|
||||||
aliasing that resolved derivation goal */
|
aliasing that resolved derivation goal */
|
||||||
|
@ -3166,6 +3167,15 @@ void DerivationGoal::registerOutputs()
|
||||||
[&](DerivationOutputCAFloating dof) {
|
[&](DerivationOutputCAFloating dof) {
|
||||||
return newInfoFromCA(dof);
|
return newInfoFromCA(dof);
|
||||||
},
|
},
|
||||||
|
[&](DerivationOutputDeferred) {
|
||||||
|
// No derivation should reach that point without having been
|
||||||
|
// rewritten first
|
||||||
|
assert(false);
|
||||||
|
// Ugly, but the compiler insists on having this return a value
|
||||||
|
// of type `ValidPathInfo` despite the `assert(false)`, so
|
||||||
|
// let's provide it
|
||||||
|
return *(ValidPathInfo*)0;
|
||||||
|
},
|
||||||
}, output.output);
|
}, output.output);
|
||||||
|
|
||||||
/* Calculate where we'll move the output files. In the checking case we
|
/* Calculate where we'll move the output files. In the checking case we
|
||||||
|
|
|
@ -21,6 +21,9 @@ std::optional<StorePath> DerivationOutput::path(const Store & store, std::string
|
||||||
[](DerivationOutputCAFloating dof) -> std::optional<StorePath> {
|
[](DerivationOutputCAFloating dof) -> std::optional<StorePath> {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
},
|
},
|
||||||
|
[](DerivationOutputDeferred) -> std::optional<StorePath> {
|
||||||
|
return std::nullopt;
|
||||||
|
},
|
||||||
}, output);
|
}, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,6 +40,7 @@ bool derivationIsCA(DerivationType dt) {
|
||||||
case DerivationType::InputAddressed: return false;
|
case DerivationType::InputAddressed: return false;
|
||||||
case DerivationType::CAFixed: return true;
|
case DerivationType::CAFixed: return true;
|
||||||
case DerivationType::CAFloating: return true;
|
case DerivationType::CAFloating: return true;
|
||||||
|
case DerivationType::DeferredInputAddressed: return false;
|
||||||
};
|
};
|
||||||
// Since enums can have non-variant values, but making a `default:` would
|
// Since enums can have non-variant values, but making a `default:` would
|
||||||
// disable exhaustiveness warnings.
|
// disable exhaustiveness warnings.
|
||||||
|
@ -48,6 +52,7 @@ bool derivationIsFixed(DerivationType dt) {
|
||||||
case DerivationType::InputAddressed: return false;
|
case DerivationType::InputAddressed: return false;
|
||||||
case DerivationType::CAFixed: return true;
|
case DerivationType::CAFixed: return true;
|
||||||
case DerivationType::CAFloating: return false;
|
case DerivationType::CAFloating: return false;
|
||||||
|
case DerivationType::DeferredInputAddressed: return false;
|
||||||
};
|
};
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
|
@ -57,6 +62,7 @@ bool derivationIsImpure(DerivationType dt) {
|
||||||
case DerivationType::InputAddressed: return false;
|
case DerivationType::InputAddressed: return false;
|
||||||
case DerivationType::CAFixed: return true;
|
case DerivationType::CAFixed: return true;
|
||||||
case DerivationType::CAFloating: return false;
|
case DerivationType::CAFloating: return false;
|
||||||
|
case DerivationType::DeferredInputAddressed: return false;
|
||||||
};
|
};
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
|
@ -180,6 +186,11 @@ static DerivationOutput parseDerivationOutput(const Store & store,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (pathS == "") {
|
||||||
|
return DerivationOutput {
|
||||||
|
.output = DerivationOutputDeferred { }
|
||||||
|
};
|
||||||
|
}
|
||||||
validatePath(pathS);
|
validatePath(pathS);
|
||||||
return DerivationOutput {
|
return DerivationOutput {
|
||||||
.output = DerivationOutputInputAddressed {
|
.output = DerivationOutputInputAddressed {
|
||||||
|
@ -325,6 +336,11 @@ string Derivation::unparse(const Store & store, bool maskOutputs,
|
||||||
s += ','; printUnquotedString(s, makeFileIngestionPrefix(dof.method) + printHashType(dof.hashType));
|
s += ','; printUnquotedString(s, makeFileIngestionPrefix(dof.method) + printHashType(dof.hashType));
|
||||||
s += ','; printUnquotedString(s, "");
|
s += ','; printUnquotedString(s, "");
|
||||||
},
|
},
|
||||||
|
[&](DerivationOutputDeferred) {
|
||||||
|
s += ','; printUnquotedString(s, "");
|
||||||
|
s += ','; printUnquotedString(s, "");
|
||||||
|
s += ','; printUnquotedString(s, "");
|
||||||
|
}
|
||||||
}, i.second.output);
|
}, i.second.output);
|
||||||
s += ')';
|
s += ')';
|
||||||
}
|
}
|
||||||
|
@ -389,7 +405,7 @@ std::string outputPathName(std::string_view drvName, std::string_view outputName
|
||||||
|
|
||||||
DerivationType BasicDerivation::type() const
|
DerivationType BasicDerivation::type() const
|
||||||
{
|
{
|
||||||
std::set<std::string_view> inputAddressedOutputs, fixedCAOutputs, floatingCAOutputs;
|
std::set<std::string_view> inputAddressedOutputs, fixedCAOutputs, floatingCAOutputs, deferredIAOutputs;
|
||||||
std::optional<HashType> floatingHashType;
|
std::optional<HashType> floatingHashType;
|
||||||
for (auto & i : outputs) {
|
for (auto & i : outputs) {
|
||||||
std::visit(overloaded {
|
std::visit(overloaded {
|
||||||
|
@ -408,22 +424,27 @@ DerivationType BasicDerivation::type() const
|
||||||
throw Error("All floating outputs must use the same hash type");
|
throw Error("All floating outputs must use the same hash type");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
[&](DerivationOutputDeferred _) {
|
||||||
|
deferredIAOutputs.insert(i.first);
|
||||||
|
},
|
||||||
}, i.second.output);
|
}, i.second.output);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inputAddressedOutputs.empty() && fixedCAOutputs.empty() && floatingCAOutputs.empty()) {
|
if (inputAddressedOutputs.empty() && fixedCAOutputs.empty() && floatingCAOutputs.empty() && deferredIAOutputs.empty()) {
|
||||||
throw Error("Must have at least one output");
|
throw Error("Must have at least one output");
|
||||||
} else if (! inputAddressedOutputs.empty() && fixedCAOutputs.empty() && floatingCAOutputs.empty()) {
|
} else if (! inputAddressedOutputs.empty() && fixedCAOutputs.empty() && floatingCAOutputs.empty() && deferredIAOutputs.empty()) {
|
||||||
return DerivationType::InputAddressed;
|
return DerivationType::InputAddressed;
|
||||||
} else if (inputAddressedOutputs.empty() && ! fixedCAOutputs.empty() && floatingCAOutputs.empty()) {
|
} else if (inputAddressedOutputs.empty() && ! fixedCAOutputs.empty() && floatingCAOutputs.empty() && deferredIAOutputs.empty()) {
|
||||||
if (fixedCAOutputs.size() > 1)
|
if (fixedCAOutputs.size() > 1)
|
||||||
// FIXME: Experimental feature?
|
// FIXME: Experimental feature?
|
||||||
throw Error("Only one fixed output is allowed for now");
|
throw Error("Only one fixed output is allowed for now");
|
||||||
if (*fixedCAOutputs.begin() != "out")
|
if (*fixedCAOutputs.begin() != "out")
|
||||||
throw Error("Single fixed output must be named \"out\"");
|
throw Error("Single fixed output must be named \"out\"");
|
||||||
return DerivationType::CAFixed;
|
return DerivationType::CAFixed;
|
||||||
} else if (inputAddressedOutputs.empty() && fixedCAOutputs.empty() && ! floatingCAOutputs.empty()) {
|
} else if (inputAddressedOutputs.empty() && fixedCAOutputs.empty() && ! floatingCAOutputs.empty() && deferredIAOutputs.empty()) {
|
||||||
return DerivationType::CAFloating;
|
return DerivationType::CAFloating;
|
||||||
|
} else if (inputAddressedOutputs.empty() && fixedCAOutputs.empty() && floatingCAOutputs.empty() && !deferredIAOutputs.empty()) {
|
||||||
|
return DerivationType::DeferredInputAddressed;
|
||||||
} else {
|
} else {
|
||||||
throw Error("Can't mix derivation output types");
|
throw Error("Can't mix derivation output types");
|
||||||
}
|
}
|
||||||
|
@ -454,6 +475,8 @@ static const DrvHashModulo & pathDerivationModulo(Store & store, const StorePath
|
||||||
return h->second;
|
return h->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UnknownHashes unknownHashes;
|
||||||
|
|
||||||
/* See the header for interface details. These are the implementation details.
|
/* See the header for interface details. These are the implementation details.
|
||||||
|
|
||||||
For fixed-output derivations, each hash in the map is not the
|
For fixed-output derivations, each hash in the map is not the
|
||||||
|
@ -476,7 +499,7 @@ DrvHashModulo hashDerivationModulo(Store & store, const Derivation & drv, bool m
|
||||||
/* Return a fixed hash for fixed-output derivations. */
|
/* Return a fixed hash for fixed-output derivations. */
|
||||||
switch (drv.type()) {
|
switch (drv.type()) {
|
||||||
case DerivationType::CAFloating:
|
case DerivationType::CAFloating:
|
||||||
throw Error("Regular input-addressed derivations are not yet allowed to depend on CA derivations");
|
return unknownHashes;
|
||||||
case DerivationType::CAFixed: {
|
case DerivationType::CAFixed: {
|
||||||
std::map<std::string, Hash> outputHashes;
|
std::map<std::string, Hash> outputHashes;
|
||||||
for (const auto & i : drv.outputs) {
|
for (const auto & i : drv.outputs) {
|
||||||
|
@ -491,12 +514,15 @@ DrvHashModulo hashDerivationModulo(Store & store, const Derivation & drv, bool m
|
||||||
}
|
}
|
||||||
case DerivationType::InputAddressed:
|
case DerivationType::InputAddressed:
|
||||||
break;
|
break;
|
||||||
|
case DerivationType::DeferredInputAddressed:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For other derivations, replace the inputs paths with recursive
|
/* For other derivations, replace the inputs paths with recursive
|
||||||
calls to this function. */
|
calls to this function. */
|
||||||
std::map<std::string, StringSet> inputs2;
|
std::map<std::string, StringSet> inputs2;
|
||||||
for (auto & i : drv.inputDrvs) {
|
for (auto & i : drv.inputDrvs) {
|
||||||
|
bool hasUnknownHash = false;
|
||||||
const auto & res = pathDerivationModulo(store, i.first);
|
const auto & res = pathDerivationModulo(store, i.first);
|
||||||
std::visit(overloaded {
|
std::visit(overloaded {
|
||||||
// Regular non-CA derivation, replace derivation
|
// Regular non-CA derivation, replace derivation
|
||||||
|
@ -514,7 +540,13 @@ DrvHashModulo hashDerivationModulo(Store & store, const Derivation & drv, bool m
|
||||||
justOut);
|
justOut);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
[&](UnknownHashes) {
|
||||||
|
hasUnknownHash = true;
|
||||||
|
},
|
||||||
}, res);
|
}, res);
|
||||||
|
if (hasUnknownHash) {
|
||||||
|
return unknownHashes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return hashString(htSHA256, drv.unparse(store, maskOutputs, &inputs2));
|
return hashString(htSHA256, drv.unparse(store, maskOutputs, &inputs2));
|
||||||
|
@ -620,6 +652,11 @@ void writeDerivation(Sink & out, const Store & store, const BasicDerivation & dr
|
||||||
<< (makeFileIngestionPrefix(dof.method) + printHashType(dof.hashType))
|
<< (makeFileIngestionPrefix(dof.method) + printHashType(dof.hashType))
|
||||||
<< "";
|
<< "";
|
||||||
},
|
},
|
||||||
|
[&](DerivationOutputDeferred) {
|
||||||
|
out << ""
|
||||||
|
<< ""
|
||||||
|
<< "";
|
||||||
|
},
|
||||||
}, i.second.output);
|
}, i.second.output);
|
||||||
}
|
}
|
||||||
worker_proto::write(store, out, drv.inputSrcs);
|
worker_proto::write(store, out, drv.inputSrcs);
|
||||||
|
@ -645,7 +682,6 @@ std::string downstreamPlaceholder(const Store & store, const StorePath & drvPath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// N.B. Outputs are left unchanged
|
|
||||||
static void rewriteDerivation(Store & store, BasicDerivation & drv, const StringMap & rewrites) {
|
static void rewriteDerivation(Store & store, BasicDerivation & drv, const StringMap & rewrites) {
|
||||||
|
|
||||||
debug("Rewriting the derivation");
|
debug("Rewriting the derivation");
|
||||||
|
@ -666,6 +702,21 @@ static void rewriteDerivation(Store & store, BasicDerivation & drv, const String
|
||||||
newEnv.emplace(envName, envValue);
|
newEnv.emplace(envName, envValue);
|
||||||
}
|
}
|
||||||
drv.env = newEnv;
|
drv.env = newEnv;
|
||||||
|
|
||||||
|
auto hashModulo = hashDerivationModulo(store, Derivation(drv), true);
|
||||||
|
for (auto & [outputName, output] : drv.outputs) {
|
||||||
|
if (std::holds_alternative<DerivationOutputDeferred>(output.output)) {
|
||||||
|
Hash h = std::get<Hash>(hashModulo);
|
||||||
|
auto outPath = store.makeOutputPath(outputName, h, drv.name);
|
||||||
|
drv.env[outputName] = store.printStorePath(outPath);
|
||||||
|
output = DerivationOutput {
|
||||||
|
.output = DerivationOutputInputAddressed {
|
||||||
|
.path = std::move(outPath),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -41,12 +41,18 @@ struct DerivationOutputCAFloating
|
||||||
HashType hashType;
|
HashType hashType;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Input-addressed output which depends on a (CA) derivation whose hash isn't
|
||||||
|
* known atm
|
||||||
|
*/
|
||||||
|
struct DerivationOutputDeferred {};
|
||||||
|
|
||||||
struct DerivationOutput
|
struct DerivationOutput
|
||||||
{
|
{
|
||||||
std::variant<
|
std::variant<
|
||||||
DerivationOutputInputAddressed,
|
DerivationOutputInputAddressed,
|
||||||
DerivationOutputCAFixed,
|
DerivationOutputCAFixed,
|
||||||
DerivationOutputCAFloating
|
DerivationOutputCAFloating,
|
||||||
|
DerivationOutputDeferred
|
||||||
> output;
|
> output;
|
||||||
std::optional<HashType> hashAlgoOpt(const Store & store) const;
|
std::optional<HashType> hashAlgoOpt(const Store & store) const;
|
||||||
/* Note, when you use this function you should make sure that you're passing
|
/* Note, when you use this function you should make sure that you're passing
|
||||||
|
@ -72,6 +78,7 @@ typedef std::map<string, string> StringPairs;
|
||||||
|
|
||||||
enum struct DerivationType : uint8_t {
|
enum struct DerivationType : uint8_t {
|
||||||
InputAddressed,
|
InputAddressed,
|
||||||
|
DeferredInputAddressed,
|
||||||
CAFixed,
|
CAFixed,
|
||||||
CAFloating,
|
CAFloating,
|
||||||
};
|
};
|
||||||
|
@ -167,9 +174,12 @@ std::string outputPathName(std::string_view drvName, std::string_view outputName
|
||||||
// whose output hashes are always known since they are fixed up-front.
|
// whose output hashes are always known since they are fixed up-front.
|
||||||
typedef std::map<std::string, Hash> CaOutputHashes;
|
typedef std::map<std::string, Hash> CaOutputHashes;
|
||||||
|
|
||||||
|
struct UnknownHashes {};
|
||||||
|
|
||||||
typedef std::variant<
|
typedef std::variant<
|
||||||
Hash, // regular DRV normalized hash
|
Hash, // regular DRV normalized hash
|
||||||
CaOutputHashes
|
CaOutputHashes, // Fixed-output derivation hashes
|
||||||
|
UnknownHashes // Deferred hashes for floating outputs drvs and their dependencies
|
||||||
> DrvHashModulo;
|
> DrvHashModulo;
|
||||||
|
|
||||||
/* Returns hashes with the details of fixed-output subderivations
|
/* Returns hashes with the details of fixed-output subderivations
|
||||||
|
|
|
@ -573,6 +573,8 @@ void LocalStore::checkDerivationOutputs(const StorePath & drvPath, const Derivat
|
||||||
[&](DerivationOutputCAFloating _) {
|
[&](DerivationOutputCAFloating _) {
|
||||||
/* Nothing to check */
|
/* Nothing to check */
|
||||||
},
|
},
|
||||||
|
[&](DerivationOutputDeferred) {
|
||||||
|
},
|
||||||
}, i.second.output);
|
}, i.second.output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -817,7 +819,7 @@ std::map<std::string, std::optional<StorePath>> LocalStore::queryPartialDerivati
|
||||||
}
|
}
|
||||||
/* can't just use else-if instead of `!haveCached` because we need to unlock
|
/* can't just use else-if instead of `!haveCached` because we need to unlock
|
||||||
`drvPathResolutions` before it is locked in `Derivation::resolve`. */
|
`drvPathResolutions` before it is locked in `Derivation::resolve`. */
|
||||||
if (!haveCached && drv.type() == DerivationType::CAFloating) {
|
if (!haveCached && (drv.type() == DerivationType::CAFloating || drv.type() == DerivationType::DeferredInputAddressed)) {
|
||||||
/* Try resolve drv and use that path instead. */
|
/* Try resolve drv and use that path instead. */
|
||||||
auto attempt = drv.tryResolve(*this);
|
auto attempt = drv.tryResolve(*this);
|
||||||
if (!attempt)
|
if (!attempt)
|
||||||
|
|
|
@ -82,6 +82,7 @@ struct CmdShowDerivation : InstallablesCommand
|
||||||
[&](DerivationOutputCAFloating dof) {
|
[&](DerivationOutputCAFloating dof) {
|
||||||
outputObj.attr("hashAlgo", makeFileIngestionPrefix(dof.method) + printHashType(dof.hashType));
|
outputObj.attr("hashAlgo", makeFileIngestionPrefix(dof.method) + printHashType(dof.hashType));
|
||||||
},
|
},
|
||||||
|
[&](DerivationOutputDeferred) {},
|
||||||
}, output.output);
|
}, output.output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ rec {
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
rootCA = mkDerivation {
|
rootCA = mkDerivation {
|
||||||
name = "dependent";
|
name = "rootCA";
|
||||||
outputs = [ "out" "dev" ];
|
outputs = [ "out" "dev" ];
|
||||||
buildCommand = ''
|
buildCommand = ''
|
||||||
echo "building a CA derivation"
|
echo "building a CA derivation"
|
||||||
|
@ -51,4 +51,13 @@ rec {
|
||||||
outputHashMode = "recursive";
|
outputHashMode = "recursive";
|
||||||
outputHashAlgo = "sha256";
|
outputHashAlgo = "sha256";
|
||||||
};
|
};
|
||||||
|
dependentNonCA = mkDerivation {
|
||||||
|
name = "dependent-non-ca";
|
||||||
|
buildCommand = ''
|
||||||
|
echo "Didn't cut-off"
|
||||||
|
echo "building dependent-non-ca"
|
||||||
|
mkdir -p $out
|
||||||
|
echo ${rootCA}/non-ca-hello > $out/dep
|
||||||
|
'';
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ secondSeedArgs=(-j0)
|
||||||
# dependent derivations always being already built.
|
# dependent derivations always being already built.
|
||||||
#testDerivation dependentCA
|
#testDerivation dependentCA
|
||||||
testDerivation transitivelyDependentCA
|
testDerivation transitivelyDependentCA
|
||||||
|
testDerivation dependentNonCA
|
||||||
|
|
||||||
nix-instantiate --experimental-features ca-derivations ./content-addressed.nix -A rootCA --arg seed 5
|
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
|
nix-collect-garbage --experimental-features ca-derivations --option keep-derivations true
|
||||||
|
|
Loading…
Reference in a new issue