Add realise and eval

This commit is contained in:
Emery Hemingway 2023-05-30 13:32:29 +01:00
parent b601d9a1b7
commit 4e3e77171c
8 changed files with 94 additions and 51 deletions

2
.envrc
View File

@ -1,2 +1,2 @@
source_env ..
use flake work#nix_actor
use flake syndicate#nix_actor

View File

@ -6,26 +6,28 @@ An actor for interacting with the [Nix](https://nixos.org/) daemon via the [Synd
## Example configuration
```
; create and publish a dedicated dataspace
let ?nixspace = dataspace
<nixspace $nixspace>
? <nixspace ?nixspace> $nixspace [
$nixspace [
; request a build of nixpkgs#hello
? <nix-build "nixpkgs#hello" ?output> [
$log ! <log "-" { hello: $output }>
? <realise "/nix/store/sv1yikjpf7q8b9w4xszb2ipg0cgcq1xv-imv-4.4.0.drv" ?outputs> [ ]
? <eval "3 * 4" {} _> []
? <eval "builtins.getEnv \"PATH\"" {impure: ""} _> []
? ?any [
$log ! <log "-" { nix: $any }>
]
$config [
<require-service <daemon nix_actor>>
? <service-object <daemon nix_actor> ?cap> [
$cap {
dataspace: $nixspace
}
]
<daemon nix_actor {
argv: "/usr/local/nix_actor"
protocol: application/syndicate
}>
]
]
; start nix_actor as a daemon
<require-service <daemon nix_actor>>
<daemon nix_actor {
argv: "/run/current-system/sw/bin/nix_actor"
protocol: application/syndicate
}>
; hand-off a capablity to the Nix dataspace to the actor
? <service-object <daemon nix_actor> ?actor> [
$actor <serve $nixspace>
]
```

View File

@ -1 +1,4 @@
include ../syndicate-nim/depends.tup
NIM_FLAGS += --path:$(TUP_CWD)/../syndicate-nim/src
NIM_FLAGS += --backend:cpp

View File

@ -1,13 +1,9 @@
# Package
version = "20230530"
author = "Emery Hemingway"
description = "Syndicated Nix Actor"
license = "Unlicense"
srcDir = "src"
bin = @["nix_actor"]
backend = "cpp"
version = "20230326"
author = "Emery Hemingway"
description = "Syndicated Nix Actor"
license = "Unlicense"
srcDir = "src"
bin = @["nix_actor"]
# Dependencies
requires "nim >= 1.6.10", "syndicate >= 20230326"
requires "nim >= 1.6.10", "syndicate >= 20230530"

View File

@ -1,4 +1,7 @@
version 1 .
Build = <nix-build @input string @output any> .
Serve = <serve @cap #!any> .
Realise = <realise @drv string @outputs [string ...]> .
Eval = <eval @expr string @options {symbol: any ...:...} @result any> .

View File

@ -1,2 +1,3 @@
include_rules
: nix_actor.nim | $(SYNDICATE_PROTOCOL) ./<protocol> |> !nim_bin |>
: nix_actor.nim | $(SYNDICATE_PROTOCOL) ./<protocol> |> !nim_bin |> {bin}
: {bin} |> !assert_built |>

View File

@ -1,35 +1,67 @@
# SPDX-FileCopyrightText: ☭ Emery Hemingway
# SPDX-License-Identifier: Unlicense
import std/[asyncdispatch, json, osproc]
import std/[asyncdispatch, json, osproc, strutils, tables]
import preserves, preserves/jsonhooks
import syndicate
from syndicate/protocols/dataspace import Observe
import ./nix_actor/protocol
import ./nix_actor/[main, store]
type Observe = dataspace.Observe[Ref]
type
Value = Preserve[void]
Options = Table[Symbol, Value]
Observe = dataspace.Observe[Ref]
proc build(spec: string): Build =
var execOutput = execProcess("nix", args = ["build", "--json", "--no-link", spec], options = {poUsePath})
stderr.writeLine execOutput
var js = parseJson(execOutput)
Build(input: spec, output: js[0].toPreserve)
proc realise(realise: Realise): seq[string] =
var execlines = execProcess("nix-store", args = ["--realize", realise.drv], options = {poUsePath})
split(strip(execlines), '\n')
proc eval(eval: Eval): Value =
var args = @["eval", "--json", "--expr", eval.expr]
for sym, val in eval.options:
add(args, "--" & $sym)
if not val.isString "":
var js: JsonNode
if fromPreserve(js, val): add(args, $js)
else: stderr.writeLine "invalid option ", sym, " ", val
var execOutput = strip execProcess("nix", args = args, options = {poUsePath})
if execOutput != "":
var js = parseJson(execOutput)
result = js.toPreserve
proc bootNixFacet(ds: Ref; turn: var Turn): Facet =
# let store = openStore()
inFacet(turn) do (turn: var Turn):
let storePathObservation = ?Observe(pattern: !Build) ?? {0: grabLit()}
during(turn, ds, storePathObservation) do (spec: string):
stderr.writeLine "build ", spec
let a = build(spec)
discard publish(turn, ds, a)
result = inFacet(turn) do (turn: var Turn):
during(turn, ds, ?Observe(pattern: !Build) ?? {0: grabLit()}) do (spec: string):
discard publish(turn, ds, build(spec))
during(turn, ds, ?Observe(pattern: !Realise) ?? {0: grabLit()}) do (drvPath: string):
var ass = Realise(drv: drvPath)
ass.outputs = realise(ass)
discard publish(turn, ds, ass)
during(turn, ds, ?Observe(pattern: !Eval) ?? {0: grabLit(), 1: grabDict()}) do (e: string, o: Value):
var ass = Eval(expr: e)
if not fromPreserve(ass.options, unpackLiterals(o)):
stderr.writeLine "invalid options ", o
else:
ass.result = eval(ass)
discard publish(turn, ds, ass)
type Args {.preservesDictionary.} = object
dataspace: Ref
proc bootNixActor(root: Ref; turn: var Turn) =
connectStdio(root, turn)
during(turn, root, ?Serve) do (ds: Ref):
during(turn, root, ?Args) do (ds: Ref):
discard bootNixFacet(ds, turn)
initNix() # Nix lib isn't actually being used but it's nice to know that it links.
bootDataspace("main", bootNixActor)
runForever()
runActor("main", bootNixActor)

View File

@ -1,17 +1,23 @@
import
std/typetraits, preserves
preserves, std/tables
type
Serve* {.preservesRecord: "serve".} = object
`cap`* {.preservesEmbedded.}: Preserve[void]
Eval* {.preservesRecord: "eval".} = object
`expr`*: string
`options`*: Table[Symbol, Preserve[void]]
`result`*: Preserve[void]
Realise* {.preservesRecord: "realise".} = object
`drv`*: string
`outputs`*: seq[string]
Build* {.preservesRecord: "nix-build".} = object
`input`*: string
`output`*: Preserve[void]
proc `$`*(x: Serve | Build): string =
proc `$`*(x: Eval | Realise | Build): string =
`$`(toPreserve(x))
proc encode*(x: Serve | Build): seq[byte] =
proc encode*(x: Eval | Realise | Build): seq[byte] =
encode(toPreserve(x))