builtins.fetchGit: Return an attrset with revision info
This adds rev, shortRev and revCount attributes, equal to what Hydra provides. E.g. $ nix eval '(fetchGit https://github.com/NixOS/patchelf.git)' { outPath = "/nix/store/ghigrkw02l440g8vfxa9wj4c3zpfmw99-source"; rev = "29c085fd9d3fc972f75b3961905d6b4ecce7eb2b"; revCount = 303; shortRev = "29c085f"; }
This commit is contained in:
parent
f9686885be
commit
e38382895d
3 changed files with 54 additions and 18 deletions
|
@ -667,7 +667,7 @@ std::pair<bool, std::string> EvalState::resolveSearchPathElem(const SearchPathEl
|
||||||
try {
|
try {
|
||||||
if (hasPrefix(elem.second, "git://") || hasSuffix(elem.second, ".git"))
|
if (hasPrefix(elem.second, "git://") || hasSuffix(elem.second, ".git"))
|
||||||
// FIXME: support specifying revision/branch
|
// FIXME: support specifying revision/branch
|
||||||
res = { true, exportGit(store, elem.second, "master") };
|
res = { true, exportGit(store, elem.second, "master").storePath };
|
||||||
else
|
else
|
||||||
res = { true, getDownloader()->downloadCached(store, elem.second, true) };
|
res = { true, getDownloader()->downloadCached(store, elem.second, true) };
|
||||||
} catch (DownloadError & e) {
|
} catch (DownloadError & e) {
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#include "fetchgit.hh"
|
||||||
#include "primops.hh"
|
#include "primops.hh"
|
||||||
#include "eval-inline.hh"
|
#include "eval-inline.hh"
|
||||||
#include "download.hh"
|
#include "download.hh"
|
||||||
|
@ -8,11 +9,13 @@
|
||||||
|
|
||||||
#include <regex>
|
#include <regex>
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
using namespace std::string_literals;
|
using namespace std::string_literals;
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
Path exportGit(ref<Store> store, const std::string & uri,
|
GitInfo exportGit(ref<Store> store, const std::string & uri,
|
||||||
const std::string & ref, const std::string & rev,
|
const std::string & ref, const std::string & rev,
|
||||||
const std::string & name)
|
const std::string & name)
|
||||||
{
|
{
|
||||||
|
@ -56,36 +59,56 @@ Path exportGit(ref<Store> store, const std::string & uri,
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: check whether rev is an ancestor of ref.
|
// FIXME: check whether rev is an ancestor of ref.
|
||||||
std::string commitHash = rev != "" ? rev : chomp(readFile(localRefFile));
|
GitInfo gitInfo;
|
||||||
|
gitInfo.rev = rev != "" ? rev : chomp(readFile(localRefFile));
|
||||||
|
gitInfo.shortRev = std::string(gitInfo.rev, 0, 7);
|
||||||
|
|
||||||
printTalkative("using revision %s of repo '%s'", uri, commitHash);
|
printTalkative("using revision %s of repo '%s'", uri, gitInfo.rev);
|
||||||
|
|
||||||
std::string storeLinkName = hashString(htSHA512, name + std::string("\0"s) + commitHash).to_string(Base32, false);
|
std::string storeLinkName = hashString(htSHA512, name + std::string("\0"s) + gitInfo.rev).to_string(Base32, false);
|
||||||
Path storeLink = cacheDir + "/" + storeLinkName + ".link";
|
Path storeLink = cacheDir + "/" + storeLinkName + ".link";
|
||||||
PathLocks storeLinkLock({storeLink}, fmt("waiting for lock on '%1%'...", storeLink));
|
PathLocks storeLinkLock({storeLink}, fmt("waiting for lock on '%1%'...", storeLink));
|
||||||
|
|
||||||
if (pathExists(storeLink)) {
|
try {
|
||||||
auto storePath = readLink(storeLink);
|
// FIXME: doesn't handle empty lines
|
||||||
store->addTempRoot(storePath);
|
auto json = nlohmann::json::parse(readFile(storeLink));
|
||||||
if (store->isValidPath(storePath)) {
|
|
||||||
return storePath;
|
assert(json["uri"] == uri && json["name"] == name && json["rev"] == gitInfo.rev);
|
||||||
|
|
||||||
|
gitInfo.storePath = json["storePath"];
|
||||||
|
|
||||||
|
if (store->isValidPath(gitInfo.storePath)) {
|
||||||
|
gitInfo.revCount = json["revCount"];
|
||||||
|
return gitInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} catch (SysError & e) {
|
||||||
|
if (e.errNo != ENOENT) throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: should pipe this, or find some better way to extract a
|
// FIXME: should pipe this, or find some better way to extract a
|
||||||
// revision.
|
// revision.
|
||||||
auto tar = runProgram("git", true, { "-C", cacheDir, "archive", commitHash });
|
auto tar = runProgram("git", true, { "-C", cacheDir, "archive", gitInfo.rev });
|
||||||
|
|
||||||
Path tmpDir = createTempDir();
|
Path tmpDir = createTempDir();
|
||||||
AutoDelete delTmpDir(tmpDir, true);
|
AutoDelete delTmpDir(tmpDir, true);
|
||||||
|
|
||||||
runProgram("tar", true, { "x", "-C", tmpDir }, tar);
|
runProgram("tar", true, { "x", "-C", tmpDir }, tar);
|
||||||
|
|
||||||
auto storePath = store->addToStore(name, tmpDir);
|
gitInfo.storePath = store->addToStore(name, tmpDir);
|
||||||
|
|
||||||
replaceSymlink(storePath, storeLink);
|
gitInfo.revCount = std::stoull(runProgram("git", true, { "-C", cacheDir, "rev-list", "--count", gitInfo.rev }));
|
||||||
|
|
||||||
return storePath;
|
nlohmann::json json;
|
||||||
|
json["storePath"] = gitInfo.storePath;
|
||||||
|
json["uri"] = uri;
|
||||||
|
json["name"] = name;
|
||||||
|
json["rev"] = gitInfo.rev;
|
||||||
|
json["revCount"] = gitInfo.revCount;
|
||||||
|
|
||||||
|
writeFile(storeLink, json.dump());
|
||||||
|
|
||||||
|
return gitInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void prim_fetchGit(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
static void prim_fetchGit(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
|
@ -127,9 +150,14 @@ static void prim_fetchGit(EvalState & state, const Pos & pos, Value * * args, Va
|
||||||
} else
|
} else
|
||||||
url = state.forceStringNoCtx(*args[0], pos);
|
url = state.forceStringNoCtx(*args[0], pos);
|
||||||
|
|
||||||
Path storePath = exportGit(state.store, url, ref, rev, name);
|
auto gitInfo = exportGit(state.store, url, ref, rev, name);
|
||||||
|
|
||||||
mkString(v, storePath, PathSet({storePath}));
|
state.mkAttrs(v, 8);
|
||||||
|
mkString(*state.allocAttr(v, state.sOutPath), gitInfo.storePath, PathSet({gitInfo.storePath}));
|
||||||
|
mkString(*state.allocAttr(v, state.symbols.create("rev")), gitInfo.rev);
|
||||||
|
mkString(*state.allocAttr(v, state.symbols.create("shortRev")), gitInfo.shortRev);
|
||||||
|
mkInt(*state.allocAttr(v, state.symbols.create("revCount")), gitInfo.revCount);
|
||||||
|
v.attrs->sort();
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp r("fetchGit", 1, prim_fetchGit);
|
static RegisterPrimOp r("fetchGit", 1, prim_fetchGit);
|
||||||
|
|
|
@ -2,13 +2,21 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "ref.hh"
|
#include "util.hh"
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
class Store;
|
class Store;
|
||||||
|
|
||||||
Path exportGit(ref<Store> store, const std::string & uri,
|
struct GitInfo
|
||||||
|
{
|
||||||
|
Path storePath;
|
||||||
|
std::string rev;
|
||||||
|
std::string shortRev;
|
||||||
|
uint64_t revCount = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
GitInfo exportGit(ref<Store> store, const std::string & uri,
|
||||||
const std::string & ref, const std::string & rev = "",
|
const std::string & ref, const std::string & rev = "",
|
||||||
const std::string & name = "");
|
const std::string & name = "");
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue