1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2024-09-19 10:50:24 -04:00

Raise EvalError if remote is missing. Unpack archive before adding to nix store

This commit is contained in:
Tobias Bergkvist 2023-04-05 03:30:35 +02:00
parent 566103edb8
commit 4452d36181

View file

@ -1,14 +1,17 @@
#include "primops.hh" #include "primops.hh"
#include "store-api.hh" #include "store-api.hh"
#include "cache.hh" #include "cache.hh"
#include "tarfile.hh"
#include "archive.hh"
namespace nix { namespace nix {
static void prim_fetchGitArchive(EvalState & state, const PosIdx pos, Value * * args, Value & v) static void prim_fetchGitArchive(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{ {
std::optional<Hash> expectedHash; std::optional<Hash> expectedHash;
std::string name = "source.tar.gz"; std::optional<std::string> remote;
std::string remote = ""; std::string name = "source";
std::string format = "tar.gz"; std::string format = "tar.gz";
std::string version = "HEAD"; std::string version = "HEAD";
@ -20,7 +23,7 @@ static void prim_fetchGitArchive(EvalState & state, const PosIdx pos, Value * *
else if (n == "sha256") else if (n == "sha256")
expectedHash = newHashAllowEmpty(state.forceStringNoCtx(*attr.value, attr.pos, "while evaluating the sha256 of the git archive we should fetch"), htSHA256); expectedHash = newHashAllowEmpty(state.forceStringNoCtx(*attr.value, attr.pos, "while evaluating the sha256 of the git archive we should fetch"), htSHA256);
else if (n == "remote") else if (n == "remote")
remote = state.forceStringNoCtx(*attr.value, attr.pos, "while evaluating the remote of the git archive we should fetch"); remote.emplace(state.forceStringNoCtx(*attr.value, attr.pos, "while evaluating the remote of the git archive we should fetch"));
else if (n == "format") else if (n == "format")
format = state.forceStringNoCtx(*attr.value, attr.pos, "while evaluating the format of the git archive we should fetch"); format = state.forceStringNoCtx(*attr.value, attr.pos, "while evaluating the format of the git archive we should fetch");
else if (n == "version") else if (n == "version")
@ -32,6 +35,12 @@ static void prim_fetchGitArchive(EvalState & state, const PosIdx pos, Value * *
})); }));
} }
if (!remote) {
state.debugThrowLastTrace(EvalError({
.msg = hintfmt("missing required argument 'remote' to 'fetchGitArchive'"),
.errPos = state.positions[pos]
}));
}
if (evalSettings.pureEval && !expectedHash) { if (evalSettings.pureEval && !expectedHash) {
state.debugThrowLastTrace(EvalError({ state.debugThrowLastTrace(EvalError({
.msg = hintfmt("in pure evaluation mode, 'fetchGitArchive' requires a 'sha256' argument"), .msg = hintfmt("in pure evaluation mode, 'fetchGitArchive' requires a 'sha256' argument"),
@ -49,7 +58,7 @@ static void prim_fetchGitArchive(EvalState & state, const PosIdx pos, Value * *
auto inAttrs = fetchers::Attrs({ auto inAttrs = fetchers::Attrs({
{"type", "git-archive"}, {"type", "git-archive"},
{"name", name}, {"name", name},
{"remote", remote}, {"remote", *remote},
{"version", version}, {"version", version},
{"format", format} {"format", format}
}); });
@ -61,38 +70,43 @@ static void prim_fetchGitArchive(EvalState & state, const PosIdx pos, Value * *
return; return;
} }
// Run `git archive`
auto [errorCode, programOutput] = runProgram(RunOptions { auto [errorCode, programOutput] = runProgram(RunOptions {
.program = "git", .program = "git",
.args = {"archive", "--format=" + format, "--remote=" + remote, version}, .args = {"archive", "--format=" + format, "--remote=" + *remote, version},
.mergeStderrToStdout = true .mergeStderrToStdout = true
}); });
if (errorCode) { if (errorCode) {
state.debugThrowLastTrace(EvalError({ state.debugThrowLastTrace(EvalError({
.msg = hintfmt(programOutput), .msg = hintfmt("git archive failed with exit code %i:\n" + programOutput, errorCode),
.errPos = state.positions[pos] .errPos = state.positions[pos]
})); }));
} }
// Add archive to nix store auto tarSource = StringSource(programOutput);
auto hash = expectedHash ? expectedHash.value() : hashString(htSHA256, programOutput); auto tmpDir = createTempDir();
auto storePath = state.store->makeFixedOutputPath(FileIngestionMethod::Flat, hash, name); AutoDelete(tmpDir, true);
unpackTarfile(tarSource, tmpDir);
StringSink narSink; PathFilter filter = [](const Path &) { return true; };
narSink << "nix-archive-1" << "(" << "type" << "regular" << "contents" << programOutput << ")"; auto storePath = state.store->addToStore(name, tmpDir, FileIngestionMethod::Recursive, htSHA256, filter);
auto narSource = StringSource(narSink.s); if (expectedHash) {
auto narHash = hashString(htSHA256, narSink.s); auto narHash = state.store->queryPathInfo(storePath)->narHash;
auto narSize = narSink.s.size(); if (narHash != *expectedHash) {
state.debugThrowLastTrace(EvalError({
auto info = ValidPathInfo { storePath, narHash }; .msg = hintfmt(
info.narSize = narSize; "hash mismatch in git archive downloaded from (remote) :\n specified: %s\n got: %s",
info.ca = FixedOutputHash { FileIngestionMethod::Flat, hash }; expectedHash->to_string(Base32, true),
narHash.to_string(Base32, true)
state.store->addToStore(info, narSource, NoRepair, NoCheckSigs); ),
.errPos = state.positions[pos]
}));
}
}
state.allowAndSetStorePathString(storePath, v); state.allowAndSetStorePathString(storePath, v);
auto infoAttrs = fetchers::Attrs({});
bool locked = (bool) expectedHash; bool locked = (bool) expectedHash;
fetchers::getCache()->add(state.store, inAttrs, {}, storePath, locked); fetchers::getCache()->add(state.store, inAttrs, infoAttrs, storePath, locked);
} }
static RegisterPrimOp primop_fetchGitArchive({ static RegisterPrimOp primop_fetchGitArchive({