forked from lix-project/lix
commit
65e88694c2
13
flake.nix
13
flake.nix
|
@ -14,13 +14,22 @@
|
||||||
nixpkgs = deps.nixpkgs;
|
nixpkgs = deps.nixpkgs;
|
||||||
};
|
};
|
||||||
|
|
||||||
packages.nix = hydraJobs.build.x86_64-linux;
|
checks = {
|
||||||
|
binaryTarball = hydraJobs.binaryTarball.x86_64-linux;
|
||||||
|
perlBindings = hydraJobs.perlBindings.x86_64-linux;
|
||||||
|
inherit (hydraJobs.tests) remoteBuilds nix-copy-closure;
|
||||||
|
setuid = hydraJobs.tests.setuid.x86_64-linux;
|
||||||
|
};
|
||||||
|
|
||||||
|
packages = {
|
||||||
|
nix = hydraJobs.build.x86_64-linux;
|
||||||
|
nix-perl-bindings = hydraJobs.perlBindings.x86_64-linux;
|
||||||
|
};
|
||||||
|
|
||||||
defaultPackage = packages.nix;
|
defaultPackage = packages.nix;
|
||||||
|
|
||||||
devShell = import ./shell.nix {
|
devShell = import ./shell.nix {
|
||||||
nixpkgs = deps.nixpkgs;
|
nixpkgs = deps.nixpkgs;
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
, nixpkgs ? builtins.fetchTarball https://github.com/NixOS/nixpkgs-channels/archive/nixos-19.03.tar.gz
|
, nixpkgs ? builtins.fetchTarball https://github.com/NixOS/nixpkgs-channels/archive/nixos-19.03.tar.gz
|
||||||
}:
|
}:
|
||||||
|
|
||||||
with import (builtins.fetchTarball https://github.com/NixOS/nixpkgs-channels/archive/nixos-19.03.tar.gz) { system = builtins.currentSystem or "x86_64-linux"; };
|
with import nixpkgs { system = builtins.currentSystem or "x86_64-linux"; };
|
||||||
|
|
||||||
with import ./release-common.nix { inherit pkgs; };
|
with import ./release-common.nix { inherit pkgs; };
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,10 @@ namespace nix {
|
||||||
class Store;
|
class Store;
|
||||||
class EvalState;
|
class EvalState;
|
||||||
enum RepairFlag : bool;
|
enum RepairFlag : bool;
|
||||||
|
|
||||||
|
namespace flake {
|
||||||
struct FlakeRegistry;
|
struct FlakeRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
typedef void (* PrimOpFun) (EvalState & state, const Pos & pos, Value * * args, Value & v);
|
typedef void (* PrimOpFun) (EvalState & state, const Pos & pos, Value * * args, Value & v);
|
||||||
|
@ -323,12 +326,12 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
const std::vector<std::shared_ptr<FlakeRegistry>> getFlakeRegistries();
|
const std::vector<std::shared_ptr<flake::FlakeRegistry>> getFlakeRegistries();
|
||||||
|
|
||||||
std::shared_ptr<FlakeRegistry> getGlobalFlakeRegistry();
|
std::shared_ptr<flake::FlakeRegistry> getGlobalFlakeRegistry();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<FlakeRegistry> _globalFlakeRegistry;
|
std::shared_ptr<flake::FlakeRegistry> _globalFlakeRegistry;
|
||||||
std::once_flag _globalFlakeRegistryInit;
|
std::once_flag _globalFlakeRegistryInit;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,10 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
using namespace flake;
|
||||||
|
|
||||||
|
namespace flake {
|
||||||
|
|
||||||
/* Read a registry. */
|
/* Read a registry. */
|
||||||
std::shared_ptr<FlakeRegistry> readRegistry(const Path & path)
|
std::shared_ptr<FlakeRegistry> readRegistry(const Path & path)
|
||||||
{
|
{
|
||||||
|
@ -133,24 +137,6 @@ void writeLockFile(const LockFile & lockFile, const Path & path)
|
||||||
writeFile(path, json.dump(4) + "\n"); // '4' = indentation in json file
|
writeFile(path, json.dump(4) + "\n"); // '4' = indentation in json file
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<FlakeRegistry> EvalState::getGlobalFlakeRegistry()
|
|
||||||
{
|
|
||||||
std::call_once(_globalFlakeRegistryInit, [&]() {
|
|
||||||
auto path = evalSettings.flakeRegistry;
|
|
||||||
|
|
||||||
if (!hasPrefix(path, "/")) {
|
|
||||||
CachedDownloadRequest request(evalSettings.flakeRegistry);
|
|
||||||
request.name = "flake-registry.json";
|
|
||||||
request.gcRoot = true;
|
|
||||||
path = getDownloader()->downloadCached(store, request).path;
|
|
||||||
}
|
|
||||||
|
|
||||||
_globalFlakeRegistry = readRegistry(path);
|
|
||||||
});
|
|
||||||
|
|
||||||
return _globalFlakeRegistry;
|
|
||||||
}
|
|
||||||
|
|
||||||
Path getUserRegistryPath()
|
Path getUserRegistryPath()
|
||||||
{
|
{
|
||||||
return getHome() + "/.config/nix/registry.json";
|
return getHome() + "/.config/nix/registry.json";
|
||||||
|
@ -170,17 +156,6 @@ std::shared_ptr<FlakeRegistry> getFlagRegistry(RegistryOverrides registryOverrid
|
||||||
return flagRegistry;
|
return flagRegistry;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This always returns a vector with flakeReg, userReg, globalReg.
|
|
||||||
// If one of them doesn't exist, the registry is left empty but does exist.
|
|
||||||
const Registries EvalState::getFlakeRegistries()
|
|
||||||
{
|
|
||||||
Registries registries;
|
|
||||||
registries.push_back(getFlagRegistry(registryOverrides));
|
|
||||||
registries.push_back(getUserRegistry());
|
|
||||||
registries.push_back(getGlobalFlakeRegistry());
|
|
||||||
return registries;
|
|
||||||
}
|
|
||||||
|
|
||||||
static FlakeRef lookupFlake(EvalState & state, const FlakeRef & flakeRef, const Registries & registries,
|
static FlakeRef lookupFlake(EvalState & state, const FlakeRef & flakeRef, const Registries & registries,
|
||||||
std::vector<FlakeRef> pastSearches = {});
|
std::vector<FlakeRef> pastSearches = {});
|
||||||
|
|
||||||
|
@ -327,7 +302,9 @@ Flake getFlake(EvalState & state, const FlakeRef & flakeRef, bool impureIsAllowe
|
||||||
|
|
||||||
state.forceAttrs(vInfo);
|
state.forceAttrs(vInfo);
|
||||||
|
|
||||||
if (auto epoch = vInfo.attrs->get(state.symbols.create("epoch"))) {
|
auto sEpoch = state.symbols.create("epoch");
|
||||||
|
|
||||||
|
if (auto epoch = vInfo.attrs->get(sEpoch)) {
|
||||||
flake.epoch = state.forceInt(*(**epoch).value, *(**epoch).pos);
|
flake.epoch = state.forceInt(*(**epoch).value, *(**epoch).pos);
|
||||||
if (flake.epoch > 2019)
|
if (flake.epoch > 2019)
|
||||||
throw Error("flake '%s' requires unsupported epoch %d; please upgrade Nix", flakeRef, flake.epoch);
|
throw Error("flake '%s' requires unsupported epoch %d; please upgrade Nix", flakeRef, flake.epoch);
|
||||||
|
@ -342,14 +319,18 @@ Flake getFlake(EvalState & state, const FlakeRef & flakeRef, bool impureIsAllowe
|
||||||
if (auto description = vInfo.attrs->get(state.sDescription))
|
if (auto description = vInfo.attrs->get(state.sDescription))
|
||||||
flake.description = state.forceStringNoCtx(*(**description).value, *(**description).pos);
|
flake.description = state.forceStringNoCtx(*(**description).value, *(**description).pos);
|
||||||
|
|
||||||
if (auto requires = vInfo.attrs->get(state.symbols.create("requires"))) {
|
auto sRequires = state.symbols.create("requires");
|
||||||
|
|
||||||
|
if (auto requires = vInfo.attrs->get(sRequires)) {
|
||||||
state.forceList(*(**requires).value, *(**requires).pos);
|
state.forceList(*(**requires).value, *(**requires).pos);
|
||||||
for (unsigned int n = 0; n < (**requires).value->listSize(); ++n)
|
for (unsigned int n = 0; n < (**requires).value->listSize(); ++n)
|
||||||
flake.requires.push_back(FlakeRef(state.forceStringNoCtx(
|
flake.requires.push_back(FlakeRef(state.forceStringNoCtx(
|
||||||
*(**requires).value->listElems()[n], *(**requires).pos)));
|
*(**requires).value->listElems()[n], *(**requires).pos)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std::optional<Attr *> nonFlakeRequires = vInfo.attrs->get(state.symbols.create("nonFlakeRequires"))) {
|
auto sNonFlakeRequires = state.symbols.create("nonFlakeRequires");
|
||||||
|
|
||||||
|
if (std::optional<Attr *> nonFlakeRequires = vInfo.attrs->get(sNonFlakeRequires)) {
|
||||||
state.forceAttrs(*(**nonFlakeRequires).value, *(**nonFlakeRequires).pos);
|
state.forceAttrs(*(**nonFlakeRequires).value, *(**nonFlakeRequires).pos);
|
||||||
for (Attr attr : *(*(**nonFlakeRequires).value).attrs) {
|
for (Attr attr : *(*(**nonFlakeRequires).value).attrs) {
|
||||||
std::string myNonFlakeUri = state.forceStringNoCtx(*attr.value, *attr.pos);
|
std::string myNonFlakeUri = state.forceStringNoCtx(*attr.value, *attr.pos);
|
||||||
|
@ -358,12 +339,25 @@ Flake getFlake(EvalState & state, const FlakeRef & flakeRef, bool impureIsAllowe
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto provides = vInfo.attrs->get(state.symbols.create("provides"))) {
|
auto sProvides = state.symbols.create("provides");
|
||||||
|
|
||||||
|
if (auto provides = vInfo.attrs->get(sProvides)) {
|
||||||
state.forceFunction(*(**provides).value, *(**provides).pos);
|
state.forceFunction(*(**provides).value, *(**provides).pos);
|
||||||
flake.vProvides = (**provides).value;
|
flake.vProvides = (**provides).value;
|
||||||
} else
|
} else
|
||||||
throw Error("flake '%s' lacks attribute 'provides'", flakeRef);
|
throw Error("flake '%s' lacks attribute 'provides'", flakeRef);
|
||||||
|
|
||||||
|
for (auto & attr : *vInfo.attrs) {
|
||||||
|
if (attr.name != sEpoch &&
|
||||||
|
attr.name != state.sName &&
|
||||||
|
attr.name != state.sDescription &&
|
||||||
|
attr.name != sRequires &&
|
||||||
|
attr.name != sNonFlakeRequires &&
|
||||||
|
attr.name != sProvides)
|
||||||
|
throw Error("flake '%s' has an unsupported attribute '%s', at %s",
|
||||||
|
flakeRef, attr.name, *attr.pos);
|
||||||
|
}
|
||||||
|
|
||||||
return flake;
|
return flake;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -572,18 +566,11 @@ void callFlake(EvalState & state, const ResolvedFlake & resFlake, Value & v)
|
||||||
v.attrs->sort();
|
v.attrs->sort();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the `provides` of the top flake, while assigning to `v` the provides
|
|
||||||
// of the dependencies as well.
|
|
||||||
void makeFlakeValue(EvalState & state, const FlakeRef & flakeRef, HandleLockFile handle, Value & v)
|
|
||||||
{
|
|
||||||
callFlake(state, resolveFlake(state, flakeRef, handle), v);
|
|
||||||
}
|
|
||||||
|
|
||||||
// This function is exposed to be used in nix files.
|
// This function is exposed to be used in nix files.
|
||||||
static void prim_getFlake(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
static void prim_getFlake(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
makeFlakeValue(state, state.forceStringNoCtx(*args[0], pos),
|
callFlake(state, resolveFlake(state, state.forceStringNoCtx(*args[0], pos),
|
||||||
evalSettings.pureEval ? AllPure : UseUpdatedLockFile, v);
|
evalSettings.pureEval ? AllPure : UseUpdatedLockFile), v);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp r2("getFlake", 1, prim_getFlake);
|
static RegisterPrimOp r2("getFlake", 1, prim_getFlake);
|
||||||
|
@ -618,3 +605,34 @@ void gitCloneFlake(FlakeRef flakeRef, EvalState & state, Registries registries,
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<flake::FlakeRegistry> EvalState::getGlobalFlakeRegistry()
|
||||||
|
{
|
||||||
|
std::call_once(_globalFlakeRegistryInit, [&]() {
|
||||||
|
auto path = evalSettings.flakeRegistry;
|
||||||
|
|
||||||
|
if (!hasPrefix(path, "/")) {
|
||||||
|
CachedDownloadRequest request(evalSettings.flakeRegistry);
|
||||||
|
request.name = "flake-registry.json";
|
||||||
|
request.gcRoot = true;
|
||||||
|
path = getDownloader()->downloadCached(store, request).path;
|
||||||
|
}
|
||||||
|
|
||||||
|
_globalFlakeRegistry = readRegistry(path);
|
||||||
|
});
|
||||||
|
|
||||||
|
return _globalFlakeRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This always returns a vector with flakeReg, userReg, globalReg.
|
||||||
|
// If one of them doesn't exist, the registry is left empty but does exist.
|
||||||
|
const Registries EvalState::getFlakeRegistries()
|
||||||
|
{
|
||||||
|
Registries registries;
|
||||||
|
registries.push_back(getFlagRegistry(registryOverrides));
|
||||||
|
registries.push_back(getUserRegistry());
|
||||||
|
registries.push_back(getGlobalFlakeRegistry());
|
||||||
|
return registries;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -5,13 +5,15 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
struct Value;
|
||||||
|
class EvalState;
|
||||||
|
|
||||||
|
namespace flake {
|
||||||
|
|
||||||
static const size_t FLAG_REGISTRY = 0;
|
static const size_t FLAG_REGISTRY = 0;
|
||||||
static const size_t USER_REGISTRY = 1;
|
static const size_t USER_REGISTRY = 1;
|
||||||
static const size_t GLOBAL_REGISTRY = 2;
|
static const size_t GLOBAL_REGISTRY = 2;
|
||||||
|
|
||||||
struct Value;
|
|
||||||
class EvalState;
|
|
||||||
|
|
||||||
struct FlakeRegistry
|
struct FlakeRegistry
|
||||||
{
|
{
|
||||||
std::map<FlakeRef, FlakeRef> entries;
|
std::map<FlakeRef, FlakeRef> entries;
|
||||||
|
@ -73,8 +75,6 @@ enum HandleLockFile : unsigned int
|
||||||
, UseNewLockFile // `RecreateLockFile` without writing to file
|
, UseNewLockFile // `RecreateLockFile` without writing to file
|
||||||
};
|
};
|
||||||
|
|
||||||
void makeFlakeValue(EvalState &, const FlakeRef &, HandleLockFile, Value &);
|
|
||||||
|
|
||||||
std::shared_ptr<FlakeRegistry> readRegistry(const Path &);
|
std::shared_ptr<FlakeRegistry> readRegistry(const Path &);
|
||||||
|
|
||||||
void writeRegistry(const FlakeRegistry &, const Path &);
|
void writeRegistry(const FlakeRegistry &, const Path &);
|
||||||
|
@ -143,3 +143,5 @@ void updateLockFile(EvalState &, const FlakeRef & flakeRef, bool recreateLockFil
|
||||||
void gitCloneFlake(FlakeRef flakeRef, EvalState &, Registries, const Path & destDir);
|
void gitCloneFlake(FlakeRef flakeRef, EvalState &, Registries, const Path & destDir);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -12,7 +12,10 @@ struct Value;
|
||||||
class Bindings;
|
class Bindings;
|
||||||
class EvalState;
|
class EvalState;
|
||||||
class Store;
|
class Store;
|
||||||
|
|
||||||
|
namespace flake {
|
||||||
enum HandleLockFile : unsigned int;
|
enum HandleLockFile : unsigned int;
|
||||||
|
}
|
||||||
|
|
||||||
/* A command that require a Nix store. */
|
/* A command that require a Nix store. */
|
||||||
struct StoreCommand : virtual Command
|
struct StoreCommand : virtual Command
|
||||||
|
@ -71,7 +74,7 @@ struct MixFlakeOptions : virtual Args
|
||||||
|
|
||||||
MixFlakeOptions();
|
MixFlakeOptions();
|
||||||
|
|
||||||
HandleLockFile getLockFileMode();
|
flake::HandleLockFile getLockFileMode();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SourceExprCommand : virtual Args, EvalCommand, MixFlakeOptions
|
struct SourceExprCommand : virtual Args, EvalCommand, MixFlakeOptions
|
||||||
|
|
146
src/nix/flake.cc
146
src/nix/flake.cc
|
@ -3,13 +3,17 @@
|
||||||
#include "shared.hh"
|
#include "shared.hh"
|
||||||
#include "progress-bar.hh"
|
#include "progress-bar.hh"
|
||||||
#include "eval.hh"
|
#include "eval.hh"
|
||||||
|
#include "eval-inline.hh"
|
||||||
#include "primops/flake.hh"
|
#include "primops/flake.hh"
|
||||||
|
#include "get-drvs.hh"
|
||||||
|
#include "store-api.hh"
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
|
||||||
using namespace nix;
|
using namespace nix;
|
||||||
|
using namespace nix::flake;
|
||||||
|
|
||||||
class FlakeCommand : virtual Args, public EvalCommand, public MixFlakeOptions
|
class FlakeCommand : virtual Args, public EvalCommand, public MixFlakeOptions
|
||||||
{
|
{
|
||||||
|
@ -33,12 +37,12 @@ public:
|
||||||
Flake getFlake()
|
Flake getFlake()
|
||||||
{
|
{
|
||||||
auto evalState = getEvalState();
|
auto evalState = getEvalState();
|
||||||
return nix::getFlake(*evalState, getFlakeRef(), useRegistries);
|
return flake::getFlake(*evalState, getFlakeRef(), useRegistries);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResolvedFlake resolveFlake()
|
ResolvedFlake resolveFlake()
|
||||||
{
|
{
|
||||||
return nix::resolveFlake(*getEvalState(), getFlakeRef(), getLockFileMode());
|
return flake::resolveFlake(*getEvalState(), getFlakeRef(), getLockFileMode());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -195,6 +199,19 @@ struct CmdFlakeUpdate : FlakeCommand
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void enumerateProvides(EvalState & state, Value & vFlake,
|
||||||
|
std::function<void(const std::string & name, Value & vProvide)> callback)
|
||||||
|
{
|
||||||
|
state.forceAttrs(vFlake);
|
||||||
|
|
||||||
|
auto vProvides = (*vFlake.attrs->get(state.symbols.create("provides")))->value;
|
||||||
|
|
||||||
|
state.forceAttrs(*vProvides);
|
||||||
|
|
||||||
|
for (auto & attr : *vProvides->attrs)
|
||||||
|
callback(attr.name, *attr.value);
|
||||||
|
}
|
||||||
|
|
||||||
struct CmdFlakeInfo : FlakeCommand, MixJSON
|
struct CmdFlakeInfo : FlakeCommand, MixJSON
|
||||||
{
|
{
|
||||||
std::string name() override
|
std::string name() override
|
||||||
|
@ -207,19 +224,133 @@ struct CmdFlakeInfo : FlakeCommand, MixJSON
|
||||||
return "list info about a given flake";
|
return "list info about a given flake";
|
||||||
}
|
}
|
||||||
|
|
||||||
CmdFlakeInfo () { }
|
|
||||||
|
|
||||||
void run(nix::ref<nix::Store> store) override
|
void run(nix::ref<nix::Store> store) override
|
||||||
{
|
{
|
||||||
auto flake = getFlake();
|
auto flake = getFlake();
|
||||||
stopProgressBar();
|
stopProgressBar();
|
||||||
if (json)
|
|
||||||
std::cout << flakeToJson(flake).dump() << std::endl;
|
if (json) {
|
||||||
else
|
auto json = flakeToJson(flake);
|
||||||
|
|
||||||
|
auto state = getEvalState();
|
||||||
|
|
||||||
|
auto vFlake = state->allocValue();
|
||||||
|
flake::callFlake(*state, flake, *vFlake);
|
||||||
|
|
||||||
|
auto provides = nlohmann::json::object();
|
||||||
|
|
||||||
|
enumerateProvides(*state,
|
||||||
|
*vFlake,
|
||||||
|
[&](const std::string & name, Value & vProvide) {
|
||||||
|
auto provide = nlohmann::json::object();
|
||||||
|
|
||||||
|
if (name == "checks" || name == "packages") {
|
||||||
|
state->forceAttrs(vProvide);
|
||||||
|
for (auto & aCheck : *vProvide.attrs)
|
||||||
|
provide[aCheck.name] = nlohmann::json::object();
|
||||||
|
}
|
||||||
|
|
||||||
|
provides[name] = provide;
|
||||||
|
});
|
||||||
|
|
||||||
|
json["provides"] = std::move(provides);
|
||||||
|
|
||||||
|
std::cout << json.dump() << std::endl;
|
||||||
|
} else
|
||||||
printFlakeInfo(flake);
|
printFlakeInfo(flake);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CmdFlakeCheck : FlakeCommand, MixJSON
|
||||||
|
{
|
||||||
|
bool build = true;
|
||||||
|
|
||||||
|
CmdFlakeCheck()
|
||||||
|
{
|
||||||
|
mkFlag()
|
||||||
|
.longName("no-build")
|
||||||
|
.description("do not build checks")
|
||||||
|
.set(&build, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string name() override
|
||||||
|
{
|
||||||
|
return "check";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string description() override
|
||||||
|
{
|
||||||
|
return "check whether the flake evaluates and run its tests";
|
||||||
|
}
|
||||||
|
|
||||||
|
void run(nix::ref<nix::Store> store) override
|
||||||
|
{
|
||||||
|
settings.readOnlyMode = !build;
|
||||||
|
|
||||||
|
auto state = getEvalState();
|
||||||
|
auto flake = resolveFlake();
|
||||||
|
|
||||||
|
auto checkDerivation = [&](const std::string & attrPath, Value & v) {
|
||||||
|
try {
|
||||||
|
auto drvInfo = getDerivation(*state, v, false);
|
||||||
|
if (!drvInfo)
|
||||||
|
throw Error("flake attribute '%s' is not a derivation", attrPath);
|
||||||
|
// FIXME: check meta attributes
|
||||||
|
return drvInfo->queryDrvPath();
|
||||||
|
} catch (Error & e) {
|
||||||
|
e.addPrefix(fmt("while checking flake attribute '" ANSI_BOLD "%s" ANSI_NORMAL "':\n", attrPath));
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
PathSet drvPaths;
|
||||||
|
|
||||||
|
{
|
||||||
|
Activity act(*logger, lvlInfo, actUnknown, "evaluating flake");
|
||||||
|
|
||||||
|
auto vFlake = state->allocValue();
|
||||||
|
flake::callFlake(*state, flake, *vFlake);
|
||||||
|
|
||||||
|
enumerateProvides(*state,
|
||||||
|
*vFlake,
|
||||||
|
[&](const std::string & name, Value & vProvide) {
|
||||||
|
Activity act(*logger, lvlChatty, actUnknown,
|
||||||
|
fmt("checking flake output '%s'", name));
|
||||||
|
|
||||||
|
try {
|
||||||
|
state->forceValue(vProvide);
|
||||||
|
|
||||||
|
if (name == "checks") {
|
||||||
|
state->forceAttrs(vProvide);
|
||||||
|
for (auto & aCheck : *vProvide.attrs)
|
||||||
|
drvPaths.insert(checkDerivation(
|
||||||
|
name + "." + (std::string) aCheck.name, *aCheck.value));
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (name == "packages") {
|
||||||
|
state->forceAttrs(vProvide);
|
||||||
|
for (auto & aCheck : *vProvide.attrs)
|
||||||
|
checkDerivation(
|
||||||
|
name + "." + (std::string) aCheck.name, *aCheck.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (name == "defaultPackage" || name == "devShell")
|
||||||
|
checkDerivation(name, vProvide);
|
||||||
|
|
||||||
|
} catch (Error & e) {
|
||||||
|
e.addPrefix(fmt("while checking flake output '" ANSI_BOLD "%s" ANSI_NORMAL "':\n", name));
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (build) {
|
||||||
|
Activity act(*logger, lvlInfo, actUnknown, "running flake checks");
|
||||||
|
store->buildPaths(drvPaths);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct CmdFlakeAdd : MixEvalArgs, Command
|
struct CmdFlakeAdd : MixEvalArgs, Command
|
||||||
{
|
{
|
||||||
FlakeUri alias;
|
FlakeUri alias;
|
||||||
|
@ -386,6 +517,7 @@ struct CmdFlake : virtual MultiCommand, virtual Command
|
||||||
: MultiCommand({make_ref<CmdFlakeList>()
|
: MultiCommand({make_ref<CmdFlakeList>()
|
||||||
, make_ref<CmdFlakeUpdate>()
|
, make_ref<CmdFlakeUpdate>()
|
||||||
, make_ref<CmdFlakeInfo>()
|
, make_ref<CmdFlakeInfo>()
|
||||||
|
, make_ref<CmdFlakeCheck>()
|
||||||
, make_ref<CmdFlakeDeps>()
|
, make_ref<CmdFlakeDeps>()
|
||||||
, make_ref<CmdFlakeAdd>()
|
, make_ref<CmdFlakeAdd>()
|
||||||
, make_ref<CmdFlakeRemove>()
|
, make_ref<CmdFlakeRemove>()
|
||||||
|
|
|
@ -32,8 +32,9 @@ MixFlakeOptions::MixFlakeOptions()
|
||||||
.set(&useRegistries, false);
|
.set(&useRegistries, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
HandleLockFile MixFlakeOptions::getLockFileMode()
|
flake::HandleLockFile MixFlakeOptions::getLockFileMode()
|
||||||
{
|
{
|
||||||
|
using namespace flake;
|
||||||
return
|
return
|
||||||
useRegistries
|
useRegistries
|
||||||
? recreateLockFile
|
? recreateLockFile
|
||||||
|
@ -163,18 +164,20 @@ struct InstallableAttrPath : InstallableValue
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void makeFlakeClosureGCRoot(Store & store, const FlakeRef & origFlakeRef, const ResolvedFlake & resFlake)
|
void makeFlakeClosureGCRoot(Store & store,
|
||||||
|
const FlakeRef & origFlakeRef,
|
||||||
|
const flake::ResolvedFlake & resFlake)
|
||||||
{
|
{
|
||||||
if (std::get_if<FlakeRef::IsPath>(&origFlakeRef.data)) return;
|
if (std::get_if<FlakeRef::IsPath>(&origFlakeRef.data)) return;
|
||||||
|
|
||||||
/* Get the store paths of all non-local flakes. */
|
/* Get the store paths of all non-local flakes. */
|
||||||
PathSet closure;
|
PathSet closure;
|
||||||
|
|
||||||
std::queue<std::reference_wrapper<const ResolvedFlake>> queue;
|
std::queue<std::reference_wrapper<const flake::ResolvedFlake>> queue;
|
||||||
queue.push(resFlake);
|
queue.push(resFlake);
|
||||||
|
|
||||||
while (!queue.empty()) {
|
while (!queue.empty()) {
|
||||||
const ResolvedFlake & flake = queue.front();
|
const flake::ResolvedFlake & flake = queue.front();
|
||||||
queue.pop();
|
queue.pop();
|
||||||
if (!std::get_if<FlakeRef::IsPath>(&flake.flake.sourceInfo.resolvedRef.data))
|
if (!std::get_if<FlakeRef::IsPath>(&flake.flake.sourceInfo.resolvedRef.data))
|
||||||
closure.insert(flake.flake.sourceInfo.storePath);
|
closure.insert(flake.flake.sourceInfo.storePath);
|
||||||
|
@ -233,9 +236,9 @@ struct InstallableFlake : InstallableValue
|
||||||
|
|
||||||
auto emptyArgs = state.allocBindings(0);
|
auto emptyArgs = state.allocBindings(0);
|
||||||
|
|
||||||
|
if (searchPackages) {
|
||||||
// As a convenience, look for the attribute in
|
// As a convenience, look for the attribute in
|
||||||
// 'provides.packages'.
|
// 'provides.packages'.
|
||||||
if (searchPackages) {
|
|
||||||
if (auto aPackages = *vProvides->attrs->get(state.symbols.create("packages"))) {
|
if (auto aPackages = *vProvides->attrs->get(state.symbols.create("packages"))) {
|
||||||
try {
|
try {
|
||||||
auto * v = findAlongAttrPath(state, *attrPaths.begin(), *emptyArgs, *aPackages->value);
|
auto * v = findAlongAttrPath(state, *attrPaths.begin(), *emptyArgs, *aPackages->value);
|
||||||
|
@ -244,6 +247,17 @@ struct InstallableFlake : InstallableValue
|
||||||
} catch (AttrPathNotFound & e) {
|
} catch (AttrPathNotFound & e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// As a temporary hack until Nixpkgs is properly converted
|
||||||
|
// to provide a clean 'packages' set, look in 'legacyPackages'.
|
||||||
|
if (auto aPackages = *vProvides->attrs->get(state.symbols.create("legacyPackages"))) {
|
||||||
|
try {
|
||||||
|
auto * v = findAlongAttrPath(state, *attrPaths.begin(), *emptyArgs, *aPackages->value);
|
||||||
|
state.forceValue(*v);
|
||||||
|
return v;
|
||||||
|
} catch (AttrPathNotFound & e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, look for it in 'provides'.
|
// Otherwise, look for it in 'provides'.
|
||||||
|
|
Loading…
Reference in a new issue