1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-06-24 22:11:15 +02:00

Add builtins.fetchGitArchive

This commit is contained in:
Tobias Bergkvist 2023-04-02 05:33:44 +02:00
parent 2ef99cd104
commit 566103edb8

View file

@ -0,0 +1,121 @@
#include "primops.hh"
#include "store-api.hh"
#include "cache.hh"
namespace nix {
static void prim_fetchGitArchive(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
std::optional<Hash> expectedHash;
std::string name = "source.tar.gz";
std::string remote = "";
std::string format = "tar.gz";
std::string version = "HEAD";
state.forceValue(*args[0], pos);
for (auto & attr : *args[0]->attrs) {
std::string_view n(state.symbols[attr.name]);
if (n == "name")
name = state.forceStringNoCtx(*attr.value, attr.pos, "while evaluating the name of the git archive we should fetch");
else if (n == "sha256")
expectedHash = newHashAllowEmpty(state.forceStringNoCtx(*attr.value, attr.pos, "while evaluating the sha256 of the git archive we should fetch"), htSHA256);
else if (n == "remote")
remote = state.forceStringNoCtx(*attr.value, attr.pos, "while evaluating the remote of the git archive we should fetch");
else if (n == "format")
format = state.forceStringNoCtx(*attr.value, attr.pos, "while evaluating the format of the git archive we should fetch");
else if (n == "version")
version = state.forceStringNoCtx(*attr.value, attr.pos, "while evaluating the version of the git archive we should fetch");
else
state.debugThrowLastTrace(EvalError({
.msg = hintfmt("unsupported argument '%s' to 'fetchGitArchive'", n),
.errPos = state.positions[attr.pos]
}));
}
if (evalSettings.pureEval && !expectedHash) {
state.debugThrowLastTrace(EvalError({
.msg = hintfmt("in pure evaluation mode, 'fetchGitArchive' requires a 'sha256' argument"),
.errPos = state.positions[pos]
}));
}
if (expectedHash) {
auto expectedPath = state.store->makeFixedOutputPath(FileIngestionMethod::Recursive, *expectedHash, name, {});
if (state.store->isValidPath(expectedPath)) {
state.allowAndSetStorePathString(expectedPath, v);
return;
}
}
auto inAttrs = fetchers::Attrs({
{"type", "git-archive"},
{"name", name},
{"remote", remote},
{"version", version},
{"format", format}
});
if (auto res = fetchers::getCache()->lookup(state.store, inAttrs)) {
auto infoAttrs = res->first;
auto storePath = res->second;
state.allowAndSetStorePathString(storePath, v);
return;
}
// Run `git archive`
auto [errorCode, programOutput] = runProgram(RunOptions {
.program = "git",
.args = {"archive", "--format=" + format, "--remote=" + remote, version},
.mergeStderrToStdout = true
});
if (errorCode) {
state.debugThrowLastTrace(EvalError({
.msg = hintfmt(programOutput),
.errPos = state.positions[pos]
}));
}
// Add archive to nix store
auto hash = expectedHash ? expectedHash.value() : hashString(htSHA256, programOutput);
auto storePath = state.store->makeFixedOutputPath(FileIngestionMethod::Flat, hash, name);
StringSink narSink;
narSink << "nix-archive-1" << "(" << "type" << "regular" << "contents" << programOutput << ")";
auto narSource = StringSource(narSink.s);
auto narHash = hashString(htSHA256, narSink.s);
auto narSize = narSink.s.size();
auto info = ValidPathInfo { storePath, narHash };
info.narSize = narSize;
info.ca = FixedOutputHash { FileIngestionMethod::Flat, hash };
state.store->addToStore(info, narSource, NoRepair, NoCheckSigs);
state.allowAndSetStorePathString(storePath, v);
bool locked = (bool) expectedHash;
fetchers::getCache()->add(state.store, inAttrs, {}, storePath, locked);
}
static RegisterPrimOp primop_fetchGitArchive({
.name = "fetchGitArchive",
.args = {"args"},
.doc = R"(
Fetch a git archive using the git-archive command.
See https://git-scm.com/docs/git-archive
*args* is an attribute set with the following attributes:
- `name`
- `remote`
- `format`
- `version`
- `sha256`
To fetch a version from a private repository over SSH:
```nix
builtins.fetchGitArchive {
remote = "git@gitlab.com:my-secret/repository.git";
version = "v1.2.3";
}
```
)",
.fun = prim_fetchGitArchive,
});
}