1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-06-24 22:11:15 +02:00
nix/src/nix-instantiate/nix-instantiate.cc
John Ericson d972f9e2e2 Split out store-open.hh and store-registration.hh
The existing header is a bit too big. Now the following use-cases are
separated, and get their own headers:

- Using or implementing an arbitrary store: remaining `store-api.hh`

  This is closer to just being about the `Store` (and `StoreConfig`)
  classes, as one would expect.

- Opening a store from a textual description: `store-open.hh`

  Opening an aribtrary store implementation like this requires some sort
  of store registration mechanism to exists, but the caller doesn't need
  to know how it works. This just exposes the functions which use such a
  mechanism, without exposing the mechanism itself

- Registering a store implementation: `store-registration.hh`

  This requires understanding how the mechanism actually works, and the
  mechanism in question involves templated machinery in headers we
  rather not expose to things that don't need it, as it would slow down
  compilation for no reason.
2025-05-14 16:07:57 -04:00

206 lines
7.3 KiB
C++

#include "nix/store/globals.hh"
#include "nix/expr/print-ambiguous.hh"
#include "nix/main/shared.hh"
#include "nix/expr/eval.hh"
#include "nix/expr/eval-inline.hh"
#include "nix/expr/get-drvs.hh"
#include "nix/expr/attr-path.hh"
#include "nix/util/signals.hh"
#include "nix/expr/value-to-xml.hh"
#include "nix/expr/value-to-json.hh"
#include "nix/store/store-open.hh"
#include "nix/store/local-fs-store.hh"
#include "nix/cmd/common-eval-args.hh"
#include "nix/cmd/legacy.hh"
#include "man-pages.hh"
#include <map>
#include <iostream>
using namespace nix;
static Path gcRoot;
static int rootNr = 0;
enum OutputKind { okPlain, okRaw, okXML, okJSON };
void processExpr(EvalState & state, const Strings & attrPaths,
bool parseOnly, bool strict, Bindings & autoArgs,
bool evalOnly, OutputKind output, bool location, Expr * e)
{
if (parseOnly) {
e->show(state.symbols, std::cout);
std::cout << "\n";
return;
}
Value vRoot;
state.eval(e, vRoot);
for (auto & i : attrPaths) {
Value & v(*findAlongAttrPath(state, i, autoArgs, vRoot).first);
state.forceValue(v, v.determinePos(noPos));
NixStringContext context;
if (evalOnly) {
Value vRes;
if (autoArgs.empty())
vRes = v;
else
state.autoCallFunction(autoArgs, v, vRes);
if (output == okRaw)
std::cout << *state.coerceToString(noPos, vRes, context, "while generating the nix-instantiate output");
// We intentionally don't output a newline here. The default PS1 for Bash in NixOS starts with a newline
// and other interactive shells like Zsh are smart enough to print a missing newline before the prompt.
else if (output == okXML)
printValueAsXML(state, strict, location, vRes, std::cout, context, noPos);
else if (output == okJSON) {
printValueAsJSON(state, strict, vRes, v.determinePos(noPos), std::cout, context);
std::cout << std::endl;
} else {
if (strict) state.forceValueDeep(vRes);
std::set<const void *> seen;
printAmbiguous(vRes, state.symbols, std::cout, &seen, std::numeric_limits<int>::max());
std::cout << std::endl;
}
} else {
PackageInfos drvs;
getDerivations(state, v, "", autoArgs, drvs, false);
for (auto & i : drvs) {
auto drvPath = i.requireDrvPath();
auto drvPathS = state.store->printStorePath(drvPath);
/* What output do we want? */
std::string outputName = i.queryOutputName();
if (outputName == "")
throw Error("derivation '%1%' lacks an 'outputName' attribute", drvPathS);
if (gcRoot == "")
printGCWarning();
else {
Path rootName = absPath(gcRoot);
if (++rootNr > 1) rootName += "-" + std::to_string(rootNr);
auto store2 = state.store.dynamic_pointer_cast<LocalFSStore>();
if (store2)
drvPathS = store2->addPermRoot(drvPath, rootName);
}
std::cout << fmt("%s%s\n", drvPathS, (outputName != "out" ? "!" + outputName : ""));
}
}
}
}
static int main_nix_instantiate(int argc, char * * argv)
{
{
Strings files;
bool readStdin = false;
bool fromArgs = false;
bool findFile = false;
bool evalOnly = false;
bool parseOnly = false;
OutputKind outputKind = okPlain;
bool xmlOutputSourceLocation = true;
bool strict = false;
Strings attrPaths;
bool wantsReadWrite = false;
struct MyArgs : LegacyArgs, MixEvalArgs
{
using LegacyArgs::LegacyArgs;
};
MyArgs myArgs(std::string(baseNameOf(argv[0])), [&](Strings::iterator & arg, const Strings::iterator & end) {
if (*arg == "--help")
showManPage("nix-instantiate");
else if (*arg == "--version")
printVersion("nix-instantiate");
else if (*arg == "-")
readStdin = true;
else if (*arg == "--expr" || *arg == "-E")
fromArgs = true;
else if (*arg == "--eval" || *arg == "--eval-only")
evalOnly = true;
else if (*arg == "--read-write-mode")
wantsReadWrite = true;
else if (*arg == "--parse" || *arg == "--parse-only")
parseOnly = evalOnly = true;
else if (*arg == "--find-file")
findFile = true;
else if (*arg == "--attr" || *arg == "-A")
attrPaths.push_back(getArg(*arg, arg, end));
else if (*arg == "--add-root")
gcRoot = getArg(*arg, arg, end);
else if (*arg == "--indirect")
;
else if (*arg == "--raw")
outputKind = okRaw;
else if (*arg == "--xml")
outputKind = okXML;
else if (*arg == "--json")
outputKind = okJSON;
else if (*arg == "--no-location")
xmlOutputSourceLocation = false;
else if (*arg == "--strict")
strict = true;
else if (*arg == "--dry-run")
settings.readOnlyMode = true;
else if (*arg != "" && arg->at(0) == '-')
return false;
else
files.push_back(*arg);
return true;
});
myArgs.parseCmdline(argvToStrings(argc, argv));
if (evalOnly && !wantsReadWrite)
settings.readOnlyMode = true;
auto store = openStore();
auto evalStore = myArgs.evalStoreUrl ? openStore(*myArgs.evalStoreUrl) : store;
auto state = std::make_unique<EvalState>(myArgs.lookupPath, evalStore, fetchSettings, evalSettings, store);
state->repair = myArgs.repair;
Bindings & autoArgs = *myArgs.getAutoArgs(*state);
if (attrPaths.empty()) attrPaths = {""};
if (findFile) {
for (auto & i : files) {
auto p = state->findFile(i);
if (auto fn = p.getPhysicalPath())
std::cout << fn->string() << std::endl;
else
throw Error("'%s' has no physical path", p);
}
return 0;
}
if (readStdin) {
Expr * e = state->parseStdin();
processExpr(*state, attrPaths, parseOnly, strict, autoArgs,
evalOnly, outputKind, xmlOutputSourceLocation, e);
} else if (files.empty() && !fromArgs)
files.push_back("./default.nix");
for (auto & i : files) {
Expr * e = fromArgs
? state->parseExprFromString(i, state->rootPath("."))
: state->parseExprFromFile(resolveExprPath(lookupFileArg(*state, i)));
processExpr(*state, attrPaths, parseOnly, strict, autoArgs,
evalOnly, outputKind, xmlOutputSourceLocation, e);
}
state->maybePrintStats();
return 0;
}
}
static RegisterLegacyCommand r_nix_instantiate("nix-instantiate", main_nix_instantiate);