852d059e2f
This extends the calling convention for nint in a non-breaking way: If the called script returns an attribute set instead of a string the following is done: * If the attributes `stdout` and/or `stderr` exist, their content (which must be a string currently) is written to the respective output. * If the attribute `exit` exists, nint will exit with the given exit code. Must be a number that can be converted to an `i32`. If it's missing, nint will exit without indicating an error. Change-Id: I209cf178fee3d970fdea3b26e4049e944af47457 Reviewed-on: https://cl.tvl.fyi/c/depot/+/3547 Tested-by: BuildkiteCI Reviewed-by: tazjin <mail@tazj.in>
93 lines
2.6 KiB
Markdown
93 lines
2.6 KiB
Markdown
# nint — Nix INTerpreter
|
|
|
|
`nint` is a shebang compatible interpreter for nix. It is currently
|
|
implemented as a fairly trivial wrapper around `nix-instantiate --eval`.
|
|
It allows to run nix expressions as command line tools if they conform
|
|
to the following calling convention:
|
|
|
|
* Every nix script needs to evaluate to a function which takes an
|
|
attribute set as its single argument. Ideally a set pattern with
|
|
an ellipsis should be used. By default `nint` passes the following
|
|
arguments:
|
|
|
|
* `currentDir`: the current working directory as a nix path
|
|
* `argv`: a list of arguments to the invokation including the
|
|
program name at `builtins.head argv`.
|
|
* Extra arguments can be manually passed as described below.
|
|
|
|
* The return value must either be
|
|
|
|
* A string which is rendered to `stdout`.
|
|
|
|
* An attribute set with the following optional attributes:
|
|
|
|
* `stdout`: A string that's rendered to `stdout`
|
|
* `stderr`: A string that's rendered to `stderr`
|
|
* `exit`: A number which is used as an exit code.
|
|
If missing, nint always exits with 0 (or equivalent).
|
|
|
|
## Usage
|
|
|
|
```
|
|
nint [ --arg ARG VALUE … ] script.nix [ ARGS … ]
|
|
```
|
|
|
|
Instead of `--arg`, `--argstr` can also be used. They both work
|
|
like the flags of the same name for `nix-instantiate` and may
|
|
be specified any number of times as long as they are passed
|
|
*before* the nix expression to run.
|
|
|
|
Below is a shebang which also passes `depot` as an argument
|
|
(note the usage of `env -S` to get around the shebang limitation
|
|
to two arguments).
|
|
|
|
```nix
|
|
#!/usr/bin/env -S nint --arg depot /path/to/depot
|
|
```
|
|
|
|
## Limitations
|
|
|
|
* No side effects except for writing to `stdout`.
|
|
|
|
* Output is not streaming, i. e. even if the output is incrementally
|
|
calculated, nothing will be printed until the full output is available.
|
|
With plain nix strings we can't do better anyways.
|
|
|
|
* Limited error handling for the script, no way to set the exit code etc.
|
|
|
|
Some of these limitations may be possible to address in the future by using
|
|
an alternative nix interpreter and a more elaborate calling convention.
|
|
|
|
## Example
|
|
|
|
Below is a (very simple) implementation of a `ls(1)`-like program in nix:
|
|
|
|
```nix
|
|
#!/usr/bin/env nint
|
|
{ currentDir, argv, ... }:
|
|
|
|
let
|
|
lib = import <nixpkgs/lib>;
|
|
|
|
dirs =
|
|
let
|
|
args = builtins.tail argv;
|
|
in
|
|
if args == []
|
|
then [ currentDir ]
|
|
else args;
|
|
|
|
makeAbsolute = p:
|
|
if builtins.isPath p
|
|
then p
|
|
else if builtins.match "^/.*" p != null
|
|
then p
|
|
else "${toString currentDir}/${p}";
|
|
in
|
|
|
|
lib.concatStringsSep "\n"
|
|
(lib.flatten
|
|
(builtins.map
|
|
(d: (builtins.attrNames (builtins.readDir (makeAbsolute d))))
|
|
dirs)) + "\n"
|
|
```
|