11 These functions break up the work of partially validating the
12 'solutions' attrset and massaging it into env/cli args.
14 Note: some of the left-most args do not *have* to be passed as
15 deep as they are, but I've done so to provide more error context
18 # for brevity / line length
19 spaces = l: builtins.concatStringsSep " " l;
20 colons = l: builtins.concatStringsSep ":" l;
21 semicolons = l: builtins.concatStringsSep ";" l;
23 # Throw a fit with dotted attr path context
24 nope = path: msg: throw "${builtins.concatStringsSep "." path}: ${msg}";
26 # Special-case directive value representations by type
28 solution: env: name: val:
29 if builtins.isInt val then
31 else if builtins.isString val then
33 else if true == val then
35 else if false == val then
37 else if null == val then
39 else if builtins.isList val then
40 "${name}:${semicolons (map lib.escapeShellArg val)}"
42 nope [ solution env name ] "unexpected type: ${builtins.typeOf val}";
44 # Build fake/fix/keep directives from Nix types
47 lib.mapAttrsToList (phraseDirective solution env) val;
49 # Custom ~search-path routine to handle relative path strings
52 if lib.isDerivation input then
53 ((lib.getOutput "bin" input) + "/bin")
54 else if builtins.isString input then
57 throw "unexpected type for input: ${builtins.typeOf input}";
59 # Special-case value representation by type/name
62 if env == "inputs" then
63 (colons (map relSafeBinPath val))
64 else if builtins.isString val then
66 else if builtins.isList val then
68 else if builtins.isAttrs val then
69 spaces (phraseDirectives solution env val)
71 nope [ solution env ] "unexpected type: ${builtins.typeOf val}";
73 # Shell-format each env value
76 lib.escapeShellArg (phraseEnvVal solution env value);
78 # Build a single ENV=val pair
81 "RESHOLVE_${lib.toUpper env}=${shellEnv solution env value}";
85 - claimed by phraseArgs
86 - only needed for binlore.collect
96 # Verify required arguments are present
106 # Pull out specific solution keys to build ENV=val pairs
108 solution: value: spaces (lib.mapAttrsToList (phraseEnv solution) (removeUnneededArgs value));
110 # Pull out specific solution keys to build CLI argstring
117 spaces (flags ++ scripts);
122 hasUnresholved = builtins.hasAttr "unresholved" value;
125 drvs = value.inputs ++ lib.optionals hasUnresholved [ value.unresholved ];
126 strip = if hasUnresholved then [ value.unresholved ] else [ ];
129 # Build a single resholve invocation
132 if validateSolution value then
133 # we pass resholve a directory
134 "RESHOLVE_LORE=${binlore.collect (phraseBinloreArgs value)} ${phraseEnvs solution value} ${resholve}/bin/resholve --overwrite ${phraseArgs value}"
136 throw "invalid solution"; # shouldn't trigger for now
139 solutions: unresholved:
140 (builtins.mapAttrs (name: value: value // { inherit unresholved; }) solutions);
142 # Build resholve invocation for each solution.
144 solutions: unresholved:
145 builtins.concatStringsSep "\n" (
146 lib.mapAttrsToList phraseInvocation (injectUnresholved solutions unresholved)
150 subshell/PS4/set -x and : command to output resholve envs
151 and invocation. Extra context makes it clearer what the
152 Nix API is doing, makes nix-shell debugging easier, etc.
157 prep ? ''cd "$out"'',
162 PS4=$'\x1f'"\033[33m[resholve context]\033[0m "
164 : invoking resholve with PWD=$PWD
168 phraseContextForPWD =
174 phraseContextForOut = invokable: phraseContext { inherit invokable; };
176 phraseSolution = name: solution: (phraseContextForOut (phraseInvocation name solution));
178 solutions: unresholved: phraseContextForOut (phraseCommands solutions unresholved);
181 name: partialSolution: text:
188 (phraseContextForPWD (
189 phraseInvocation name (
192 scripts = [ "${placeholder "out"}" ];
198 + lib.optionalString (partialSolution.interpreter != "none") ''
199 ${partialSolution.interpreter} -n $out
203 name: partialSolution: text:
207 destination = "/bin/${name}";
210 ${phraseContextForOut (
211 phraseInvocation name (
214 scripts = [ "bin/${name}" ];
219 + lib.optionalString (partialSolution.interpreter != "none") ''
220 ${partialSolution.interpreter} -n $out/bin/${name}
236 Knock out our special solutions arg, but otherwise
237 just build what the caller is giving us. We'll
238 actually resholve it separately below (after we
239 generate binlore for it).
242 stdenv.mkDerivation (
243 (removeAttrs attrs [ "solutions" ])
246 pname = "${pname}-unresholved";
252 resholve in a separate derivation; some concerns:
253 - we aren't keeping many of the user's args, so they
254 can't readily set LOGLEVEL and such...
255 - not sure how this affects multiple outputs
257 lib.extendDerivation true passthru (
258 stdenv.mkDerivation {
260 inherit version pname;
261 buildInputs = [ resholve ];
262 disallowedReferences = [ resholve ];
264 # retain a reference to the base
265 passthru = unresholved.passthru // {
266 unresholved = unresholved;
267 # fallback attr for update bot to query our src
268 originalSrc = unresholved.src;
271 # do these imply that we should use NoCC or something?
272 dontConfigure = true;
279 # enable below for verbose debug info if needed
280 # supports default python.logging levels
282 preFixup = phraseSolutions solutions unresholved;
284 # don't break the metadata...
285 meta = unresholved.meta;