forked from lix-project/lix
Move LockFile and related types to a separate file
This commit is contained in:
parent
278114d559
commit
9e99b5205c
|
@ -1,4 +1,5 @@
|
||||||
#include "flake.hh"
|
#include "flake.hh"
|
||||||
|
#include "lockfile.hh"
|
||||||
#include "primops.hh"
|
#include "primops.hh"
|
||||||
#include "eval-inline.hh"
|
#include "eval-inline.hh"
|
||||||
#include "fetchGit.hh"
|
#include "fetchGit.hh"
|
||||||
|
@ -50,104 +51,6 @@ void writeRegistry(const FlakeRegistry & registry, const Path & path)
|
||||||
writeFile(path, json.dump(4)); // The '4' is the number of spaces used in the indentation in the json file.
|
writeFile(path, json.dump(4)); // The '4' is the number of spaces used in the indentation in the json file.
|
||||||
}
|
}
|
||||||
|
|
||||||
AbstractDep::AbstractDep(const nlohmann::json & json)
|
|
||||||
: ref(json["uri"])
|
|
||||||
, narHash(Hash((std::string) json["narHash"]))
|
|
||||||
{
|
|
||||||
if (!ref.isImmutable())
|
|
||||||
throw Error("lockfile contains mutable flakeref '%s'", ref);
|
|
||||||
}
|
|
||||||
|
|
||||||
nlohmann::json AbstractDep::toJson() const
|
|
||||||
{
|
|
||||||
nlohmann::json json;
|
|
||||||
json["uri"] = ref.to_string();
|
|
||||||
json["narHash"] = narHash.to_string(SRI);
|
|
||||||
return json;
|
|
||||||
}
|
|
||||||
|
|
||||||
Path AbstractDep::computeStorePath(Store & store) const
|
|
||||||
{
|
|
||||||
return store.makeFixedOutputPath(true, narHash, "source");
|
|
||||||
}
|
|
||||||
|
|
||||||
FlakeDep::FlakeDep(const nlohmann::json & json)
|
|
||||||
: FlakeInputs(json)
|
|
||||||
, AbstractDep(json)
|
|
||||||
, id(json["id"])
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
nlohmann::json FlakeDep::toJson() const
|
|
||||||
{
|
|
||||||
auto json = FlakeInputs::toJson();
|
|
||||||
json.update(AbstractDep::toJson());
|
|
||||||
json["id"] = id;
|
|
||||||
return json;
|
|
||||||
}
|
|
||||||
|
|
||||||
FlakeInputs::FlakeInputs(const nlohmann::json & json)
|
|
||||||
{
|
|
||||||
auto nonFlakeInputs = json["nonFlakeInputs"];
|
|
||||||
for (auto i = nonFlakeInputs.begin(); i != nonFlakeInputs.end(); ++i)
|
|
||||||
nonFlakeDeps.insert_or_assign(i.key(), NonFlakeDep(*i));
|
|
||||||
|
|
||||||
auto inputs = json["inputs"];
|
|
||||||
for (auto i = inputs.begin(); i != inputs.end(); ++i)
|
|
||||||
flakeDeps.insert_or_assign(i.key(), FlakeDep(*i));
|
|
||||||
}
|
|
||||||
|
|
||||||
nlohmann::json FlakeInputs::toJson() const
|
|
||||||
{
|
|
||||||
nlohmann::json json;
|
|
||||||
{
|
|
||||||
auto j = nlohmann::json::object();
|
|
||||||
for (auto & i : nonFlakeDeps)
|
|
||||||
j[i.first] = i.second.toJson();
|
|
||||||
json["nonFlakeInputs"] = std::move(j);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
auto j = nlohmann::json::object();
|
|
||||||
for (auto & i : flakeDeps)
|
|
||||||
j[i.first.to_string()] = i.second.toJson();
|
|
||||||
json["inputs"] = std::move(j);
|
|
||||||
}
|
|
||||||
return json;
|
|
||||||
}
|
|
||||||
|
|
||||||
nlohmann::json LockFile::toJson() const
|
|
||||||
{
|
|
||||||
auto json = FlakeInputs::toJson();
|
|
||||||
json["version"] = 2;
|
|
||||||
return json;
|
|
||||||
}
|
|
||||||
|
|
||||||
LockFile readLockFile(const Path & path)
|
|
||||||
{
|
|
||||||
if (pathExists(path)) {
|
|
||||||
auto json = nlohmann::json::parse(readFile(path));
|
|
||||||
|
|
||||||
auto version = json.value("version", 0);
|
|
||||||
if (version != 2)
|
|
||||||
throw Error("lock file '%s' has unsupported version %d", path, version);
|
|
||||||
|
|
||||||
return LockFile(json);
|
|
||||||
} else
|
|
||||||
return LockFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ostream & operator <<(std::ostream & stream, const LockFile & lockFile)
|
|
||||||
{
|
|
||||||
stream << lockFile.toJson().dump(4); // '4' = indentation in json file
|
|
||||||
return stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
void writeLockFile(const LockFile & lockFile, const Path & path)
|
|
||||||
{
|
|
||||||
createDirs(dirOf(path));
|
|
||||||
writeFile(path, fmt("%s\n", lockFile));
|
|
||||||
}
|
|
||||||
|
|
||||||
Path getUserRegistryPath()
|
Path getUserRegistryPath()
|
||||||
{
|
{
|
||||||
return getHome() + "/.config/nix/registry.json";
|
return getHome() + "/.config/nix/registry.json";
|
||||||
|
@ -471,7 +374,7 @@ ResolvedFlake resolveFlake(EvalState & state, const FlakeRef & topRef, HandleLoc
|
||||||
if (!recreateLockFile(handleLockFile)) {
|
if (!recreateLockFile(handleLockFile)) {
|
||||||
// If recreateLockFile, start with an empty lockfile
|
// If recreateLockFile, start with an empty lockfile
|
||||||
// FIXME: symlink attack
|
// FIXME: symlink attack
|
||||||
oldLockFile = readLockFile(
|
oldLockFile = LockFile::read(
|
||||||
state.store->toRealPath(flake.sourceInfo.storePath)
|
state.store->toRealPath(flake.sourceInfo.storePath)
|
||||||
+ "/" + flake.sourceInfo.resolvedRef.subdir + "/flake.lock");
|
+ "/" + flake.sourceInfo.resolvedRef.subdir + "/flake.lock");
|
||||||
}
|
}
|
||||||
|
@ -483,7 +386,7 @@ ResolvedFlake resolveFlake(EvalState & state, const FlakeRef & topRef, HandleLoc
|
||||||
if (!(lockFile == oldLockFile)) {
|
if (!(lockFile == oldLockFile)) {
|
||||||
if (allowedToWrite(handleLockFile)) {
|
if (allowedToWrite(handleLockFile)) {
|
||||||
if (auto refData = std::get_if<FlakeRef::IsPath>(&topRef.data)) {
|
if (auto refData = std::get_if<FlakeRef::IsPath>(&topRef.data)) {
|
||||||
writeLockFile(lockFile, refData->path + (topRef.subdir == "" ? "" : "/" + topRef.subdir) + "/flake.lock");
|
lockFile.write(refData->path + (topRef.subdir == "" ? "" : "/" + topRef.subdir) + "/flake.lock");
|
||||||
|
|
||||||
// Hack: Make sure that flake.lock is visible to Git, so it ends up in the Nix store.
|
// Hack: Make sure that flake.lock is visible to Git, so it ends up in the Nix store.
|
||||||
runProgram("git", true, { "-C", refData->path, "add",
|
runProgram("git", true, { "-C", refData->path, "add",
|
||||||
|
|
|
@ -2,15 +2,12 @@
|
||||||
|
|
||||||
#include "types.hh"
|
#include "types.hh"
|
||||||
#include "flakeref.hh"
|
#include "flakeref.hh"
|
||||||
|
#include "lockfile.hh"
|
||||||
#include <variant>
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
struct Value;
|
struct Value;
|
||||||
class EvalState;
|
class EvalState;
|
||||||
class Store;
|
|
||||||
|
|
||||||
namespace flake {
|
namespace flake {
|
||||||
|
|
||||||
|
@ -40,86 +37,6 @@ enum HandleLockFile : unsigned int
|
||||||
, UseNewLockFile // `RecreateLockFile` without writing to file
|
, UseNewLockFile // `RecreateLockFile` without writing to file
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AbstractDep
|
|
||||||
{
|
|
||||||
FlakeRef ref;
|
|
||||||
Hash narHash;
|
|
||||||
|
|
||||||
AbstractDep(const FlakeRef & flakeRef, const Hash & narHash)
|
|
||||||
: ref(flakeRef), narHash(narHash) {};
|
|
||||||
|
|
||||||
AbstractDep(const nlohmann::json & json);
|
|
||||||
|
|
||||||
nlohmann::json toJson() const;
|
|
||||||
|
|
||||||
Path computeStorePath(Store & store) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct NonFlakeDep : AbstractDep
|
|
||||||
{
|
|
||||||
using AbstractDep::AbstractDep;
|
|
||||||
|
|
||||||
bool operator ==(const NonFlakeDep & other) const
|
|
||||||
{
|
|
||||||
return ref == other.ref && narHash == other.narHash;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FlakeDep;
|
|
||||||
|
|
||||||
struct FlakeInputs
|
|
||||||
{
|
|
||||||
std::map<FlakeRef, FlakeDep> flakeDeps;
|
|
||||||
std::map<FlakeAlias, NonFlakeDep> nonFlakeDeps;
|
|
||||||
|
|
||||||
FlakeInputs() {};
|
|
||||||
FlakeInputs(const nlohmann::json & json);
|
|
||||||
|
|
||||||
nlohmann::json toJson() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FlakeDep : FlakeInputs, AbstractDep
|
|
||||||
{
|
|
||||||
FlakeId id;
|
|
||||||
|
|
||||||
FlakeDep(const FlakeId & id, const FlakeRef & flakeRef, const Hash & narHash)
|
|
||||||
: AbstractDep(flakeRef, narHash), id(id) {};
|
|
||||||
|
|
||||||
FlakeDep(const nlohmann::json & json);
|
|
||||||
|
|
||||||
bool operator ==(const FlakeDep & other) const
|
|
||||||
{
|
|
||||||
return
|
|
||||||
id == other.id
|
|
||||||
&& ref == other.ref
|
|
||||||
&& narHash == other.narHash
|
|
||||||
&& flakeDeps == other.flakeDeps
|
|
||||||
&& nonFlakeDeps == other.nonFlakeDeps;
|
|
||||||
}
|
|
||||||
|
|
||||||
nlohmann::json toJson() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct LockFile : FlakeInputs
|
|
||||||
{
|
|
||||||
bool operator ==(const LockFile & other) const
|
|
||||||
{
|
|
||||||
return
|
|
||||||
flakeDeps == other.flakeDeps
|
|
||||||
&& nonFlakeDeps == other.nonFlakeDeps;
|
|
||||||
}
|
|
||||||
|
|
||||||
LockFile() {}
|
|
||||||
LockFile(const nlohmann::json & json) : FlakeInputs(json) {}
|
|
||||||
LockFile(FlakeDep && dep)
|
|
||||||
{
|
|
||||||
flakeDeps = std::move(dep.flakeDeps);
|
|
||||||
nonFlakeDeps = std::move(dep.nonFlakeDeps);
|
|
||||||
}
|
|
||||||
|
|
||||||
nlohmann::json toJson() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SourceInfo
|
struct SourceInfo
|
||||||
{
|
{
|
||||||
// Immutable flakeref that this source tree was obtained from.
|
// Immutable flakeref that this source tree was obtained from.
|
||||||
|
|
104
src/libexpr/primops/lockfile.cc
Normal file
104
src/libexpr/primops/lockfile.cc
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
#include "lockfile.hh"
|
||||||
|
#include "store-api.hh"
|
||||||
|
|
||||||
|
namespace nix::flake {
|
||||||
|
|
||||||
|
AbstractDep::AbstractDep(const nlohmann::json & json)
|
||||||
|
: ref(json["uri"])
|
||||||
|
, narHash(Hash((std::string) json["narHash"]))
|
||||||
|
{
|
||||||
|
if (!ref.isImmutable())
|
||||||
|
throw Error("lockfile contains mutable flakeref '%s'", ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
nlohmann::json AbstractDep::toJson() const
|
||||||
|
{
|
||||||
|
nlohmann::json json;
|
||||||
|
json["uri"] = ref.to_string();
|
||||||
|
json["narHash"] = narHash.to_string(SRI);
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
Path AbstractDep::computeStorePath(Store & store) const
|
||||||
|
{
|
||||||
|
return store.makeFixedOutputPath(true, narHash, "source");
|
||||||
|
}
|
||||||
|
|
||||||
|
FlakeDep::FlakeDep(const nlohmann::json & json)
|
||||||
|
: FlakeInputs(json)
|
||||||
|
, AbstractDep(json)
|
||||||
|
, id(json["id"])
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
nlohmann::json FlakeDep::toJson() const
|
||||||
|
{
|
||||||
|
auto json = FlakeInputs::toJson();
|
||||||
|
json.update(AbstractDep::toJson());
|
||||||
|
json["id"] = id;
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
FlakeInputs::FlakeInputs(const nlohmann::json & json)
|
||||||
|
{
|
||||||
|
auto nonFlakeInputs = json["nonFlakeInputs"];
|
||||||
|
for (auto i = nonFlakeInputs.begin(); i != nonFlakeInputs.end(); ++i)
|
||||||
|
nonFlakeDeps.insert_or_assign(i.key(), NonFlakeDep(*i));
|
||||||
|
|
||||||
|
auto inputs = json["inputs"];
|
||||||
|
for (auto i = inputs.begin(); i != inputs.end(); ++i)
|
||||||
|
flakeDeps.insert_or_assign(i.key(), FlakeDep(*i));
|
||||||
|
}
|
||||||
|
|
||||||
|
nlohmann::json FlakeInputs::toJson() const
|
||||||
|
{
|
||||||
|
nlohmann::json json;
|
||||||
|
{
|
||||||
|
auto j = nlohmann::json::object();
|
||||||
|
for (auto & i : nonFlakeDeps)
|
||||||
|
j[i.first] = i.second.toJson();
|
||||||
|
json["nonFlakeInputs"] = std::move(j);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto j = nlohmann::json::object();
|
||||||
|
for (auto & i : flakeDeps)
|
||||||
|
j[i.first.to_string()] = i.second.toJson();
|
||||||
|
json["inputs"] = std::move(j);
|
||||||
|
}
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
nlohmann::json LockFile::toJson() const
|
||||||
|
{
|
||||||
|
auto json = FlakeInputs::toJson();
|
||||||
|
json["version"] = 2;
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
LockFile LockFile::read(const Path & path)
|
||||||
|
{
|
||||||
|
if (pathExists(path)) {
|
||||||
|
auto json = nlohmann::json::parse(readFile(path));
|
||||||
|
|
||||||
|
auto version = json.value("version", 0);
|
||||||
|
if (version != 2)
|
||||||
|
throw Error("lock file '%s' has unsupported version %d", path, version);
|
||||||
|
|
||||||
|
return LockFile(json);
|
||||||
|
} else
|
||||||
|
return LockFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream & operator <<(std::ostream & stream, const LockFile & lockFile)
|
||||||
|
{
|
||||||
|
stream << lockFile.toJson().dump(4); // '4' = indentation in json file
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LockFile::write(const Path & path) const
|
||||||
|
{
|
||||||
|
createDirs(dirOf(path));
|
||||||
|
writeFile(path, fmt("%s\n", *this));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
110
src/libexpr/primops/lockfile.hh
Normal file
110
src/libexpr/primops/lockfile.hh
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "flakeref.hh"
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
class Store;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace nix::flake {
|
||||||
|
|
||||||
|
/* Common lock file information about a flake input, namely the
|
||||||
|
immutable ref and the NAR hash. */
|
||||||
|
struct AbstractDep
|
||||||
|
{
|
||||||
|
FlakeRef ref;
|
||||||
|
Hash narHash;
|
||||||
|
|
||||||
|
AbstractDep(const FlakeRef & flakeRef, const Hash & narHash)
|
||||||
|
: ref(flakeRef), narHash(narHash)
|
||||||
|
{
|
||||||
|
assert(ref.isImmutable());
|
||||||
|
};
|
||||||
|
|
||||||
|
AbstractDep(const nlohmann::json & json);
|
||||||
|
|
||||||
|
nlohmann::json toJson() const;
|
||||||
|
|
||||||
|
Path computeStorePath(Store & store) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Lock file information about a non-flake input. */
|
||||||
|
struct NonFlakeDep : AbstractDep
|
||||||
|
{
|
||||||
|
using AbstractDep::AbstractDep;
|
||||||
|
|
||||||
|
bool operator ==(const NonFlakeDep & other) const
|
||||||
|
{
|
||||||
|
return ref == other.ref && narHash == other.narHash;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FlakeDep;
|
||||||
|
|
||||||
|
/* Lock file information about the dependencies of a flake. */
|
||||||
|
struct FlakeInputs
|
||||||
|
{
|
||||||
|
std::map<FlakeRef, FlakeDep> flakeDeps;
|
||||||
|
std::map<FlakeAlias, NonFlakeDep> nonFlakeDeps;
|
||||||
|
|
||||||
|
FlakeInputs() {};
|
||||||
|
FlakeInputs(const nlohmann::json & json);
|
||||||
|
|
||||||
|
nlohmann::json toJson() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Lock file information about a flake input. */
|
||||||
|
struct FlakeDep : FlakeInputs, AbstractDep
|
||||||
|
{
|
||||||
|
FlakeId id;
|
||||||
|
|
||||||
|
FlakeDep(const FlakeId & id, const FlakeRef & flakeRef, const Hash & narHash)
|
||||||
|
: AbstractDep(flakeRef, narHash), id(id) {};
|
||||||
|
|
||||||
|
FlakeDep(const nlohmann::json & json);
|
||||||
|
|
||||||
|
bool operator ==(const FlakeDep & other) const
|
||||||
|
{
|
||||||
|
return
|
||||||
|
id == other.id
|
||||||
|
&& ref == other.ref
|
||||||
|
&& narHash == other.narHash
|
||||||
|
&& flakeDeps == other.flakeDeps
|
||||||
|
&& nonFlakeDeps == other.nonFlakeDeps;
|
||||||
|
}
|
||||||
|
|
||||||
|
nlohmann::json toJson() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* An entire lock file. Note that this cannot be a FlakeDep for the
|
||||||
|
top-level flake, because then the lock file would need to contain
|
||||||
|
the hash of the top-level flake, but committing the lock file
|
||||||
|
would invalidate that hash. */
|
||||||
|
struct LockFile : FlakeInputs
|
||||||
|
{
|
||||||
|
bool operator ==(const LockFile & other) const
|
||||||
|
{
|
||||||
|
return
|
||||||
|
flakeDeps == other.flakeDeps
|
||||||
|
&& nonFlakeDeps == other.nonFlakeDeps;
|
||||||
|
}
|
||||||
|
|
||||||
|
LockFile() {}
|
||||||
|
LockFile(const nlohmann::json & json) : FlakeInputs(json) {}
|
||||||
|
LockFile(FlakeDep && dep)
|
||||||
|
{
|
||||||
|
flakeDeps = std::move(dep.flakeDeps);
|
||||||
|
nonFlakeDeps = std::move(dep.nonFlakeDeps);
|
||||||
|
}
|
||||||
|
|
||||||
|
nlohmann::json toJson() const;
|
||||||
|
|
||||||
|
static LockFile read(const Path & path);
|
||||||
|
|
||||||
|
void write(const Path & path) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue