Add path flakeref variant

Unlike file://<path>, this allows the path to be a dirty Git tree, so

  nix build /path/to/flake:attr

is a convenient way to test building a local flake.
This commit is contained in:
Eelco Dolstra 2019-04-08 22:46:25 +02:00
parent a9ceeeb4b0
commit 6a4c7fb975
6 changed files with 49 additions and 5 deletions

View file

@ -170,7 +170,7 @@ GitInfo exportGit(ref<Store> store, const std::string & uri,
json["uri"] = uri; json["uri"] = uri;
json["name"] = name; json["name"] = name;
json["rev"] = gitInfo.rev; json["rev"] = gitInfo.rev;
json["revCount"] = gitInfo.revCount; json["revCount"] = *gitInfo.revCount;
writeFile(storeLink, json.dump()); writeFile(storeLink, json.dump());
@ -224,7 +224,7 @@ static void prim_fetchGit(EvalState & state, const Pos & pos, Value * * args, Va
mkString(*state.allocAttr(v, state.sOutPath), gitInfo.storePath, PathSet({gitInfo.storePath})); 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("rev")), gitInfo.rev);
mkString(*state.allocAttr(v, state.symbols.create("shortRev")), gitInfo.shortRev); mkString(*state.allocAttr(v, state.symbols.create("shortRev")), gitInfo.shortRev);
mkInt(*state.allocAttr(v, state.symbols.create("revCount")), gitInfo.revCount); mkInt(*state.allocAttr(v, state.symbols.create("revCount")), gitInfo.revCount.value_or(0));
v.attrs->sort(); v.attrs->sort();
if (state.allowedPaths) if (state.allowedPaths)

View file

@ -11,7 +11,7 @@ struct GitInfo
Path storePath; Path storePath;
std::string rev; std::string rev;
std::string shortRev; std::string shortRev;
uint64_t revCount = 0; std::optional<uint64_t> revCount;
}; };
GitInfo exportGit(ref<Store> store, const std::string & uri, GitInfo exportGit(ref<Store> store, const std::string & uri,

View file

@ -129,6 +129,7 @@ struct FlakeSourceInfo
{ {
Path storePath; Path storePath;
std::optional<Hash> rev; std::optional<Hash> rev;
std::optional<uint64_t> revCount;
}; };
static FlakeSourceInfo fetchFlake(EvalState & state, const FlakeRef & flakeRef) static FlakeSourceInfo fetchFlake(EvalState & state, const FlakeRef & flakeRef)
@ -178,6 +179,18 @@ static FlakeSourceInfo fetchFlake(EvalState & state, const FlakeRef & flakeRef)
FlakeSourceInfo info; FlakeSourceInfo info;
info.storePath = gitInfo.storePath; info.storePath = gitInfo.storePath;
info.rev = Hash(gitInfo.rev, htSHA1); info.rev = Hash(gitInfo.rev, htSHA1);
info.revCount = gitInfo.revCount;
return info;
}
else if (auto refData = std::get_if<FlakeRef::IsPath>(&directFlakeRef.data)) {
if (!pathExists(refData->path + "/.git"))
throw Error("flake '%s' does not reference a Git repository", refData->path);
auto gitInfo = exportGit(state.store, refData->path, {}, "", "source");
FlakeSourceInfo info;
info.storePath = gitInfo.storePath;
info.rev = Hash(gitInfo.rev, htSHA1);
info.revCount = gitInfo.revCount;
return info; return info;
} }
@ -206,6 +219,8 @@ Flake getFlake(EvalState & state, const FlakeRef & flakeRef)
} }
Flake flake(newFlakeRef); Flake flake(newFlakeRef);
flake.path = flakePath;
flake.revCount = sourceInfo.revCount;
Value vInfo; Value vInfo;
state.evalFile(flakePath + "/flake.nix", vInfo); // FIXME: symlink attack state.evalFile(flakePath + "/flake.nix", vInfo); // FIXME: symlink attack
@ -349,10 +364,20 @@ Value * makeFlakeValue(EvalState & state, const FlakeRef & flakeRef, bool impure
for (auto & flake : flakes) { for (auto & flake : flakes) {
auto vFlake = state.allocAttr(*vResult, flake.second.id); auto vFlake = state.allocAttr(*vResult, flake.second.id);
if (topFlakeId == flake.second.id) vTop = vFlake; if (topFlakeId == flake.second.id) vTop = vFlake;
state.mkAttrs(*vFlake, 2);
state.mkAttrs(*vFlake, 4);
mkString(*state.allocAttr(*vFlake, state.sDescription), flake.second.description); mkString(*state.allocAttr(*vFlake, state.sDescription), flake.second.description);
state.store->assertStorePath(flake.second.path);
mkString(*state.allocAttr(*vFlake, state.sOutPath), flake.second.path, {flake.second.path});
if (flake.second.revCount)
mkInt(*state.allocAttr(*vFlake, state.symbols.create("revCount")), *flake.second.revCount);
auto vProvides = state.allocAttr(*vFlake, state.symbols.create("provides")); auto vProvides = state.allocAttr(*vFlake, state.symbols.create("provides"));
mkApp(*vProvides, *flake.second.vProvides, *vResult); mkApp(*vProvides, *flake.second.vProvides, *vResult);
vFlake->attrs->sort(); vFlake->attrs->sort();
} }

View file

@ -35,6 +35,7 @@ struct Flake
FlakeRef ref; FlakeRef ref;
std::string description; std::string description;
Path path; Path path;
std::optional<uint64_t> revCount;
std::vector<FlakeRef> requires; std::vector<FlakeRef> requires;
std::shared_ptr<FlakeRegistry> lockFile; std::shared_ptr<FlakeRegistry> lockFile;
Value * vProvides; // FIXME: gc Value * vProvides; // FIXME: gc

View file

@ -106,6 +106,12 @@ FlakeRef::FlakeRef(const std::string & uri)
data = d; data = d;
} }
else if (hasPrefix(uri, "/")) {
IsPath d;
d.path = canonPath(uri);
data = d;
}
else else
throw Error("'%s' is not a valid flake reference", uri); throw Error("'%s' is not a valid flake reference", uri);
} }
@ -135,6 +141,10 @@ std::string FlakeRef::to_string() const
(refData->rev ? "&rev=" + refData->rev->to_string(Base16, false) : ""); (refData->rev ? "&rev=" + refData->rev->to_string(Base16, false) : "");
} }
else if (auto refData = std::get_if<FlakeRef::IsPath>(&data)) {
return refData->path;
}
else abort(); else abort();
} }
@ -149,6 +159,9 @@ bool FlakeRef::isImmutable() const
else if (auto refData = std::get_if<FlakeRef::IsGit>(&data)) else if (auto refData = std::get_if<FlakeRef::IsGit>(&data))
return (bool) refData->rev; return (bool) refData->rev;
else if (std::get_if<FlakeRef::IsPath>(&data))
return false;
else abort(); else abort();
} }

View file

@ -122,9 +122,14 @@ struct FlakeRef
std::optional<Hash> rev; std::optional<Hash> rev;
}; };
struct IsPath
{
Path path;
};
// Git, Tarball // Git, Tarball
std::variant<IsFlakeId, IsGitHub, IsGit> data; std::variant<IsFlakeId, IsGitHub, IsGit, IsPath> data;
// Parse a flake URI. // Parse a flake URI.
FlakeRef(const std::string & uri); FlakeRef(const std::string & uri);