aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libexpr/primops/flake.cc167
-rw-r--r--src/libexpr/primops/flake.hh10
-rw-r--r--src/libexpr/primops/flakeref.hh50
-rw-r--r--src/nix/build.cc3
-rw-r--r--src/nix/command.hh3
-rw-r--r--src/nix/flake.cc45
-rw-r--r--src/nix/installables.cc1
7 files changed, 102 insertions, 177 deletions
diff --git a/src/libexpr/primops/flake.cc b/src/libexpr/primops/flake.cc
index 729b1da95..145d79446 100644
--- a/src/libexpr/primops/flake.cc
+++ b/src/libexpr/primops/flake.cc
@@ -28,10 +28,8 @@ std::shared_ptr<FlakeRegistry> readRegistry(const Path & path)
throw Error("flake registry '%s' has unsupported version %d", path, version);
auto flakes = json["flakes"];
- for (auto i = flakes.begin(); i != flakes.end(); ++i) {
- FlakeRegistry::Entry entry{FlakeRef(i->value("uri", ""))};
- registry->entries.emplace(i.key(), entry);
- }
+ for (auto i = flakes.begin(); i != flakes.end(); ++i)
+ registry->entries.emplace(i.key(), FlakeRef(i->value("uri", "")));
return registry;
}
@@ -41,9 +39,8 @@ void writeRegistry(FlakeRegistry registry, Path path)
{
nlohmann::json json;
json["version"] = 1;
- for (auto elem : registry.entries) {
- json["flakes"][elem.first] = { {"uri", elem.second.ref.to_string()} };
- }
+ for (auto elem : registry.entries)
+ json["flakes"][elem.first.to_string()] = { {"uri", elem.second.to_string()} };
createDirs(dirOf(path));
writeFile(path, json.dump(4)); // The '4' is the number of spaces used in the indentation in the json file.
}
@@ -127,106 +124,31 @@ void writeLockFile(LockFile lockFile, Path path)
writeFile(path, json.dump(4)); // '4' = indentation in json file
}
-Path getUserRegistryPath()
->>>>>>> Fixed dependency resolution
-{
- FlakeRef flakeRef(json["uri"]);
- if (!flakeRef.isImmutable())
- throw Error("requested to fetch FlakeRef '%s' purely, which is mutable", flakeRef.to_string());
-
- LockFile::FlakeEntry entry(flakeRef);
-
- auto nonFlakeRequires = json["nonFlakeRequires"];
-
- for (auto i = nonFlakeRequires.begin(); i != nonFlakeRequires.end(); ++i) {
- FlakeRef flakeRef(i->value("uri", ""));
- if (!flakeRef.isImmutable())
- throw Error("requested to fetch FlakeRef '%s' purely, which is mutable", flakeRef.to_string());
- entry.nonFlakeEntries.insert_or_assign(i.key(), flakeRef);
- }
-
- auto requires = json["requires"];
-
- for (auto i = requires.begin(); i != requires.end(); ++i)
- entry.flakeEntries.insert_or_assign(i.key(), readFlakeEntry(*i));
-
- return entry;
-}
-
-LockFile readLockFile(const Path & path)
+std::shared_ptr<FlakeRegistry> getGlobalRegistry()
{
- LockFile lockFile;
-
- if (!pathExists(path))
- return lockFile;
-
- auto json = nlohmann::json::parse(readFile(path));
-
- auto version = json.value("version", 0);
- if (version != 1)
- throw Error("lock file '%s' has unsupported version %d", path, version);
-
- auto nonFlakeRequires = json["nonFlakeRequires"];
-
- for (auto i = nonFlakeRequires.begin(); i != nonFlakeRequires.end(); ++i) {
- FlakeRef flakeRef(i->value("uri", ""));
- if (!flakeRef.isImmutable())
- throw Error("requested to fetch FlakeRef '%s' purely, which is mutable", flakeRef.to_string());
- lockFile.nonFlakeEntries.insert_or_assign(i.key(), flakeRef);
- }
-
- auto requires = json["requires"];
-
- for (auto i = requires.begin(); i != requires.end(); ++i)
- lockFile.flakeEntries.insert_or_assign(i.key(), readFlakeEntry(*i));
-
- return lockFile;
+ return std::make_shared<FlakeRegistry>();
}
-nlohmann::json flakeEntryToJson(LockFile::FlakeEntry & entry)
+Path getUserRegistryPath()
{
- nlohmann::json json;
- json["uri"] = entry.ref.to_string();
- for (auto & x : entry.nonFlakeEntries)
- json["nonFlakeRequires"][x.first]["uri"] = x.second.to_string();
- for (auto & x : entry.flakeEntries)
- json["requires"][x.first] = flakeEntryToJson(x.second);
- return json;
+ return getHome() + "/.config/nix/registry.json";
}
-void writeLockFile(LockFile lockFile, Path path)
+std::shared_ptr<FlakeRegistry> getUserRegistry()
{
- nlohmann::json json;
- json["version"] = 1;
- json["nonFlakeRequires"];
- for (auto & x : lockFile.nonFlakeEntries)
- json["nonFlakeRequires"][x.first]["uri"] = x.second.to_string();
- for (auto & x : lockFile.flakeEntries)
- json["requires"][x.first] = flakeEntryToJson(x.second);
- createDirs(dirOf(path));
- writeFile(path, json.dump(4)); // '4' = indentation in json file
+ return readRegistry(getUserRegistryPath());
}
-Path getUserRegistryPath()
+std::shared_ptr<FlakeRegistry> getLocalRegistry()
{
- return getHome() + "/.config/nix/registry.json";
-}
-std::shared_ptr<FlakeRegistry> getGlobalRegistry()
-{
- // FIXME: get from nixos.org.
Path registryFile = settings.nixDataDir + "/nix/flake-registry.json";
return readRegistry(registryFile);
}
-std::shared_ptr<FlakeRegistry> getUserRegistry()
-{
- return readRegistry(getUserRegistryPath());
-}
-
std::shared_ptr<FlakeRegistry> getFlagRegistry()
{
+ // TODO (Nick): Implement this.
return std::make_shared<FlakeRegistry>();
- // TODO: Implement this once the right flags are implemented.
}
const std::vector<std::shared_ptr<FlakeRegistry>> EvalState::getFlakeRegistries()
@@ -259,9 +181,9 @@ Value * makeFlakeRegistryValue(EvalState & state)
for (auto & registry : registries) {
for (auto & entry : registry->entries) {
- auto vEntry = state.allocAttr(*v, entry.first);
+ auto vEntry = state.allocAttr(*v, entry.first.to_string());
state.mkAttrs(*vEntry, 2);
- mkString(*state.allocAttr(*vEntry, state.symbols.create("uri")), entry.second.ref.to_string());
+ mkString(*state.allocAttr(*vEntry, state.symbols.create("uri")), entry.second.to_string());
vEntry->attrs->sort();
}
}
@@ -272,23 +194,30 @@ Value * makeFlakeRegistryValue(EvalState & state)
}
static FlakeRef lookupFlake(EvalState & state, const FlakeRef & flakeRef,
- std::vector<std::shared_ptr<FlakeRegistry>> registries)
+ std::vector<std::shared_ptr<FlakeRegistry>> registries, std::vector<FlakeRef> pastSearches = {})
{
- if (auto refData = std::get_if<FlakeRef::IsAlias>(&flakeRef.data)) {
- for (auto registry : registries) {
- auto i = registry->entries.find(refData->alias);
- if (i != registry->entries.end()) {
- auto newRef = FlakeRef(i->second.ref);
- if (!newRef.isDirect())
- throw Error("found indirect flake URI '%s' in the flake registry", i->second.ref.to_string());
- if (flakeRef.ref) newRef.setRef(*flakeRef.ref);
- if (flakeRef.rev) newRef.setRev(*flakeRef.rev);
- return newRef;
+ for (std::shared_ptr<FlakeRegistry> registry : registries) {
+ auto i = registry->entries.find(flakeRef);
+ if (i != registry->entries.end()) {
+ auto newRef = i->second;
+ if (std::get_if<FlakeRef::IsAlias>(&flakeRef.data)) {
+ if (flakeRef.ref) newRef.ref = flakeRef.ref;
+ if (flakeRef.rev) newRef.rev = flakeRef.rev;
+ }
+ std::string errorMsg = "found cycle in flake registries: ";
+ for (FlakeRef oldRef : pastSearches) {
+ errorMsg += oldRef.to_string();
+ if (oldRef == newRef)
+ throw Error(errorMsg);
+ errorMsg += " - ";
}
+ pastSearches.push_back(newRef);
+ return lookupFlake(state, newRef, registries, pastSearches);
}
- throw Error("cannot find flake with alias '%s' in the flake registry or in the flake lock file", refData->alias);
- } else
- return flakeRef;
+ }
+ if (!flakeRef.isDirect())
+ throw Error("indirect flake URI '%s' is the result of a lookup", flakeRef.to_string());
+ return flakeRef;
}
struct FlakeSourceInfo
@@ -302,6 +231,7 @@ static FlakeSourceInfo fetchFlake(EvalState & state, const FlakeRef flakeRef, bo
{
FlakeRef fRef = lookupFlake(state, flakeRef, state.getFlakeRegistries());
+ // This only downloads only one revision of the repo, not the entire history.
if (auto refData = std::get_if<FlakeRef::IsGitHub>(&fRef.data)) {
if (evalSettings.pureEval && !impureIsAllowed && !fRef.isImmutable())
throw Error("requested to fetch FlakeRef '%s' purely, which is mutable", fRef.to_string());
@@ -332,6 +262,7 @@ static FlakeSourceInfo fetchFlake(EvalState & state, const FlakeRef flakeRef, bo
return info;
}
+ // This downloads the entire git history
else if (auto refData = std::get_if<FlakeRef::IsGit>(&fRef.data)) {
auto gitInfo = exportGit(state.store, refData->uri, fRef.ref,
fRef.rev ? fRef.rev->to_string(Base16, false) : "", "source");
@@ -342,7 +273,7 @@ static FlakeSourceInfo fetchFlake(EvalState & state, const FlakeRef flakeRef, bo
return info;
}
- else if (auto refData = std::get_if<FlakeRef::IsPath>(&directFlakeRef.data)) {
+ else if (auto refData = std::get_if<FlakeRef::IsPath>(&fRef.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");
@@ -452,7 +383,7 @@ NonFlake getNonFlake(EvalState & state, const FlakeRef & flakeRef, FlakeAlias al
dependencies.
FIXME: this should return a graph of flakes.
*/
-Dependencies resolveFlake(EvalState & state, const FlakeRef & topRef, bool impureTopRef, bool isTopFlake = true)
+Dependencies resolveFlake(EvalState & state, const FlakeRef & topRef, bool impureTopRef, bool isTopFlake)
{
Flake flake = getFlake(state, topRef, isTopFlake && impureTopRef);
Dependencies deps(flake);
@@ -461,7 +392,7 @@ Dependencies resolveFlake(EvalState & state, const FlakeRef & topRef, bool impur
deps.nonFlakeDeps.push_back(getNonFlake(state, nonFlakeInfo.second, nonFlakeInfo.first));
for (auto & newFlakeRef : flake.requires)
- deps.flakeDeps.push_back(resolveFlake(state, newFlakeRef, impureTopRef, false));
+ deps.flakeDeps.push_back(resolveFlake(state, newFlakeRef, false));
return deps;
}
@@ -505,25 +436,23 @@ void updateLockFile(EvalState & state, Path path)
// Return the `provides` of the top flake, while assigning to `v` the provides
// of the dependencies as well.
-Value * makeFlakeValue(EvalState & state, FlakeUri flakeUri, Value & v)
+Value * makeFlakeValue(EvalState & state, const FlakeRef & flakeRef, bool impureTopRef, Value & v)
{
- FlakeRef flakeRef = FlakeRef(flakeUri);
-
- Dependencies deps = resolveFlake(state, flakeRef, impure);
+ Dependencies deps = resolveFlake(state, flakeRef, impureTopRef);
- // // FIXME: we should call each flake with only its dependencies
- // // (rather than the closure of the top-level flake).
+ // FIXME: we should call each flake with only its dependencies
+ // (rather than the closure of the top-level flake).
auto vResult = state.allocValue();
// This will store the attribute set of the `nonFlakeRequires` and the `requires.provides`.
state.mkAttrs(*vResult, deps.flakeDeps.size());
- Value * vTop = 0;
+ Value * vTop = state.allocAttr(*vResult, deps.flake.id);
- for (auto & flake : deps.flakeDeps) {
+ for (auto & dep : deps.flakeDeps) {
+ Flake flake = dep.flake;
auto vFlake = state.allocAttr(*vResult, flake.id);
- if (deps.topFlakeId == flake.id) vTop = vFlake;
state.mkAttrs(*vFlake, 4);
@@ -532,7 +461,7 @@ Value * makeFlakeValue(EvalState & state, FlakeUri flakeUri, Value & v)
state.store->assertStorePath(flake.path);
mkString(*state.allocAttr(*vFlake, state.sOutPath), flake.path, {flake.path});
- if (flake.second.revCount)
+ if (flake.revCount)
mkInt(*state.allocAttr(*vFlake, state.symbols.create("revCount")), *flake.revCount);
auto vProvides = state.allocAttr(*vFlake, state.symbols.create("provides"));
diff --git a/src/libexpr/primops/flake.hh b/src/libexpr/primops/flake.hh
index adf8b07af..9da065234 100644
--- a/src/libexpr/primops/flake.hh
+++ b/src/libexpr/primops/flake.hh
@@ -10,13 +10,7 @@ class EvalState;
struct FlakeRegistry
{
- struct Entry
- {
- FlakeRef ref;
- Entry(const FlakeRef & flakeRef) : ref(flakeRef) {};
- Entry operator=(const Entry & entry) { return Entry(entry.ref); }
- };
- std::map<FlakeAlias, Entry> entries;
+ std::map<FlakeRef, FlakeRef> entries;
};
struct LockFile
@@ -79,7 +73,7 @@ struct Dependencies
Dependencies(const Flake & flake) : flake(flake) {}
};
-Dependencies resolveFlake(EvalState &, const FlakeRef &, bool impureTopRef, bool isTopFlake);
+Dependencies resolveFlake(EvalState &, const FlakeRef &, bool impureTopRef, bool isTopFlake = true);
FlakeRegistry updateLockFile(EvalState &, Flake &);
diff --git a/src/libexpr/primops/flakeref.hh b/src/libexpr/primops/flakeref.hh
index 32904953a..d789a6f70 100644
--- a/src/libexpr/primops/flakeref.hh
+++ b/src/libexpr/primops/flakeref.hh
@@ -103,47 +103,59 @@ typedef std::string FlakeUri;
struct FlakeRef
{
- std::optional<std::string> ref;
- std::optional<Hash> rev;
-
struct IsAlias
{
FlakeAlias alias;
+ bool operator<(const IsAlias & b) const { return alias < b.alias; };
+ bool operator==(const IsAlias & b) const { return alias == b.alias; };
};
- struct IsGitHub
- {
+ struct IsGitHub {
std::string owner, repo;
+ bool operator<(const IsGitHub & b) const {
+ return std::make_tuple(owner, repo) < std::make_tuple(b.owner, b.repo);
+ }
+ bool operator==(const IsGitHub & b) const {
+ return owner == b.owner && repo == b.repo;
+ }
};
// Git, Tarball
struct IsGit
{
std::string uri;
+ bool operator<(const IsGit & b) const { return uri < b.uri; }
+ bool operator==(const IsGit & b) const { return uri == b.uri; }
};
struct IsPath
{
Path path;
+ bool operator<(const IsPath & b) const { return path < b.path; }
+ bool operator==(const IsPath & b) const { return path == b.path; }
};
// Git, Tarball
- std::variant<IsFlakeId, IsGitHub, IsGit, IsPath> data;
+ std::variant<IsAlias, IsGitHub, IsGit, IsPath> data;
- // Parse a flake URI.
- FlakeRef(const std::string & uri, bool allowRelative = false);
+ std::optional<std::string> ref;
+ std::optional<Hash> rev;
- // Default constructor
- FlakeRef(const FlakeRef & flakeRef) : data(flakeRef.data) {};
+ bool operator<(const FlakeRef & flakeRef) const
+ {
+ return std::make_tuple(this->data, ref, rev) <
+ std::make_tuple(flakeRef.data, flakeRef.ref, flakeRef.rev);
+ }
+
+ bool operator==(const FlakeRef & flakeRef) const
+ {
+ return std::make_tuple(this->data, ref, rev) ==
+ std::make_tuple(flakeRef.data, flakeRef.ref, flakeRef.rev);
+ }
- /* Unify two flake references so that the resulting reference
- combines the information from both. For example,
- "nixpkgs/<hash>" and "github:NixOS/nixpkgs" unifies to
- "nixpkgs/master". May throw an exception if the references are
- incompatible (e.g. "nixpkgs/<hash1>" and "nixpkgs/<hash2>",
- where hash1 != hash2). */
- FlakeRef(const FlakeRef & a, const FlakeRef & b);
+ // Parse a flake URI.
+ FlakeRef(const std::string & uri, bool allowRelative = false);
// FIXME: change to operator <<.
std::string to_string() const;
@@ -160,9 +172,5 @@ struct FlakeRef
bool isImmutable() const;
FlakeRef baseRef() const;
-
- void setRef(std::optional<std::string> ref) { ref = ref; }
-
- void setRev(std::optional<Hash> rev) { rev = rev; }
};
}
diff --git a/src/nix/build.cc b/src/nix/build.cc
index a2fc56e69..5a3d9d31a 100644
--- a/src/nix/build.cc
+++ b/src/nix/build.cc
@@ -1,4 +1,3 @@
-#include "primops/flake.hh"
#include "eval.hh"
#include "command.hh"
#include "common-args.hh"
@@ -78,7 +77,7 @@ struct CmdBuild : MixDryRun, InstallablesCommand
}
}
- // std::string flakeUri = "";
+ // FlakeUri flakeUri = "";
// if(updateLock)
// for (uint i = 0; i < installables.size(); i++)
// // if (auto flakeUri = installableToFlakeUri)
diff --git a/src/nix/command.hh b/src/nix/command.hh
index 83959bf9a..56e1e6f34 100644
--- a/src/nix/command.hh
+++ b/src/nix/command.hh
@@ -1,6 +1,7 @@
#pragma once
#include "args.hh"
+#include "primops/flake.hh"
#include "common-eval-args.hh"
namespace nix {
@@ -46,7 +47,7 @@ struct GitRepoCommand : virtual Args
struct FlakeCommand : virtual Args
{
- std::string flakeUri;
+ FlakeUri flakeUri;
FlakeCommand()
{
diff --git a/src/nix/flake.cc b/src/nix/flake.cc
index df944a148..dbf0d3e9a 100644
--- a/src/nix/flake.cc
+++ b/src/nix/flake.cc
@@ -1,4 +1,3 @@
-#include "primops/flake.hh"
#include "command.hh"
#include "common-args.hh"
#include "shared.hh"
@@ -29,11 +28,9 @@ struct CmdFlakeList : StoreCommand, MixEvalArgs
stopProgressBar();
- for (auto & registry : registries) {
- for (auto & entry : registry->entries) {
- std::cout << entry.first << " " << entry.second.ref.to_string() << "\n";
- }
- }
+ for (auto & registry : registries)
+ for (auto & entry : registry->entries)
+ std::cout << entry.first.to_string() << " " << entry.second.to_string() << "\n";
}
};
@@ -81,7 +78,7 @@ struct CmdFlakeDeps : FlakeCommand, MixJSON, StoreCommand, MixEvalArgs
FlakeRef flakeRef(flakeUri);
- Dependencies deps = resolveFlake(*evalState, flakeRef, true, true);
+ Dependencies deps = resolveFlake(*evalState, flakeRef, true);
std::queue<Dependencies> todo;
todo.push(deps);
@@ -135,15 +132,15 @@ struct CmdFlakeInfo : FlakeCommand, MixJSON, MixEvalArgs, StoreCommand
void run(nix::ref<nix::Store> store) override
{
auto evalState = std::make_shared<EvalState>(searchPath, store);
- nix::Flake flake = nix::getFlake(*evalState, FlakeRef(flakeUri));
+ nix::Flake flake = nix::getFlake(*evalState, FlakeRef(flakeUri), true);
printFlakeInfo(flake, json);
}
};
struct CmdFlakeAdd : MixEvalArgs, Command
{
- FlakeAlias flakeAlias;
- FlakeUri flakeUri;
+ FlakeUri alias;
+ FlakeUri uri;
std::string name() override
{
@@ -157,25 +154,24 @@ struct CmdFlakeAdd : MixEvalArgs, Command
CmdFlakeAdd()
{
- expectArg("flake-id", &flakeAlias);
- expectArg("flake-uri", &flakeUri);
+ expectArg("alias", &alias);
+ expectArg("flake-uri", &uri);
}
void run() override
{
- FlakeRef newFlakeRef(flakeUri);
+ FlakeRef aliasRef(alias);
Path userRegistryPath = getUserRegistryPath();
auto userRegistry = readRegistry(userRegistryPath);
- FlakeRegistry::Entry entry(newFlakeRef);
- userRegistry->entries.erase(flakeAlias);
- userRegistry->entries.insert_or_assign(flakeAlias, newFlakeRef);
+ userRegistry->entries.erase(aliasRef);
+ userRegistry->entries.insert_or_assign(aliasRef, FlakeRef(uri));
writeRegistry(*userRegistry, userRegistryPath);
}
};
struct CmdFlakeRemove : virtual Args, MixEvalArgs, Command
{
- FlakeAlias flakeAlias;
+ FlakeUri alias;
std::string name() override
{
@@ -189,21 +185,21 @@ struct CmdFlakeRemove : virtual Args, MixEvalArgs, Command
CmdFlakeRemove()
{
- expectArg("flake-id", &flakeAlias);
+ expectArg("alias", &alias);
}
void run() override
{
Path userRegistryPath = getUserRegistryPath();
auto userRegistry = readRegistry(userRegistryPath);
- userRegistry->entries.erase(flakeAlias);
+ userRegistry->entries.erase(FlakeRef(alias));
writeRegistry(*userRegistry, userRegistryPath);
}
};
struct CmdFlakePin : virtual Args, StoreCommand, MixEvalArgs
{
- FlakeAlias flakeAlias;
+ FlakeUri alias;
std::string name() override
{
@@ -217,7 +213,7 @@ struct CmdFlakePin : virtual Args, StoreCommand, MixEvalArgs
CmdFlakePin()
{
- expectArg("flake-id", &flakeAlias);
+ expectArg("alias", &alias);
}
void run(nix::ref<nix::Store> store) override
@@ -226,14 +222,13 @@ struct CmdFlakePin : virtual Args, StoreCommand, MixEvalArgs
Path userRegistryPath = getUserRegistryPath();
FlakeRegistry userRegistry = *readRegistry(userRegistryPath);
- auto it = userRegistry.entries.find(flakeAlias);
+ auto it = userRegistry.entries.find(FlakeRef(alias));
if (it != userRegistry.entries.end()) {
- FlakeRef oldRef = it->second.ref;
- it->second.ref = getFlake(*evalState, oldRef, true).ref;
+ it->second = getFlake(*evalState, it->second, true).ref;
// The 'ref' in 'flake' is immutable.
writeRegistry(userRegistry, userRegistryPath);
} else
- throw Error("the flake alias '%s' does not exist in the user registry", flakeAlias);
+ throw Error("the flake alias '%s' does not exist in the user registry", alias);
}
};
diff --git a/src/nix/installables.cc b/src/nix/installables.cc
index e792ce96d..13a68a797 100644
--- a/src/nix/installables.cc
+++ b/src/nix/installables.cc
@@ -7,7 +7,6 @@
#include "get-drvs.hh"
#include "store-api.hh"
#include "shared.hh"
-#include "primops/flake.hh"
#include <regex>