1 #include "globals.hh"
2 #include "shared.hh"
3 #include "eval.hh"
4 #include "eval-inline.hh"
5 #include "get-drvs.hh"
6 #include "attr-path.hh"
7 #include "value-to-xml.hh"
8 #include "value-to-json.hh"
9 #include "util.hh"
10 #include "store-api.hh"
11 #include "common-eval-args.hh"
12 #include "legacy.hh"
13 
14 #include <map>
15 #include <iostream>
16 
17 
18 using namespace nix;
19 
20 
21 static Path gcRoot;
22 static int rootNr = 0;
23 static bool indirectRoot = false;
24 
25 
26 enum OutputKind { okPlain, okXML, okJSON };
27 
28 
processExpr(EvalState & state,const Strings & attrPaths,bool parseOnly,bool strict,Bindings & autoArgs,bool evalOnly,OutputKind output,bool location,Expr * e)29 void processExpr(EvalState & state, const Strings & attrPaths,
30     bool parseOnly, bool strict, Bindings & autoArgs,
31     bool evalOnly, OutputKind output, bool location, Expr * e)
32 {
33     if (parseOnly) {
34         std::cout << format("%1%\n") % *e;
35         return;
36     }
37 
38     Value vRoot;
39     state.eval(e, vRoot);
40 
41     for (auto & i : attrPaths) {
42         Value & v(*findAlongAttrPath(state, i, autoArgs, vRoot));
43         state.forceValue(v);
44 
45         PathSet context;
46         if (evalOnly) {
47             Value vRes;
48             if (autoArgs.empty())
49                 vRes = v;
50             else
51                 state.autoCallFunction(autoArgs, v, vRes);
52             if (output == okXML)
53                 printValueAsXML(state, strict, location, vRes, std::cout, context);
54             else if (output == okJSON)
55                 printValueAsJSON(state, strict, vRes, std::cout, context);
56             else {
57                 if (strict) state.forceValueDeep(vRes);
58                 std::cout << vRes << std::endl;
59             }
60         } else {
61             DrvInfos drvs;
62             getDerivations(state, v, "", autoArgs, drvs, false);
63             for (auto & i : drvs) {
64                 Path drvPath = i.queryDrvPath();
65 
66                 /* What output do we want? */
67                 string outputName = i.queryOutputName();
68                 if (outputName == "")
69                     throw Error(format("derivation '%1%' lacks an 'outputName' attribute ") % drvPath);
70 
71                 if (gcRoot == "")
72                     printGCWarning();
73                 else {
74                     Path rootName = indirectRoot ? absPath(gcRoot) : gcRoot;
75                     if (++rootNr > 1) rootName += "-" + std::to_string(rootNr);
76                     auto store2 = state.store.dynamic_pointer_cast<LocalFSStore>();
77                     if (store2)
78                         drvPath = store2->addPermRoot(drvPath, rootName, indirectRoot);
79                 }
80                 std::cout << format("%1%%2%\n") % drvPath % (outputName != "out" ? "!" + outputName : "");
81             }
82         }
83     }
84 }
85 
86 
_main(int argc,char ** argv)87 static int _main(int argc, char * * argv)
88 {
89     {
90         Strings files;
91         bool readStdin = false;
92         bool fromArgs = false;
93         bool findFile = false;
94         bool evalOnly = false;
95         bool parseOnly = false;
96         OutputKind outputKind = okPlain;
97         bool xmlOutputSourceLocation = true;
98         bool strict = false;
99         Strings attrPaths;
100         bool wantsReadWrite = false;
101         RepairFlag repair = NoRepair;
102 
103         struct MyArgs : LegacyArgs, MixEvalArgs
104         {
105             using LegacyArgs::LegacyArgs;
106         };
107 
108         MyArgs myArgs(baseNameOf(argv[0]), [&](Strings::iterator & arg, const Strings::iterator & end) {
109             if (*arg == "--help")
110                 showManPage("nix-instantiate");
111             else if (*arg == "--version")
112                 printVersion("nix-instantiate");
113             else if (*arg == "-")
114                 readStdin = true;
115             else if (*arg == "--expr" || *arg == "-E")
116                 fromArgs = true;
117             else if (*arg == "--eval" || *arg == "--eval-only")
118                 evalOnly = true;
119             else if (*arg == "--read-write-mode")
120                 wantsReadWrite = true;
121             else if (*arg == "--parse" || *arg == "--parse-only")
122                 parseOnly = evalOnly = true;
123             else if (*arg == "--find-file")
124                 findFile = true;
125             else if (*arg == "--attr" || *arg == "-A")
126                 attrPaths.push_back(getArg(*arg, arg, end));
127             else if (*arg == "--add-root")
128                 gcRoot = getArg(*arg, arg, end);
129             else if (*arg == "--indirect")
130                 indirectRoot = true;
131             else if (*arg == "--xml")
132                 outputKind = okXML;
133             else if (*arg == "--json")
134                 outputKind = okJSON;
135             else if (*arg == "--no-location")
136                 xmlOutputSourceLocation = false;
137             else if (*arg == "--strict")
138                 strict = true;
139             else if (*arg == "--repair")
140                 repair = Repair;
141             else if (*arg == "--dry-run")
142                 settings.readOnlyMode = true;
143             else if (*arg != "" && arg->at(0) == '-')
144                 return false;
145             else
146                 files.push_back(*arg);
147             return true;
148         });
149 
150         myArgs.parseCmdline(argvToStrings(argc, argv));
151 
152         initPlugins();
153 
154         if (evalOnly && !wantsReadWrite)
155             settings.readOnlyMode = true;
156 
157         auto store = openStore();
158 
159         auto state = std::make_unique<EvalState>(myArgs.searchPath, store);
160         state->repair = repair;
161 
162         Bindings & autoArgs = *myArgs.getAutoArgs(*state);
163 
164         if (attrPaths.empty()) attrPaths = {""};
165 
166         if (findFile) {
167             for (auto & i : files) {
168                 Path p = state->findFile(i);
169                 if (p == "") throw Error(format("unable to find '%1%'") % i);
170                 std::cout << p << std::endl;
171             }
172             return 0;
173         }
174 
175         if (readStdin) {
176             Expr * e = state->parseStdin();
177             processExpr(*state, attrPaths, parseOnly, strict, autoArgs,
178                 evalOnly, outputKind, xmlOutputSourceLocation, e);
179         } else if (files.empty() && !fromArgs)
180             files.push_back("./default.nix");
181 
182         for (auto & i : files) {
183             Expr * e = fromArgs
184                 ? state->parseExprFromString(i, absPath("."))
185                 : state->parseExprFromFile(resolveExprPath(state->checkSourcePath(lookupFileArg(*state, i))));
186             processExpr(*state, attrPaths, parseOnly, strict, autoArgs,
187                 evalOnly, outputKind, xmlOutputSourceLocation, e);
188         }
189 
190         state->printStats();
191 
192         return 0;
193     }
194 }
195 
196 static RegisterLegacyCommand s1("nix-instantiate", _main);
197