summary refs log tree commit diff
path: root/pkgs/development/misc/resholve/resholve-package.nix
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/development/misc/resholve/resholve-package.nix')
-rw-r--r--pkgs/development/misc/resholve/resholve-package.nix97
1 files changed, 97 insertions, 0 deletions
diff --git a/pkgs/development/misc/resholve/resholve-package.nix b/pkgs/development/misc/resholve/resholve-package.nix
new file mode 100644
index 00000000000..cc971196a4f
--- /dev/null
+++ b/pkgs/development/misc/resholve/resholve-package.nix
@@ -0,0 +1,97 @@
+{ stdenv, lib, resholve }:
+
+{ pname
+, src
+, version
+, passthru ? { }
+, solutions
+, ...
+}@attrs:
+let
+  inherit stdenv;
+  /* These functions break up the work of partially validating the
+   * 'solutions' attrset and massaging it into env/cli args.
+   *
+   * Note: some of the left-most args do not *have* to be passed as
+   * deep as they are, but I've done so to provide more error context
+   */
+
+  # for brevity / line length
+  spaces = l: builtins.concatStringsSep " " l;
+  semicolons = l: builtins.concatStringsSep ";" l;
+
+  /* Throw a fit with dotted attr path context */
+  nope = path: msg:
+    throw "${builtins.concatStringsSep "." path}: ${msg}";
+
+  /* Special-case directive value representations by type */
+  makeDirective = solution: env: name: val:
+    if builtins.isInt val then builtins.toString val
+    else if builtins.isString val then name
+    else if true == val then name
+    else if false == val then "" # omit!
+    else if null == val then "" # omit!
+    else if builtins.isList val then "${name}:${semicolons val}"
+    else nope [ solution env name ] "unexpected type: ${builtins.typeOf val}";
+
+  /* Build fake/fix/keep directives from Nix types */
+  makeDirectives = solution: env: val:
+    lib.mapAttrsToList (makeDirective solution env) val;
+
+  /* Special-case value representation by type/name */
+  makeEnvVal = solution: env: val:
+    if env == "inputs" then lib.makeBinPath val
+    else if builtins.isString val then val
+    else if builtins.isList val then spaces val
+    else if builtins.isAttrs val then spaces (makeDirectives solution env val)
+    else nope [ solution env ] "unexpected type: ${builtins.typeOf val}";
+
+  /* Shell-format each env value */
+  shellEnv = solution: env: value:
+    lib.escapeShellArg (makeEnvVal solution env value);
+
+  /* Build a single ENV=val pair */
+  makeEnv = solution: env: value:
+    "RESHOLVE_${lib.toUpper env}=${shellEnv solution env value}";
+
+  /* Discard attrs claimed by makeArgs */
+  removeCliArgs = value:
+    removeAttrs value [ "scripts" "flags" ];
+
+  /* Verify required arguments are present */
+  validateSolution = { scripts, inputs, interpreter, ... }: true;
+
+  /* Pull out specific solution keys to build ENV=val pairs */
+  makeEnvs = solution: value:
+    spaces (lib.mapAttrsToList (makeEnv solution) (removeCliArgs value));
+
+  /* Pull out specific solution keys to build CLI argstring */
+  makeArgs = { flags ? [ ], scripts, ... }:
+    spaces (flags ++ scripts);
+
+  /* Build a single resholve invocation */
+  makeInvocation = solution: value:
+    if validateSolution value then
+      "${makeEnvs solution value} resholve --overwrite ${makeArgs value}"
+    else throw "invalid solution"; # shouldn't trigger for now
+
+  /* Build resholve invocation for each solution. */
+  makeCommands = solutions:
+    lib.mapAttrsToList makeInvocation solutions;
+
+  self = (stdenv.mkDerivation ((removeAttrs attrs [ "solutions" ])
+    // {
+    inherit pname version src;
+    buildInputs = [ resholve ];
+
+    # enable below for verbose debug info if needed
+    # supports default python.logging levels
+    # LOGLEVEL="INFO";
+    preFixup = ''
+      pushd "$out"
+      ${builtins.concatStringsSep "\n" (makeCommands solutions)}
+      popd
+    '';
+  }));
+in
+lib.extendDerivation true passthru self