1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2024-10-18 00:16:11 -04:00
This commit is contained in:
Théophane Hufschmitt 2024-10-14 08:31:18 +02:00 committed by GitHub
commit d2db8c0ad4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 218 additions and 0 deletions

View file

@ -0,0 +1,14 @@
synopsis: Add `nix store import` and `nix store export`
prs: #9474
issues: #9038
description: {
Added a pair of new commands: [`nix store import`] and [`nix store export`].
[`nix store export`]: @docroot@/command-ref/new-cli/nix3-store-export.md
[`nix store import`]: @docroot@/command-ref/new-cli/nix3-store-import.md
}

15
src/nix/store-export.md Normal file
View file

@ -0,0 +1,15 @@
R""(
# Examples
* Export the closure of a given installable and re-import it in another machine
```console
$ nix store export --recursive --format binary nixpkgs#hello > hello-closure.tar
$ ssh user@otherHost nix store import < hello-closure.tar
```
# Description
This command generates an archive containing the serialisation of *installable*, as well as all the metadata required so that it can be imported with [`nix store import`](@docroot@/command-ref/new-cli/nix3-store-import.md).
)""

134
src/nix/store-import.cc Normal file
View file

@ -0,0 +1,134 @@
#include "command.hh"
#include "store-api.hh"
using namespace nix;
struct MixImportExport : virtual Args
{
enum struct ArchiveFormat
{
Binary,
};
std::optional<ArchiveFormat> format = std::nullopt;
MixImportExport()
{
addFlag(
{.longName = "format",
.description = R"(
Format of the archive.
The only supported format is `binary`, which corresponds to the format used by [`nix-store --export`](@docroot@/command-ref/nix-store/export.md).
)",
.labels = {"format"},
.handler = {[&](std::string_view arg) {
if (arg == "binary")
format = ArchiveFormat::Binary;
else
throw Error("Unknown archive format: %s", arg);
}}});
}
};
struct CmdStoreExport : StorePathsCommand, MixImportExport
{
std::string description() override
{
return "Export the given store path(s) in a way that can be imported by `nix store import`.";
}
std::string doc() override
{
return
#include "store-export.md"
;
}
std::optional<Path> outputFile = std::nullopt;
CmdStoreExport()
{
addFlag({
.longName = "output-file",
.description = "Write the archive to the given file instead of stdout.",
.labels = {"file"},
.handler = {&outputFile},
});
}
void run(ref<Store> store, StorePaths && storePaths) override
{
// We don't use the format parameter now, but we still want to enforce it
// being specified to not block us on backwards-compatibility.
if (!format)
throw UsageError("`--format` must be specified");
StorePathSet pathsAsSet;
pathsAsSet.insert(storePaths.begin(), storePaths.end());
auto sink = [&]() -> FdSink {
if (outputFile) {
if (*outputFile == "-") {
return FdSink(STDOUT_FILENO);
} else {
auto fd = open(outputFile->c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644);
return FdSink(fd);
}
} else if (isatty(STDOUT_FILENO)) {
throw Error("Refusing to write binary data to a terminal. Use `--output-file` to specify a file to write to.");
} else {
return FdSink(STDOUT_FILENO);
}
}();
store->exportPaths(pathsAsSet, sink);
sink.flush();
}
};
struct CmdStoreImport : StoreCommand, MixImportExport
{
std::string description() override
{
return "Import the given store path(s) from a file created by `nix store export`.";
}
std::string doc() override
{
return
#include "store-import.md"
;
}
std::optional<Path> inputFile = std::nullopt;
CmdStoreImport() {
addFlag({
.longName = "input-file",
.description = "Read the archive from the given file instead of stdin.",
.labels = {"file"},
.handler = {&inputFile},
});
}
void run(ref<Store> store) override
{
FdSource source = [&]() -> FdSource {
if (inputFile && *inputFile != "-") {
auto fd = open(inputFile->c_str(), O_RDONLY);
return FdSource(fd);
} else {
return FdSource(STDIN_FILENO);
}
}();
auto paths = store->importPaths(source, NoCheckSigs);
for (auto & path : paths)
logger->cout("%s", store->printStorePath(path));
}
};
static auto rStoreExport = registerCommand2<CmdStoreExport>({"store", "export"});
static auto rStoreImport = registerCommand2<CmdStoreImport>({"store", "import"});

16
src/nix/store-import.md Normal file
View file

@ -0,0 +1,16 @@
R""(
# Examples
* Import a closure that has been exported from another machine
```console
$ ssh user@otherHost nix store export --recursive --format binary nixpkgs#hello > hello-closure.tar
$ nix store import < hello-closure.tar
```
# Description
This command reads an archive of store paths, as produced by [`nix store export`](@docroot@/command-ref/new-cli/nix3-store-export.md), and adds it to the store.
)""

View file

@ -107,6 +107,7 @@ nix_tests = \
completions.sh \
impure-derivations.sh \
path-from-hash-part.sh \
store-import-export.sh \
path-info.sh \
toString-path.sh \
read-only-store.sh \

View file

@ -0,0 +1,38 @@
source config.sh
clearStore
BUILT_STORE_PATHS=$(nix build -f ./dependencies.nix input1_drv input2_drv --no-link --print-out-paths | sort)
# Make sure that we require the `--format` argument.
expect 1 nix store export --recursive $BUILT_STORE_PATHS > "$TEST_ROOT/store-export" 2> /dev/null || \
fail "nix store export should require the --format argument"
nix store export --format binary --recursive $BUILT_STORE_PATHS > "$TEST_ROOT/store-export"
clearStore
IMPORTED_STORE_PATHS=$(nix store import < "$TEST_ROOT/store-export" | sort)
# Make sure that the paths we built previously are still valid.
for BUILT_STORE_PATH in $BUILT_STORE_PATHS; do
nix path-info "$BUILT_STORE_PATH" || \
fail "path $BUILT_STORE_PATH should have been imported but isn't valid"
done
# Make sure that all the imported paths are valid.
for IMPORTED_STORE_PATH in $IMPORTED_STORE_PATHS; do
nix path-info "$IMPORTED_STORE_PATH" ||
fail "path $BUILT_STORE_PATH should have been imported but isn't valid"
done
faketty () {
# Run a command in a pseudo-terminal.
script -qefc "$(printf "%q " "$@")" /dev/null
}
! faketty nix store export --format binary --recursive $BUILT_STORE_PATHS > /dev/null || \
fail "nix store export should refuse to write in a tty by default"
faketty nix store export --format binary --recursive $BUILT_STORE_PATHS --output-file - > /dev/null || \
fail "nix store export should accept to write in a tty if explicitly asked to"
nix store export --format binary --recursive $BUILT_STORE_PATHS --output-file "$TEST_ROOT/store-export2"
diff "$TEST_ROOT/store-export" "$TEST_ROOT/store-export2" || \
fail '`nix store export --output-file blah` should be equivalent to `nix store export > blah`'