#include <iostream>
#include <map>
#include "libexpr/attr-path.hh"
#include "libexpr/common-eval-args.hh"
#include "libexpr/eval-inline.hh"
#include "libexpr/eval.hh"
#include "libexpr/get-drvs.hh"
#include "libexpr/value-to-json.hh"
#include "libexpr/value-to-xml.hh"
#include "libmain/shared.hh"
#include "libstore/globals.hh"
#include "libstore/store-api.hh"
#include "libutil/util.hh"
#include "nix/legacy.hh"
using namespace nix;
static Path gcRoot;
static int rootNr = 0;
static bool indirectRoot = false;
enum OutputKind { okPlain, 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) {
std::cout << format("%1%\n") % *e;
return;
}
Value vRoot;
state.eval(e, vRoot);
for (auto& i : attrPaths) {
Value& v(*findAlongAttrPath(state, i, autoArgs, vRoot));
state.forceValue(v);
PathSet context;
if (evalOnly) {
Value vRes;
if (autoArgs->empty()) {
vRes = v;
} else {
state.autoCallFunction(autoArgs, v, vRes);
}
if (output == okXML) {
printValueAsXML(state, strict, location, vRes, std::cout, context);
} else if (output == okJSON) {
printValueAsJSON(state, strict, vRes, std::cout, context);
} else {
if (strict) {
state.forceValueDeep(vRes);
}
std::cout << vRes << std::endl;
}
} else {
DrvInfos drvs;
getDerivations(state, v, "", autoArgs, drvs, false);
for (auto& i : drvs) {
Path drvPath = i.queryDrvPath();
/* What output do we want? */
std::string outputName = i.queryOutputName();
if (outputName.empty()) {
throw Error(
format("derivation '%1%' lacks an 'outputName' attribute ") %
drvPath);
}
if (gcRoot.empty()) {
printGCWarning();
} else {
Path rootName = indirectRoot ? absPath(gcRoot) : gcRoot;
if (++rootNr > 1) {
rootName += "-" + std::to_string(rootNr);
}
auto store2 = state.store.dynamic_pointer_cast<LocalFSStore>();
if (store2) {
drvPath = store2->addPermRoot(drvPath, rootName, indirectRoot);
}
}
std::cout << format("%1%%2%\n") % drvPath %
(outputName != "out" ? "!" + outputName : "");
}
}
}
}
static int _main(int argc, char** argv) {
{
Strings files;
bool readStdin = false;
bool fromArgs = false;
bool findFile = false;
bool evalOnly = false;
bool parseOnly = false;
bool traceFileAccess = false;
OutputKind outputKind = okPlain;
bool xmlOutputSourceLocation = true;
bool strict = false;
Strings attrPaths;
bool wantsReadWrite = false;
RepairFlag repair = NoRepair;
struct MyArgs : LegacyArgs, MixEvalArgs {
using LegacyArgs::LegacyArgs;
};
MyArgs myArgs(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") {
indirectRoot = true;
} 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 == "--repair") {
repair = Repair;
} else if (*arg == "--dry-run") {
settings.readOnlyMode = true;
} else if (*arg == "--trace-file-access") {
traceFileAccess = true;
} else if (*arg == "--trace-file-access=true") {
traceFileAccess = true;
} else if (*arg == "--trace-file-access=false") {
traceFileAccess = false;
} else if (*arg == "--notrace-file-access") {
traceFileAccess = false;
} 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 state = std::make_unique<EvalState>(myArgs.searchPath, store);
state->repair = repair;
if (traceFileAccess) {
state->EnableFileAccessTracing([](const Path& path) {
std::cerr << "trace: depot-scan: " << path << "\n";
});
}
std::unique_ptr<Bindings> autoArgs = myArgs.getAutoArgs(*state);
if (attrPaths.empty()) {
attrPaths = {""};
}
if (findFile) {
for (auto& i : files) {
Path p = state->findFile(i);
if (p.empty()) {
throw Error(format("unable to find '%1%'") % i);
}
std::cout << p << std::endl;
}
return 0;
}
if (readStdin) {
Expr* e = state->parseStdin();
processExpr(*state, attrPaths, parseOnly, strict, autoArgs.get(),
evalOnly, outputKind, xmlOutputSourceLocation, e);
} else if (files.empty() && !fromArgs) {
files.push_back("./default.nix");
}
for (auto& i : files) {
Expr* e = fromArgs
? state->parseExprFromString(i, absPath("."))
: state->parseExprFromFile(resolveExprPath(
state->checkSourcePath(lookupFileArg(*state, i))));
processExpr(*state, attrPaths, parseOnly, strict, autoArgs.get(),
evalOnly, outputKind, xmlOutputSourceLocation, e);
}
state->printStats();
return 0;
}
}
static RegisterLegacyCommand s1("nix-instantiate", _main);