Move LockFile and related types to a separate file

This commit is contained in:
Eelco Dolstra 2019-06-04 20:01:21 +02:00
parent 278114d559
commit 9e99b5205c
No known key found for this signature in database
GPG key ID: 8170B4726D7198DE
4 changed files with 218 additions and 184 deletions

View file

@ -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",

View file

@ -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.

View 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));
}
}

View 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;
};
}