chore(nint): move from //users/sterni to //nix
Since //web/bubblegum depends on nint, we need to move it to a non user directory to conform with the policy established via cl/3434. Note that this likely doesn't mean greater stability (which isn't really implied in depot anyways), since I still would like to use a more elaborate calling convention to allow for additional useful features. Change-Id: I616f905d8df13e3363674aab69a797b0d39fdd79 Reviewed-on: https://cl.tvl.fyi/c/depot/+/3506 Tested-by: BuildkiteCI Reviewed-by: tazjin <mail@tazj.in>
This commit is contained in:
parent
5d5fb4e6a1
commit
318d10e608
8 changed files with 7 additions and 8 deletions
|
@ -1,85 +0,0 @@
|
|||
# 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 should always be a string (throwing is also okay)
|
||||
which is printed to stdout by `nint`.
|
||||
|
||||
## 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"
|
||||
```
|
|
@ -1,14 +0,0 @@
|
|||
{ depot, pkgs, ... }:
|
||||
|
||||
let
|
||||
inherit (depot.nix.writers)
|
||||
rustSimpleBin
|
||||
;
|
||||
in
|
||||
|
||||
rustSimpleBin {
|
||||
name = "nint";
|
||||
dependencies = [
|
||||
depot.third_party.rust-crates.serde_json
|
||||
];
|
||||
} (builtins.readFile ./nint.rs)
|
|
@ -1,110 +0,0 @@
|
|||
extern crate serde_json;
|
||||
|
||||
use serde_json::Value;
|
||||
use std::ffi::OsString;
|
||||
use std::os::unix::ffi::{OsStringExt, OsStrExt};
|
||||
use std::io::{Error, ErrorKind, Write};
|
||||
use std::process::Command;
|
||||
|
||||
fn render_nix_string(s: &OsString) -> OsString {
|
||||
let mut rendered = Vec::new();
|
||||
|
||||
rendered.extend(b"\"");
|
||||
|
||||
for b in s.as_os_str().as_bytes() {
|
||||
match char::from(*b) {
|
||||
'\"' => rendered.extend(b"\\\""),
|
||||
'\\' => rendered.extend(b"\\\\"),
|
||||
'$' => rendered.extend(b"\\$"),
|
||||
_ => rendered.push(*b),
|
||||
}
|
||||
}
|
||||
|
||||
rendered.extend(b"\"");
|
||||
|
||||
OsString::from_vec(rendered)
|
||||
}
|
||||
|
||||
fn render_nix_list(arr: &[OsString]) -> OsString {
|
||||
let mut rendered = Vec::new();
|
||||
|
||||
rendered.extend(b"[ ");
|
||||
|
||||
for el in arr {
|
||||
rendered.extend(render_nix_string(el).as_os_str().as_bytes());
|
||||
rendered.extend(b" ");
|
||||
}
|
||||
|
||||
rendered.extend(b"]");
|
||||
|
||||
OsString::from_vec(rendered)
|
||||
}
|
||||
|
||||
fn main() -> std::io::Result<()> {
|
||||
let mut nix_args = Vec::new();
|
||||
|
||||
let mut args = std::env::args_os().into_iter();
|
||||
let mut in_args = true;
|
||||
|
||||
let mut argv: Vec<OsString> = Vec::new();
|
||||
|
||||
// skip argv[0]
|
||||
args.next();
|
||||
|
||||
loop {
|
||||
let arg = match args.next() {
|
||||
Some(a) => a,
|
||||
None => break,
|
||||
};
|
||||
|
||||
if !arg.to_str().map(|s| s.starts_with("-")).unwrap_or(false) {
|
||||
in_args = false;
|
||||
}
|
||||
|
||||
if in_args {
|
||||
match(arg.to_str()) {
|
||||
Some("--arg") | Some("--argstr") => {
|
||||
nix_args.push(arg);
|
||||
nix_args.push(args.next().unwrap());
|
||||
nix_args.push(args.next().unwrap());
|
||||
Ok(())
|
||||
}
|
||||
_ => Err(Error::new(ErrorKind::Other, "unknown argument")),
|
||||
}?
|
||||
} else {
|
||||
argv.push(arg);
|
||||
}
|
||||
}
|
||||
|
||||
if argv.len() < 1 {
|
||||
Err(Error::new(ErrorKind::Other, "missing argv"))
|
||||
} else {
|
||||
let cd = std::env::current_dir()?.into_os_string();
|
||||
|
||||
nix_args.push(OsString::from("--arg"));
|
||||
nix_args.push(OsString::from("currentDir"));
|
||||
nix_args.push(cd);
|
||||
|
||||
nix_args.push(OsString::from("--arg"));
|
||||
nix_args.push(OsString::from("argv"));
|
||||
nix_args.push(render_nix_list(&argv[..]));
|
||||
|
||||
nix_args.push(OsString::from("--eval"));
|
||||
nix_args.push(OsString::from("--json"));
|
||||
|
||||
nix_args.push(argv[0].clone());
|
||||
|
||||
let run = Command::new("nix-instantiate")
|
||||
.args(nix_args)
|
||||
.output()?;
|
||||
|
||||
match serde_json::from_slice(&run.stdout[..]) {
|
||||
Ok(Value::String(s)) => Ok(print!("{}", s)),
|
||||
Ok(_) => Err(Error::new(ErrorKind::Other, "output must be a string")),
|
||||
_ => {
|
||||
std::io::stderr().write_all(&run.stderr[..]);
|
||||
Err(Error::new(ErrorKind::Other, "internal nix error"))
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue