nixpkgs mirror (for testing)
github.com/NixOS/nixpkgs
nix
1{ stdenv, lib, resholve }:
2
3{ pname
4, src
5, version
6, passthru ? { }
7, solutions
8, ...
9}@attrs:
10let
11 inherit stdenv;
12 /* These functions break up the work of partially validating the
13 * 'solutions' attrset and massaging it into env/cli args.
14 *
15 * Note: some of the left-most args do not *have* to be passed as
16 * deep as they are, but I've done so to provide more error context
17 */
18
19 # for brevity / line length
20 spaces = l: builtins.concatStringsSep " " l;
21 semicolons = l: builtins.concatStringsSep ";" l;
22
23 /* Throw a fit with dotted attr path context */
24 nope = path: msg:
25 throw "${builtins.concatStringsSep "." path}: ${msg}";
26
27 /* Special-case directive value representations by type */
28 makeDirective = solution: env: name: val:
29 if builtins.isInt val then builtins.toString val
30 else if builtins.isString val then name
31 else if true == val then name
32 else if false == val then "" # omit!
33 else if null == val then "" # omit!
34 else if builtins.isList val then "${name}:${semicolons val}"
35 else nope [ solution env name ] "unexpected type: ${builtins.typeOf val}";
36
37 /* Build fake/fix/keep directives from Nix types */
38 makeDirectives = solution: env: val:
39 lib.mapAttrsToList (makeDirective solution env) val;
40
41 /* Special-case value representation by type/name */
42 makeEnvVal = solution: env: val:
43 if env == "inputs" then lib.makeBinPath val
44 else if builtins.isString val then val
45 else if builtins.isList val then spaces val
46 else if builtins.isAttrs val then spaces (makeDirectives solution env val)
47 else nope [ solution env ] "unexpected type: ${builtins.typeOf val}";
48
49 /* Shell-format each env value */
50 shellEnv = solution: env: value:
51 lib.escapeShellArg (makeEnvVal solution env value);
52
53 /* Build a single ENV=val pair */
54 makeEnv = solution: env: value:
55 "RESHOLVE_${lib.toUpper env}=${shellEnv solution env value}";
56
57 /* Discard attrs claimed by makeArgs */
58 removeCliArgs = value:
59 removeAttrs value [ "scripts" "flags" ];
60
61 /* Verify required arguments are present */
62 validateSolution = { scripts, inputs, interpreter, ... }: true;
63
64 /* Pull out specific solution keys to build ENV=val pairs */
65 makeEnvs = solution: value:
66 spaces (lib.mapAttrsToList (makeEnv solution) (removeCliArgs value));
67
68 /* Pull out specific solution keys to build CLI argstring */
69 makeArgs = { flags ? [ ], scripts, ... }:
70 spaces (flags ++ scripts);
71
72 /* Build a single resholve invocation */
73 makeInvocation = solution: value:
74 if validateSolution value then
75 "${makeEnvs solution value} resholve --overwrite ${makeArgs value}"
76 else throw "invalid solution"; # shouldn't trigger for now
77
78 /* Build resholve invocation for each solution. */
79 makeCommands = solutions:
80 lib.mapAttrsToList makeInvocation solutions;
81
82 self = (stdenv.mkDerivation ((removeAttrs attrs [ "solutions" ])
83 // {
84 inherit pname version src;
85 buildInputs = [ resholve ];
86
87 # enable below for verbose debug info if needed
88 # supports default python.logging levels
89 # LOGLEVEL="INFO";
90 preFixup = ''
91 pushd "$out"
92 ${builtins.concatStringsSep "\n" (makeCommands solutions)}
93 popd
94 '';
95 }));
96in
97lib.extendDerivation true passthru self