summary refs log tree commit diff
diff options
context:
space:
mode:
authorTravis A. Everett <travis.a.everett@gmail.com>2022-04-08 01:45:09 -0500
committerYt <raphael@megzari.com>2022-04-08 21:13:20 -0400
commit09d441d21c547254cbd6eb2f2ba8f079b2a16a32 (patch)
tree3b50406c0ef6ab62c460343313ad735c0201049f
parent9a83d8ce9490bc240518440f66e9366c6cab1de7 (diff)
downloadnixpkgs-09d441d21c547254cbd6eb2f2ba8f079b2a16a32.tar
nixpkgs-09d441d21c547254cbd6eb2f2ba8f079b2a16a32.tar.gz
nixpkgs-09d441d21c547254cbd6eb2f2ba8f079b2a16a32.tar.bz2
nixpkgs-09d441d21c547254cbd6eb2f2ba8f079b2a16a32.tar.lz
nixpkgs-09d441d21c547254cbd6eb2f2ba8f079b2a16a32.tar.xz
nixpkgs-09d441d21c547254cbd6eb2f2ba8f079b2a16a32.tar.zst
nixpkgs-09d441d21c547254cbd6eb2f2ba8f079b2a16a32.zip
resholve: 0.6.9 -> 0.8.0
Also track upstream .nix changes over same window.
-rw-r--r--pkgs/development/misc/resholve/README.md169
-rw-r--r--pkgs/development/misc/resholve/default.nix42
-rw-r--r--pkgs/development/misc/resholve/resholve-package.nix37
-rw-r--r--pkgs/development/misc/resholve/resholve-utils.nix169
-rw-r--r--pkgs/development/misc/resholve/resholve.nix13
-rw-r--r--pkgs/development/misc/resholve/source.nix4
-rw-r--r--pkgs/development/misc/resholve/test.nix75
-rw-r--r--pkgs/top-level/aliases.nix9
-rw-r--r--pkgs/top-level/all-packages.nix2
9 files changed, 302 insertions, 218 deletions
diff --git a/pkgs/development/misc/resholve/README.md b/pkgs/development/misc/resholve/README.md
index 0b4bcb371ad..1ea8843c01e 100644
--- a/pkgs/development/misc/resholve/README.md
+++ b/pkgs/development/misc/resholve/README.md
@@ -1,9 +1,18 @@
 # Using resholve's Nix API
+resholve replaces bare references (subject to a PATH search at runtime) to external commands and scripts with absolute paths.
 
-resholve converts bare executable references in shell scripts to absolute
-paths. This will hopefully make its way into the Nixpkgs manual soon, but
-until then I'll outline how to use the `resholvePackage`, `resholveScript`,
-and `resholveScriptBin` functions.
+This small super-power helps ensure script dependencies are declared, present, and don't unexpectedly shift when the PATH changes.
+
+resholve is developed to enable the Nix package manager to package and integrate Shell projects, but its features are not Nix-specific and inevitably have other applications.
+
+<!-- generated from resholve's repo; best to suggest edits there (or at least notify me) -->
+
+This will hopefully make its way into the Nixpkgs manual soon, but
+until then I'll outline how to use the functions:
+- `resholve.mkDerivation` (formerly `resholvePackage`)
+- `resholve.writeScript` (formerly `resholveScript`)
+- `resholve.writeScriptBin` (formerly `resholveScriptBin`)
+- `resholve.phraseSolution` (new in resholve 0.8.0)
 
 > Fair warning: resholve does *not* aspire to resolving all valid Shell
 > scripts. It depends on the OSH/Oil parser, which aims to support most (but
@@ -11,7 +20,7 @@ and `resholveScriptBin` functions.
 
 ## API Concepts
 
-The main difference between `resholvePackage` and other builder functions
+The main difference between `resholve.mkDerivation` and other builder functions
 is the `solutions` attrset, which describes which scripts to resolve and how.
 Each "solution" (k=v pair) in this attrset describes one resholve invocation.
 
@@ -22,70 +31,81 @@ Each "solution" (k=v pair) in this attrset describes one resholve invocation.
 > - Packages with scripts that require conflicting directives can use multiple
 >   solutions to resolve the scripts separately, but produce a single package.
 
-The `resholveScript` and `resholveScriptBin` functions support a _single_
-`solution` attrset. This is basically the same as any single solution in `resholvePackage`, except that it doesn't need a `scripts` attr (it is automatically added).
+`resholve.writeScript` and `resholve.writeScriptBin` support a _single_
+`solution` attrset. This is basically the same as any single solution in `resholve.mkDerivation`, except that it doesn't need a `scripts` attr (it is automatically added). `resholve.phraseSolution` also only accepts a single solution--but it _does_ still require the `scripts` attr.
 
-## Basic `resholvePackage` Example
+## Basic `resholve.mkDerivation` Example
 
-Here's a simple example from one of my own projects, with annotations:
-<!--
-TODO: ideally this will use a nixpkgs example; but we don't have any IN yet
-and the first package PR (bashup-events) is too complex for this context.
--->
+Here's a simple example of how `resholve.mkDerivation` is already used in nixpkgs:
 
-```nix
-{ stdenv, lib, resholvePackage, fetchFromGitHub, bashup-events44, bashInteractive_5, doCheck ? true, shellcheck }:
+<!-- TODO: figure out how to pull this externally? -->
 
-resholvePackage rec {
-  pname = "shellswain";
-  version = "unreleased";
+```nix
+{ lib
+, fetchFromGitHub
+, resholve
+, substituteAll
+, bash
+, coreutils
+, goss
+, which
+}:
+
+resholve.mkDerivation rec {
+  pname = "dgoss";
+  version = "0.3.16";
 
   src = fetchFromGitHub {
-    # ...
+    owner = "aelsabbahy";
+    repo = "goss";
+    rev = "v${version}";
+    sha256 = "1m5w5vwmc9knvaihk61848rlq7qgdyylzpcwi64z84rkw8qdnj6p";
   };
 
-  solutions = {
-    # Give each solution a short name. This is what you'd use to
-    # override its settings, and it shows in (some) error messages.
-    profile = {
-      # the only *required* arguments are the 3 below
+  dontConfigure = true;
+  dontBuild = true;
 
-      # Specify 1 or more $out-relative script paths. Unlike many
-      # builders, resholvePackage modifies the output files during
-      # fixup (to correctly resolve in-package sourcing).
-      scripts = [ "bin/shellswain.bash" ];
-
-      # "none" for no shebang, "${bash}/bin/bash" for bash, etc.
-      interpreter = "none";
+  installPhase = ''
+    sed -i '2i GOSS_PATH=${goss}/bin/goss' extras/dgoss/dgoss
+    install -D extras/dgoss/dgoss $out/bin/dgoss
+  '';
 
-      # packages resholve should resolve executables from
-      inputs = [ bashup-events44 ];
+  solutions = {
+    default = {
+      scripts = [ "bin/dgoss" ];
+      interpreter = "${bash}/bin/bash";
+      inputs = [ coreutils which ];
+      fake = {
+        external = [ "docker" ];
+      };
     };
   };
 
-  makeFlags = [ "prefix=${placeholder "out"}" ];
-
-  inherit doCheck;
-  checkInputs = [ shellcheck ];
-
-  # ...
+  meta = with lib; {
+    homepage = "https://github.com/aelsabbahy/goss/blob/v${version}/extras/dgoss/README.md";
+    description = "Convenience wrapper around goss that aims to bring the simplicity of goss to docker containers";
+    license = licenses.asl20;
+    platforms = platforms.linux;
+    maintainers = with maintainers; [ hyzual ];
+  };
 }
 ```
 
-## Basic `resholveScript` and `resholveScriptBin` examples
+
+## Basic `resholve.writeScript` and `resholve.writeScriptBin` examples
 
 Both of these functions have the same basic API. This example is a little
 trivial for now. If you have a real usage that you find helpful, please PR it.
 
 ```nix
-resholvedScript = resholveScript "name" {
+resholvedScript = resholve.writeScript "name" {
     inputs = [ file ];
     interpreter = "${bash}/bin/bash";
   } ''
     echo "Hello"
     file .
   '';
-resholvedScriptBin = resholveScriptBin "name" {
+resholvedScriptBin = resholve.writeScriptBin "name" {
     inputs = [ file ];
     interpreter = "${bash}/bin/bash";
   } ''
@@ -94,25 +114,56 @@ resholvedScriptBin = resholveScriptBin "name" {
   '';
 ```
 
+
+## Basic `resholve.phraseSolution` example
+
+This function has a similar API to `writeScript` and `writeScriptBin`, except it does require a `scripts` attr. It is intended to make resholve a little easier to mix into more types of build. This example is a little
+trivial for now. If you have a real usage that you find helpful, please PR it.
+
+```nix
+{ stdenv, resholve, module1 }:
+
+stdenv.mkDerivation {
+  # pname = "testmod3";
+  # version = "unreleased";
+  # src = ...;
+
+  installPhase = ''
+    mkdir -p $out/bin
+    install conjure.sh $out/bin/conjure.sh
+    ${resholve.phraseSolution "conjure" {
+      scripts = [ "bin/conjure.sh" ];
+      interpreter = "${bash}/bin/bash";
+      inputs = [ module1 ];
+      fake = {
+        external = [ "jq" "openssl" ];
+      };
+    }}
+  '';
+}
+```
+
+
 ## Options
 
-`resholvePackage` maps Nix types/idioms into the flags and environment variables
+`resholve.mkDerivation` maps Nix types/idioms into the flags and environment variables
 that the `resholve` CLI expects. Here's an overview:
 
-| Option        | Type    | Containing                                            |
-| ------------- | ------- | ----------------------------------------------------- |
-| scripts       | list    | $out-relative string paths to resolve                 |
-| inputs        | list    | packages to resolve executables from                  |
-| interpreter   | string  | 'none' or abspath for shebang                         |
-| prologue      | file    | text to insert before the first code-line             |
-| epilogue      | file    | text to insert after the last code-line               |
-| flags         | list    | strings to pass as flags                              |
-| fake          | attrset | [directives](#controlling-resolution-with-directives) |
-| fix           | attrset | [directives](#controlling-resolution-with-directives) |
-| keep          | attrset | [directives](#controlling-resolution-with-directives) |
-| lore          | string  | [lore directory](#controlling-nested-resolution-with-lore)  |
-| execers       | list    | [execer lore directive](#controlling-nested-resolution-with-lore) |
-| wrappers      | list    | [wrapper lore directive](#controlling-nested-resolution-with-lore) |
+| Option | Type | Containing |
+|--------|------|------------|
+| scripts | `<list>` | scripts to resolve (`$out`-relative paths) |
+| interpreter | `"none"` `<path>` | The absolute interpreter `<path>` for the script's shebang. The special value `none` ensures there is no shebang. |
+| inputs | `<packages>` | Packages to resolve external dependencies from. |
+| fake | `<directives>` | pretend some commands exist |
+| fix | `<directives>` | fix things we can't auto-fix/ignore |
+| keep | `<directives>` | keep things we can't auto-fix/ignore |
+| lore | `<directory>` | control nested resolution |
+| execer | `<statements>` | modify nested resolution |
+| wrapper | `<statements>` | modify nested resolution |
+| prologue | `<file>` | insert file before resolved script |
+| epilogue | `<file>` | insert file after resolved script |
+
+<!-- TODO: section below is largely custom for nixpkgs, but I would LIKE to wurst it. -->
 
 ## Controlling resolution with directives
 
@@ -184,6 +235,7 @@ keep = {
 };
 ```
 
+
 > **Note:** For now, at least, you'll need to reference the manpage to completely understand these examples.
 
 ## Controlling nested resolution with lore
@@ -213,7 +265,7 @@ There will be more mechanisms for controlling this process in the future
 the main lever is the ability to substitute your own lore. This is how you'd
 do it piecemeal:
 
-```
+```nix
 # --execer 'cannot:${openssl.bin}/bin/openssl can:${openssl.bin}/bin/c_rehash'
 execer = [
   /*
@@ -237,5 +289,6 @@ execer = [
 ];
 ```
 
+
 The format is fairly simple to generate--you can script your own generator if
 you need to modify the lore.
diff --git a/pkgs/development/misc/resholve/default.nix b/pkgs/development/misc/resholve/default.nix
index 714c4ecabe0..b2ee3c1d1b5 100644
--- a/pkgs/development/misc/resholve/default.nix
+++ b/pkgs/development/misc/resholve/default.nix
@@ -1,5 +1,5 @@
 { callPackage
-, writeTextFile
+, ...
 }:
 
 let
@@ -7,47 +7,15 @@ let
   deps = callPackage ./deps.nix { };
 in
 rec {
+  # resholve itself
   resholve = callPackage ./resholve.nix {
     inherit (source) rSrc version;
     inherit (deps.oil) oildev;
+    inherit resholve-utils;
   };
+  # funcs to validate and phrase invocations of resholve
+  # and use those invocations to build packages
   resholve-utils = callPackage ./resholve-utils.nix {
     inherit resholve;
   };
-  resholvePackage = callPackage ./resholve-package.nix {
-    inherit resholve resholve-utils;
-  };
-  resholveScript = name: partialSolution: text:
-    writeTextFile {
-      inherit name text;
-      executable = true;
-      checkPhase = ''
-        (
-          PS4=$'\x1f'"\033[33m[resholve context]\033[0m "
-          set -x
-          ${resholve-utils.makeInvocation name (partialSolution // {
-            scripts = [ "${placeholder "out"}" ];
-          })}
-        )
-        ${partialSolution.interpreter} -n $out
-      '';
-    };
-  resholveScriptBin = name: partialSolution: text:
-    writeTextFile rec {
-      inherit name text;
-      executable = true;
-      destination = "/bin/${name}";
-      checkPhase = ''
-        (
-          cd "$out"
-          PS4=$'\x1f'"\033[33m[resholve context]\033[0m "
-          set -x
-          : changing directory to $PWD
-          ${resholve-utils.makeInvocation name (partialSolution // {
-            scripts = [ "bin/${name}" ];
-          })}
-        )
-        ${partialSolution.interpreter} -n $out/bin/${name}
-      '';
-    };
 }
diff --git a/pkgs/development/misc/resholve/resholve-package.nix b/pkgs/development/misc/resholve/resholve-package.nix
deleted file mode 100644
index 89852efb8ba..00000000000
--- a/pkgs/development/misc/resholve/resholve-package.nix
+++ /dev/null
@@ -1,37 +0,0 @@
-{ stdenv, lib, resholve, resholve-utils }:
-
-{ pname
-, src
-, version
-, passthru ? { }
-, solutions
-, ...
-}@attrs:
-let
-  inherit stdenv;
-
-  self = (stdenv.mkDerivation ((removeAttrs attrs [ "solutions" ])
-    // {
-    inherit pname version src;
-    buildInputs = (lib.optionals (builtins.hasAttr "buildInputs" attrs) attrs.buildInputs) ++ [ resholve ];
-
-    # enable below for verbose debug info if needed
-    # supports default python.logging levels
-    # LOGLEVEL="INFO";
-    /*
-      subshell/PS4/set -x and : command to output resholve envs
-      and invocation. Extra context makes it clearer what the
-      Nix API is doing, makes nix-shell debugging easier, etc.
-    */
-    preFixup = ''
-      (
-        cd "$out"
-        PS4=$'\x1f'"\033[33m[resholve context]\033[0m "
-        set -x
-        : changing directory to $PWD
-        ${builtins.concatStringsSep "\n" (resholve-utils.makeCommands solutions)}
-      )
-    '';
-  }));
-in
-lib.extendDerivation true passthru self
diff --git a/pkgs/development/misc/resholve/resholve-utils.nix b/pkgs/development/misc/resholve/resholve-utils.nix
index 2d3c55b8756..27e347e7c4a 100644
--- a/pkgs/development/misc/resholve/resholve-utils.nix
+++ b/pkgs/development/misc/resholve/resholve-utils.nix
@@ -1,4 +1,4 @@
-{ lib, resholve, binlore }:
+{ lib, stdenv, resholve, binlore, writeTextFile }:
 
 rec {
   /* These functions break up the work of partially validating the
@@ -10,6 +10,7 @@ rec {
 
   # for brevity / line length
   spaces = l: builtins.concatStringsSep " " l;
+  colons = l: builtins.concatStringsSep ":" l;
   semicolons = l: builtins.concatStringsSep ";" l;
 
   /* Throw a fit with dotted attr path context */
@@ -17,58 +18,186 @@ rec {
     throw "${builtins.concatStringsSep "." path}: ${msg}";
 
   /* Special-case directive value representations by type */
-  makeDirective = solution: env: name: val:
+  phraseDirective = 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 if builtins.isList val then "${name}:${semicolons (map lib.escapeShellArg 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;
+  phraseDirectives = solution: env: val:
+    lib.mapAttrsToList (phraseDirective solution env) val;
+
+  /* Custom ~search-path routine to handle relative path strings */
+  relSafeBinPath = input:
+    if lib.isDerivation input then ((lib.getOutput "bin" input) + "/bin")
+    else if builtins.isString input then input
+    else throw "unexpected type for input: ${builtins.typeOf input}";
 
   /* Special-case value representation by type/name */
-  makeEnvVal = solution: env: val:
-    if env == "inputs" then lib.makeBinPath val
+  phraseEnvVal = solution: env: val:
+    if env == "inputs" then (colons (map relSafeBinPath 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 if builtins.isAttrs val then spaces (phraseDirectives 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);
+    lib.escapeShellArg (phraseEnvVal solution env value);
 
   /* Build a single ENV=val pair */
-  makeEnv = solution: env: value:
+  phraseEnv = solution: env: value:
     "RESHOLVE_${lib.toUpper env}=${shellEnv solution env value}";
 
-  /* Discard attrs claimed by makeArgs */
-  removeCliArgs = value:
-    removeAttrs value [ "scripts" "flags" ];
+  /* Discard attrs:
+  - claimed by phraseArgs
+  - only needed for binlore.collect
+  */
+  removeUnneededArgs = value:
+    removeAttrs value [ "scripts" "flags" "unresholved" ];
 
   /* 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));
+  phraseEnvs = solution: value:
+    spaces (lib.mapAttrsToList (phraseEnv solution) (removeUnneededArgs value));
 
   /* Pull out specific solution keys to build CLI argstring */
-  makeArgs = { flags ? [ ], scripts, ... }:
+  phraseArgs = { flags ? [ ], scripts, ... }:
     spaces (flags ++ scripts);
 
+  phraseBinloreArgs = value:
+    let
+      hasUnresholved = builtins.hasAttr "unresholved" value;
+    in {
+      drvs = value.inputs ++
+        lib.optionals hasUnresholved [ value.unresholved ];
+      strip = if hasUnresholved then [ value.unresholved ] else [ ];
+    };
+
   /* Build a single resholve invocation */
-  makeInvocation = solution: value:
+  phraseInvocation = solution: value:
     if validateSolution value then
     # we pass resholve a directory
-      "RESHOLVE_LORE=${binlore.collect { drvs = value.inputs; } } ${makeEnvs solution value} ${resholve}/bin/resholve --overwrite ${makeArgs value}"
+      "RESHOLVE_LORE=${binlore.collect (phraseBinloreArgs value) } ${phraseEnvs solution value} ${resholve}/bin/resholve --overwrite ${phraseArgs value}"
     else throw "invalid solution"; # shouldn't trigger for now
 
+  injectUnresholved = solutions: unresholved: (builtins.mapAttrs (name: value: value // { inherit unresholved; } ) solutions);
+
   /* Build resholve invocation for each solution. */
-  makeCommands = solutions:
-    lib.mapAttrsToList makeInvocation solutions;
+  phraseCommands = solutions: unresholved:
+    builtins.concatStringsSep "\n" (
+      lib.mapAttrsToList phraseInvocation (injectUnresholved solutions unresholved)
+    );
+
+  /*
+    subshell/PS4/set -x and : command to output resholve envs
+    and invocation. Extra context makes it clearer what the
+    Nix API is doing, makes nix-shell debugging easier, etc.
+  */
+  phraseContext = { invokable, prep ? ''cd "$out"'' }: ''
+    (
+      ${prep}
+      PS4=$'\x1f'"\033[33m[resholve context]\033[0m "
+      set -x
+      : invoking resholve with PWD=$PWD
+      ${invokable}
+    )
+  '';
+  phraseContextForPWD = invokable: phraseContext { inherit invokable; prep = ""; };
+  phraseContextForOut = invokable: phraseContext { inherit invokable; };
+
+  phraseSolution = name: solution: (phraseContextForOut (phraseInvocation name solution));
+  phraseSolutions = solutions: unresholved:
+    phraseContextForOut (phraseCommands solutions unresholved);
+
+  writeScript = name: partialSolution: text:
+    writeTextFile {
+      inherit name text;
+      executable = true;
+      checkPhase = ''
+         ${(phraseContextForPWD (
+             phraseInvocation name (
+               partialSolution // {
+                 scripts = [ "${placeholder "out"}" ];
+               }
+             )
+           )
+         )}
+        ${partialSolution.interpreter} -n $out
+      '';
+    };
+  writeScriptBin = name: partialSolution: text:
+    writeTextFile rec {
+      inherit name text;
+      executable = true;
+      destination = "/bin/${name}";
+      checkPhase = ''
+        ${phraseContextForOut (
+            phraseInvocation name (
+              partialSolution // {
+                scripts = [ "bin/${name}" ];
+              }
+            )
+          )
+        }
+        ${partialSolution.interpreter} -n $out/bin/${name}
+      '';
+    };
+  mkDerivation = { pname
+    , src
+    , version
+    , passthru ? { }
+    , solutions
+    , ...
+    }@attrs:
+    let
+      inherit stdenv;
+
+      /*
+      Knock out our special solutions arg, but otherwise
+      just build what the caller is giving us. We'll
+      actually resholve it separately below (after we
+      generate binlore for it).
+      */
+      unresholved = (stdenv.mkDerivation ((removeAttrs attrs [ "solutions" ])
+        // {
+        inherit pname version src;
+      }));
+    in
+    /*
+    resholve in a separate derivation; some concerns:
+    - we aren't keeping many of the user's args, so they
+      can't readily set LOGLEVEL and such...
+    - not sure how this affects multiple outputs
+    */
+    lib.extendDerivation true passthru (stdenv.mkDerivation {
+      src = unresholved;
+      version = unresholved.version;
+      pname = "resholved-${unresholved.pname}";
+      buildInputs = [ resholve ];
+
+      # retain a reference to the base
+      passthru = unresholved.passthru // {
+        unresholved = unresholved;
+      };
+
+      # do these imply that we should use NoCC or something?
+      dontConfigure = true;
+      dontBuild = true;
+
+      installPhase = ''
+        cp -R $src $out
+      '';
+
+      # enable below for verbose debug info if needed
+      # supports default python.logging levels
+      # LOGLEVEL="INFO";
+      preFixup = phraseSolutions solutions unresholved;
+    });
 }
diff --git a/pkgs/development/misc/resholve/resholve.nix b/pkgs/development/misc/resholve/resholve.nix
index f364b73158e..959e7ee0cb5 100644
--- a/pkgs/development/misc/resholve/resholve.nix
+++ b/pkgs/development/misc/resholve/resholve.nix
@@ -7,14 +7,13 @@
 , version
 , oildev
 , binlore
+, resholve-utils
 }:
 
 python27Packages.buildPythonApplication {
   pname = "resholve";
   inherit version;
   src = rSrc;
-  format = "other";
-  dontBuild = true;
 
   nativeBuildInputs = [ installShellFiles ];
 
@@ -32,13 +31,12 @@ python27Packages.buildPythonApplication {
   ];
 
   patchPhase = ''
-    for file in resholve; do
+    for file in setup.cfg _resholve/version.py; do
       substituteInPlace $file --subst-var-by version ${version}
     done
   '';
 
-  installPhase = ''
-    install -Dm755 resholve $out/bin/resholve
+   postInstall = ''
     installManPage resholve.1
   '';
 
@@ -48,7 +46,10 @@ python27Packages.buildPythonApplication {
     rm $out/nix-support/propagated-build-inputs
   '';
 
-  passthru.tests = callPackage ./test.nix { inherit rSrc; inherit binlore; };
+  passthru = {
+    inherit (resholve-utils) mkDerivation phraseSolution writeScript writeScriptBin;
+    tests = callPackage ./test.nix { inherit rSrc binlore; };
+  };
 
   meta = with lib; {
     description = "Resolve external shell-script dependencies";
diff --git a/pkgs/development/misc/resholve/source.nix b/pkgs/development/misc/resholve/source.nix
index f2d431d37ef..ee69f6c21be 100644
--- a/pkgs/development/misc/resholve/source.nix
+++ b/pkgs/development/misc/resholve/source.nix
@@ -3,7 +3,7 @@
 }:
 
 rec {
-  version = "0.6.9";
+  version = "0.8.0";
   rSrc =
     # local build -> `make ci`; `make clean` to restore
     # return to remote source
@@ -14,6 +14,6 @@ rec {
         owner = "abathur";
         repo = "resholve";
         rev = "v${version}";
-        hash = "sha256-y9O5w4wA/kR8zoPay9pGs3vwxNqq3JEeZmX0wBJq4UQ=";
+        hash = "sha256-oWS4ZBPjgH2UvYmvHVVRcyl15r3VS964BmB89y9DGo8=";
       };
 }
diff --git a/pkgs/development/misc/resholve/test.nix b/pkgs/development/misc/resholve/test.nix
index 2c17cf2ea03..2b8a3ec3d29 100644
--- a/pkgs/development/misc/resholve/test.nix
+++ b/pkgs/development/misc/resholve/test.nix
@@ -2,10 +2,8 @@
 , stdenv
 , callPackage
 , resholve
-, resholvePackage
-, resholveScript
-, resholveScriptBin
 , shunit2
+, fetchFromGitHub
 , coreutils
 , gnused
 , gnugrep
@@ -34,46 +32,7 @@ let
   parsed_packages = [ coreutils sqlite util-linux gnused gawk findutils rlwrap gnutar bc ];
 in
 rec {
-  re_shunit2 = with shunit2;
-    resholvePackage {
-      inherit pname src version installPhase;
-      solutions = {
-        shunit = {
-          interpreter = "none";
-          scripts = [ "bin/shunit2" ];
-          inputs = [ coreutils gnused gnugrep findutils ];
-          # resholve's Nix API is analogous to the CLI flags
-          # documented in 'man resholve'
-          fake = {
-            # "missing" functions shunit2 expects the user to declare
-            function = [
-              "oneTimeSetUp"
-              "oneTimeTearDown"
-              "setUp"
-              "tearDown"
-              "suite"
-              "noexec"
-            ];
-            # shunit2 is both bash and zsh compatible, and in
-            # some zsh-specific code it uses this non-bash builtin
-            builtin = [ "setopt" ];
-          };
-          fix = {
-            # stray absolute path; make it resolve from coreutils
-            "/usr/bin/od" = true;
-          };
-          keep = {
-            # variables invoked as commands; long-term goal is to
-            # resolve the *variable*, but that is complexish, so
-            # this is where we are...
-            "$__SHUNIT_CMD_ECHO_ESC" = true;
-            "$_SHUNIT_LINENO_" = true;
-            "$SHUNIT_CMD_TPUT" = true;
-          };
-        };
-      };
-    };
-  module1 = resholvePackage {
+  module1 = resholve.mkDerivation {
     pname = "testmod1";
     version = "unreleased";
 
@@ -97,7 +56,7 @@ rec {
 
     is_it_okay_with_arbitrary_envs = "shonuff";
   };
-  module2 = resholvePackage {
+  module2 = resholve.mkDerivation {
     pname = "testmod2";
     version = "unreleased";
 
@@ -105,19 +64,20 @@ rec {
     setSourceRoot = "sourceRoot=$(echo */tests/nix/openssl)";
 
     installPhase = ''
-      mkdir -p $out/bin
+      mkdir -p $out/bin $out/libexec
       install openssl.sh $out/bin/openssl.sh
+      install libexec.sh $out/libexec/invokeme
       install profile $out/profile
     '';
-
+    # LOGLEVEL="DEBUG";
     solutions = {
       openssl = {
         fix = {
           aliases = true;
         };
-        scripts = [ "bin/openssl.sh" ];
+        scripts = [ "bin/openssl.sh" "libexec/invokeme" ];
         interpreter = "none";
-        inputs = [ re_shunit2 openssl.bin ];
+        inputs = [ shunit2 openssl.bin "libexec" "libexec/invokeme" ];
         execer = [
           /*
             This is the same verdict binlore will
@@ -136,7 +96,8 @@ rec {
       };
     };
   };
-  module3 = resholvePackage {
+  # demonstrate that we could use resholve in larger build
+  module3 = stdenv.mkDerivation {
     pname = "testmod3";
     version = "unreleased";
 
@@ -146,15 +107,15 @@ rec {
     installPhase = ''
       mkdir -p $out/bin
       install conjure.sh $out/bin/conjure.sh
-    '';
-
-    solutions = {
-      conjure = {
+      ${resholve.phraseSolution "conjure" {
         scripts = [ "bin/conjure.sh" ];
         interpreter = "${bash}/bin/bash";
         inputs = [ module1 ];
-      };
-    };
+        fake = {
+          external = [ "jq" "openssl" ];
+        };
+      }}
+    '';
   };
 
   cli = stdenv.mkDerivation {
@@ -204,14 +165,14 @@ rec {
   };
 
   # Caution: ci.nix asserts the equality of both of these w/ diff
-  resholvedScript = resholveScript "resholved-script" {
+  resholvedScript = resholve.writeScript "resholved-script" {
     inputs = [ file ];
     interpreter = "${bash}/bin/bash";
   } ''
     echo "Hello"
     file .
   '';
-  resholvedScriptBin = resholveScriptBin "resholved-script-bin" {
+  resholvedScriptBin = resholve.writeScriptBin "resholved-script-bin" {
     inputs = [ file ];
     interpreter = "${bash}/bin/bash";
   } ''
diff --git a/pkgs/top-level/aliases.nix b/pkgs/top-level/aliases.nix
index f3a3ed3404d..41c3f40f052 100644
--- a/pkgs/top-level/aliases.nix
+++ b/pkgs/top-level/aliases.nix
@@ -1039,6 +1039,15 @@ mapAliases ({
   redshift-wlr = throw "redshift-wlr has been replaced by gammastep"; # Added 2021-12-25
   reicast = throw "reicast has been removed from nixpkgs as it is unmaintained, please use flycast instead"; # Added 2022-03-07
   renpy = throw "renpy has been removed from nixpkgs, it was unmaintained and the latest packaged version required python2"; # Added 2022-01-12
+
+  /* 3 resholve aliases below added 2022-04-08 to ease breaking change
+  - convert to throw after 2022-07-01
+  - drop after 2022-11-30?
+  */
+  resholvePackage = builtins.trace "resholvePackage is deprecated, use resholve.mkDerivation instead" resholve.mkDerivation;
+  resholveScript = builtins.trace "resholveScript is deprecated, use resholve.writeScript instead" resholve.writeScript;
+  resholveScriptBin = builtins.trace "resholveScriptBin is deprecated, use resholve.writeScriptBin instead" resholve.writeScriptBin;
+
   residualvm = throw "residualvm was merged to scummvm code in 2018-06-15; consider using scummvm"; # Added 2021-11-27
   retroArchCores = throw "retroArchCores has been removed. Please use overrides instead, e.g.: `retroarch.override { cores = with libretro; [ ... ]; }`"; # Added 2021-11-19
   retroshare06 = retroshare;
diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix
index 9e8b9406d34..ae2bbc045ec 100644
--- a/pkgs/top-level/all-packages.nix
+++ b/pkgs/top-level/all-packages.nix
@@ -9540,7 +9540,7 @@ with pkgs;
   rescuetime = libsForQt5.callPackage ../applications/misc/rescuetime { };
 
   inherit (callPackage ../development/misc/resholve { })
-    resholve resholvePackage resholveScript resholveScriptBin;
+    resholve;
 
   restool = callPackage ../os-specific/linux/restool {};