diff options
author | Eelco Dolstra <eelco.dolstra@logicblox.com> | 2016-04-29T18·14+0200 |
---|---|---|
committer | Eelco Dolstra <eelco.dolstra@logicblox.com> | 2016-04-29T18·47+0200 |
commit | 38539b943a060d9cdfc24d6e5d997c0885b8aa2f (patch) | |
tree | 3f17e49cd6f969dec78befab26e7c68ce3c05956 /src/libexpr/primops | |
parent | 83258225e6be25cd706df0f96dcbd4b04c352056 (diff) |
Add fetchgit builtin
The function builtins.fetchgit fetches Git repositories at evaluation time, similar to builtins.fetchTarball. (Perhaps the name should be changed, being confusing with respect to Nixpkgs's fetchgit function, with works at build time.) Example: (import (builtins.fetchgit git://github.com/NixOS/nixpkgs) {}).hello or (import (builtins.fetchgit { url = git://github.com/NixOS/nixpkgs-channels; rev = "nixos-16.03"; }) {}).hello Note that the result does not contain a .git directory.
Diffstat (limited to 'src/libexpr/primops')
-rw-r--r-- | src/libexpr/primops/fetchgit.cc | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/src/libexpr/primops/fetchgit.cc b/src/libexpr/primops/fetchgit.cc new file mode 100644 index 000000000000..e2a545ee0562 --- /dev/null +++ b/src/libexpr/primops/fetchgit.cc @@ -0,0 +1,77 @@ +#include "primops.hh" +#include "eval-inline.hh" +#include "download.hh" +#include "store-api.hh" + +namespace nix { + +static void prim_fetchgit(EvalState & state, const Pos & pos, Value * * args, Value & v) +{ + // FIXME: cut&paste from fetch(). + if (state.restricted) throw Error("‘fetchgit’ is not allowed in restricted mode"); + + std::string url; + std::string rev = "master"; + + state.forceValue(*args[0]); + + if (args[0]->type == tAttrs) { + + state.forceAttrs(*args[0], pos); + + for (auto & attr : *args[0]->attrs) { + string name(attr.name); + if (name == "url") + url = state.forceStringNoCtx(*attr.value, *attr.pos); + else if (name == "rev") + rev = state.forceStringNoCtx(*attr.value, *attr.pos); + else + throw EvalError(format("unsupported argument ‘%1%’ to ‘fetchgit’, at %3%") % attr.name % attr.pos); + } + + if (url.empty()) + throw EvalError(format("‘url’ argument required, at %1%") % pos); + + } else + url = state.forceStringNoCtx(*args[0], pos); + + if (!isUri(url)) + throw EvalError(format("‘%s’ is not a valid URI, at %s") % url % pos); + + Path cacheDir = getCacheDir() + "/nix/git"; + + if (!pathExists(cacheDir)) { + createDirs(cacheDir); + runProgram("git", true, { "init", "--bare", cacheDir }); + } + + Activity act(*logger, lvlInfo, format("fetching Git repository ‘%s’") % url); + + std::string localRef = "pid-" + std::to_string(getpid()); + Path localRefFile = cacheDir + "/refs/heads/" + localRef; + + runProgram("git", true, { "-C", cacheDir, "fetch", url, rev + ":" + localRef }); + + std::string commitHash = chomp(readFile(localRefFile)); + + unlink(localRefFile.c_str()); + + debug(format("got revision ‘%s’") % commitHash); + + // FIXME: should pipe this, or find some better way to extract a + // revision. + auto tar = runProgram("git", true, { "-C", cacheDir, "archive", commitHash }); + + Path tmpDir = createTempDir(); + AutoDelete delTmpDir(tmpDir, true); + + runProgram("tar", true, { "x", "-C", tmpDir }, tar); + + Path storePath = state.store->addToStore("git-export", tmpDir); + + mkString(v, storePath, PathSet({storePath})); +} + +static RegisterPrimOp r("__fetchgit", 1, prim_fetchgit); + +} |