Use the (un)stable Nix C bindings
This commit is contained in:
parent
5483b54158
commit
576157b901
1
Tupfile
1
Tupfile
|
@ -1,3 +1,2 @@
|
|||
include_rules
|
||||
: |> !nim_lk |> | ./<lock>
|
||||
: lock.json |> !nim_cfg |> | ./<lock>
|
||||
|
|
172
lock.json
172
lock.json
|
@ -1 +1,171 @@
|
|||
{"depends":[{"method":"fetchzip","packages":["syndicate"],"path":"/nix/store/008s11kkqscfqxs6g29q77c38pnrlppi-source","ref":"20231005","rev":"552e51899c82c0c2f4f466382be7d8e22a1da689","sha256":"1j3k0zlh5z02adhfvb7rdqz8fjzc6gri4v3v1fgcv2h2b7vrf0dg","srcDir":"src","url":"https://git.syndicate-lang.org/ehmry/syndicate-nim/archive/552e51899c82c0c2f4f466382be7d8e22a1da689.tar.gz"},{"method":"fetchzip","packages":["coap"],"path":"/nix/store/pqj933cnw7r7hp46jrpjlwh1yr0jvckp-source","ref":"20230331","rev":"a134213b51a8d250684f2ba26802ffa97fae4ffb","sha256":"1wbix6d8l26nj7m3xinh4m2f27n4ma0yzs3x5lpann2ha0y51k8b","srcDir":"src","url":"https://codeberg.org/eris/nim-coap/archive/a134213b51a8d250684f2ba26802ffa97fae4ffb.tar.gz"},{"method":"fetchzip","packages":["hashlib"],"path":"/nix/store/v03nzlpdgbfxd2zhcnkfbkq01d5kqxcl-source","rev":"84e0247555e4488594975900401baaf5bbbfb53","sha256":"1pfczsv8kl36qpv543f93d2y2vgz2acckssfap7l51s2x62m6qwx","srcDir":"","url":"https://github.com/khchen/hashlib/archive/84e0247555e4488594975900401baaf5bbbfb53.tar.gz"},{"method":"fetchzip","packages":["preserves"],"path":"/nix/store/vx6ihnickx7d5lwy69i8k7fsjicv33r3-source","ref":"20230914","rev":"c915accf7d2a36ca1f323e2f02e2df7375e815f1","sha256":"11rlcbs9mvk335ibkbj8fk9aslhmnlaiqhcsjpp5n04k447sr7nx","srcDir":"src","url":"https://git.syndicate-lang.org/ehmry/preserves-nim/archive/c915accf7d2a36ca1f323e2f02e2df7375e815f1.tar.gz"},{"method":"fetchzip","packages":["eris"],"path":"/nix/store/lxa6ba8r9hhs06k6f2iyznwjxix1klv1-source","ref":"20230823","rev":"49d8117367d3530533dc1d6a9111ddd134b08b1e","sha256":"0lq9a04cayf04nnhn0gvp5phlij0cis38v7cz7jmgks2xvz1bcbr","srcDir":"src","url":"https://codeberg.org/eris/nim-eris/archive/49d8117367d3530533dc1d6a9111ddd134b08b1e.tar.gz"},{"method":"fetchzip","packages":["cbor"],"path":"/nix/store/70cqa9s36dqnmsf179cn9psj77jhqi1l-source","ref":"20230619","rev":"a4a1affd45ba90bea24e08733ae2bd02fe058166","sha256":"005ib6im97x9pdbg6p0fy58zpdwdbkpmilxa8nhrrb1hnpjzz90p","srcDir":"src","url":"https://git.sr.ht/~ehmry/nim_cbor/archive/a4a1affd45ba90bea24e08733ae2bd02fe058166.tar.gz"},{"method":"fetchzip","packages":["freedesktop_org"],"path":"/nix/store/98wncmx58cfnhv3y96lzwm22zvyk9b1h-source","ref":"20230210","rev":"fb04d0862aca4be2edcc0eafa94b1840030231c8","sha256":"0wj5m09x1pr36gv8p5r72p6l3wwl01y8scpnlzx7q0h5ij6jaj6s","srcDir":"src","url":"https://git.sr.ht/~ehmry/freedesktop_org/archive/fb04d0862aca4be2edcc0eafa94b1840030231c8.tar.gz"},{"method":"fetchzip","packages":["configparser"],"path":"/nix/store/4zl5v7i6cj3f9sayvsjcx2h20lqwr9a6-source","ref":"newSection","rev":"695f1285d63f1954c25eb1f42798d90fa7bcbe14","sha256":"0b0pb5i0kir130ia2zf8zcgdz8awms161i6p83ri3nbgibbjnr37","srcDir":"src","url":"https://github.com/ehmry/nim-configparser/archive/695f1285d63f1954c25eb1f42798d90fa7bcbe14.tar.gz"},{"method":"fetchzip","packages":["tkrzw"],"path":"/nix/store/4x9wxyli4dy719svg1zaww0c0b3xckp0-source","ref":"20220922","rev":"efd87edb7b063182c1a1fa018006a87b515d589b","sha256":"1h0sdvai4gkkz48xfh67wa1xz2k8bkkba8q6snnbllmhmywd9apb","srcDir":"src","url":"https://git.sr.ht/~ehmry/nim-tkrzw/archive/efd87edb7b063182c1a1fa018006a87b515d589b.tar.gz"},{"method":"fetchzip","packages":["getdns"],"path":"/nix/store/x9xmn7w4k6jg8nv5bnx148ibhnsfh362-source","ref":"20221222","rev":"c73cbe288d9f9480586b8fa87f6d794ffb6a6ce6","sha256":"1sbgx2x51szr22i72n7c8jglnfmr8m7y7ga0v85d58fwadiv7g6b","srcDir":"src","url":"https://git.sr.ht/~ehmry/getdns-nim/archive/c73cbe288d9f9480586b8fa87f6d794ffb6a6ce6.tar.gz"},{"method":"fetchzip","packages":["nimcrypto"],"path":"/nix/store/zyr8zwh7vaiycn1s4r8cxwc71f2k5l0h-source","ref":"traditional-api","rev":"602c5d20c69c76137201b5d41f788f72afb95aa8","sha256":"1dmdmgb6b9m5f8dyxk781nnd61dsk3hdxqks7idk9ncnpj9fng65","srcDir":"","url":"https://github.com/cheatfate/nimcrypto/archive/602c5d20c69c76137201b5d41f788f72afb95aa8.tar.gz"},{"method":"fetchzip","packages":["taps"],"path":"/nix/store/did1li0xk9qih80pvxqhjc4np3ijlfjj-source","ref":"20230331","rev":"4f9c9972d74eb39c662b43ed79d761e109bf00f1","sha256":"12qsizmisr1q0q4x37c5q6gmnqb5mp0bid7s3jlcsjvhc4jw2q57","srcDir":"src","url":"https://git.sr.ht/~ehmry/nim_taps/archive/4f9c9972d74eb39c662b43ed79d761e109bf00f1.tar.gz"},{"method":"fetchzip","packages":["base32"],"path":"/nix/store/qcnchjsak3hyn4c6r0zd6qvm7j8y1747-source","ref":"0.1.3","rev":"f541038fbe49fdb118cc2002d29824b9fc4bfd61","sha256":"16gh1ifp9hslsg0is0v1ya7rxqfhq5hjqzc3pfdqvcgibp5ybh06","srcDir":"","url":"https://github.com/OpenSystemsLab/base32.nim/archive/f541038fbe49fdb118cc2002d29824b9fc4bfd61.tar.gz"},{"method":"fetchzip","packages":["npeg"],"path":"/nix/store/ffkxmjmigfs7zhhiiqm0iw2c34smyciy-source","ref":"1.2.1","rev":"26d62fdc40feb84c6533956dc11d5ee9ea9b6c09","sha256":"0xpzifjkfp49w76qmaylan8q181bs45anmp46l4bwr3lkrr7bpwh","srcDir":"src","url":"https://github.com/zevv/npeg/archive/26d62fdc40feb84c6533956dc11d5ee9ea9b6c09.tar.gz"}]}
|
||||
{
|
||||
"depends": [
|
||||
{
|
||||
"method": "fetchzip",
|
||||
"packages": [
|
||||
"base32"
|
||||
],
|
||||
"path": "/nix/store/qcnchjsak3hyn4c6r0zd6qvm7j8y1747-source",
|
||||
"ref": "0.1.3",
|
||||
"rev": "f541038fbe49fdb118cc2002d29824b9fc4bfd61",
|
||||
"sha256": "16gh1ifp9hslsg0is0v1ya7rxqfhq5hjqzc3pfdqvcgibp5ybh06",
|
||||
"srcDir": "",
|
||||
"url": "https://github.com/OpenSystemsLab/base32.nim/archive/f541038fbe49fdb118cc2002d29824b9fc4bfd61.tar.gz"
|
||||
},
|
||||
{
|
||||
"method": "fetchzip",
|
||||
"packages": [
|
||||
"cbor"
|
||||
],
|
||||
"path": "/nix/store/70cqa9s36dqnmsf179cn9psj77jhqi1l-source",
|
||||
"ref": "20230619",
|
||||
"rev": "a4a1affd45ba90bea24e08733ae2bd02fe058166",
|
||||
"sha256": "005ib6im97x9pdbg6p0fy58zpdwdbkpmilxa8nhrrb1hnpjzz90p",
|
||||
"srcDir": "src",
|
||||
"url": "https://git.sr.ht/~ehmry/nim_cbor/archive/a4a1affd45ba90bea24e08733ae2bd02fe058166.tar.gz"
|
||||
},
|
||||
{
|
||||
"method": "fetchzip",
|
||||
"packages": [
|
||||
"coap"
|
||||
],
|
||||
"path": "/nix/store/pqj933cnw7r7hp46jrpjlwh1yr0jvckp-source",
|
||||
"ref": "20230331",
|
||||
"rev": "a134213b51a8d250684f2ba26802ffa97fae4ffb",
|
||||
"sha256": "1wbix6d8l26nj7m3xinh4m2f27n4ma0yzs3x5lpann2ha0y51k8b",
|
||||
"srcDir": "src",
|
||||
"url": "https://codeberg.org/eris/nim-coap/archive/a134213b51a8d250684f2ba26802ffa97fae4ffb.tar.gz"
|
||||
},
|
||||
{
|
||||
"method": "fetchzip",
|
||||
"packages": [
|
||||
"configparser"
|
||||
],
|
||||
"path": "/nix/store/4zl5v7i6cj3f9sayvsjcx2h20lqwr9a6-source",
|
||||
"ref": "newSection",
|
||||
"rev": "695f1285d63f1954c25eb1f42798d90fa7bcbe14",
|
||||
"sha256": "0b0pb5i0kir130ia2zf8zcgdz8awms161i6p83ri3nbgibbjnr37",
|
||||
"srcDir": "src",
|
||||
"url": "https://github.com/ehmry/nim-configparser/archive/695f1285d63f1954c25eb1f42798d90fa7bcbe14.tar.gz"
|
||||
},
|
||||
{
|
||||
"method": "fetchzip",
|
||||
"packages": [
|
||||
"eris"
|
||||
],
|
||||
"path": "/nix/store/lxa6ba8r9hhs06k6f2iyznwjxix1klv1-source",
|
||||
"ref": "20230823",
|
||||
"rev": "49d8117367d3530533dc1d6a9111ddd134b08b1e",
|
||||
"sha256": "0lq9a04cayf04nnhn0gvp5phlij0cis38v7cz7jmgks2xvz1bcbr",
|
||||
"srcDir": "src",
|
||||
"url": "https://codeberg.org/eris/nim-eris/archive/49d8117367d3530533dc1d6a9111ddd134b08b1e.tar.gz"
|
||||
},
|
||||
{
|
||||
"method": "fetchzip",
|
||||
"packages": [
|
||||
"freedesktop_org"
|
||||
],
|
||||
"path": "/nix/store/98wncmx58cfnhv3y96lzwm22zvyk9b1h-source",
|
||||
"ref": "20230210",
|
||||
"rev": "fb04d0862aca4be2edcc0eafa94b1840030231c8",
|
||||
"sha256": "0wj5m09x1pr36gv8p5r72p6l3wwl01y8scpnlzx7q0h5ij6jaj6s",
|
||||
"srcDir": "src",
|
||||
"url": "https://git.sr.ht/~ehmry/freedesktop_org/archive/fb04d0862aca4be2edcc0eafa94b1840030231c8.tar.gz"
|
||||
},
|
||||
{
|
||||
"method": "fetchzip",
|
||||
"packages": [
|
||||
"getdns"
|
||||
],
|
||||
"path": "/nix/store/x9xmn7w4k6jg8nv5bnx148ibhnsfh362-source",
|
||||
"ref": "20221222",
|
||||
"rev": "c73cbe288d9f9480586b8fa87f6d794ffb6a6ce6",
|
||||
"sha256": "1sbgx2x51szr22i72n7c8jglnfmr8m7y7ga0v85d58fwadiv7g6b",
|
||||
"srcDir": "src",
|
||||
"url": "https://git.sr.ht/~ehmry/getdns-nim/archive/c73cbe288d9f9480586b8fa87f6d794ffb6a6ce6.tar.gz"
|
||||
},
|
||||
{
|
||||
"method": "fetchzip",
|
||||
"packages": [
|
||||
"hashlib"
|
||||
],
|
||||
"path": "/nix/store/fav82xdbicvlk34nmcbl89zx99lr3mbs-source",
|
||||
"rev": "f9455d4be988e14e3dc7933eb7cc7d7c4820b7ac",
|
||||
"sha256": "1sx6j952lj98629qfgr7ds5aipyw9d6lldcnnqs205wpj4pkcjb3",
|
||||
"srcDir": "",
|
||||
"url": "https://github.com/ehmry/hashlib/archive/f9455d4be988e14e3dc7933eb7cc7d7c4820b7ac.tar.gz"
|
||||
},
|
||||
{
|
||||
"method": "fetchzip",
|
||||
"packages": [
|
||||
"nimcrypto"
|
||||
],
|
||||
"path": "/nix/store/zyr8zwh7vaiycn1s4r8cxwc71f2k5l0h-source",
|
||||
"ref": "traditional-api",
|
||||
"rev": "602c5d20c69c76137201b5d41f788f72afb95aa8",
|
||||
"sha256": "1dmdmgb6b9m5f8dyxk781nnd61dsk3hdxqks7idk9ncnpj9fng65",
|
||||
"srcDir": "",
|
||||
"url": "https://github.com/cheatfate/nimcrypto/archive/602c5d20c69c76137201b5d41f788f72afb95aa8.tar.gz"
|
||||
},
|
||||
{
|
||||
"method": "fetchzip",
|
||||
"packages": [
|
||||
"npeg"
|
||||
],
|
||||
"path": "/nix/store/ffkxmjmigfs7zhhiiqm0iw2c34smyciy-source",
|
||||
"ref": "1.2.1",
|
||||
"rev": "26d62fdc40feb84c6533956dc11d5ee9ea9b6c09",
|
||||
"sha256": "0xpzifjkfp49w76qmaylan8q181bs45anmp46l4bwr3lkrr7bpwh",
|
||||
"srcDir": "src",
|
||||
"url": "https://github.com/zevv/npeg/archive/26d62fdc40feb84c6533956dc11d5ee9ea9b6c09.tar.gz"
|
||||
},
|
||||
{
|
||||
"method": "fetchzip",
|
||||
"packages": [
|
||||
"preserves"
|
||||
],
|
||||
"path": "/nix/store/fmb2yckksz7iv3qdkk5gk1j060kppkq9-source",
|
||||
"ref": "20231102",
|
||||
"rev": "4faeb766dc3945bcfacaa1a836ef6ab29b20ceb0",
|
||||
"sha256": "1a3g5bk1l1h250q3p6sqv6r1lpsplp330qqyp48r0i4a5r0jksq3",
|
||||
"srcDir": "src",
|
||||
"url": "https://git.syndicate-lang.org/ehmry/preserves-nim/archive/4faeb766dc3945bcfacaa1a836ef6ab29b20ceb0.tar.gz"
|
||||
},
|
||||
{
|
||||
"method": "fetchzip",
|
||||
"packages": [
|
||||
"syndicate"
|
||||
],
|
||||
"path": "/nix/store/nhpvl223vbzdrlzikw7pgyfxs344w7ma-source",
|
||||
"ref": "20231108",
|
||||
"rev": "095418032180e360ea27ec7fcd63193944b68e2c",
|
||||
"sha256": "09pbml2chzz0v5zpz67fs7raj0mfmg8qrih2vz85xxc51h7ncqvw",
|
||||
"srcDir": "src",
|
||||
"url": "https://git.syndicate-lang.org/ehmry/syndicate-nim/archive/095418032180e360ea27ec7fcd63193944b68e2c.tar.gz"
|
||||
},
|
||||
{
|
||||
"method": "fetchzip",
|
||||
"packages": [
|
||||
"taps"
|
||||
],
|
||||
"path": "/nix/store/did1li0xk9qih80pvxqhjc4np3ijlfjj-source",
|
||||
"ref": "20230331",
|
||||
"rev": "4f9c9972d74eb39c662b43ed79d761e109bf00f1",
|
||||
"sha256": "12qsizmisr1q0q4x37c5q6gmnqb5mp0bid7s3jlcsjvhc4jw2q57",
|
||||
"srcDir": "src",
|
||||
"url": "https://git.sr.ht/~ehmry/nim_taps/archive/4f9c9972d74eb39c662b43ed79d761e109bf00f1.tar.gz"
|
||||
},
|
||||
{
|
||||
"method": "fetchzip",
|
||||
"packages": [
|
||||
"tkrzw"
|
||||
],
|
||||
"path": "/nix/store/4x9wxyli4dy719svg1zaww0c0b3xckp0-source",
|
||||
"ref": "20220922",
|
||||
"rev": "efd87edb7b063182c1a1fa018006a87b515d589b",
|
||||
"sha256": "1h0sdvai4gkkz48xfh67wa1xz2k8bkkba8q6snnbllmhmywd9apb",
|
||||
"srcDir": "src",
|
||||
"url": "https://git.sr.ht/~ehmry/nim-tkrzw/archive/efd87edb7b063182c1a1fa018006a87b515d589b.tar.gz"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
version = "20231009"
|
||||
version = "20231208"
|
||||
author = "Emery Hemingway"
|
||||
description = "Syndicated Nix Actor"
|
||||
license = "Unlicense"
|
||||
|
|
|
@ -10,7 +10,7 @@ Realise = <realise @drv string @outputs StringSeq> .
|
|||
|
||||
Instantiate = <instantiate @expr string @options AttrSet @result any> .
|
||||
|
||||
Eval = <eval @expr string @options {symbol: any ...:...} @result any> .
|
||||
Eval = <eval @expr string @path string @result any> .
|
||||
|
||||
Narinfo = <narinfo @path string @info AttrSet> .
|
||||
|
||||
|
|
|
@ -3,14 +3,15 @@
|
|||
let
|
||||
nix' = pkgs.nix.overrideAttrs (final: prev: {
|
||||
src = pkgs.fetchFromGitHub {
|
||||
owner = "NixOS";
|
||||
owner = "tweag";
|
||||
repo = "nix";
|
||||
rev = "2.13.3";
|
||||
hash = "sha256-jUc2ccTR8f6MGY2pUKgujm+lxSPNGm/ZAP+toX+nMNc=";
|
||||
rev = "nix-c-bindings";
|
||||
hash = "sha256-xOyU79lsz0THOj1LccfsDS45089n2DhlkWxaJFeKriY=";
|
||||
};
|
||||
});
|
||||
in pkgs.nim2Packages.buildNimPackage {
|
||||
in pkgs.buildNimPackage {
|
||||
name = "dummy";
|
||||
nativeBuildInputs = [ pkgs.pkg-config ];
|
||||
buildInputs = [ pkgs.boost nix' ];
|
||||
lockFile = ./lock.json;
|
||||
}
|
||||
|
|
|
@ -1,184 +1,81 @@
|
|||
# SPDX-FileCopyrightText: ☭ Emery Hemingway
|
||||
# SPDX-License-Identifier: Unlicense
|
||||
|
||||
import std/[json, os, osproc, strutils, tables]
|
||||
import eris/memory_stores
|
||||
import preserves, preserves/jsonhooks
|
||||
import syndicate, syndicate/relays
|
||||
from syndicate/protocols/dataspace import Observe
|
||||
import ./nix_actor/[clients, daemons]
|
||||
import ./nix_actor/libnix/[libexpr, main, stdpuspus, store]
|
||||
import std/[os, strutils, tables]
|
||||
import preserves, syndicate, syndicate/relays
|
||||
# from syndicate/protocols/dataspace import Observe
|
||||
import ./nix_actor/[nix_api, nix_api_value]
|
||||
import ./nix_actor/protocol
|
||||
|
||||
var nixVersion {.importcpp: "nix::nixVersion", header: "globals.hh".}: StdString
|
||||
|
||||
type
|
||||
Value = Preserve[void]
|
||||
Observe = dataspace.Observe[Cap]
|
||||
|
||||
proc toPreserve(state: EvalState; val: libexpr.ValueObj | libExpr.ValuePtr; E = void): Preserve[E] {.gcsafe.} =
|
||||
## Convert a Nix value to a Preserves value.
|
||||
# See nix::printValueAsJSON
|
||||
case val.kind
|
||||
of nInt:
|
||||
result = val.integer.toPreserve(E)
|
||||
of nFloat:
|
||||
result = val.fpoint.toPreserve(E)
|
||||
of nBool:
|
||||
result = val.boolean.toPreserve(E)
|
||||
of nString:
|
||||
result = val.shallowString.toPreserve(E)
|
||||
of nPath:
|
||||
result = toSymbol($val.path, E)
|
||||
of nNull:
|
||||
proc toPreserve(state: State; value: Value; E = void): Preserve[E] {.gcsafe.} =
|
||||
var ctx: NixContext
|
||||
stderr.writeLine get_type(ctx, value).int
|
||||
case get_type(ctx, value)
|
||||
of NIX_TYPE_THUNK: raiseAssert "cannot preserve thunk"
|
||||
of NIX_TYPE_INT:
|
||||
result = getInt(ctx, value).toPreserve(E)
|
||||
of NIX_TYPE_FLOAT:
|
||||
result = getFloat(ctx, value).toPreserve(E)
|
||||
of NIX_TYPE_BOOL:
|
||||
result = getBool(ctx, value).toPreserve(E)
|
||||
of NIX_TYPE_STRING:
|
||||
result = ($getString(ctx, value)).toPreserve(E)
|
||||
of NIX_TYPE_PATH:
|
||||
result = ($getPathString(ctx, value)).toPreserve(E)
|
||||
of NIX_TYPE_NULL:
|
||||
result = initRecord[E]("null")
|
||||
of nAttrs:
|
||||
of NIX_TYPE_ATTRS:
|
||||
result = initDictionary(E)
|
||||
for sym, attr in val.pairs:
|
||||
let key = symbolString(state, sym).toSymbol(E)
|
||||
# Nix string to Nim string to Preserves symbol
|
||||
result[key] = state.toPreserve(attr, E)
|
||||
of nList:
|
||||
result = initSequence(0, E)
|
||||
for e in val.items:
|
||||
result.sequence.add(state.toPreserve(e, E))
|
||||
else:
|
||||
raise newException(ValueError, "cannot preserve " & $val.kind)
|
||||
|
||||
proc eval(state: EvalState; code: string): Value =
|
||||
## Evaluate Nix `code` to a Preserves value.
|
||||
var nixVal: libexpr.ValueObj
|
||||
let expr = state.parseExprFromString(code, getCurrentDir())
|
||||
state.eval(expr, nixVal)
|
||||
state.forceValueDeep(nixVal)
|
||||
state.toPreserve(nixVal, void)
|
||||
|
||||
proc parseArgs(args: var seq[string]; opts: AttrSet) =
|
||||
for sym, val in opts:
|
||||
add(args, "--" & $sym)
|
||||
if not val.isString "":
|
||||
var js: JsonNode
|
||||
if fromPreserve(js, val): add(args, $js)
|
||||
else: stderr.writeLine "invalid option --", sym, " ", val
|
||||
|
||||
#[
|
||||
proc parseNarinfo(info: var AttrSet; text: string) =
|
||||
var
|
||||
key, val: string
|
||||
off: int
|
||||
while off < len(text):
|
||||
off = off + parseUntil(text, key, ':', off) + 1
|
||||
off = off + skipWhitespace(text, off)
|
||||
off = off + parseUntil(text, val, '\n', off) + 1
|
||||
if key != "" and val != "":
|
||||
if allCharsInSet(val, Digits):
|
||||
info[Symbol key] = val.parsePreserves
|
||||
else:
|
||||
info[Symbol key] = val.toPreserve
|
||||
|
||||
proc narinfo(turn: var Turn; ds: Cap; path: string) =
|
||||
let
|
||||
client = newAsyncHttpClient()
|
||||
url = "https://cache.nixos.org/" & path & ".narinfo"
|
||||
futGet = get(client, url)
|
||||
addCallback(futGet, turn) do (turn: var Turn):
|
||||
let resp = read(futGet)
|
||||
if code(resp) != Http200:
|
||||
close(client)
|
||||
else:
|
||||
let futBody = body(resp)
|
||||
addCallback(futBody, turn) do (turn: var Turn):
|
||||
close(client)
|
||||
var narinfo = Narinfo(path: path)
|
||||
parseNarinfo(narinfo.info, read(futBody))
|
||||
discard publish(turn, ds, narinfo)
|
||||
]# # I never link to openssl if I can avoid it.
|
||||
|
||||
proc build(spec: string): Build =
|
||||
var execOutput = execProcess("nix", args = ["build", "--json", "--no-link", spec], options = {poUsePath})
|
||||
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 instantiate(instantiate: Instantiate): Value =
|
||||
const cmd = "nix-instantiate"
|
||||
var args = @["--expr", instantiate.expr]
|
||||
parseArgs(args, instantiate.options)
|
||||
var execOutput = strip execProcess(cmd, args = args, options = {poUsePath})
|
||||
execOutput.toPreserve
|
||||
|
||||
proc bootNixFacet(turn: var Turn; ds: Cap): Facet =
|
||||
# let store = openStore()
|
||||
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: !Instantiate) ?? {0: grabLit(), 1: grabDict()}) do (e: string, o: Value):
|
||||
var ass = Instantiate(expr: e)
|
||||
if not fromPreserve(ass.options, unpackLiterals(o)):
|
||||
stderr.writeLine "invalid options ", o
|
||||
else:
|
||||
ass.result = instantiate(ass)
|
||||
discard publish(turn, ds, ass)
|
||||
|
||||
#[
|
||||
during(turn, ds, ?Observe(pattern: !Narinfo) ?? {0: grabLit()}) do (path: string):
|
||||
narinfo(turn, ds, path)
|
||||
]#
|
||||
let n = getAttrsSize(ctx, value)
|
||||
var i: cuint
|
||||
while i < n:
|
||||
var (key, val) = get_attr_byidx(ctx, value, state, i)
|
||||
inc(i)
|
||||
result[toSymbol($key, E)] = toPreserve(state, val, E)
|
||||
stderr.writeLine(result)
|
||||
# close(val)
|
||||
of NIX_TYPE_LIST:
|
||||
let n = getListSize(ctx, value)
|
||||
result = initSequence(n, E)
|
||||
var i: cuint
|
||||
while i < n:
|
||||
var val = getListByIdx(ctx, value, state, i)
|
||||
result[i] = toPreserve(state, val, E)
|
||||
inc(i)
|
||||
# close(val)
|
||||
of NIX_TYPE_FUNCTION, NIX_TYPE_EXTERNAL:
|
||||
raiseAssert "TODO: need a failure type"
|
||||
|
||||
type
|
||||
CapArgs {.preservesDictionary.} = object
|
||||
BootArgs {.preservesDictionary.} = object
|
||||
dataspace: Cap
|
||||
ClientSideArgs {.preservesDictionary.} = object
|
||||
`listen-socket`: string
|
||||
DaemonSideArgs {.preservesDictionary.} = object
|
||||
`daemon-socket`: string
|
||||
|
||||
proc runNixActor(nixState: EvalState) =
|
||||
let erisStore = newMemoryStore()
|
||||
proc main() =
|
||||
initLibexpr()
|
||||
|
||||
runActor("nix_actor") do (root: Cap; turn: var Turn):
|
||||
connectStdio(root, turn)
|
||||
connectStdio(turn, root)
|
||||
|
||||
let pat = ?CapArgs
|
||||
during(turn, root, pat) do (ds: Cap):
|
||||
during(turn, root, ?BootArgs) do (ds: Cap):
|
||||
let
|
||||
store = openStore()
|
||||
state = newState(store)
|
||||
|
||||
discard publish(turn, ds,
|
||||
initRecord("nixVersion", toPreserve($nixVersion.c_str)))
|
||||
|
||||
discard bootNixFacet(turn, ds)
|
||||
|
||||
let pat = ?Observe(pattern: !Eval) ?? {0: grabLit(), 1: grabDict()}
|
||||
during(turn, ds, pat) do (e: string, o: Assertion):
|
||||
var ass = Eval(expr: e)
|
||||
doAssert fromPreserve(ass.options, unpackLiterals(o))
|
||||
# unused options
|
||||
let pat = ?Observe(pattern: !Eval) ?? {0: grabLit(), 1: grabLit()}
|
||||
during(turn, ds, pat) do (expr: string, path: string):
|
||||
var
|
||||
value: Value
|
||||
ass = Eval(expr: expr, path: path)
|
||||
try:
|
||||
ass.result = eval(nixState, ass.expr)
|
||||
value = evalFromString(state, ass.expr, ass.path)
|
||||
force(state, value)
|
||||
ass.result = toPreserve(state, value, void)
|
||||
discard publish(turn, ds, ass)
|
||||
except CatchableError as err:
|
||||
stderr.writeLine "failed to evaluate ", ass.expr, ": ", err.msg
|
||||
except StdException as err:
|
||||
stderr.writeLine "failed to evaluate ", ass.expr, ": ", err.what
|
||||
|
||||
during(turn, root, ?ClientSideArgs) do (socketPath: string):
|
||||
bootClientSide(turn, ds, erisStore, socketPath)
|
||||
|
||||
during(turn, root, ?DaemonSideArgs) do (socketPath: string):
|
||||
bootDaemonSide(turn, ds, erisStore, socketPath)
|
||||
|
||||
proc main =
|
||||
initNix()
|
||||
initGC()
|
||||
let nixStore = openStore()
|
||||
runNixActor(newEvalState(nixStore))
|
||||
close(value)
|
||||
do:
|
||||
close(state)
|
||||
close(store)
|
||||
|
||||
main()
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
backend:cpp
|
|
@ -155,14 +155,11 @@ proc callDaemon(turn: var Turn; path: string; action: proc (daemon: Session; tur
|
|||
|
||||
proc bootDaemonSide*(turn: var Turn; ds: Cap; store: ErisStore; socketPath: string) =
|
||||
|
||||
during(turn, ds, ?Observe(pattern: !Missing) ?? {0: grab()}) do (a: Preserve[Cap]):
|
||||
during(turn, ds, ?Observe(pattern: !Missing) ?? {0: grab()}) do (targets: Literal[StringSeq]):
|
||||
# cannot use `grabLit` here because an array is a compound
|
||||
# TODO: unpack to a `Pattern`
|
||||
let daemon = callDaemon(turn, socketPath) do (daemon: Session; turn: var Turn):
|
||||
var targets: StringSeq
|
||||
doAssert targets.fromPreserve(unpackLiterals(a))
|
||||
# unpack <arr [<lit " …">]>
|
||||
let missFut = queryMissing(daemon, targets)
|
||||
let missFut = queryMissing(daemon, targets.value)
|
||||
addCallback(missFut, turn) do (turn: var Turn):
|
||||
close(daemon)
|
||||
var miss = read(missFut)
|
||||
|
@ -180,15 +177,12 @@ proc bootDaemonSide*(turn: var Turn; ds: Cap; store: ErisStore; socketPath: stri
|
|||
do:
|
||||
close(daemon)
|
||||
|
||||
during(turn, ds, ?Observe(pattern: !PathInfo) ?? {1: grabDict()}) do (pat: Value):
|
||||
var daemon: Session
|
||||
var request: AddToStoreClientAttrs
|
||||
if request.fromPreserve(unpackLiterals pat):
|
||||
daemon = callDaemon(turn, socketPath) do (daemon: Session; turn: var Turn):
|
||||
let fut = addToStore(daemon, store, request)
|
||||
addCallback(fut, turn) do (turn: var Turn):
|
||||
close(daemon)
|
||||
var (path, info) = read(fut)
|
||||
discard publish(turn, ds, initRecord("path", path.toPreserve, info.toPreserve))
|
||||
during(turn, ds, ?Observe(pattern: !PathInfo) ?? {1: grabDict()}) do (request: Literal[AddToStoreClientAttrs]):
|
||||
let daemon = callDaemon(turn, socketPath) do (daemon: Session; turn: var Turn):
|
||||
let fut = addToStore(daemon, store, request.value)
|
||||
addCallback(fut, turn) do (turn: var Turn):
|
||||
close(daemon)
|
||||
var (path, info) = read(fut)
|
||||
discard publish(turn, ds, initRecord("path", path.toPreserve, info.toPreserve))
|
||||
do:
|
||||
close(daemon)
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
# SPDX-FileCopyrightText: ☭ Emery Hemingway
|
||||
# SPDX-License-Identifier: Unlicense
|
||||
|
||||
import ./nix_api_types, ./nix_api_util, ./nix_api_value, ./nix_api_store, ./nix_api_expr
|
||||
|
||||
export NixContext, Store, State, Value, ValueType,
|
||||
gc_decref, isNil
|
||||
|
||||
{.passC: staticExec("pkg-config --cflags nix-expr-c").}
|
||||
{.passL: staticExec("pkg-config --libs nix-expr-c").}
|
||||
|
||||
# Always pass NixContext as a nil pointer.
|
||||
|
||||
proc initLibexpr* =
|
||||
var ctx: NixContext
|
||||
discard libexpr_init(ctx)
|
||||
|
||||
proc openStore*(uri: string, params: varargs[string]): Store =
|
||||
var ctx: NixContext
|
||||
var args = allocCStringArray(params)
|
||||
defer: deallocCStringArray(args)
|
||||
result = store_open(ctx, uri, addr args)
|
||||
|
||||
proc openStore*(): Store =
|
||||
var ctx: NixContext
|
||||
result = store_open(ctx, nil, nil)
|
||||
|
||||
proc close*(store: Store) = store_unref(store)
|
||||
|
||||
proc newState*(store: Store; searchPath: varargs[string]): State =
|
||||
var ctx: NixContext
|
||||
var path = allocCStringArray(searchPath)
|
||||
defer: deallocCStringArray(path)
|
||||
result = state_create(ctx, path, store)
|
||||
|
||||
proc close*(state: State) = state_free(state)
|
||||
|
||||
proc newValue*(state: State): Value =
|
||||
var ctx: NixContext
|
||||
alloc_value(ctx, state)
|
||||
|
||||
proc evalFromString*(state: State; expr, path: string): Value =
|
||||
var ctx: NixContext
|
||||
result = alloc_value(ctx, state)
|
||||
discard expr_eval_from_string(ctx, state, expr, path, result)
|
||||
|
||||
proc close*(value: Value) =
|
||||
var ctx: NixContext
|
||||
discard gc_decref(ctx, cast[pointer](value))
|
||||
|
||||
proc force*(state: State; value: Value) =
|
||||
var ctx: NixContext
|
||||
discard value_force(ctx, state, value)
|
||||
|
||||
proc get_attr_byidx*(ctx: NixContext; value: Value; state: State; i: cuint): (cstring, Value) =
|
||||
var ctx: NixContext
|
||||
result[1] = get_attr_byidx(ctx, value, state, i, addr result[0])
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
## Module generated by c2nim for nix_api_expr.h
|
||||
|
||||
import ./nix_api_types
|
||||
|
||||
{.pragma: nix_api_expr, header: "nix_api_expr.h", importc: "nix_$1".}
|
||||
|
||||
proc libexpr_init*(context: NixContext): nix_err {.nix_api_expr.}
|
||||
|
||||
proc expr_eval_from_string*(context: NixContext; state: State; expr: cstring; path: cstring; value: Value): nix_err {.nix_api_expr.}
|
||||
|
||||
proc value_call*(context: NixContext; state: State; fn: Value; arg: Value; value: Value): nix_err {.nix_api_expr.}
|
||||
|
||||
proc value_force*(context: NixContext; state: State; value: Value): nix_err {.nix_api_expr.}
|
||||
|
||||
proc value_force_deep*(context: NixContext; state: State; value: Value): nix_err {.nix_api_expr.}
|
||||
|
||||
proc state_create*(context: NixContext; searchPath: cstringArray; store: Store): State {.nix_api_expr.}
|
||||
|
||||
proc state_free*(state: State) {.nix_api_expr.}
|
||||
|
||||
proc gc_incref*(context: NixContext; `object`: pointer): nix_err {.nix_api_expr.}
|
||||
|
||||
proc gc_decref*(context: NixContext; `object`: pointer): nix_err {.nix_api_expr.}
|
||||
|
||||
proc gc_now*() {.nix_api_expr.}
|
||||
|
||||
proc gc_register_finalizer*(obj: pointer; cd: pointer; finalizer: proc (obj: pointer; cd: pointer)) {.nix_api_expr.}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
## Module generated by c2nim for nix_api_store.h
|
||||
|
||||
import ./nix_api_types
|
||||
|
||||
{.pragma: nix_api_store, header: "nix_api_store.h", importc: "nix_$1".}
|
||||
|
||||
proc libstore_init*(context: NixContext): nix_err {.nix_api_store.}
|
||||
|
||||
proc init_plugins*(context: NixContext): nix_err {.nix_api_store.}
|
||||
|
||||
proc store_open*(a1: NixContext; uri: cstring; params: ptr cstringArray): Store {.nix_api_store.}
|
||||
|
||||
proc store_unref*(store: Store) {.nix_api_store.}
|
||||
|
||||
proc store_get_uri*(context: NixContext; store: Store; dest: cstring; n: cuint): nix_err {.nix_api_store.}
|
||||
|
||||
proc store_parse_path*(context: NixContext; store: Store; path: cstring): StorePath {.nix_api_store.}
|
||||
|
||||
proc store_path_free*(p: StorePath) {.nix_api_store.}
|
||||
|
||||
proc store_is_valid_path*(context: NixContext; store: Store; path: StorePath): bool {.nix_api_store.}
|
||||
|
||||
proc store_build*(context: NixContext; store: Store; path: StorePath; userdata: pointer; callback: proc (userdata: pointer; outname: cstring; `out`: cstring)): nix_err {.nix_api_store.}
|
||||
|
||||
proc store_get_version*(a1: NixContext; store: Store; dest: cstring; n: cuint): nix_err {.nix_api_store.}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
## Module generated by c2nim for nix_api_util.h
|
||||
|
||||
import ./nix_api_types
|
||||
|
||||
{.pragma: nix_api_util, header: "nix_api_util.h", importc: "nix_$1".}
|
||||
{.pragma: importUtil, header: "nix_api_util.h", importc.}
|
||||
|
||||
var
|
||||
NIX_OK* {.importUtil.}: cint
|
||||
NIX_ERR_UNKNOWN* {.importUtil.}: cint
|
||||
NIX_ERR_OVERFLOW* {.importUtil.}: cint
|
||||
NIX_ERR_KEY* {.importUtil.}: cint
|
||||
NIX_ERR_NIX_ERROR* {.importUtil.}: cint
|
||||
|
||||
proc c_context_create*(): NixContext {.nix_api_util.}
|
||||
|
||||
proc c_context_free*(context: NixContext) {.nix_api_util.}
|
||||
|
||||
proc libutil_init*(context: NixContext): nix_err {.nix_api_util.}
|
||||
|
||||
proc setting_get*(context: NixContext; key: cstring; value: cstring; n: cint): nix_err {.nix_api_util.}
|
||||
|
||||
proc setting_set*(context: NixContext; key: cstring; value: cstring): nix_err {.nix_api_util.}
|
||||
|
||||
proc version_get*(): cstring {.nix_api_util.}
|
||||
|
||||
proc err_msg*(context: NixContext; ctx: NixContext; n: ptr cuint): cstring {.nix_api_util.}
|
||||
|
||||
proc err_info_msg*(context: NixContext; read_context: NixContext; value: cstring; n: cint): nix_err {.nix_api_util.}
|
||||
|
||||
proc err_name*(context: NixContext; read_context: NixContext; value: cstring; n: cint): nix_err {.nix_api_util.}
|
||||
|
||||
proc err_code*(read_context: NixContext): nix_err {.nix_api_util.}
|
||||
|
||||
proc set_err_msg*(context: NixContext; err: nix_err; msg: cstring): nix_err {.nix_api_util.}
|
|
@ -0,0 +1,72 @@
|
|||
## Module generated by c2nim for nix_api_value.h
|
||||
|
||||
import ./nix_api_types
|
||||
|
||||
type
|
||||
PrimOpFun* = proc (user_data: pointer; context: NixContext; state: ptr State; args: ptr Value; ret: Value)
|
||||
|
||||
# proc alloc_primop*(context: NixContext; fun: PrimOpFun; arity: cint; name: cstring; args: cstringArray; doc: cstring; user_data: pointer): ptr PrimOp {.importc: "nix_$1", header: "nix_api_value.h".}
|
||||
|
||||
# proc register_primop*(context: NixContext; primOp: ptr PrimOp): nix_err {.importc: "nix_$1", header: "nix_api_value.h".}
|
||||
|
||||
proc alloc_value*(context: NixContext; state: State): Value {.importc: "nix_$1", header: "nix_api_value.h".}
|
||||
|
||||
proc get_type*(context: NixContext; value: Value): ValueType {.importc: "nix_$1", header: "nix_api_value.h".}
|
||||
|
||||
proc get_typename*(context: NixContext; value: Value): cstring {.importc: "nix_$1", header: "nix_api_value.h".}
|
||||
|
||||
proc get_bool*(context: NixContext; value: Value): bool {.importc: "nix_$1", header: "nix_api_value.h".}
|
||||
|
||||
proc get_string*(context: NixContext; value: Value): cstring {.importc: "nix_$1", header: "nix_api_value.h".}
|
||||
|
||||
proc get_path_string*(context: NixContext; value: Value): cstring {.importc: "nix_$1", header: "nix_api_value.h".}
|
||||
|
||||
proc get_list_size*(context: NixContext; value: Value): cuint {.importc: "nix_$1", header: "nix_api_value.h".}
|
||||
|
||||
proc get_attrs_size*(context: NixContext; value: Value): cuint {.importc: "nix_$1", header: "nix_api_value.h".}
|
||||
|
||||
proc get_float*(context: NixContext; value: Value): cdouble {.importc: "nix_$1", header: "nix_api_value.h".}
|
||||
|
||||
proc get_int*(context: NixContext; value: Value): int64 {.importc: "nix_$1", header: "nix_api_value.h".}
|
||||
|
||||
# proc get_external*(context: NixContext; a2: Value): ptr ExternalValue {.importc: "nix_$1", header: "nix_api_value.h".}
|
||||
|
||||
proc get_list_byidx*(context: NixContext; value: Value; state: State; ix: cuint): Value {.importc: "nix_$1", header: "nix_api_value.h".}
|
||||
|
||||
proc get_attr_byname*(context: NixContext; value: Value; state: State; name: cstring): Value {.importc: "nix_$1", header: "nix_api_value.h".}
|
||||
|
||||
proc has_attr_byname*(context: NixContext; value: Value; state: State; name: cstring): bool {.importc: "nix_$1", header: "nix_api_value.h".}
|
||||
|
||||
proc get_attr_byidx*(context: NixContext; value: Value; state: State; i: cuint; name: ptr cstring): Value {.importc: "nix_$1", header: "nix_api_value.h".}
|
||||
|
||||
proc get_attr_name_byidx*(context: NixContext; value: Value; state: State; i: cuint): cstring {.importc: "nix_$1", header: "nix_api_value.h".}
|
||||
|
||||
proc set_bool*(context: NixContext; value: Value; b: bool): nix_err {.importc: "nix_$1", header: "nix_api_value.h".}
|
||||
|
||||
proc set_string*(context: NixContext; value: Value; str: cstring): nix_err {.importc: "nix_$1", header: "nix_api_value.h".}
|
||||
|
||||
proc set_path_string*(context: NixContext; value: Value; str: cstring): nix_err {.importc: "nix_$1", header: "nix_api_value.h".}
|
||||
|
||||
proc set_float*(context: NixContext; value: Value; d: cdouble): nix_err {.importc: "nix_$1", header: "nix_api_value.h".}
|
||||
|
||||
proc set_int*(context: NixContext; value: Value; i: int64): nix_err {.importc: "nix_$1", header: "nix_api_value.h".}
|
||||
|
||||
proc set_null*(context: NixContext; value: Value): nix_err {.importc: "nix_$1", header: "nix_api_value.h".}
|
||||
|
||||
# proc set_external*(context: NixContext; value: Value; val: ptr ExternalValue): nix_err {.importc: "nix_$1", header: "nix_api_value.h".}
|
||||
|
||||
proc make_list*(context: NixContext; s: State; value: Value; size: cuint): nix_err {.importc: "nix_$1", header: "nix_api_value.h".}
|
||||
|
||||
proc set_list_byidx*(context: NixContext; value: Value; ix: cuint; elem: Value): nix_err {.importc: "nix_$1", header: "nix_api_value.h".}
|
||||
|
||||
# proc make_attrs*(context: NixContext; value: Value; b: ptr BindingsBuilder): nix_err {.importc: "nix_$1", header: "nix_api_value.h".}
|
||||
|
||||
# proc set_primop*(context: NixContext; value: Value; op: ptr PrimOp): nix_err {.importc: "nix_$1", header: "nix_api_value.h".}
|
||||
|
||||
proc copy_value*(context: NixContext; value: Value; source: Value): nix_err {.importc: "nix_$1", header: "nix_api_value.h".}
|
||||
|
||||
# proc make_bindings_builder*(context: NixContext; state: State; capacity: csize_t): ptr BindingsBuilder {.importc: "nix_$1", header: "nix_api_value.h".}
|
||||
|
||||
# proc bindings_builder_insert*(context: NixContext; builder: ptr BindingsBuilder; name: cstring; value: Value): nix_err {.importc: "nix_$1", header: "nix_api_value.h".}
|
||||
|
||||
# proc bindings_builder_free*(builder: ptr BindingsBuilder) {.importc: "nix_$1", header: "nix_api_value.h".}
|
|
@ -0,0 +1,369 @@
|
|||
type
|
||||
Snoop = ref object
|
||||
client, daemon: AsyncSocket
|
||||
buffer: seq[Word]
|
||||
version: Version
|
||||
|
||||
type ValidPathInfo = object
|
||||
path: string
|
||||
deriver: string
|
||||
narHash: string
|
||||
references: StringSet
|
||||
registrationTime, narSize: BiggestInt
|
||||
ultimate: bool
|
||||
sigs: StringSet
|
||||
ca: string
|
||||
|
||||
proc send(session: Snoop; sock: AsyncSocket; words: varargs[Word]): Future[void] =
|
||||
for i, word in words: session.buffer[i] = word
|
||||
send(sock, addr session.buffer[0], words.len shl 3)
|
||||
|
||||
proc send(session: Snoop; sock: AsyncSocket; s: string): Future[void] =
|
||||
let wordCount = (s.len + 7) shr 3
|
||||
if wordCount > session.buffer.len: setLen(session.buffer, wordCount)
|
||||
session.buffer[0] = Word s.len
|
||||
if wordCount > 0:
|
||||
session.buffer[wordCount] = 0x00
|
||||
copyMem(addr session.buffer[1], unsafeAddr s[0], s.len)
|
||||
send(sock, addr session.buffer[0], (succ wordCount) shl 3)
|
||||
|
||||
proc passWord(a, b: AsyncSocket): Future[Word] {.async.} =
|
||||
var w = await recvWord(a)
|
||||
await send(b, addr w, sizeof(Word))
|
||||
return w
|
||||
|
||||
proc passString(session: Snoop; a, b: AsyncSocket): Future[string] {.async.} =
|
||||
var s = await recvString(a)
|
||||
await send(session, b, s)
|
||||
return s
|
||||
|
||||
proc passStringSeq(session: Snoop; a, b: AsyncSocket): Future[seq[string]] {.async.} =
|
||||
let count = int(await passWord(a, b))
|
||||
var strings = newSeq[string](count)
|
||||
for i in 0..<count: strings[i] = await passString(session, a, b)
|
||||
return strings
|
||||
|
||||
proc passStringSet(session: Snoop; a, b: AsyncSocket): Future[StringSet] {.async.} =
|
||||
let count = int(await passWord(a, b))
|
||||
var strings = initHashSet[string](count)
|
||||
for i in 0..<count: incl(strings, await passString(session, a, b))
|
||||
return strings
|
||||
|
||||
proc passStringMap(session: Snoop; a, b: AsyncSocket): Future[StringTableCap] {.async.} =
|
||||
var table = newStringTable(modeCaseSensitive)
|
||||
let n = await passWord(a, b)
|
||||
for i in 1..n:
|
||||
var
|
||||
key = await passString(session, a, b)
|
||||
val = await passString(session, a, b)
|
||||
table[key] = val
|
||||
return table
|
||||
|
||||
proc passClientWord(session: Snoop): Future[Word] =
|
||||
passWord(session.client, session.daemon)
|
||||
|
||||
proc passDaemonWord(session: Snoop): Future[Word] =
|
||||
passWord(session.daemon, session.client)
|
||||
|
||||
proc passClientString(session: Snoop): Future[string] =
|
||||
passString(session, session.client, session.daemon)
|
||||
|
||||
proc passDaemonString(session: Snoop): Future[string] =
|
||||
passString(session, session.daemon, session.client)
|
||||
|
||||
proc passClientStringSeq(session: Snoop): Future[seq[string]] =
|
||||
passStringSeq(session, session.client, session.daemon)
|
||||
|
||||
proc passDaemonStringSeq(session: Snoop): Future[seq[string]] =
|
||||
passStringSeq(session, session.daemon, session.client)
|
||||
|
||||
proc passClientStringSet(session: Snoop): Future[StringSet] =
|
||||
passStringSet(session, session.client, session.daemon)
|
||||
|
||||
proc passDaemonStringSet(session: Snoop): Future[StringSet] =
|
||||
passStringSet(session, session.daemon, session.client)
|
||||
|
||||
proc passClientStringMap(session: Snoop): Future[StringTableCap] =
|
||||
passStringMap(session, session.client, session.daemon)
|
||||
|
||||
proc passDaemonStringMap(session: Snoop): Future[StringTableCap] =
|
||||
passStringMap(session, session.daemon, session.client)
|
||||
|
||||
proc passDaemonValidPathInfo(session: Snoop; includePath: bool): Future[PathInfo] {.async.} =
|
||||
var info: PathInfo
|
||||
if includePath:
|
||||
info.path = await passDaemonString(session)
|
||||
info.deriver = await passDaemonString(session)
|
||||
info.narHash = await passDaemonString(session)
|
||||
info.references = await passDaemonStringSet(session)
|
||||
info.registrationTime = BiggestInt(await passDaemonWord(session))
|
||||
info.narSize = BiggestInt(await passDaemonWord(session))
|
||||
assert session.version.minor >= 16
|
||||
info.ultimate = (await passDaemonWord(session)) != 0
|
||||
info.sigs = await passDaemonStringSet(session)
|
||||
info.ca = await passDaemonString(session)
|
||||
return info
|
||||
|
||||
proc passChunks(session: Snoop; a, b: AsyncSocket): Future[int] {.async.} =
|
||||
var total: int
|
||||
while true:
|
||||
let chunkLen = int(await passWord(a, b))
|
||||
if chunkLen == 0:
|
||||
break
|
||||
else:
|
||||
let wordLen = (chunkLen + 7) shr 3
|
||||
if session.buffer.len < wordLen: setLen(session.buffer, wordLen)
|
||||
let recvLen = await recvInto(a, addr session.buffer[0], chunkLen)
|
||||
# each chunk must be recved contiguously
|
||||
if recvLen != chunkLen:
|
||||
raise newException(ProtocolError, "invalid chunk read")
|
||||
await send(b, addr session.buffer[0], recvLen)
|
||||
inc(total, recvLen)
|
||||
return total
|
||||
|
||||
proc passClientChunks(session: Snoop): Future[int] =
|
||||
passChunks(session, session.client, session.daemon)
|
||||
|
||||
proc passErrorDaemonError(session: Snoop) {.async.} =
|
||||
let
|
||||
typ = await passDaemonString(session)
|
||||
assert typ == "Error"
|
||||
let
|
||||
lvl = await passDaemonWord(session)
|
||||
name = await passDaemonString(session)
|
||||
msg = passDaemonString(session)
|
||||
havePos = await passDaemonWord(session)
|
||||
assert havePos == 0
|
||||
let
|
||||
nrTraces = await passDaemonWord(session)
|
||||
for i in 1..nrTraces:
|
||||
let havPos = await passDaemonWord(session)
|
||||
assert havPos == 0
|
||||
let msg = await passDaemonString(session)
|
||||
|
||||
proc passDaemonFields(session: Snoop): Future[Fields] {.async.} =
|
||||
let count = await passDaemonWord(session)
|
||||
var fields = newSeq[Field](count)
|
||||
for i in 0..<count:
|
||||
let typ = await passDaemonWord(session)
|
||||
case typ
|
||||
of 0:
|
||||
let num = await passDaemonWord(session)
|
||||
fields[i] = Field(orKind: FieldKind.int, int: int num)
|
||||
of 1:
|
||||
let str = await passDaemonString(session)
|
||||
fields[i] = Field(orKind: FieldKind.string, string: str)
|
||||
else:
|
||||
raiseAssert "unknown field type " & $typ
|
||||
return fields
|
||||
|
||||
proc passWork(session: Snoop) {.async.} =
|
||||
while true:
|
||||
let word = await passDaemonWord(session)
|
||||
case word
|
||||
|
||||
of STDERR_WRITE:
|
||||
discard await passDaemonString(session)
|
||||
|
||||
of STDERR_READ:
|
||||
discard await passClientString(session)
|
||||
|
||||
of STDERR_ERROR:
|
||||
assert session.version.minor >= 26
|
||||
await passErrorDaemonError(session)
|
||||
|
||||
of STDERR_NEXT:
|
||||
let s = await passDaemonString(session)
|
||||
|
||||
of STDERR_START_ACTIVITY:
|
||||
var act: ActionStart
|
||||
act.id = BiggestInt(await passDaemonWord(session))
|
||||
act.level = BiggestInt(await passDaemonWord(session))
|
||||
act.`type` = BiggestInt(await passDaemonWord(session))
|
||||
act.text = await passDaemonString(session)
|
||||
act.fields = await passDaemonFields(session)
|
||||
act.parent = BiggestInt(await passDaemonWord(session))
|
||||
|
||||
of STDERR_STOP_ACTIVITY:
|
||||
var act: ActionStop
|
||||
act.id = BiggestInt(await passDaemonWord(session))
|
||||
|
||||
of STDERR_RESULT:
|
||||
var act: ActionResult
|
||||
act.id = BiggestInt(await passDaemonWord(session))
|
||||
act.`type` = BiggestInt(await passDaemonWord(session))
|
||||
act.fields = await passDaemonFields(session)
|
||||
|
||||
of STDERR_LAST:
|
||||
break
|
||||
|
||||
else:
|
||||
raise newException(ProtocolError, "unknown work verb " & $word)
|
||||
|
||||
#[
|
||||
proc fromClient(miss: var Missing; socket: AsyncSocket) {.async.} =
|
||||
result.targets = await passClientStringSet(session)
|
||||
|
||||
proc fromDaemon(miss: var Missing; socket: AsyncSocket) {.async.} =
|
||||
miss.willBuild = await passDaemonStringSet(session)
|
||||
miss.willSubstitute = await passDaemonStringSet(session)
|
||||
miss.unknown = await passDaemonStringSet(session)
|
||||
miss.downloadSize = BiggestInt await passDaemonWord(session)
|
||||
miss.narSize = BiggestInt await passDaemonWord(session)
|
||||
]#
|
||||
|
||||
proc loop(session: Snoop) {.async.} =
|
||||
var chunksTotal: int
|
||||
try:
|
||||
while not session.client.isClosed:
|
||||
let wop = await passClientWord(session)
|
||||
case wop
|
||||
of wopIsValidPath:
|
||||
let path = await passClientString(session)
|
||||
stderr.writeLine "wopIsValidPath ", path
|
||||
await passWork(session)
|
||||
let word = await passDaemonWord(session)
|
||||
|
||||
of wopAddToStore:
|
||||
assert session.version.minor >= 25
|
||||
let
|
||||
name = await passClientString(session)
|
||||
caMethod = await passClientString(session)
|
||||
refs = await passClientStringSet(session)
|
||||
repairBool = await passClientWord(session)
|
||||
stderr.writeLine "wopAddToStore ", name
|
||||
let n = await passClientChunks(session)
|
||||
inc(chunksTotal, n)
|
||||
await passWork(session)
|
||||
let info = await passDaemonValidPathInfo(session, true)
|
||||
|
||||
of wopAddTempRoot:
|
||||
let path = await passClientString(session)
|
||||
stderr.writeLine "wopAddTempRoot ", path
|
||||
await passWork(session)
|
||||
discard await passDaemonWord(session)
|
||||
|
||||
of wopAddIndirectRoot:
|
||||
let path = await passClientString(session)
|
||||
stderr.writeLine "wopAddIndirectRoot ", path
|
||||
await passWork(session)
|
||||
discard await passDaemonWord(session)
|
||||
|
||||
of wopSetOptions:
|
||||
discard passClientWord(session) # keepFailed
|
||||
discard passClientWord(session) # keepGoing
|
||||
discard passClientWord(session) # tryFallback
|
||||
discard passClientWord(session) # verbosity
|
||||
discard passClientWord(session) # maxBuildJobs
|
||||
discard passClientWord(session) # maxSilentTime
|
||||
discard passClientWord(session) # useBuildHook
|
||||
discard passClientWord(session) # verboseBuild
|
||||
discard passClientWord(session) # logType
|
||||
discard passClientWord(session) # printBuildTrace
|
||||
discard passClientWord(session) # buildCores
|
||||
discard passClientWord(session) # useSubstitutes
|
||||
assert session.version.minor >= 12
|
||||
let overrides = await passClientStringMap(session)
|
||||
await passWork(session)
|
||||
|
||||
of wopQueryPathInfo:
|
||||
assert session.version >= 17
|
||||
let path = await passClientString(session)
|
||||
stderr.writeLine "wopQueryPathInfo ", path
|
||||
await passWork(session)
|
||||
let valid = await passDaemonWord(session)
|
||||
if valid != 0:
|
||||
var info = await passDaemonValidPathInfo(session, false)
|
||||
info.path = path
|
||||
stderr.writeLine "wopQueryPathInfo ", $info
|
||||
|
||||
of wopQueryMissing:
|
||||
assert session.version >= 30
|
||||
var miss: Missing
|
||||
miss.targets = await passClientStringSeq(session)
|
||||
await passWork(session)
|
||||
miss.willBuild = await passDaemonStringSet(session)
|
||||
miss.willSubstitute = await passDaemonStringSet(session)
|
||||
miss.unknown = await passDaemonStringSet(session)
|
||||
miss.downloadSize = BiggestInt await passDaemonWord(session)
|
||||
miss.narSize = BiggestInt await passDaemonWord(session)
|
||||
stderr.writeLine "wopQueryMissing ", $miss
|
||||
|
||||
of wopBuildPathsWithResults:
|
||||
assert session.version >= 34
|
||||
let
|
||||
drvs = await passClientStringSeq(session)
|
||||
buildMode = await passClientWord(session)
|
||||
stderr.writeLine "wopBuildPathsWithResults drvs ", $drvs
|
||||
await passWork(session)
|
||||
let count = await passDaemonWord(session)
|
||||
for _ in 1..count:
|
||||
let
|
||||
path = await passDaemonString(session)
|
||||
status = await passDaemonWord(session)
|
||||
errorMsg = await passDaemonString(session)
|
||||
timesBUild = await passDaemonWord(session)
|
||||
isNonDeterministic = await passDaemonWord(session)
|
||||
startTime = await passDaemonWord(session)
|
||||
stopTime = await passDaemonWord(session)
|
||||
outputs = await passDaemonStringMap(session)
|
||||
|
||||
else:
|
||||
stderr.writeLine "unknown worker op ", wop.int
|
||||
break
|
||||
except ProtocolError as err:
|
||||
stderr.writeLine "connection terminated"
|
||||
stderr.writeLine "chunk bytes transfered: ", formatSize(chunksTotal)
|
||||
finally:
|
||||
close(session.daemon)
|
||||
close(session.client)
|
||||
|
||||
proc handshake(listener: AsyncSocket): Future[Snoop] {.async.} =
|
||||
## Take the next connection from `listener` and return a `Session`.
|
||||
let session = Snoop(buffer: newSeq[Word](1024)) # 8KiB
|
||||
session.client = await listener.accept()
|
||||
session.daemon = newAsyncSocket(
|
||||
domain = AF_UNIX,
|
||||
sockType = SOCK_STREAM,
|
||||
protocol = cast[Protocol](0),
|
||||
buffered = false,
|
||||
)
|
||||
await connectUnix(session.daemon, daemonSocketPath())
|
||||
let clientMagic = await passClientWord(session)
|
||||
if clientMagic != WORKER_MAGIC_1:
|
||||
raise newException(ProtocolError, "invalid protocol magic")
|
||||
let daemonMagic = await passDaemonWord(session)
|
||||
let daemonVersion = await passDaemonWord(session)
|
||||
session.version = Version(await passClientWord(session))
|
||||
if session.version < PROTOCOL_VERSION:
|
||||
raise newException(ProtocolError, "obsolete protocol version")
|
||||
assert session.version.minor >= 14
|
||||
discard await(passClientWord(session))
|
||||
# obsolete CPU affinity
|
||||
assert session.version.minor >= 11
|
||||
discard await(passClientWord(session))
|
||||
# obsolete reserveSpace
|
||||
assert session.version.minor >= 33
|
||||
let daemonVersionString = await passDaemonString(session)
|
||||
assert daemonVersionString == $store.nixVersion
|
||||
await passWork(session)
|
||||
return session
|
||||
|
||||
proc emulateSocket*(path: string) {.async, gcsafe.} =
|
||||
let listener = newAsyncSocket(
|
||||
domain = AF_UNIX,
|
||||
sockType = SOCK_STREAM,
|
||||
protocol = cast[Protocol](0),
|
||||
buffered = false)
|
||||
bindUnix(listener, path)
|
||||
listen(listener)
|
||||
stderr.writeLine "listening on ", path
|
||||
while not listener.isClosed:
|
||||
try:
|
||||
let session = await handshake(listener)
|
||||
assert not session.isNil
|
||||
asyncCheck loop(session)
|
||||
except ProtocolError:
|
||||
close(session)
|
||||
finally:
|
||||
close(session)
|
|
@ -5,7 +5,7 @@ import
|
|||
type
|
||||
Eval* {.preservesRecord: "eval".} = object
|
||||
`expr`*: string
|
||||
`options`*: Table[Symbol, Preserve[void]]
|
||||
`path`*: string
|
||||
`result`*: Preserve[void]
|
||||
|
||||
AttrSet* = Table[Symbol, Preserve[void]]
|
||||
|
|
Loading…
Reference in New Issue