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"
 | 
						|
```
 |