nixpkgs mirror (for testing)
github.com/NixOS/nixpkgs
nix
1# Using resholve's Nix API
2resholve replaces bare references (subject to a PATH search at runtime) to external commands and scripts with absolute paths.
3
4This small super-power helps ensure script dependencies are declared, present, and don't unexpectedly shift when the PATH changes.
5
6resholve 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.
7
8<!-- generated from resholve's repo; best to suggest edits there (or at least notify me) -->
9
10This will hopefully make its way into the Nixpkgs manual soon, but
11until then I'll outline how to use the functions:
12- `resholve.mkDerivation` (formerly `resholvePackage`)
13- `resholve.writeScript` (formerly `resholveScript`)
14- `resholve.writeScriptBin` (formerly `resholveScriptBin`)
15- `resholve.phraseSolution` (new in resholve 0.8.0)
16
17> Fair warning: resholve does *not* aspire to resolving all valid Shell
18> scripts. It depends on the OSH/Oil parser, which aims to support most (but
19> not all) Bash. resholve aims to be a ~90% sort of solution.
20
21## API Concepts
22
23The main difference between `resholve.mkDerivation` and other builder functions
24is the `solutions` attrset, which describes which scripts to resolve and how.
25Each "solution" (k=v pair) in this attrset describes one resholve invocation.
26
27> NOTE: For most shell packages, one invocation will probably be enough:
28> - Packages with a single script will only need one solution.
29> - Packages with multiple scripts can still use one solution if the scripts
30> don't require conflicting directives.
31> - Packages with scripts that require conflicting directives can use multiple
32> solutions to resolve the scripts separately, but produce a single package.
33
34`resholve.writeScript` and `resholve.writeScriptBin` support a _single_
35`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.
36
37## Basic `resholve.mkDerivation` Example
38
39Here's a simple example of how `resholve.mkDerivation` is already used in nixpkgs:
40
41<!-- TODO: figure out how to pull this externally? -->
42
43```nix
44{ lib
45, fetchFromGitHub
46, resholve
47, substituteAll
48, bash
49, coreutils
50, goss
51, which
52}:
53
54resholve.mkDerivation rec {
55 pname = "dgoss";
56 version = "0.3.16";
57
58 src = fetchFromGitHub {
59 owner = "aelsabbahy";
60 repo = "goss";
61 rev = "v${version}";
62 sha256 = "1m5w5vwmc9knvaihk61848rlq7qgdyylzpcwi64z84rkw8qdnj6p";
63 };
64
65 dontConfigure = true;
66 dontBuild = true;
67
68 installPhase = ''
69 sed -i '2i GOSS_PATH=${goss}/bin/goss' extras/dgoss/dgoss
70 install -D extras/dgoss/dgoss $out/bin/dgoss
71 '';
72
73 solutions = {
74 default = {
75 scripts = [ "bin/dgoss" ];
76 interpreter = "${bash}/bin/bash";
77 inputs = [ coreutils which ];
78 fake = {
79 external = [ "docker" ];
80 };
81 };
82 };
83
84 meta = with lib; {
85 homepage = "https://github.com/aelsabbahy/goss/blob/v${version}/extras/dgoss/README.md";
86 description = "Convenience wrapper around goss that aims to bring the simplicity of goss to docker containers";
87 license = licenses.asl20;
88 platforms = platforms.linux;
89 maintainers = with maintainers; [ hyzual ];
90 };
91}
92```
93
94
95## Basic `resholve.writeScript` and `resholve.writeScriptBin` examples
96
97Both of these functions have the same basic API. This example is a little
98trivial for now. If you have a real usage that you find helpful, please PR it.
99
100```nix
101resholvedScript = resholve.writeScript "name" {
102 inputs = [ file ];
103 interpreter = "${bash}/bin/bash";
104 } ''
105 echo "Hello"
106 file .
107 '';
108resholvedScriptBin = resholve.writeScriptBin "name" {
109 inputs = [ file ];
110 interpreter = "${bash}/bin/bash";
111 } ''
112 echo "Hello"
113 file .
114 '';
115```
116
117
118## Basic `resholve.phraseSolution` example
119
120This 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
121trivial for now. If you have a real usage that you find helpful, please PR it.
122
123```nix
124{ stdenv, resholve, module1 }:
125
126stdenv.mkDerivation {
127 # pname = "testmod3";
128 # version = "unreleased";
129 # src = ...;
130
131 installPhase = ''
132 mkdir -p $out/bin
133 install conjure.sh $out/bin/conjure.sh
134 ${resholve.phraseSolution "conjure" {
135 scripts = [ "bin/conjure.sh" ];
136 interpreter = "${bash}/bin/bash";
137 inputs = [ module1 ];
138 fake = {
139 external = [ "jq" "openssl" ];
140 };
141 }}
142 '';
143}
144```
145
146
147## Options
148
149`resholve.mkDerivation` maps Nix types/idioms into the flags and environment variables
150that the `resholve` CLI expects. Here's an overview:
151
152| Option | Type | Containing |
153|--------|------|------------|
154| scripts | `<list>` | scripts to resolve (`$out`-relative paths) |
155| interpreter | `"none"` `<path>` | The absolute interpreter `<path>` for the script's shebang. The special value `none` ensures there is no shebang. |
156| inputs | `<packages>` | Packages to resolve external dependencies from. |
157| fake | `<directives>` | pretend some commands exist |
158| fix | `<directives>` | fix things we can't auto-fix/ignore |
159| keep | `<directives>` | keep things we can't auto-fix/ignore |
160| lore | `<directory>` | control nested resolution |
161| execer | `<statements>` | modify nested resolution |
162| wrapper | `<statements>` | modify nested resolution |
163| prologue | `<file>` | insert file before resolved script |
164| epilogue | `<file>` | insert file after resolved script |
165
166<!-- TODO: section below is largely custom for nixpkgs, but I would LIKE to wurst it. -->
167
168## Controlling resolution with directives
169
170In order to resolve a script, resholve will make you disambiguate how it should
171handle any potential problems it encounters with directives. There are currently
1723 types:
1731. `fake` directives tell resholve to pretend it knows about an identifier
174 such as a function, builtin, external command, etc. if there's a good reason
175 it doesn't already know about it. Common examples:
176 - builtins for a non-bash shell
177 - loadable builtins
178 - platform-specific external commands in cross-platform conditionals
1792. `fix` directives give resholve permission to fix something that it can't
180 safely fix automatically. Common examples:
181 - resolving commands in aliases (this is appropriate for standalone scripts
182 that use aliases non-interactively--but it would prevent profile/rc
183 scripts from using the latest current-system symlinks.)
184 - resolve commands in a variable definition
185 - resolve an absolute command path from inputs as if it were a bare reference
1863. `keep` directives tell resholve not to raise an error (i.e., ignore)
187 something it would usually object to. Common examples:
188 - variables used as/within the first word of a command
189 - pre-existing absolute or user-relative (~) command paths
190 - dynamic (variable) arguments to commands known to accept/run other commands
191
192> NOTE: resholve has a (growing) number of directives detailed in `man resholve`
193> via `nixpkgs.resholve`.
194
195Each of these 3 types is represented by its own attrset, where you can think
196of the key as a scope. The value should be:
197- `true` for any directives that the resholve CLI accepts as a single word
198- a list of strings for all other options
199<!--
200TODO: these should be fully-documented here, but I'm already maintaining
201more copies of their specification/behavior than I like, and continuing to
202add more at this early date will only ensure that I spend more time updating
203docs and less time filling in feature gaps.
204
205Full documentation may be greatly accellerated if someone can help me sort out
206single-sourcing. See: https://github.com/abathur/resholve/issues/19
207-->
208
209This will hopefully make more sense when you see it. Here are CLI examples
210from the manpage, and the Nix equivalents:
211
212```nix
213# --fake 'f:setUp;tearDown builtin:setopt source:/etc/bashrc'
214fake = {
215 # fake accepts the initial of valid identifier types as a CLI convenience.
216 # Use full names in the Nix API.
217 function = [ "setUp" "tearDown" ];
218 builtin = [ "setopt" ];
219 source = [ "/etc/bashrc" ];
220};
221
222# --fix 'aliases $GIT:gix /bin/bash'
223fix = {
224 # all single-word directives use `true` as value
225 aliases = true;
226 "$GIT" = [ "gix" ];
227 "/bin/bash";
228};
229
230# --keep 'source:$HOME /etc/bashrc ~/.bashrc'
231keep = {
232 source = [ "$HOME" ];
233 "/etc/bashrc" = true;
234 "~/.bashrc" = true;
235};
236```
237
238
239> **Note:** For now, at least, you'll need to reference the manpage to completely understand these examples.
240
241## Controlling nested resolution with lore
242
243Initially, resolution of commands in the arguments to command-executing
244commands was limited to one level for a hard-coded list of builtins and
245external commands. resholve can now resolve these recursively.
246
247This feature combines information (_lore_) that the resholve Nix API
248obtains via binlore ([nixpkgs](../../tools/analysis/binlore), [repo](https://github.com/abathur/resholve)),
249with some rules (internal to resholve) for locating sub-executions in
250some of the more common commands.
251
252- "execer" lore identifies whether an executable can, cannot,
253 or might execute its arguments. Every "can" or "might" verdict requires
254 either built-in rules for finding the executable, or human triage.
255- "wrapper" lore maps shell exec wrappers to the programs they exec so
256 that resholve can substitute an executable's verdict for its wrapper's.
257
258> **Caution:** At least when it comes to common utilities, it's best to treat
259> overrides as a stopgap until they can be properly handled in resholve and/or
260> binlore. Please report things you have to override and, if possible, help
261> get them sorted.
262
263There will be more mechanisms for controlling this process in the future
264(and your reports/experiences will play a role in shaping them...) For now,
265the main lever is the ability to substitute your own lore. This is how you'd
266do it piecemeal:
267
268```nix
269# --execer 'cannot:${openssl.bin}/bin/openssl can:${openssl.bin}/bin/c_rehash'
270execer = [
271 /*
272 This is the same verdict binlore will
273 come up with. It's a no-op just to demo
274 how to fiddle lore via the Nix API.
275 */
276 "cannot:${openssl.bin}/bin/openssl"
277 # different verdict, but not used
278 "can:${openssl.bin}/bin/c_rehash"
279];
280
281# --wrapper '${gnugrep}/bin/egrep:${gnugrep}/bin/grep'
282execer = [
283 /*
284 This is the same verdict binlore will
285 come up with. It's a no-op just to demo
286 how to fiddle lore via the Nix API.
287 */
288 "${gnugrep}/bin/egrep:${gnugrep}/bin/grep"
289];
290```
291
292
293The format is fairly simple to generate--you can script your own generator if
294you need to modify the lore.