kernel.hoon 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919
  1. /+ *wrapper
  2. =>
  3. |%
  4. +$ state-0 [%0 *]
  5. +$ state-1 [%1 *]
  6. +$ state-2 [%2 cached-hoon=(unit (trap vase)) bc=build-cache pc=parse-cache]
  7. ::
  8. ++ empty-trap-vase
  9. ^- (trap vase)
  10. => vaz=!>(~)
  11. |.(vaz)
  12. ::
  13. +$ versioned-state
  14. $% state-0
  15. state-1
  16. state-2
  17. ==
  18. +$ choo-state state-2
  19. ::
  20. ++ moat (keep choo-state)
  21. +$ cause
  22. $% $: %build
  23. pat=cord
  24. tex=cord
  25. directory=(list [cord cord])
  26. arbitrary=?
  27. out=cord
  28. ==
  29. [%file %write path=@t contents=@ success=?]
  30. [%boot hoon-txt=cord]
  31. ==
  32. +$ effect
  33. $% [%file %write path=@t contents=@]
  34. [%exit id=@]
  35. ==
  36. ::
  37. :: $entry: path of a file along with unit of its contents.
  38. ::
  39. :: If unit is null, the path must exist inside of the dir map.
  40. ::
  41. +$ entry [pat=path tex=(unit cord)]
  42. ::
  43. +$ hash @
  44. ::
  45. :: $build-cache: holds up to date cached build artifacts, keyed by merkle hash
  46. +$ build-cache (map hash (trap vase))
  47. ::
  48. :: $build-result: result of a build
  49. ::
  50. :: either a (trap vase) or an error trace.
  51. ::
  52. +$ build-result (each (trap vase) tang)
  53. ::
  54. :: $taut: file import from /lib or /sur
  55. ::
  56. +$ taut [face=(unit term) pax=term]
  57. ::
  58. :: $pile: preprocessed hoon file
  59. ::
  60. +$ pile
  61. $: sur=(list taut) :: /-
  62. lib=(list taut) :: /+
  63. raw=(list [face=(unit term) pax=path]) :: /=
  64. bar=(list [face=term mark=@tas =path]) :: /*
  65. hax=(list taut) :: /#
  66. =hoon
  67. ==
  68. ::
  69. ::
  70. :: $parse-cache: content addressed cache of preprocessed hoon files.
  71. ::
  72. +$ parse-cache (map hash pile)
  73. --
  74. ::
  75. =<
  76. ~& >> %choo-choo
  77. %- (moat &)
  78. ^- fort:moat
  79. |_ k=choo-state
  80. +* builder +>
  81. ::
  82. :: +load: upgrade from previous state
  83. ::
  84. ::
  85. ++ load
  86. |= old=versioned-state
  87. ^- choo-state
  88. ::
  89. :: We do not use the result of the soft because
  90. :: clamming (trap vase) overwrites the contents
  91. :: with the bunt resulting in the honc and the build
  92. :: artifacts being replaced with empty-trap-vase.
  93. ::
  94. ?~ ((soft versioned-state) old)
  95. ~> %slog.[0 leaf+"choo: +load old state does not nest under versioned-state. Try booting with --new to start from scratch."]
  96. !!
  97. ?- -.old
  98. %0
  99. ~> %slog.[0 leaf+"update 0-to-2, starting from scratch"]
  100. *choo-state
  101. ::
  102. %1
  103. ~> %slog.[0 leaf+"update 1-to-2, starting from scratch"]
  104. *choo-state
  105. ::
  106. %2
  107. ~> %slog.[0 leaf+"no update"]
  108. old
  109. ::
  110. ==
  111. ::
  112. :: +peek: external inspect
  113. ::
  114. ++ peek
  115. |= =path
  116. ^- (unit (unit *))
  117. ?+ path ~
  118. [%booted ~]
  119. ``?=(^ cached-hoon.k)
  120. ==
  121. ::
  122. :: +poke: external apply
  123. ::
  124. ++ poke
  125. |= [=wire eny=@ our=@ux now=@da dat=*]
  126. ^- [(list effect) choo-state]
  127. =/ cause=(unit cause) ((soft cause) dat)
  128. ?~ cause
  129. ~& "input is not a proper cause"
  130. !!
  131. =/ cause u.cause
  132. ~& -.cause
  133. ?- -.cause
  134. %file
  135. ?: success.cause
  136. ~& > "choo: output written successfully to {<path.cause>}"
  137. [[%exit 0]~ k]
  138. ~& > "choo: failed to write output to {<path.cause>}"
  139. [[%exit 1]~ k]
  140. ::
  141. %boot
  142. ~& >> hoon-version+hoon-version
  143. ?: ?=(^ cached-hoon.k)
  144. [~ k]
  145. ~& "Please be patient. This will take a few minutes."
  146. [~ k(cached-hoon `(build-honc hoon-txt.cause))]
  147. ::
  148. %build
  149. ~& >> "building path: {<pat.cause>}"
  150. =/ =entry
  151. ~| "path did not parse: {<pat.cause>}"
  152. [(parse-file-path pat.cause) `tex.cause]
  153. =/ dir
  154. %- ~(gas by *(map path cord))
  155. (turn directory.cause |=((pair @t @t) [(stab p) q]))
  156. ?> ?=(^ cached-hoon.k)
  157. =/ [compiled=* new-bc=build-cache new-pc=parse-cache]
  158. ?: arbitrary.cause
  159. %- ~(create-arbitrary builder u.cached-hoon.k bc.k pc.k)
  160. [entry dir]
  161. %- ~(create builder u.cached-hoon.k bc.k pc.k)
  162. [entry dir]
  163. :_ k(bc new-bc, pc new-pc)
  164. =/ write-effect
  165. :* %file
  166. %write
  167. path=out.cause
  168. contents=(jam compiled)
  169. ==
  170. =/ success !=(compiled empty-trap-vase)
  171. ?: success
  172. ~& >>> "choo: build succeeded, sending out write effect"
  173. [write-effect]~
  174. ~& >>> "choo: build failed, skipping write and exiting"
  175. [%exit 1]~
  176. ==
  177. --
  178. ::
  179. :: build system
  180. ::
  181. =>
  182. ::
  183. :: dependency system
  184. ::
  185. |%
  186. +$ raut
  187. :: resolved taut - pax contains real path to file after running taut through +get-fit
  188. [face=(unit @tas) pax=path]
  189. ++ rile
  190. :: resolved pile
  191. $: sur=(list raut)
  192. lib=(list raut)
  193. raw=(list raut)
  194. bar=(list raut)
  195. hax=(list raut)
  196. =hoon
  197. ==
  198. ::
  199. :: +parse-file-path: parse cord of earth file path to path
  200. ++ parse-file-path
  201. |= pat=cord
  202. (rash pat gawp)
  203. ::
  204. :: +gawp: parse an absolute earth file path
  205. ++ gawp
  206. %+ sear
  207. |= p=path
  208. ^- (unit path)
  209. ?: ?=([~ ~] p) `~
  210. ?. =(~ (rear p)) `p
  211. ~
  212. ;~(pfix fas (most fas bic))
  213. ::
  214. :: +bic: parse file/dir name in earth file path
  215. ++ bic
  216. %+ cook
  217. |=(a=tape (rap 3 ^-((list @) a)))
  218. (star ;~(pose nud low hig hep dot sig cab))
  219. ::
  220. ++ to-wain :: cord to line list
  221. |= txt=cord
  222. ^- wain
  223. ?~ txt ~
  224. =/ len=@ (met 3 txt)
  225. =/ cut =+(cut -(a 3, c 1, d txt))
  226. =/ sub sub
  227. =| [i=@ out=wain]
  228. |- ^+ out
  229. =+ |- ^- j=@
  230. ?: ?| =(i len)
  231. =(10 (cut(b i)))
  232. ==
  233. i
  234. $(i +(i))
  235. =. out :_ out
  236. (cut(b i, c (sub j i)))
  237. ?: =(j len)
  238. (flop out)
  239. $(i +(j))
  240. ::
  241. ++ parse-pile
  242. |= [pax=path tex=tape]
  243. ^- pile
  244. =/ [=hair res=(unit [=pile =nail])]
  245. %- road |.
  246. ((pile-rule pax) [1 1] tex)
  247. ?^ res pile.u.res
  248. %- mean
  249. =/ lyn p.hair
  250. =/ col q.hair
  251. ^- (list tank)
  252. :~ leaf+"syntax error at [{<lyn>} {<col>}] in {<pax>}"
  253. ::
  254. =/ =wain (to-wain (crip tex))
  255. ?: (gth lyn (lent wain))
  256. '<<end of file>>'
  257. (snag (dec lyn) wain)
  258. ::
  259. leaf+(runt [(dec col) '-'] "^")
  260. ==
  261. ::
  262. ++ pile-rule
  263. |= pax=path
  264. %- full
  265. %+ ifix
  266. :_ gay
  267. :: parse optional /? and ignore
  268. ::
  269. ;~(plug gay (punt ;~(plug fas wut gap dem gap)))
  270. |^
  271. ;~ plug
  272. %+ cook (bake zing (list (list taut)))
  273. %+ rune hep
  274. (most ;~(plug com gaw) taut-rule)
  275. ::
  276. %+ cook (bake zing (list (list taut)))
  277. %+ rune lus
  278. (most ;~(plug com gaw) taut-rule)
  279. ::
  280. %+ rune tis
  281. ;~(plug ;~(pose (cold ~ tar) (stag ~ sym)) ;~(pfix gap stap))
  282. ::
  283. %+ rune tar
  284. ;~ (glue gap)
  285. sym
  286. ;~(pfix cen sym)
  287. ;~(pfix stap)
  288. ==
  289. ::
  290. %+ cook (bake zing (list (list taut)))
  291. %+ rune hax
  292. (most ;~(plug com gaw) taut-rule)
  293. ::
  294. %+ stag %tssg
  295. (most gap tall:(vang & pax))
  296. ==
  297. ::
  298. ++ pant
  299. |* fel=rule
  300. ;~(pose fel (easy ~))
  301. ::
  302. ++ mast
  303. |* [bus=rule fel=rule]
  304. ;~(sfix (more bus fel) bus)
  305. ::
  306. ++ rune
  307. |* [bus=rule fel=rule]
  308. %- pant
  309. %+ mast gap
  310. ;~(pfix fas bus gap fel)
  311. --
  312. ::
  313. ++ taut-rule
  314. %+ cook |=(taut +<)
  315. ;~ pose
  316. (stag ~ ;~(pfix tar sym)) :: *foo -> [~ %foo]
  317. ;~(plug (stag ~ sym) ;~(pfix tis sym)) :: bar=foo -> [[~ %bar] %foo]
  318. (cook |=(a=term [`a a]) sym) :: foo -> [[~ %foo] %foo]
  319. ==
  320. ::
  321. ++ segments
  322. |= suffix=@tas
  323. ^- (list path)
  324. =/ parser
  325. (most hep (cook crip ;~(plug ;~(pose low nud) (star ;~(pose low nud)))))
  326. =/ torn=(list @tas) (fall (rush suffix parser) ~[suffix])
  327. %- flop
  328. |- ^- (list (list @tas))
  329. ?< ?=(~ torn)
  330. ?: ?=([@ ~] torn)
  331. ~[torn]
  332. %- zing
  333. %+ turn $(torn t.torn)
  334. |= s=(list @tas)
  335. ^- (list (list @tas))
  336. ?> ?=(^ s)
  337. ~[[i.torn s] [(crip "{(trip i.torn)}-{(trip i.s)}") t.s]]
  338. ::
  339. ++ get-fit
  340. |= [pre=@ta pax=@tas dir=(map path cord)]
  341. ^- (unit path)
  342. =/ paz=(list path) (segments pax)
  343. |-
  344. ?~ paz
  345. ~& >> "{<pax>}-not-found" ~
  346. =/ last=term (rear i.paz)
  347. =. i.paz `path`(snip i.paz)
  348. =/ puz
  349. ^- path
  350. %+ snoc
  351. `path`[pre i.paz]
  352. `@ta`(rap 3 ~[last %'.' %hoon])
  353. ?^ (~(get by dir) puz)
  354. `puz
  355. $(paz t.paz)
  356. ::
  357. ++ resolve-pile
  358. :: turn fits into resolved path suffixes
  359. |= [=pile dir=(map path cord)]
  360. ^- (list raut)
  361. ;: weld
  362. (turn sur.pile |=(taut ^-(raut [face (need (get-fit %sur pax dir))])))
  363. (turn lib.pile |=(taut ^-(raut [face (need (get-fit %lib pax dir))])))
  364. ::
  365. %+ turn raw.pile
  366. |= [face=(unit term) pax=path]
  367. =/ pax-snip (snip pax)
  368. =/ pax-rear (rear pax)
  369. ^- raut
  370. [face `path`(snoc pax-snip `@ta`(rap 3 ~[pax-rear %'.' %hoon]))]
  371. ::
  372. %+ turn bar.pile
  373. |= [face=term mark=@tas pax=path]
  374. =/ pax-snip (snip pax)
  375. =/ pax-hind (rear pax-snip)
  376. =/ pax-rear (rear pax)
  377. ^- raut
  378. [`face `path`(snoc (snip pax-snip) `@ta`(rap 3 ~[pax-hind %'.' pax-rear]))]
  379. ::
  380. (turn hax.pile |=(taut ^-(raut [face (need (get-fit %dat pax dir))])))
  381. ==
  382. --
  383. ::
  384. :: builder core
  385. ::
  386. |_ [honc=(trap vase) bc=build-cache pc=parse-cache]
  387. ::
  388. ++ build-honc
  389. |= hoon-txt=cord
  390. ^- (trap vase)
  391. (swet empty-trap-vase (ream hoon-txt))
  392. ::
  393. +$ octs [p=@ud q=@]
  394. ::
  395. :: $node: entry of adjacency matrix with metadata
  396. ::
  397. +$ node
  398. $: =path
  399. hash=@
  400. :: holds only outgoing edges
  401. deps=(list raut)
  402. leaf=graph-leaf
  403. eval=? :: whether or not to kick it
  404. ==
  405. ::
  406. +$ graph-leaf
  407. $% [%hoon =hoon]
  408. [%octs =octs]
  409. ==
  410. ::
  411. :: $create: build a trap from a hoon/jock file with dependencies
  412. ::
  413. :: .entry: the entry to build
  414. :: .dir: the directory to get dependencies from
  415. ::
  416. :: this is meant to build a kernel gate that takes a hash of a the
  417. :: dependency directory.
  418. ::
  419. :: returns a trap, a build-cache, and a parse-cache
  420. ++ create
  421. |= [=entry dir=(map path cord)]
  422. ^- [* build-cache parse-cache]
  423. =/ dir-hash `@uvI`(mug dir)
  424. ~& >> dir-hash+dir-hash
  425. =/ compile
  426. (create-target entry dir)
  427. =/ ker-gen (head compile)
  428. =/ [=build-cache =parse-cache] (tail compile)
  429. :: +shot calls the kernel gate to tell it the hash of the dependency directory
  430. :_ [build-cache parse-cache]
  431. :: build failure, just return the bunted trap
  432. ?: =(ker-gen empty-trap-vase) ker-gen
  433. => %+ shot ker-gen
  434. => d=!>(dir-hash)
  435. |.(d)
  436. |.(+:^$)
  437. ::
  438. :: $create-arbitrary: builds a hoon/jock file with dependencies without file hash injection
  439. ::
  440. :: .entry: the entry to build
  441. :: .dir: the directory to get dependencies from
  442. :: returns a trap, a build-cache, and a parse-cache
  443. ++ create-arbitrary
  444. |= [=entry dir=(map path cord)]
  445. ^- [* build-cache parse-cache]
  446. =/ [tase=(trap) =build-cache =parse-cache]
  447. (create-target entry dir)
  448. :_ [build-cache parse-cache]
  449. ?: =(tase empty-trap-vase)
  450. tase
  451. => tase
  452. |.(+:^$)
  453. ::
  454. :: $create-target: builds a hoon/jock file with dependencies
  455. ::
  456. :: .entry: the entry to build
  457. :: .dir: the directory to get dependencies from
  458. ::
  459. :: returns a trap with the compiled hoon/jock file and the updated caches
  460. ++ create-target
  461. |= [=entry dir=(map path cord)]
  462. ^- [(trap vase) build-cache parse-cache]
  463. =^ parsed-dir=(map path node) pc
  464. (parse-dir entry dir)
  465. =/ all-nodes=(map path node) parsed-dir
  466. =/ [dep-dag=merk-dag =path-dag] (build-merk-dag all-nodes)
  467. ::
  468. :: delete invalid cache entries in bc
  469. =. bc
  470. %+ roll
  471. ~(tap by bc)
  472. |= [[hash=@ *] bc=_bc]
  473. ?: (~(has by dep-dag) hash)
  474. bc
  475. (~(del by bc) hash)
  476. ::
  477. =/ compile
  478. %: compile-target
  479. pat.entry
  480. path-dag
  481. all-nodes
  482. bc
  483. ==
  484. ::
  485. [(head compile) (tail compile) pc]
  486. ::
  487. :: $parse-dir: parse $entry and get dependencies from $dir
  488. ::
  489. :: .entry: entry to parse
  490. :: .dir: directory to get dependencies from
  491. ::
  492. :: returns a map of nodes and a parse cache
  493. ++ parse-dir
  494. |= [suf=entry dir=(map path cord)]
  495. ^- [(map path node) parse-cache]
  496. =| new-pc=parse-cache
  497. ~& > parsing+pat.suf
  498. |^
  499. =/ file=cord (get-file suf dir) :: get target file
  500. =/ hash=@ (shax file) :: hash target file
  501. =^ target=node new-pc
  502. ?. (is-hoon pat.suf)
  503. :_ new-pc
  504. :* pat.suf :: path
  505. hash :: hash
  506. ~ :: deps
  507. [%octs [(met 3 file) file]] :: octs
  508. %.n :: eval
  509. ==
  510. =/ =pile
  511. ?: (~(has by pc) hash)
  512. ~& parse-cache-hit+pat.suf
  513. (~(got by pc) hash)
  514. ~& parse-cache-miss+pat.suf
  515. (parse-pile pat.suf (trip file)) :: parse target file
  516. =/ deps=(list raut) (resolve-pile pile dir) :: resolve deps
  517. :_ (~(put by new-pc) hash pile)
  518. :* pat.suf :: path
  519. hash :: hash
  520. deps :: deps
  521. [%hoon hoon.pile] :: hoon
  522. (is-dat pat.suf) :: eval
  523. ==
  524. =| nodes=(map path node) :: init empty node map
  525. =. nodes (~(put by nodes) pat.suf target) :: add target node
  526. =/ seen=(set path) (~(put in *(set path)) pat.suf)
  527. (resolve-all nodes seen deps.target new-pc)
  528. ::
  529. ++ resolve-all
  530. |= [nodes=(map path node) seen=(set path) deps=(list raut) new-pc=parse-cache]
  531. ^- [(map path node) parse-cache]
  532. ?~ deps [nodes new-pc] :: done if no deps
  533. ?. (~(has in seen) pax.i.deps) :: skip if seen
  534. ~& >> parsing+pax.i.deps
  535. =/ dep-file (get-file [pax.i.deps ~] dir) :: get dep file
  536. =/ dep-hash (shax dep-file) :: hash dep file
  537. =^ dep-node=node new-pc
  538. ?. (is-hoon pax.i.deps)
  539. :_ pc
  540. :* pax.i.deps :: path
  541. dep-hash :: hash
  542. ~ :: deps
  543. [%octs [(met 3 dep-file) dep-file]] :: octs
  544. %.n
  545. ==
  546. =/ dep-pile
  547. ?: (~(has by pc) dep-hash) :: check cache
  548. ~& parse-cache-hit+pax.i.deps
  549. (~(got by pc) dep-hash)
  550. ~& parse-cache-miss+pax.i.deps
  551. (parse-pile pax.i.deps (trip dep-file)) :: parse dep file
  552. ~& >> parsed+pax.i.deps
  553. =/ dep-deps (resolve-pile dep-pile dir) :: resolve dep deps
  554. ~& >> resolved+pax.i.deps
  555. :_ (~(put by new-pc) dep-hash dep-pile) :: cache parse
  556. :* pax.i.deps
  557. dep-hash
  558. dep-deps
  559. [%hoon hoon.dep-pile]
  560. (is-dat pax.i.deps) :: eval
  561. ==
  562. =. nodes (~(put by nodes) pax.i.deps dep-node) :: add dep node
  563. =. seen (~(put in seen) pax.i.deps) :: mark as seen
  564. %= $
  565. nodes nodes
  566. seen seen
  567. deps (weld t.deps deps.dep-node) :: add new deps
  568. new-pc new-pc
  569. ==
  570. $(deps t.deps) :: next dep
  571. ::
  572. --
  573. ::
  574. :: $merk-dag: content-addressed map of nodes
  575. ::
  576. :: maps content hashes to nodes. each hash is computed from the node's
  577. :: content and the hashes of its dependencies, forming a merkle tree.
  578. :: used to detect changes in the dependency graph and enable caching.
  579. ::
  580. +$ merk-dag (map @ node)
  581. ::
  582. :: $path-dag: path-addressed map of nodes with their content hashes
  583. ::
  584. :: maps file paths to [hash node] pairs. provides a way to look up nodes
  585. :: by path while maintaining the connection to their content hash in the
  586. :: merk-dag. used during traversal to find dependencies by path.
  587. ::
  588. +$ path-dag (map path [@ node])
  589. ::
  590. :: $graph-view: adjacency matrix with easier access to neighbors
  591. ::
  592. :: used to keep track of traversal when building the merkle DAG
  593. ::
  594. +$ graph-view (map path (set path))
  595. ::
  596. :: $build-merk-dag: builds a merkle DAG out of the dependency folder
  597. ::
  598. :: .nodes: the nodes of the dependency graph
  599. ::
  600. :: returns a merkle DAG and a path-dag
  601. ++ build-merk-dag
  602. |^
  603. ::
  604. :: node set of entire dir + target
  605. |= nodes=(map path node)
  606. ^- [merk-dag path-dag]
  607. ~& >> building-merk-dag-for+~(key by nodes)
  608. ::
  609. :: need a way to uniquely identify dep directories
  610. =| dep-dag=merk-dag
  611. =| =path-dag
  612. =/ graph (build-graph-view nodes)
  613. =/ next=(map path node) (update-next nodes graph)
  614. ::
  615. :: traverse via a topological sorting of the DAG using Kahn's algorithm
  616. |-
  617. ?: .=(~ next)
  618. ?. .=(~ graph)
  619. ~|(cycle-detected+~(key by graph) !!)
  620. [dep-dag path-dag]
  621. =-
  622. %= $
  623. next (update-next nodes graph)
  624. graph graph
  625. dep-dag dd
  626. path-dag pd
  627. ==
  628. ^- [graph=(map path (set path)) dd=(map @ node) pd=^path-dag]
  629. ::
  630. :: every node in next is put into path-dag and dep-dag along with
  631. :: its hash
  632. %+ roll
  633. ~(tap by next)
  634. |= [[p=path n=node] graph=_graph dep-dag=_dep-dag path-dag=_path-dag]
  635. =/ hash (calculate-hash n dep-dag path-dag)
  636. :+ (update-graph-view graph p)
  637. (~(put by dep-dag) hash n)
  638. (~(put by path-dag) p [hash n])
  639. ::
  640. :: $calculate-hash: calculate the hash of a node
  641. ::
  642. :: .n: the node to calculate the hash of
  643. :: .dep-dag: the merkle DAG of the dependency graph
  644. :: .path-dag: the path-dag of the dependency graph
  645. ::
  646. :: returns the hash of the node
  647. ++ calculate-hash
  648. |= [n=node dep-dag=merk-dag =path-dag]
  649. ^- @
  650. %+ roll
  651. deps.n
  652. |= [raut hash=_hash.n]
  653. ?. (~(has by path-dag) pax)
  654. ~& >>> "calculate-hash: Missing {<pax>}" !!
  655. =/ [dep-hash=@ *]
  656. (~(got by path-dag) pax)
  657. (shax (rep 8 ~[hash dep-hash]))
  658. --
  659. ::
  660. :: $compile-target: compile a target hoon file
  661. ::
  662. :: .pat: path to the target hoon file
  663. :: .path-dag: the path-dag of the dependency graph
  664. :: .nodes: the nodes of the dependency graph
  665. :: .bc: the build cache
  666. ::
  667. :: returns a trap vase with the compiled hoon file and the updated build
  668. :: cache. if a build failure is detected, a bunted (trap vase) is returned
  669. :: instead.
  670. ++ compile-target
  671. |^
  672. |= [pat=path =path-dag nodes=(map path node) bc=build-cache]
  673. ^- [(trap vase) build-cache]
  674. ~& >> compiling-target+pat
  675. =/ n=node
  676. ~| """
  677. couldn't find node {<pat>} in path-dag.
  678. nodes: {<~(key by nodes)>}
  679. path-dag: {<~(key by path-dag)>}
  680. """
  681. +:(~(got by path-dag) pat)
  682. =/ graph (build-graph-view nodes)
  683. =/ next=(map path node) (update-next nodes graph)
  684. =| failed=_|
  685. |- ^- [(trap vase) build-cache]
  686. ?: failed [empty-trap-vase bc]
  687. ?: .=(~ next)
  688. =/ [=build-result new-bc=build-cache]
  689. (compile-node n path-dag bc)
  690. ?- -.build-result
  691. ::
  692. %| ~& >>> "compile-target: failed: {<pat>}"
  693. [empty-trap-vase new-bc]
  694. ::
  695. %& [p.build-result new-bc]
  696. ==
  697. =/ [err=? bc=build-cache]
  698. %+ roll ~(tap by next)
  699. |= [[p=path n=node] [err=_| bc=_bc]]
  700. =/ [=build-result new-bc=build-cache]
  701. (compile-node n path-dag bc)
  702. ?- -.build-result
  703. ::
  704. %| ~& >>> "compile-target: failed: {<p>}"
  705. [& new-bc]
  706. ::
  707. %& [err new-bc]
  708. ==
  709. =. graph
  710. (roll ~(tap by next) |=([[p=path *] g=_graph] (update-graph-view g p)))
  711. %= $
  712. next (update-next nodes graph)
  713. graph graph
  714. bc bc
  715. failed err
  716. ==
  717. ::
  718. :: $compile-node: compile a single node
  719. ::
  720. :: .n: the node to compile
  721. :: .path-dag: the path-dag of the dependency graph
  722. :: .bc: the build cache
  723. ::
  724. :: looks up the node in the build cache and compiles it if it's not already
  725. :: cached.
  726. ::
  727. :: returns a $build-result and the updated build cache
  728. ++ compile-node
  729. |= [n=node =path-dag bc=build-cache]
  730. ^- [build-result build-cache]
  731. =/ [dep-hash=@ *] (~(got by path-dag) path.n)
  732. ?: (~(has by bc) dep-hash)
  733. ~& > build-cache-hit+path.n
  734. :_ bc
  735. [%.y (~(got by bc) dep-hash)]
  736. ~& > build-cache-miss+path.n
  737. =/ =build-result (mule |.((build-node n path-dag bc)))
  738. =? bc ?=(%& -.build-result)
  739. (~(put by bc) dep-hash p.build-result)
  740. =- ?. ?=(%| -.build-result) -
  741. ((slog p.build-result) -)
  742. [build-result bc]
  743. ::
  744. :: $build-node: build a single node and its dependencies
  745. ::
  746. :: .n: the node to compile
  747. :: .path-dag: the path-dag of the dependency graph
  748. :: .bc: the build cache
  749. ::
  750. :: returns a trap vase with the compiled hoon
  751. ++ build-node
  752. |= [n=node =path-dag bc=build-cache]
  753. ^- (trap vase)
  754. ~> %bout
  755. =; dep-vaz=(trap vase)
  756. ?: ?=(%hoon -.leaf.n)
  757. ::
  758. :: Faces are resolved via depth-first search into the subject.
  759. :: We append the honc (hoon.hoon) to the end of the vase
  760. :: because imports have higher precedence when resolving faces.
  761. :: To avoid shadowing issues with hoon.hoon, attach faces to your
  762. :: imports or avoid shadowed names altogether.
  763. =/ swetted=(trap vase) (swet (slat dep-vaz honc) hoon.leaf.n)
  764. ?. eval.n
  765. swetted
  766. ~& "node {<path.n>} is eval, kicking"
  767. => [swetted=swetted vase=vase]
  768. =/ vaz=vase $:swetted
  769. => vaz=vaz
  770. |.(vaz)
  771. => octs=!>(octs.leaf.n)
  772. |.(octs)
  773. %+ roll deps.n
  774. |: [r=`raut`*raut vaz=empty-trap-vase]
  775. ~& > grabbing-dep+pax.r
  776. =/ [dep-hash=@ dep-node=node]
  777. ~| "couldn't find dep hash for {<pax.r>}"
  778. (~(got by path-dag) pax.r)
  779. =/ dep-vaz=(trap vase)
  780. ~| "couldn't find artifact for {<pax.r>} in build cache"
  781. (~(got by bc) dep-hash)
  782. ~& > attaching-face+face.r
  783. ::
  784. :: Ford imports are included in the order that they appear in the deps.
  785. (slat vaz (label-vase dep-vaz face.r))
  786. ::
  787. :: $label-vase: label a (trap vase) with a face
  788. ::
  789. :: .vaz: the (trap vase) to label
  790. :: .face: the face to label the (trap vase) with
  791. ::
  792. :: returns a (trap vase) labeled with the given face
  793. ++ label-vase
  794. |= [vaz=(trap vase) face=(unit @tas)]
  795. ^- (trap vase)
  796. ?~ face vaz
  797. => [vaz=vaz face=u.face]
  798. |.
  799. =/ vas $:vaz
  800. [[%face face p.vas] q.vas]
  801. --
  802. ::
  803. :: $update-next: returns nodes from a $graph-view that have no outgoing edges
  804. ::
  805. :: .nodes: the nodes of the dependency graph
  806. :: .gv: the graph-view of the dependency graph
  807. ::
  808. :: assumes that entries in $nodes that are not in the $graph-view have
  809. :: already been visited.
  810. ::
  811. ++ update-next
  812. |= [nodes=(map path node) gv=graph-view]
  813. ^- (map path node)
  814. ::
  815. :: if we don't have the entry in gv, already visited
  816. %+ roll
  817. ~(tap by gv)
  818. |= [[pax=path edges=(set path)] next=(map path node)]
  819. ::
  820. :: if a node has no out edges, add it to next
  821. ?. =(*(set path) edges)
  822. next
  823. %+ ~(put by next)
  824. pax
  825. (~(got by nodes) pax)
  826. ::
  827. :: $update-graph-view: updates a $graph-view by removing a $path
  828. ::
  829. :: .gv: the graph-view to update
  830. :: .p: the path to remove from the graph-view
  831. ::
  832. :: deletes the $path from the $graph-view and removes it from all edge sets
  833. ::
  834. ++ update-graph-view
  835. |= [gv=graph-view p=path]
  836. ^- graph-view
  837. =. gv (~(del by gv) p)
  838. %- ~(urn by gv)
  839. |= [pax=path edges=(set path)]
  840. (~(del in edges) p)
  841. ::
  842. :: $build-graph-view: build a graph-view from a node map
  843. ::
  844. :: .nodes: the nodes of the dependency graph
  845. ::
  846. :: returns a graph-view of the dependency graph
  847. ::
  848. ++ build-graph-view
  849. |= nodes=(map path node)
  850. ^- graph-view
  851. %- ~(urn by nodes)
  852. |= [* n=node]
  853. %- silt
  854. (turn deps.n |=(raut pax))
  855. ::
  856. :: $slat: merge two (trap vase)s
  857. ::
  858. :: .hed: the first (trap vase)
  859. :: .tal: the second (trap vase)
  860. ::
  861. :: returns a merged (trap vase)
  862. ++ slat
  863. |= [hed=(trap vase) tal=(trap vase)]
  864. ^- (trap vase)
  865. => +<
  866. |.
  867. =+ [bed bal]=[$:hed $:tal]
  868. [[%cell p:bed p:bal] [q:bed q:bal]]
  869. :: +shot: deferred slam
  870. ::
  871. :: .gat: the gate to slam with the sample as a (trap vase)
  872. :: .sam: the sample to slam with the gate
  873. ::
  874. :: NOTE: this should never run inside of a trap. if it does, the builder
  875. :: dependencies will leak into the result.
  876. ::
  877. ++ shot
  878. |= [gat=(trap vase) sam=(trap vase)]
  879. ^- (trap vase)
  880. =/ [typ=type gen=hoon]
  881. :- [%cell p:$:gat p:$:sam]
  882. [%cnsg [%$ ~] [%$ 2] [%$ 3] ~]
  883. =+ gun=(~(mint ut typ) %noun gen)
  884. => [typ=p.gun +<.$]
  885. |.
  886. [typ .*([q:$:gat q:$:sam] [%9 2 %10 [6 %0 3] %0 2])]
  887. ::
  888. :: +swet: deferred +slap
  889. ::
  890. :: NOTE: this is +swat but with a bug fixed that caused a space leak in
  891. :: the resulting trap vases.
  892. ::
  893. ++ swet
  894. |= [tap=(trap vase) gen=hoon]
  895. ^- (trap vase)
  896. =/ gun (~(mint ut p:$:tap) %noun gen)
  897. => [gun=gun tap=tap]
  898. |. ~+
  899. [p.gun .*(q:$:tap q.gun)]
  900. ::
  901. ++ get-file :: get file contents
  902. |= [suf=entry dir=(map path cord)]
  903. ^- cord
  904. ?~ tex.suf
  905. ~| "file not found: {<pat.suf>}"
  906. (~(got by dir) pat.suf)
  907. u.tex.suf
  908. ::
  909. ++ is-hoon
  910. |= pax=path
  911. ^- ?
  912. =/ end (rear pax)
  913. !=(~ (find ".hoon" (trip end)))
  914. ::
  915. ++ is-dat
  916. |= pax=path
  917. ^- ?
  918. =('dat' (head pax))
  919. --