diff --git a/Cargo.lock b/Cargo.lock index 36d8f153..627eb647 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -358,7 +358,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "choo" -version = "0.1.4" +version = "0.1.5" dependencies = [ "bytes", "clap 4.5.21", diff --git a/README.md b/README.md index 8e212552..b5bc3e74 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,8 @@ cd apps/choo cargo run --release bootstrap/kernel.hoon ../hoon-deps ``` +For large builds, the rust stack might overflow. To get around this, increase the stack size by setting: `RUST_MIN_STACK=838860`. + ## Building NockApps The `crown` library is the primary framework for building NockApps. It provides a simple interface to a `Kernel`: a Nock core which can make state transitions with effects (via the `poke()` method) and allow inspection of its state via the `peek()` method. diff --git a/apps/choo/Cargo.toml b/apps/choo/Cargo.toml index cec76ecb..ae69d22e 100644 --- a/apps/choo/Cargo.toml +++ b/apps/choo/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "choo" -version = "0.1.4" +version = "0.1.5" edition.workspace = true [dependencies] diff --git a/apps/choo/bootstrap/choo.jam b/apps/choo/bootstrap/choo.jam index 7f352454..17697e37 100644 Binary files a/apps/choo/bootstrap/choo.jam and b/apps/choo/bootstrap/choo.jam differ diff --git a/apps/choo/bootstrap/kernel.hoon b/apps/choo/bootstrap/kernel.hoon index 4eb9d712..c109c0b9 100644 --- a/apps/choo/bootstrap/kernel.hoon +++ b/apps/choo/bootstrap/kernel.hoon @@ -1,7 +1,13 @@ /+ *wrapper => |% -+$ choo-state [%0 cached-hoon=(unit (trap vase)) ~] ++$ state-0 [%0 cached-hoon=(unit (trap vase)) ~] ++$ state-1 [%1 cached-hoon=(unit (trap vase)) bc=build-cache pc=parse-cache] ++$ versioned-state + $% state-0 + state-1 + == ++$ choo-state state-1 :: ++ moat (keep choo-state) +$ cause @@ -19,6 +25,27 @@ :: If unit is null, the path must exist inside of the dir map. :: +$ entry [pat=path tex=(unit cord)] +:: ++$ hash @ ++$ build-cache (map hash (trap vase)) +:: +:: $taut: file import from /lib or /sur +:: ++$ taut [face=(unit term) pax=term] +:: +:: $pile: preprocessed hoon file +:: ++$ pile + $: sur=(list taut) :: /- + lib=(list taut) :: /+ + raw=(list [face=term =path]) + bar=(list [face=term mark=@tas =path]) + =hoon + == +:: +:: $parse-cache: content addressed cache of preprocessed hoon files. +:: ++$ parse-cache (map hash pile) -- :: =< @@ -30,9 +57,19 @@ :: :: +load: upgrade from previous state :: +:: ++ load - |= arg=choo-state - arg + |= arg=versioned-state + ^- choo-state + ?+ -.arg ~& >> %no-upgrade arg + %0 + ~& >> %upgrade-0-to-1 + :* %1 + cached-hoon.arg + *build-cache + *parse-cache + == + == :: :: +peek: external inspect :: @@ -48,7 +85,7 @@ ^- [(list effect) choo-state] =/ cause=(unit cause) ((soft cause) dat) ?~ cause - ~& >> "input is not a proper cause" + ~& >>> "input is not a proper cause" !! =/ cause u.cause ?- -.cause @@ -62,23 +99,25 @@ [~ k(cached-hoon `(build-honc hoon-txt.cause))] :: %build - =/ =entry [(stab pat.cause) `tex.cause] + ~& >> "building path: {}" + =/ =entry + ~| "path did not parse: {}" + [(stab pat.cause) `tex.cause] =/ dir %- ~(gas by *(map path cord)) (turn directory.cause |=((pair @t @t) [(stab p) q])) ?> ?=(^ cached-hoon.k) - =/ contents=@ - %- jam + =/ [compiled=* new-bc=build-cache new-pc=parse-cache] ?: arbitrary.cause - %- ~(create-arbitrary builder u.cached-hoon.k) + %- ~(create-arbitrary builder u.cached-hoon.k bc.k pc.k) [entry dir] - %- ~(create builder u.cached-hoon.k) + %- ~(create builder u.cached-hoon.k bc.k pc.k) [entry dir] - :_ k + :_ k(bc new-bc, pc new-pc) :~ :* %file %write path=(crip "out.jam") - contents=contents + contents=(jam compiled) == [%exit 0] == @@ -201,9 +240,6 @@ (cook |=(a=term [`a a]) sym) :: foo -> [[~ %foo] %foo] == :: -:: $taut: file import from /lib or /sur -:: -+$ taut [face=(unit term) pax=term] ++ segments |= suffix=@tas ^- (list path) @@ -238,45 +274,39 @@ ?^ (~(get by dir) puz) `puz $(paz t.paz) -:: preprocessed hoon file -++ pile - $: sur=(list taut) :: /- - lib=(list taut) :: /+ - raw=(list [face=term =path]) - bar=(list [face=term mark=@tas =path]) - =hoon - == :: ++ resolve-pile :: turn fits into resolved path suffixes |= [=pile dir=(map path cord)] - ^- rile - %= pile - sur (turn sur.pile |=(taut [face (need (get-fit %sur pax dir))])) - lib (turn lib.pile |=(taut [face (need (get-fit %lib pax dir))])) - raw + ^- (list raut) + ;: weld + (turn sur.pile |=(taut ^-(raut [face (need (get-fit %sur pax dir))]))) + (turn lib.pile |=(taut ^-(raut [face (need (get-fit %lib pax dir))]))) + :: %+ turn raw.pile |= [face=term pax=path] =/ pax-snip (snip pax) =/ pax-rear (rear pax) + ^- raut [`face `path`(snoc pax-snip `@ta`(rap 3 ~[pax-rear %'.' %hoon]))] :: - bar %+ turn bar.pile |= [face=term mark=@tas pax=path] ?: =(mark %hoon) =/ pax-snip (snip pax) =/ pax-rear (rear pax) + ^- raut [`face `path`(snoc pax-snip `@ta`(rap 3 ~[pax-rear %'.' %hoon]))] =/ pax-snip (snip pax) =/ pax-rear (rear pax) + ^- raut [`face `path`(snoc pax-snip `@ta`(rap 3 ~[pax-rear %'.' mark]))] == -- :: :: builder core :: -|_ honc=(trap vase) +|_ [honc=(trap vase) bc=build-cache pc=parse-cache] :: ++ build-honc |= hoon-txt=cord @@ -285,161 +315,394 @@ :: +$ octs [p=@ud q=@] :: -+$ graph-leaf - $% [%hoon =hoon] - [%octs =octs] - == +:: $node: entry of adjacency matrix with metadata :: -++ import-graph - $+ import-graph - $~ [*path ~ ~ ~ ~ *(unit @tas) [%hoon *hoon]] :: not needed in the dojo but here for some reason ++$ node $: =path - sur=(list import-graph) - lib=(list import-graph) - raw=(list import-graph) - bar=(list import-graph) - face=(unit @tas) :: the face that this node of the import graph has - leaf=graph-leaf + hash=@ + :: holds only outgoing edges + deps=(list raut) + =hoon == :: +:: $graph-view: adjacency matrix with easier access to neighbors +:: +:: used to keep track of traversal when building the merkle DAG +:: ++$ graph-view (map path (set path)) +:: +:: $create: build a trap from a hoon file with dependencies +:: +:: .entry: the entry to build +:: .dir: the directory to get dependencies from +:: +:: this is meant to build a kernel gate that takes a hash of a the +:: dependency directory. +:: +:: returns a trap, a build-cache, and a parse-cache ++ create |= [=entry dir=(map path cord)] - ^- (trap) + ^- [(trap) build-cache parse-cache] =/ dir-hash `@uvI`(mug dir) ~& >> dir-hash+dir-hash - =/ graph (make-import-graph ~ entry 0 ~ dir) - :: +shot calls the kernel gate to tell it the hash of the zkvm desk - =; ker-gen - => %+ shot ker-gen - => d=!>(dir-hash) - |.(d) - |.(+:^$) - %- head - (compile-graph (head graph) ~) + =/ compile + (create-target entry dir) + =/ ker-gen (head compile) + =/ [=build-cache =parse-cache] (tail compile) + :: +shot calls the kernel gate to tell it the hash of the dependency directory + :_ [build-cache parse-cache] + => %+ shot ker-gen + => d=!>(dir-hash) + |.(d) + |.(+:^$) +:: +:: $create-arbitrary: builds a hoon file with dependencies without file hash injection +:: +:: .entry: the entry to build +:: .dir: the directory to get dependencies from +:: +:: returns a trap, a build-cache, and a parse-cache ++ create-arbitrary + |= [=entry dir=(map path cord)] + ^- [(trap) build-cache parse-cache] + =/ [tase=(trap) =build-cache =parse-cache] + (create-target entry dir) + :_ [build-cache parse-cache] + => tase + |.(+:^$) +:: +:: $create-target: builds a hoon file with dependencies +:: +:: .entry: the entry to build +:: .dir: the directory to get dependencies from +:: +:: returns a trap with the compiled hoon file and the updated caches +++ create-target |= [=entry dir=(map path cord)] - ^- (trap) - =/ dir-hash `@uvI`(mug dir) - ~& >> dir-hash+dir-hash - =/ graph (make-import-graph ~ entry 0 ~ dir) - =/ tase - %- head - (compile-graph (head graph) ~) - => tase - |.(+:^$) + ^- [(trap vase) build-cache parse-cache] + =/ [parsed-dir=(map path node) pc=parse-cache] (parse-dir entry dir) + =/ all-nodes=(map path node) parsed-dir + =/ [dep-dag=merk-dag =path-dag] (build-merk-dag all-nodes) + :: + :: delete invalid cache entries in bc + =. bc + %+ roll + ~(tap by bc) + |= [[hash=@ *] bc=_bc] + ?: (~(has by dep-dag) hash) + bc + (~(del by bc) hash) + :: + =/ compile + %: compile-target + pat.entry + path-dag + all-nodes + bc + == + :: + [(head compile) (tail compile) pc] +:: +:: $parse-dir: parse $entry and get dependencies from $dir +:: +:: .entry: entry to parse +:: .dir: directory to get dependencies from :: -++ get-file +:: returns a map of nodes and a parse cache +++ parse-dir |= [suf=entry dir=(map path cord)] - ^- cord - ?~ tex.suf - ~| "file not found: {}" - (~(got by dir) pat.suf) - u.tex.suf -:: -++ make-import-graph - |= [face=(unit @tas) suf=entry depth=@ cache=(map path import-graph) dir=(map path cord)] - ^- [import-graph (map path import-graph)] - ~& >> building-graph-for+[depth=depth pat.suf] - ?^ existing=(~(get by cache) pat.suf) - ~& >> "reusing cached graph for {}" - [u.existing(face face) cache] :: make sure to use the provided face - =/ file=cord (get-file suf dir) - ?. (is-hoon pat.suf) - =/ graph=import-graph - :* pat.suf - ~ ~ - ~ ~ - face - [%octs [(met 3 file) file]] - == - =/ no-face=_graph - graph(face `%no-cache-entry-face) - :- graph - (~(put by cache) pat.suf no-face) - =/ rile (resolve-pile (parse-pile pat.suf (trip file)) dir) - =^ new-sur=(list import-graph) cache - %^ spin sur.rile cache - |= [raut cache=(map path import-graph)] - (make-import-graph face [pax ~] +(depth) cache dir) - =^ new-lib=(list import-graph) cache - %^ spin lib.rile cache - |= [raut cache=(map path import-graph)] - (make-import-graph face [pax ~] +(depth) cache dir) - =^ new-raw=(list import-graph) cache - %^ spin raw.rile cache - |= [raut cache=(map path import-graph)] - (make-import-graph face [pax ~] +(depth) cache dir) - =^ new-bar=(list import-graph) cache - %^ spin bar.rile cache - |= [raut cache=(map path import-graph)] - (make-import-graph face [pax ~] +(depth) cache dir) - =/ graph=import-graph - :* pat.suf - sur=new-sur - lib=new-lib - raw=new-raw - bar=new-bar - face - [%hoon hoon.rile] + ^- [(map path node) parse-cache] + ~& > parsing+pat.suf + |^ + =/ file=cord (get-file suf dir) :: get target file + =/ hash=@ (shax file) :: hash target file + =/ =pile (parse-pile pat.suf (trip file)) :: parse target file + =/ deps=(list raut) (resolve-pile pile dir) :: resolve deps + =/ target=node + :* pat.suf :: path + hash :: hash + deps :: deps + hoon.pile :: hoon == - =/ no-face=_graph - graph(face `%no-cache-entry-face) - :- graph - (~(put by cache) pat.suf no-face) + =| nodes=(map path node) :: init empty node map + =. nodes (~(put by nodes) pat.suf target) :: add target node + =/ seen=(set path) (~(put in *(set path)) pat.suf) + (resolve-all nodes seen deps) + :: + ++ resolve-all + |= [nodes=(map path node) seen=(set path) deps=(list raut)] + ^- [(map path node) parse-cache] + ?~ deps [nodes pc] :: done if no deps + ?. (~(has in seen) pax.i.deps) :: skip if seen + ~& >> parsing+pax.i.deps + =/ dep-file (get-file [pax.i.deps ~] dir) :: get dep file + =/ dep-hash (shax dep-file) :: hash dep file + =/ dep-pile + ?: (~(has by pc) dep-hash) :: check cache + (~(got by pc) dep-hash) + (parse-pile pax.i.deps (trip dep-file)) :: parse dep file + ~& >> parsed+pax.i.deps + =/ dep-deps (resolve-pile dep-pile dir) :: resolve dep deps + ~& >> resolved+pax.i.deps + =/ dep-node + :* pax.i.deps + dep-hash + dep-deps + hoon.dep-pile + == + =. nodes (~(put by nodes) pax.i.deps dep-node) :: add dep node + =. pc (~(put by pc) dep-hash dep-pile) :: cache parse + =. seen (~(put in seen) pax.i.deps) :: mark as seen + %= $ + nodes nodes + seen seen + deps (weld t.deps dep-deps) :: add new deps + == + $(deps t.deps) :: next dep + :: + ++ get-file :: get file contents + |= [suf=entry dir=(map path cord)] + ^- cord + ?~ tex.suf + ~| "file not found: {}" + (~(got by dir) pat.suf) + u.tex.suf + -- :: -++ compile-graph - :: accepts an import-graph and compiles it down to a vase +:: $compile-target: compile a target hoon file +:: +:: .pat: path to the target hoon file +:: .path-dag: the path-dag of the dependency graph +:: .nodes: the nodes of the dependency graph +:: .bc: the build cache +:: +:: returns a trap vase with the compiled hoon file and the updated build cache +++ compile-target + |= [pat=path =path-dag nodes=(map path node) bc=build-cache] + ^- [(trap vase) build-cache] + ~& >> compiling-target+pat + =/ n=node + ~| """ + couldn't find node {} in path-dag. + nodes: {<~(key by nodes)>} + path-dag: {<~(key by path-dag)>} + """ + +:(~(got by path-dag) pat) + =/ graph (build-graph-view nodes) + =/ next=(map path node) (update-next nodes graph) + =| vaz=(trap vase) + |- + ?: .=(~ next) + (compile-node n path-dag bc) + =^ vaz bc + %+ roll ~(tap by next) + |= [[p=path n=node] [v=_vaz bc=_bc]] + =^ new-vaz bc (compile-node n path-dag bc) + ?: =(vaz *_vaz) + [new-vaz bc] + [(slew v new-vaz) bc] + %= $ + next (update-next nodes graph) + graph (roll ~(tap by next) |=([[p=path *] g=_graph] (update-graph-view g p))) + bc bc + vaz vaz + == +:: +:: $compile-node: compile a single node +:: +:: .n: the node to compile +:: .path-dag: the path-dag of the dependency graph +:: .bc: the build cache +:: +:: looks up the node in the build cache and compiles it if it's not already +:: cached. +:: +:: returns a trap vase with the compiled hoon and the updated build cache +++ compile-node + |= [n=node =path-dag bc=build-cache] + ^- [(trap vase) build-cache] + ~& > compiling-node+path.n + =/ [dep-hash=@ *] (~(got by path-dag) path.n) + ?: (~(has by bc) dep-hash) + ~& > build-cache-hit+path.n + [(~(got by bc) dep-hash) bc] + ~& > build-cache-miss+path.n + =/ vaz=(trap vase) (build-node n path-dag bc) + [vaz (~(put by bc) dep-hash vaz)] +:: +:: $build-node: build a single node and its dependencies +:: +:: .n: the node to compile +:: .path-dag: the path-dag of the dependency graph +:: .bc: the build cache +:: +:: returns a trap vase with the compiled hoon +++ build-node + |= [n=node =path-dag bc=build-cache] + ^- (trap vase) + =; dep-vaz=(trap vase) + (swet (slew honc dep-vaz) hoon.n) + %+ roll + deps.n + |= [raut vaz=(trap vase)] + ~& > grabbing-dep+pax + =/ [dep-hash=@ dep-node=node] + ~| "couldn't find dep hash for {}" + (~(got by path-dag) pax) + =/ dep-vaz=(trap vase) + %+ fall (~(get by bc) dep-hash) + (build-node dep-node path-dag bc) + (slew (slew honc vaz) (label-vase dep-vaz face)) +:: +:: $label-vase: label a (trap vase) with a face +:: +:: .vaz: the (trap vase) to label +:: .face: the face to label the (trap vase) with +:: +:: returns a (trap vase) labeled with the given face +++ label-vase + |= [vaz=(trap vase) face=(unit @tas)] + ^- (trap vase) + ?~ face vaz + => [vaz=vaz face=u.face] + |. + =/ vas $:vaz + [[%face face p.vas] q.vas] +:: +:: +:: $merk-dag: content-addressed map of nodes +:: +:: maps content hashes to nodes. each hash is computed from the node's +:: content and the hashes of its dependencies, forming a merkle tree. +:: used to detect changes in the dependency graph and enable caching. +:: ++$ merk-dag (map @ node) +:: +:: $path-dag: path-addressed map of nodes with their content hashes +:: +:: maps file paths to [hash node] pairs. provides a way to look up nodes +:: by path while maintaining the connection to their content hash in the +:: merk-dag. used during traversal to find dependencies by path. +:: ++$ path-dag (map path [@ node]) +:: +:: $build-merk-dag: builds a merkle DAG out of the dependency folder +:: +:: .nodes: the nodes of the dependency graph +:: +:: returns a merkle DAG and a path-dag +++ build-merk-dag :: - |= [graph=import-graph cache=(map path (trap vase))] - ^- [(trap vase) cache=(map path (trap vase))] - |^ - :: recursively compile each dependency then cons them all together - :: (base case is when both sur and lib are ~) - ~& >> "processing {}" - ?^ existing=(~(get by cache) path.graph) - ~& >> "reusing cached vase for {}" - [(label-vase u.existing face.graph) cache] - =^ surs cache (spin sur.graph cache compile-graph) - =^ libs cache (spin lib.graph cache compile-graph) - =^ raws cache (spin raw.graph cache compile-graph) - =^ bars cache (spin bar.graph cache compile-graph) - =/ sur-all=(trap vase) (roll p.surs slew) - =/ lib-all=(trap vase) (roll p.libs slew) - =/ raw-all=(trap vase) (roll p.raws slew) - =/ bar-all=(trap vase) (roll p.bars slew) - =/ deps=(trap vase) - :: we must always make hoon.hoon available to each `hoon.graph` - :: in case it's not available on account of being hidden behind a face in other dependencies - :: - =- (roll - |=([v=(trap vase) a=(trap vase)] (slew a v))) - %+ murn ~[lib-all sur-all raw-all bar-all honc] - |= dep=(trap vase) - ?: =(*(trap vase) dep) ~ - `dep - :: compile the current `hoon.graph` against its compiled dependencies + :: node set of entire dir + target + |= nodes=(map path node) + ^- [merk-dag path-dag] + ~& >> building-merk-dag-for+~(key by nodes) :: - =/ compiled=(trap vase) - ?: ?=(%hoon -.leaf.graph) - (swet deps hoon.leaf.graph) - => octs=!>(octs.leaf.graph) - |. octs - ~& >> compiled+path.graph - :: cache the vase before adding the face so that alias can be handled jit when pulling from cache + :: need a way to uniquely identify dep directories + =| dep-dag=merk-dag + =| =path-dag + =/ graph (build-graph-view nodes) + =/ next=(map path node) (update-next nodes graph) :: - =. cache (~(put by cache) path.graph compiled) - =. compiled (label-vase compiled face.graph) - [compiled cache] + :: traverse via a topological sorting of the DAG + |- + ?: .=(~ next) + [dep-dag path-dag] + =- + %= $ + next (update-next nodes graph) + graph graph + dep-dag dd + path-dag pd + == + ^- [graph=(map path (set path)) dd=(map @ node) pd=^path-dag] :: - ++ label-vase - |= [vaz=(trap vase) face=(unit @tas)] - ^- (trap vase) - ?~ face vaz - => [vaz=vaz face=u.face] - |. - =/ vas $:vaz - [[%face face p.vas] q.vas] - -- -:: + :: every node in next is put into path-dag and dep-dag along with + :: its hash + %+ roll + ~(tap by next) + |= [[p=path n=node] graph=_graph dep-dag=_dep-dag path-dag=_path-dag] + =/ hash (calculate-hash n dep-dag path-dag) + :+ (update-graph-view graph p) + (~(put by dep-dag) hash n) + (~(put by path-dag) p [hash n]) +:: +:: $update-next: returns nodes from a $graph-view that have no outgoing edges +:: +:: .nodes: the nodes of the dependency graph +:: .gv: the graph-view of the dependency graph +:: +:: assumes that entries in $nodes that are not in the $graph-view have +:: already been visited. +:: +++ update-next + |= [nodes=(map path node) gv=graph-view] + ^- (map path node) + :: + :: if we don't have the entry in gv, already visited + %+ roll + ~(tap by gv) + |= [[pax=path edges=(set path)] next=(map path node)] + :: + :: if a node has no out edges, add it to next + ?. =(*(set path) edges) + next + %+ ~(put by next) + pax + (~(got by nodes) pax) +:: +:: $update-graph-view: updates a $graph-view by removing a $path +:: +:: .gv: the graph-view to update +:: .p: the path to remove from the graph-view +:: +:: deletes the $path from the $graph-view and removes it from all edge sets +++ update-graph-view + |= [gv=graph-view p=path] + ^- graph-view + =. gv (~(del by gv) p) + %- ~(urn by gv) + |= [pax=path edges=(set path)] + (~(del in edges) p) +:: +:: $calculate-hash: calculate the hash of a node +:: +:: .n: the node to calculate the hash of +:: .dep-dag: the merkle DAG of the dependency graph +:: .path-dag: the path-dag of the dependency graph +:: +:: returns the hash of the node +++ calculate-hash + |= [n=node dep-dag=merk-dag =path-dag] + ^- @ + %+ roll + deps.n + |= [raut hash=_hash.n] + ?. (~(has by path-dag) pax) + ~& >>> "calculate-hash: Missing {}" !! + =/ [dep-hash=@ *] + (~(got by path-dag) pax) + (shax (rep 8 ~[hash dep-hash])) +:: +:: $build-graph-view: build a graph-view from a node map +:: +:: .nodes: the nodes of the dependency graph +:: +:: returns a graph-view of the dependency graph +++ build-graph-view + |= nodes=(map path node) + ^- graph-view + %- ~(urn by nodes) + |= [* n=node] + %- silt + (turn deps.n |=(raut pax)) +:: +:: $slew: merge two (trap vase)s +:: +:: .hed: the first (trap vase) +:: .tal: the second (trap vase) +:: +:: returns a merged (trap vase) ++ slew |= [hed=(trap vase) tal=(trap vase)] ^- (trap vase) @@ -449,8 +712,11 @@ [[%cell p:bed p:bal] [q:bed q:bal]] :: +shot: deferred slam :: -:: NOTE: this should never run inside of a trap. if it does, the builder -:: dependencies will leak into the result. +:: .gat: the gate to slam with the sample as a (trap vase) +:: .sam: the sample to slam with the gate +:: +:: NOTE: this should never run inside of a trap. if it does, the builder +:: dependencies will leak into the result. :: ++ shot |= [gat=(trap vase) sam=(trap vase)] @@ -464,6 +730,7 @@ [typ .*([q:$:gat q:$:sam] [%9 2 %10 [6 %0 3] %0 2])] :: :: +swet: deferred +slap +:: :: NOTE: this is +swat but with a bug fixed that caused a space leak in :: the resulting trap vases. :: @@ -481,8 +748,4 @@ =/ end (rear pax) !=(~ (find ".hoon" (trip end))) :: -++ is-graph-leaf - |= import-graph - ^- ? - &(=(~ sur) =(~ lib)) -- diff --git a/apps/choo/main.rs b/apps/choo/main.rs index 5dd49c3e..c37bb7e3 100644 --- a/apps/choo/main.rs +++ b/apps/choo/main.rs @@ -19,7 +19,7 @@ static KERNEL_JAM: &[u8] = static HOON_TXT: &[u8] = include_bytes!(concat!( env!("CARGO_MANIFEST_DIR"), - "/../hoon-deps/lib/hoon-138.hoon" + "/../hoon/hoon-138.hoon" )); #[derive(Parser, Debug)] @@ -122,7 +122,8 @@ async fn initialize_nockapp(cli: ChooCli) -> Result Result = vec![]; @@ -176,3 +178,61 @@ async fn work_loop(mut nockapp: crown::nockapp::NockApp) { } } } + +#[cfg(test)] +mod tests { + use super::*; + use std::path::PathBuf; + use tokio::fs; + use tracing::info; + + #[ignore] + #[tokio::test] + async fn test_compile_test_app() -> Result<(), Box> { + let mut test_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_dir.pop(); + test_dir.push("test-app"); + + // Clean up any existing output file + let _ = fs::remove_file("out.jam").await; + + let mut deps_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + deps_dir.pop(); + deps_dir.push("hoon-deps"); + let entry = format!("{}/bootstrap/kernel.hoon", test_dir.display()); + + let result = async { + let cli = ChooCli { + boot: BootCli { + save_interval: 1000, + new: false, + trace: false, + log_level: "trace".to_string(), + color: ColorChoice::Auto, + state_jam: None, + }, + entry: entry.clone(), + directory: deps_dir.display().to_string(), + arbitrary: false, + }; + + let nockapp = initialize_nockapp(cli).await?; + info!("Test directory: {}", test_dir.display()); + info!("Dependencies directory: {}", deps_dir.display()); + info!("Entry file: {}", entry.clone()); + work_loop(nockapp).await; + + // TODO this doesn't work because choo exits when compilation is done. + // Verify output file exists and is not empty + let metadata = fs::metadata("out.jam").await?; + info!("Output file size: {} bytes", metadata.len()); + assert!(metadata.len() > 0, "Output file is empty"); + Ok(()) + }.await; + + // Cleanup + let _ = fs::remove_file("out.jam").await; + + result + } +} diff --git a/apps/hoon-deps/lib/hoon-138.hoon b/apps/hoon/hoon-138.hoon similarity index 100% rename from apps/hoon-deps/lib/hoon-138.hoon rename to apps/hoon/hoon-138.hoon diff --git a/apps/hoon-deps/lib/hoon-139.hoon b/apps/hoon/hoon-139.hoon similarity index 100% rename from apps/hoon-deps/lib/hoon-139.hoon rename to apps/hoon/hoon-139.hoon diff --git a/apps/test-app/bootstrap/test-ker.jam b/apps/test-app/bootstrap/test-ker.jam index bc29f481..bdc18405 100644 Binary files a/apps/test-app/bootstrap/test-ker.jam and b/apps/test-app/bootstrap/test-ker.jam differ diff --git a/crown/src/drivers/one_punch.rs b/crown/src/drivers/one_punch.rs index e22a364b..e4df00a4 100644 --- a/crown/src/drivers/one_punch.rs +++ b/crown/src/drivers/one_punch.rs @@ -9,9 +9,7 @@ use tracing::{debug, error, info}; pub fn one_punch_man(data: NounSlab, op: Operation) -> IODriverFn { make_driver(|handle| async move { let result = match op { - Operation::Poke => { - Left(handle.poke(data).await?) - } + Operation::Poke => Left(handle.poke(data).await?), Operation::Peek => { debug!("poke_once_driver: peeking with {:?}", data); Right(handle.peek(data).await?) diff --git a/crown/src/kernel/boot.rs b/crown/src/kernel/boot.rs index 8c7f2c6c..dba7e317 100644 --- a/crown/src/kernel/boot.rs +++ b/crown/src/kernel/boot.rs @@ -26,7 +26,7 @@ pub struct Cli { default_value = "1000", help = "Set the save interval for checkpoints (in ms)" )] - save_interval: u64, + pub save_interval: u64, #[arg( long,