aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libexpr/primops/flake.cc43
-rw-r--r--src/libexpr/primops/flake.hh3
-rw-r--r--src/libexpr/primops/flakeref.hh1
-rw-r--r--src/libutil/util.cc7
-rw-r--r--src/nix/flake.cc29
5 files changed, 77 insertions, 6 deletions
diff --git a/src/libexpr/primops/flake.cc b/src/libexpr/primops/flake.cc
index c098168de..d898da1e9 100644
--- a/src/libexpr/primops/flake.cc
+++ b/src/libexpr/primops/flake.cc
@@ -146,17 +146,19 @@ std::shared_ptr<FlakeRegistry> getFlagRegistry()
return std::make_shared<FlakeRegistry>();
}
-const std::vector<std::shared_ptr<FlakeRegistry>> EvalState::getFlakeRegistries()
+// This always returns a vector with globalReg, userReg, localReg, flakeReg.
+// If one of them doesn't exist, the registry is left empty but does exist.
+const Registries EvalState::getFlakeRegistries()
{
- std::vector<std::shared_ptr<FlakeRegistry>> registries;
- registries.push_back(getGlobalRegistry());
+ Registries registries;
+ registries.push_back(getGlobalRegistry()); // TODO (Nick): Doesn't this break immutability?
registries.push_back(getUserRegistry());
+ registries.push_back(std::make_shared<FlakeRegistry>()); // local
registries.push_back(getFlagRegistry());
return registries;
}
-static FlakeRef lookupFlake(EvalState & state, const FlakeRef & flakeRef,
- const std::vector<std::shared_ptr<FlakeRegistry>> & registries,
+static FlakeRef lookupFlake(EvalState & state, const FlakeRef & flakeRef, const Registries & registries,
std::vector<FlakeRef> pastSearches = {})
{
if (registries.empty() && !flakeRef.isDirect())
@@ -467,4 +469,35 @@ static void prim_getFlake(EvalState & state, const Pos & pos, Value * * args, Va
static RegisterPrimOp r2("getFlake", 1, prim_getFlake);
+void gitCloneFlake (std::string flakeUri, EvalState & state, Registries registries,
+ Path endDirectory)
+{
+ FlakeRef flakeRef(flakeUri);
+ flakeRef = lookupFlake(state, flakeRef, registries);
+
+ std::string uri;
+
+ Strings args = {"clone"};
+
+ if (auto refData = std::get_if<FlakeRef::IsGitHub>(&flakeRef.data)) {
+ uri = "git@github.com:" + refData->owner + "/" + refData->repo + ".git";
+ args.push_back(uri);
+ if (flakeRef.ref) {
+ args.push_back("--branch");
+ args.push_back(*flakeRef.ref);
+ }
+ } else if (auto refData = std::get_if<FlakeRef::IsGit>(&flakeRef.data)) {
+ args.push_back(refData->uri);
+ if (flakeRef.ref) {
+ args.push_back("--branch");
+ args.push_back(*flakeRef.ref);
+ }
+ }
+
+ if (endDirectory != "")
+ args.push_back(endDirectory);
+
+ runProgram("git", true, args);
+}
+
}
diff --git a/src/libexpr/primops/flake.hh b/src/libexpr/primops/flake.hh
index 0b70088cc..4e0d3b646 100644
--- a/src/libexpr/primops/flake.hh
+++ b/src/libexpr/primops/flake.hh
@@ -27,6 +27,8 @@ struct LockFile
std::map<FlakeId, FlakeRef> nonFlakeEntries;
};
+typedef std::vector<std::shared_ptr<FlakeRegistry>> Registries;
+
Path getUserRegistryPath();
enum RegistryAccess { DisallowRegistry, AllowRegistry, AllowRegistryAtTop };
@@ -86,4 +88,5 @@ ResolvedFlake resolveFlake(EvalState &, const FlakeRef &, RegistryAccess registr
void updateLockFile(EvalState &, const Path & path);
+void gitCloneFlake (std::string flakeUri, EvalState &, Registries, Path);
}
diff --git a/src/libexpr/primops/flakeref.hh b/src/libexpr/primops/flakeref.hh
index e599e2feb..51fdc3b70 100644
--- a/src/libexpr/primops/flakeref.hh
+++ b/src/libexpr/primops/flakeref.hh
@@ -69,6 +69,7 @@ namespace nix {
https://example.org/my/repo.git
https://example.org/my/repo.git?ref=release-1.2.3
https://example.org/my/repo.git?rev=e72daba8250068216d79d2aeef40d4d95aff6666
+ git://github.com/edolstra/dwarffs.git\?ref=flake\&rev=2efca4bc9da70fb001b26c3dc858c6397d3c4817
* /path.git(\?attr(&attr)*)?
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index b0a2b853e..f4f86c5c8 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -962,12 +962,14 @@ std::vector<char *> stringsToCharPtrs(const Strings & ss)
return res;
}
-
+// Output = "standard out" output stream
string runProgram(Path program, bool searchPath, const Strings & args,
const std::optional<std::string> & input)
{
RunOptions opts(program, args);
opts.searchPath = searchPath;
+ // This allows you to refer to a program with a pathname relative to the
+ // PATH variable.
opts.input = input;
auto res = runProgram(opts);
@@ -978,6 +980,7 @@ string runProgram(Path program, bool searchPath, const Strings & args,
return res.second;
}
+// Output = error code + "standard out" output stream
std::pair<int, std::string> runProgram(const RunOptions & options_)
{
RunOptions options(options_);
@@ -1028,6 +1031,8 @@ void runProgram2(const RunOptions & options)
if (options.searchPath)
execvp(options.program.c_str(), stringsToCharPtrs(args_).data());
+ // This allows you to refer to a program with a pathname relative
+ // to the PATH variable.
else
execv(options.program.c_str(), stringsToCharPtrs(args_).data());
diff --git a/src/nix/flake.cc b/src/nix/flake.cc
index acba912e5..6459df019 100644
--- a/src/nix/flake.cc
+++ b/src/nix/flake.cc
@@ -284,6 +284,34 @@ struct CmdFlakeInit : virtual Args, Command
}
};
+struct CmdFlakeClone : StoreCommand, FlakeCommand, MixEvalArgs
+{
+ Path endDirectory = "";
+
+ std::string name() override
+ {
+ return "clone";
+ }
+
+ std::string description() override
+ {
+ return "clone flake repository";
+ }
+
+ CmdFlakeClone()
+ {
+ expectArg("end-dir", &endDirectory, true);
+ }
+
+ void run(nix::ref<nix::Store> store) override
+ {
+ auto evalState = std::make_shared<EvalState>(searchPath, store);
+
+ Registries registries = evalState->getFlakeRegistries();
+ gitCloneFlake(flakeUri, *evalState, registries, endDirectory);
+ }
+};
+
struct CmdFlake : virtual MultiCommand, virtual Command
{
CmdFlake()
@@ -295,6 +323,7 @@ struct CmdFlake : virtual MultiCommand, virtual Command
, make_ref<CmdFlakeRemove>()
, make_ref<CmdFlakePin>()
, make_ref<CmdFlakeInit>()
+ , make_ref<CmdFlakeClone>()
})
{
}