Merge pull request #4487 from NixOS/ca/copy-drv-outputs
Copy ca derivation outputs
This commit is contained in:
commit
d2803406b5
|
@ -165,10 +165,15 @@ bool Settings::isExperimentalFeatureEnabled(const std::string & name)
|
||||||
return std::find(f.begin(), f.end(), name) != f.end();
|
return std::find(f.begin(), f.end(), name) != f.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MissingExperimentalFeature::MissingExperimentalFeature(std::string feature)
|
||||||
|
: Error("experimental Nix feature '%1%' is disabled; use '--experimental-features %1%' to override", feature)
|
||||||
|
, missingFeature(feature)
|
||||||
|
{}
|
||||||
|
|
||||||
void Settings::requireExperimentalFeature(const std::string & name)
|
void Settings::requireExperimentalFeature(const std::string & name)
|
||||||
{
|
{
|
||||||
if (!isExperimentalFeatureEnabled(name))
|
if (!isExperimentalFeatureEnabled(name))
|
||||||
throw Error("experimental Nix feature '%1%' is disabled; use '--experimental-features %1%' to override", name);
|
throw MissingExperimentalFeature(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Settings::isWSL1()
|
bool Settings::isWSL1()
|
||||||
|
|
|
@ -45,6 +45,15 @@ struct PluginFilesSetting : public BaseSetting<Paths>
|
||||||
void set(const std::string & str, bool append = false) override;
|
void set(const std::string & str, bool append = false) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class MissingExperimentalFeature: public Error
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::string missingFeature;
|
||||||
|
|
||||||
|
MissingExperimentalFeature(std::string feature);
|
||||||
|
virtual const char* sname() const override { return "MissingExperimentalFeature"; }
|
||||||
|
};
|
||||||
|
|
||||||
class Settings : public Config {
|
class Settings : public Config {
|
||||||
|
|
||||||
unsigned int getDefaultCores();
|
unsigned int getDefaultCores();
|
||||||
|
@ -632,7 +641,7 @@ public:
|
||||||
is `root`.
|
is `root`.
|
||||||
|
|
||||||
> **Warning**
|
> **Warning**
|
||||||
>
|
>
|
||||||
> Adding a user to `trusted-users` is essentially equivalent to
|
> Adding a user to `trusted-users` is essentially equivalent to
|
||||||
> giving that user root access to the system. For example, the user
|
> giving that user root access to the system. For example, the user
|
||||||
> can set `sandbox-paths` and thereby obtain read access to
|
> can set `sandbox-paths` and thereby obtain read access to
|
||||||
|
@ -722,13 +731,13 @@ public:
|
||||||
The program executes with no arguments. The program's environment
|
The program executes with no arguments. The program's environment
|
||||||
contains the following environment variables:
|
contains the following environment variables:
|
||||||
|
|
||||||
- `DRV_PATH`
|
- `DRV_PATH`
|
||||||
The derivation for the built paths.
|
The derivation for the built paths.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
`/nix/store/5nihn1a7pa8b25l9zafqaqibznlvvp3f-bash-4.4-p23.drv`
|
`/nix/store/5nihn1a7pa8b25l9zafqaqibznlvvp3f-bash-4.4-p23.drv`
|
||||||
|
|
||||||
- `OUT_PATHS`
|
- `OUT_PATHS`
|
||||||
Output paths of the built derivation, separated by a space
|
Output paths of the built derivation, separated by a space
|
||||||
character.
|
character.
|
||||||
|
|
||||||
|
@ -759,7 +768,7 @@ public:
|
||||||
documentation](https://ec.haxx.se/usingcurl-netrc.html).
|
documentation](https://ec.haxx.se/usingcurl-netrc.html).
|
||||||
|
|
||||||
> **Note**
|
> **Note**
|
||||||
>
|
>
|
||||||
> This must be an absolute path, and `~` is not resolved. For
|
> This must be an absolute path, and `~` is not resolved. For
|
||||||
> example, `~/.netrc` won't resolve to your home directory's
|
> example, `~/.netrc` won't resolve to your home directory's
|
||||||
> `.netrc`.
|
> `.netrc`.
|
||||||
|
|
|
@ -655,6 +655,7 @@ void LocalStore::checkDerivationOutputs(const StorePath & drvPath, const Derivat
|
||||||
|
|
||||||
void LocalStore::registerDrvOutput(const Realisation & info)
|
void LocalStore::registerDrvOutput(const Realisation & info)
|
||||||
{
|
{
|
||||||
|
settings.requireExperimentalFeature("ca-derivations");
|
||||||
auto state(_state.lock());
|
auto state(_state.lock());
|
||||||
retrySQLite<void>([&]() {
|
retrySQLite<void>([&]() {
|
||||||
state->stmts->RegisterRealisedOutput.use()
|
state->stmts->RegisterRealisedOutput.use()
|
||||||
|
|
|
@ -783,6 +783,36 @@ void copyStorePath(ref<Store> srcStore, ref<Store> dstStore,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::map<StorePath, StorePath> copyPaths(ref<Store> srcStore, ref<Store> dstStore, const RealisedPath::Set & paths,
|
||||||
|
RepairFlag repair, CheckSigsFlag checkSigs, SubstituteFlag substitute)
|
||||||
|
{
|
||||||
|
StorePathSet storePaths;
|
||||||
|
std::set<Realisation> realisations;
|
||||||
|
for (auto & path : paths) {
|
||||||
|
storePaths.insert(path.path());
|
||||||
|
if (auto realisation = std::get_if<Realisation>(&path.raw)) {
|
||||||
|
settings.requireExperimentalFeature("ca-derivations");
|
||||||
|
realisations.insert(*realisation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto pathsMap = copyPaths(srcStore, dstStore, storePaths, repair, checkSigs, substitute);
|
||||||
|
try {
|
||||||
|
for (auto & realisation : realisations) {
|
||||||
|
dstStore->registerDrvOutput(realisation);
|
||||||
|
}
|
||||||
|
} catch (MissingExperimentalFeature & e) {
|
||||||
|
// Don't fail if the remote doesn't support CA derivations is it might
|
||||||
|
// not be within our control to change that, and we might still want
|
||||||
|
// to at least copy the output paths.
|
||||||
|
if (e.missingFeature == "ca-derivations")
|
||||||
|
ignoreException();
|
||||||
|
else
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pathsMap;
|
||||||
|
}
|
||||||
|
|
||||||
std::map<StorePath, StorePath> copyPaths(ref<Store> srcStore, ref<Store> dstStore, const StorePathSet & storePaths,
|
std::map<StorePath, StorePath> copyPaths(ref<Store> srcStore, ref<Store> dstStore, const StorePathSet & storePaths,
|
||||||
RepairFlag repair, CheckSigsFlag checkSigs, SubstituteFlag substitute)
|
RepairFlag repair, CheckSigsFlag checkSigs, SubstituteFlag substitute)
|
||||||
{
|
{
|
||||||
|
@ -796,7 +826,6 @@ std::map<StorePath, StorePath> copyPaths(ref<Store> srcStore, ref<Store> dstStor
|
||||||
for (auto & path : storePaths)
|
for (auto & path : storePaths)
|
||||||
pathsMap.insert_or_assign(path, path);
|
pathsMap.insert_or_assign(path, path);
|
||||||
|
|
||||||
if (missing.empty()) return pathsMap;
|
|
||||||
|
|
||||||
Activity act(*logger, lvlInfo, actCopyPaths, fmt("copying %d paths", missing.size()));
|
Activity act(*logger, lvlInfo, actCopyPaths, fmt("copying %d paths", missing.size()));
|
||||||
|
|
||||||
|
@ -871,21 +900,9 @@ std::map<StorePath, StorePath> copyPaths(ref<Store> srcStore, ref<Store> dstStor
|
||||||
nrDone++;
|
nrDone++;
|
||||||
showProgress();
|
showProgress();
|
||||||
});
|
});
|
||||||
|
|
||||||
return pathsMap;
|
return pathsMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void copyClosure(ref<Store> srcStore, ref<Store> dstStore,
|
|
||||||
const StorePathSet & storePaths, RepairFlag repair, CheckSigsFlag checkSigs,
|
|
||||||
SubstituteFlag substitute)
|
|
||||||
{
|
|
||||||
StorePathSet closure;
|
|
||||||
srcStore->computeFSClosure(storePaths, closure);
|
|
||||||
copyPaths(srcStore, dstStore, closure, repair, checkSigs, substitute);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::optional<ValidPathInfo> decodeValidPathInfo(const Store & store, std::istream & str, std::optional<HashResult> hashGiven)
|
std::optional<ValidPathInfo> decodeValidPathInfo(const Store & store, std::istream & str, std::optional<HashResult> hashGiven)
|
||||||
{
|
{
|
||||||
std::string path;
|
std::string path;
|
||||||
|
|
|
@ -752,15 +752,12 @@ void copyStorePath(ref<Store> srcStore, ref<Store> dstStore,
|
||||||
that. Returns a map of what each path was copied to the dstStore
|
that. Returns a map of what each path was copied to the dstStore
|
||||||
as. */
|
as. */
|
||||||
std::map<StorePath, StorePath> copyPaths(ref<Store> srcStore, ref<Store> dstStore,
|
std::map<StorePath, StorePath> copyPaths(ref<Store> srcStore, ref<Store> dstStore,
|
||||||
const StorePathSet & storePaths,
|
const RealisedPath::Set &,
|
||||||
RepairFlag repair = NoRepair,
|
RepairFlag repair = NoRepair,
|
||||||
CheckSigsFlag checkSigs = CheckSigs,
|
CheckSigsFlag checkSigs = CheckSigs,
|
||||||
SubstituteFlag substitute = NoSubstitute);
|
SubstituteFlag substitute = NoSubstitute);
|
||||||
|
std::map<StorePath, StorePath> copyPaths(ref<Store> srcStore, ref<Store> dstStore,
|
||||||
|
const StorePathSet& paths,
|
||||||
/* Copy the closure of the specified paths from one store to another. */
|
|
||||||
void copyClosure(ref<Store> srcStore, ref<Store> dstStore,
|
|
||||||
const StorePathSet & storePaths,
|
|
||||||
RepairFlag repair = NoRepair,
|
RepairFlag repair = NoRepair,
|
||||||
CheckSigsFlag checkSigs = CheckSigs,
|
CheckSigsFlag checkSigs = CheckSigs,
|
||||||
SubstituteFlag substitute = NoSubstitute);
|
SubstituteFlag substitute = NoSubstitute);
|
||||||
|
|
|
@ -50,12 +50,12 @@ static int main_nix_copy_closure(int argc, char ** argv)
|
||||||
auto to = toMode ? openStore(remoteUri) : openStore();
|
auto to = toMode ? openStore(remoteUri) : openStore();
|
||||||
auto from = toMode ? openStore() : openStore(remoteUri);
|
auto from = toMode ? openStore() : openStore(remoteUri);
|
||||||
|
|
||||||
StorePathSet storePaths2;
|
RealisedPath::Set storePaths2;
|
||||||
for (auto & path : storePaths)
|
for (auto & path : storePaths)
|
||||||
storePaths2.insert(from->followLinksToStorePath(path));
|
storePaths2.insert(from->followLinksToStorePath(path));
|
||||||
|
|
||||||
StorePathSet closure;
|
RealisedPath::Set closure;
|
||||||
from->computeFSClosure(storePaths2, closure, false, includeOutputs);
|
RealisedPath::closure(*from, storePaths2, closure);
|
||||||
|
|
||||||
copyPaths(from, to, closure, NoRepair, NoCheckSigs, useSubstitutes);
|
copyPaths(from, to, closure, NoRepair, NoCheckSigs, useSubstitutes);
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
using namespace nix;
|
using namespace nix;
|
||||||
|
|
||||||
struct CmdCopy : StorePathsCommand
|
struct CmdCopy : RealisedPathsCommand
|
||||||
{
|
{
|
||||||
std::string srcUri, dstUri;
|
std::string srcUri, dstUri;
|
||||||
|
|
||||||
|
@ -16,10 +16,10 @@ struct CmdCopy : StorePathsCommand
|
||||||
|
|
||||||
SubstituteFlag substitute = NoSubstitute;
|
SubstituteFlag substitute = NoSubstitute;
|
||||||
|
|
||||||
using StorePathsCommand::run;
|
using RealisedPathsCommand::run;
|
||||||
|
|
||||||
CmdCopy()
|
CmdCopy()
|
||||||
: StorePathsCommand(true)
|
: RealisedPathsCommand(true)
|
||||||
{
|
{
|
||||||
addFlag({
|
addFlag({
|
||||||
.longName = "from",
|
.longName = "from",
|
||||||
|
@ -75,14 +75,15 @@ struct CmdCopy : StorePathsCommand
|
||||||
if (srcUri.empty() && dstUri.empty())
|
if (srcUri.empty() && dstUri.empty())
|
||||||
throw UsageError("you must pass '--from' and/or '--to'");
|
throw UsageError("you must pass '--from' and/or '--to'");
|
||||||
|
|
||||||
StorePathsCommand::run(store);
|
RealisedPathsCommand::run(store);
|
||||||
}
|
}
|
||||||
|
|
||||||
void run(ref<Store> srcStore, StorePaths storePaths) override
|
void run(ref<Store> srcStore, std::vector<RealisedPath> paths) override
|
||||||
{
|
{
|
||||||
ref<Store> dstStore = dstUri.empty() ? openStore() : openStore(dstUri);
|
ref<Store> dstStore = dstUri.empty() ? openStore() : openStore(dstUri);
|
||||||
|
|
||||||
copyPaths(srcStore, dstStore, StorePathSet(storePaths.begin(), storePaths.end()),
|
copyPaths(
|
||||||
|
srcStore, dstStore, RealisedPath::Set(paths.begin(), paths.end()),
|
||||||
NoRepair, checkSigs, substitute);
|
NoRepair, checkSigs, substitute);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -38,6 +38,7 @@ nix_tests = \
|
||||||
describe-stores.sh \
|
describe-stores.sh \
|
||||||
flakes.sh \
|
flakes.sh \
|
||||||
content-addressed.sh \
|
content-addressed.sh \
|
||||||
|
nix-copy-content-addressed.sh \
|
||||||
build.sh \
|
build.sh \
|
||||||
compute-levels.sh
|
compute-levels.sh
|
||||||
# parallel.sh
|
# parallel.sh
|
||||||
|
|
34
tests/nix-copy-content-addressed.sh
Executable file
34
tests/nix-copy-content-addressed.sh
Executable file
|
@ -0,0 +1,34 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
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="file://$REMOTE_STORE_DIR"
|
||||||
|
|
||||||
|
ensureCorrectlyCopied () {
|
||||||
|
attrPath="$1"
|
||||||
|
nix build --store "$REMOTE_STORE" --file ./content-addressed.nix "$attrPath"
|
||||||
|
}
|
||||||
|
|
||||||
|
testOneCopy () {
|
||||||
|
clearStore
|
||||||
|
rm -rf "$REMOTE_STORE_DIR"
|
||||||
|
|
||||||
|
attrPath="$1"
|
||||||
|
nix copy --to $REMOTE_STORE "$attrPath" --file ./content-addressed.nix
|
||||||
|
|
||||||
|
ensureCorrectlyCopied "$attrPath"
|
||||||
|
|
||||||
|
# Ensure that we can copy back what we put in the store
|
||||||
|
clearStore
|
||||||
|
nix copy --from $REMOTE_STORE \
|
||||||
|
--file ./content-addressed.nix "$attrPath" \
|
||||||
|
--no-check-sigs
|
||||||
|
}
|
||||||
|
|
||||||
|
for attrPath in rootCA dependentCA transitivelyDependentCA dependentNonCA dependentFixedOutput; do
|
||||||
|
testOneCopy "$attrPath"
|
||||||
|
done
|
Loading…
Reference in a new issue