diff --git a/ape/dojo.hoon b/ape/dojo.hoon index dcc30ba4a..54acf9a8e 100644 --- a/ape/dojo.hoon +++ b/ape/dojo.hoon @@ -100,7 +100,7 @@ house :: program state == :: ++ he :: per session - |_ [[ost=bone moz=(list move)] session] :: + |_ [moz=(list move) session] :: ++ dp :: dojo parser |% ++ dp-default-app %hood @@ -670,7 +670,11 @@ == :: ++ he-abet :: resolve - [(flop moz) %_(+> hoc (~(put by hoc) ost +<+))] + [(flop moz) %_(+> hoc (~(put by hoc) ost.hid +<+))] + :: + ++ he-abut :: discard + => he-stop + [(flop moz) %_(+> hoc (~(del by hoc) ost.hid))] :: ++ he-beak -:he-beam ++ he-beam :: logical beam @@ -681,7 +685,7 @@ ++ he-card :: emit gift |= cad=card ^+ +> - %_(+> moz [[ost cad] moz]) + %_(+> moz [[ost.hid cad] moz]) :: ++ he-send |= [way=wire him=ship dap=term cop=clap] @@ -844,10 +848,10 @@ == :: :: pattern: ++ foo |=(data he-abet:(~(he-foo he (~(got by hoc) ost)) data)) -++ arm (arm-session (~(got by hoc) ost.hid)) +++ arm (arm-session ~ (~(got by hoc) ost.hid)) ++ arm-session - |= ses=session - => ~(. he [ost.hid ~] ses) + |= [moz=(list move) ses=session] + => ~(. he moz ses) =- [wrap=- +] |* he-arm=_he-type |= _+<.he-arm ^- (quip move ..he) @@ -856,9 +860,12 @@ ++ peer-sole ~? !=(src.hid our.hid) [%dojo-peer-stranger ost.hid src.hid] :: ?> =(src.hid our.hid) - ~? (~(has by hoc) ost.hid) [%dojo-peer-replaced ost.hid] + =^ moz . + ?. (~(has by hoc) ost.hid) [~ .] + ~& [%dojo-peer-replaced ost.hid] + ~(he-abut he ~ (~(got by hoc) ost.hid)) =+ ses=%*(. *session -.dir [our.hid %home ud/0]) - (wrap he-peer):(arm-session ses) + (wrap he-peer):(arm-session moz ses) :: ++ poke-sole-action |= act=sole-action ~| poke/act %. act @@ -872,7 +879,6 @@ ++ pull |= [pax=path] ^- (quip move +>) - =^ moz +> - he-abet:~(he-stop he [[ost.hid ~] (~(got by hoc) ost.hid)]) + =^ moz +> ~(he-abut he ~ (~(got by hoc) ost.hid)) [moz +>.$(hoc (~(del by hoc) ost.hid))] -- diff --git a/ape/hood.hoon b/ape/hood.hoon index 89e218f94..a14cf7d4e 100644 --- a/ape/hood.hoon +++ b/ape/hood.hoon @@ -56,6 +56,11 @@ ~? ?=(^ saw) [%kiln-spam-lame u.saw] [~ +>] :: +++ coup-kiln-reload :: + |= [way=wire saw=(unit tang)] + ~? ?=(^ saw) [%kiln-reload-lame u.saw] + [~ +>] +:: ++ coup-drum-phat (wrap take-coup-phat):from-drum ++ coup-helm-hi (wrap coup-hi):from-helm ++ diff-sole-effect-drum-phat (wrap diff-sole-effect-phat):from-drum @@ -72,41 +77,45 @@ ++ from-helm (from-lib %helm [..$ ,_abet]:(helm)) ++ from-kiln (from-lib %kiln [..$ ,_abet]:(kiln)) :: -++ init-helm |=([way=wire *] [~ +>]) -++ made-kiln (wrap take-made):from-kiln -++ mere-kiln (wrap take-mere):from-kiln -++ mere-kiln-sync (wrap take-mere-sync):from-kiln -++ note-helm (wrap take-note):from-helm -++ onto-drum (wrap take-onto):from-drum -++ peer-drum (wrap peer):from-drum -++ poke-dill-belt (wrap poke-dill-belt):from-drum -++ poke-drum-link (wrap poke-link):from-drum -::++ poke-drum-exit (wrap poke-exit):from-drum -++ poke-drum-start (wrap poke-start):from-drum -++ poke-helm-hi (wrap poke-hi):from-helm -++ poke-helm-init (wrap poke-init):from-helm -++ poke-helm-invite (wrap poke-invite):from-helm -++ poke-helm-mass (wrap poke-mass):from-helm -++ poke-helm-reload (wrap poke-reload):from-helm -++ poke-helm-reload-desk (wrap poke-reload-desk):from-helm -++ poke-helm-reset (wrap poke-reset):from-helm -++ poke-helm-send-hi (wrap poke-send-hi):from-helm -++ poke-helm-verb (wrap poke-verb):from-helm -++ poke-helm-begin (wrap poke-begin):from-helm -++ poke-hood-sync (wrap poke-sync):from-kiln -++ poke-kiln-cp (wrap poke-cp):from-kiln -++ poke-kiln-label (wrap poke-label):from-kiln -++ poke-kiln-merge (wrap poke-merge):from-kiln -++ poke-kiln-mount (wrap poke-mount):from-kiln -++ poke-kiln-mv (wrap poke-mv):from-kiln -++ poke-kiln-rm (wrap poke-rm):from-kiln -++ poke-kiln-schedule (wrap poke-schedule):from-kiln -++ poke-kiln-sync (wrap poke-sync):from-kiln -++ poke-kiln-unmount (wrap poke-unmount):from-kiln -++ poke-kiln-unsync (wrap poke-unsync):from-kiln -++ poke-will (wrap poke-will):from-helm -++ quit-drum-phat (wrap quit-phat):from-drum -++ reap-drum-phat (wrap reap-phat):from-drum -++ woot-helm (wrap take-woot):from-helm -++ writ-kiln-sync (wrap take-writ):from-kiln +++ init-helm |=([way=wire *] [~ +>]) +++ made-kiln (wrap take-made):from-kiln +++ mere-kiln (wrap take-mere):from-kiln +++ mere-kiln-sync (wrap take-mere-sync):from-kiln +++ note-helm (wrap take-note):from-helm +++ onto-drum (wrap take-onto):from-drum +++ peer-drum (wrap peer):from-drum +++ poke-dill-belt (wrap poke-dill-belt):from-drum +++ poke-drum-link (wrap poke-link):from-drum +::++ poke-drum-exit (wrap poke-exit):from-drum +++ poke-drum-start (wrap poke-start):from-drum +++ poke-helm-hi (wrap poke-hi):from-helm +++ poke-helm-init (wrap poke-init):from-helm +++ poke-helm-invite (wrap poke-invite):from-helm +++ poke-helm-mass (wrap poke-mass):from-helm +++ poke-helm-reload (wrap poke-reload):from-helm +++ poke-helm-reload-desk (wrap poke-reload-desk):from-helm +++ poke-helm-reset (wrap poke-reset):from-helm +++ poke-helm-send-hi (wrap poke-send-hi):from-helm +++ poke-helm-verb (wrap poke-verb):from-helm +++ poke-helm-begin (wrap poke-begin):from-helm +++ poke-hood-sync (wrap poke-sync):from-kiln +++ poke-kiln-cp (wrap poke-cp):from-kiln +++ poke-kiln-label (wrap poke-label):from-kiln +++ poke-kiln-merge (wrap poke-merge):from-kiln +++ poke-kiln-cancel (wrap poke-cancel):from-kiln +++ poke-kiln-mount (wrap poke-mount):from-kiln +++ poke-kiln-mv (wrap poke-mv):from-kiln +++ poke-kiln-rm (wrap poke-rm):from-kiln +++ poke-kiln-schedule (wrap poke-schedule):from-kiln +++ poke-kiln-sync (wrap poke-sync):from-kiln +++ poke-kiln-start-autoload (wrap poke-start-autoload):from-kiln +++ poke-kiln-autoload (wrap poke-autoload):from-kiln +++ poke-kiln-unmount (wrap poke-unmount):from-kiln +++ poke-kiln-unsync (wrap poke-unsync):from-kiln +++ poke-will (wrap poke-will):from-helm +++ quit-drum-phat (wrap quit-phat):from-drum +++ reap-drum-phat (wrap reap-phat):from-drum +++ woot-helm (wrap take-woot):from-helm +++ writ-kiln-autoload (wrap take-writ-autoload):from-kiln +++ writ-kiln-sync (wrap take-writ-sync):from-kiln -- diff --git a/arvo/clay.hoon b/arvo/clay.hoon index f6c8f9bf3..e43c090fe 100644 --- a/arvo/clay.hoon +++ b/arvo/clay.hoon @@ -162,11 +162,7 @@ mer=mer.jod == =* red -> - =| yel=(list ,[p=duct q=gift]) - =| byn=(list ,[p=duct q=riot]) - =| reg=(list ,[p=duct q=gift]) - =| say=(list ,[p=duct q=path r=ship s=[p=@ud q=riff]]) - =| tag=(list move) + =| mow=(list move) |% ++ abet ^- [(list move) raft] @@ -176,23 +172,7 @@ ruf(hoy (~(put by hoy.ruf) her rug)) =+ dos=(~(put by dos.u.rom) syd [qyx dom dok mer]) ruf(fat (~(put by fat.ruf) her [(need hun) dos])) - ;: weld - %+ turn (flop yel) - |=([a=duct b=gift] [(need hun) %give b]) - :: - %+ turn (flop reg) - |=([a=duct b=gift] [a %give b]) - :: - %+ turn (flop byn) - |=([a=duct b=riot] [a %give [%writ b]]) - :: - %+ turn (flop say) - |= [a=duct b=path c=ship d=[p=@ud q=riff]] - :- a - [%pass b %a %wont [our c] [%c %question p.q.d (scot %ud p.d) ~] q.d] - :: - tag - == + (flop mow) :: ++ aver :: read |= mun=mood @@ -260,6 +240,14 @@ (mule |.(`~`~|([%expected-path got=p.pax] !!))) $(tay t.tay, can (~(put by can) ((hard path) q.q.pax) q.i.tay)) :: + ++ emit + |= mof=move + %_(+> mow [mof mow]) + :: + ++ emil + |= mof=(list move) + %_(+> mow (welp mof mow)) + :: ++ balk :: read and send |= [hen=duct cay=(unit (each cage lobe)) mun=mood] ^+ +> @@ -268,18 +256,18 @@ :: ++ bait |= [hen=duct tym=@da] - %_(+> tag :_(tag [hen %pass /tyme %t %wait tym])) + (emit hen %pass /tyme %t %wait tym) :: ++ best |= [hen=duct tym=@da] - %_(+> tag :_(tag [hen %pass /tyme %t %rest tym])) + (emit hen %pass /tyme %t %rest tym) :: ++ blab :: ship result |= [hen=duct mun=mood dat=(each cage lobe)] ^+ +> ?: ?=(%& -.dat) - +>.$(byn [[hen ~ [p.mun q.mun syd] r.mun p.dat] byn]) - =- +>.$(tag [- tag]) + (emit hen %give %writ ~ [p.mun q.mun syd] r.mun p.dat) + %- emit :* hen %pass [%blab p.mun (scot q.mun) syd r.mun] %f %exec our ~ [her syd q.mun] (lobe-to-silk:ze r.mun p.dat) == @@ -295,7 +283,15 @@ :: ++ blub :: ship stop |= hen=duct - %_(+> byn [[hen ~] byn]) + (emit hen %give %writ ~) + :: + ++ print-to-dill + |= [car=@tD tan=tank] + (emit (need hun) %give %note car tan) + :: + ++ send-over-ames + |= [a=duct b=path c=ship d=[p=@ud q=riff]] + (emit a %pass b %a %wont [our c] [%c %question p.q.d (scot %ud p.d) ~] q.d) :: ++ duce :: produce request |= rov=rove @@ -309,8 +305,10 @@ ?. ?=([%sing %v *] rav) rav [%many %| [%ud let.dom] `case`q.p.rav r.p.rav] =+ inx=nix.u.ref + =. +>+.$ + =< ?>(?=(^ ref) .) + (send-over-ames hen [(scot %ud inx) ~] her inx syd ~ vaw) %= +>+.$ - say [[hen [(scot %ud inx) ~] her [inx syd ~ vaw]] say] nix.u.ref +(nix.u.ref) bom.u.ref (~(put by bom.u.ref) inx [hen vaw]) fod.u.ref (~(put by fod.u.ref) hen inx) @@ -335,22 +333,19 @@ =+ mus=(skim can |=(paf=path =(pax (scag (lent pax) paf)))) ?~ mus +>.$ - %_ +>.$ - tag - :_ tag - :* hen %pass [%ergoing (scot %p her) syd ~] %f - %exec our ~ [her syd %da now] %tabl - ^- (list (pair silk silk)) - %+ turn `(list path)`mus - |= a=path - ^- (pair silk silk) - :- [%$ %path !>(a)] - :+ %cast %mime - =+ (need (need (read-x:ze let.dom a))) - ?: ?=(%& -<) - [%$ p.-] - (lobe-to-silk:ze a p.-) - == + %- emit + :* hen %pass [%ergoing (scot %p her) syd ~] %f + %exec our ~ [her syd %da now] %tabl + ^- (list (pair silk silk)) + %+ turn `(list path)`mus + |= a=path + ^- (pair silk silk) + :- [%$ %path !>(a)] + :+ %cast %mime + =+ (need (need (read-x:ze let.dom a))) + ?: ?=(%& -<) + [%$ p.-] + (lobe-to-silk:ze a p.-) == :: ++ ease :: release request @@ -364,8 +359,10 @@ |- ^+ +.$ =+ nux=(~(get by fod.u.ref) hen) ?~ nux +.$ + =. +.$ + =< ?>(?=(^ ref) .) + (send-over-ames hen [(scot %ud u.nux) ~] her u.nux syd ~) %= +.$ - say [[hen [(scot %ud u.nux) ~] her [u.nux syd ~]] say] fod.u.ref (~(del by fod.u.ref) hen) bom.u.ref (~(del by bom.u.ref) u.nux) == @@ -422,31 +419,19 @@ (duce `rove`[%many p.rav ptr q.q.rav r.q.rav ear]) == :: - ++ echa :: announce raw - |= [wen=@da mer=mizu] - ^+ +> - %= +> - reg ~& %merge-announce reg - :: yel [[hen %note '=' %leaf ~] yel] :: XX do better - == - :: ++ echo :: announce changes |= [wen=@da lem=nuri] ^+ +> - %_ +>.$ - yel - =+ pre=`path`~[(scot %p her) syd (scot %ud let.dom)] - ?- -.lem - | :_ yel - [hen %note '=' %leaf :(weld (trip p.lem) " " (spud pre))] - & |- ^+ yel - ?~ p.lem yel - :_ $(p.lem t.p.lem) - :- hen - :+ %note - ?-(-.q.i.p.lem %del '-', %ins '+', %dif ':') - [%leaf (spud (weld pre p.i.p.lem))] - == + =+ pre=`path`~[(scot %p her) syd (scot %ud let.dom)] + ?- -.lem + | (print-to-dill '=' %leaf :(weld (trip p.lem) " " (spud pre))) + & |- ^+ +>.^$ + ?~ p.lem +>.^$ + =. +>.^$ + %+ print-to-dill + ?-(-.q.i.p.lem %del '-', %ins '+', %dif ':') + [%leaf (spud (weld pre p.i.p.lem))] + $(p.lem t.p.lem) == :: ++ edit :: apply changes @@ -472,107 +457,97 @@ ?& ?=([?(%hoon %hook) *] (flop pax)) ?=(%mime p.p.mis) == - =- %_ +>.$ - tag (welp - tag) - dok - :- ~ - :* %+ turn del + =. +>.$ + %- emil + ^- (list move) + :~ :* hen %pass + [%inserting (scot %p her) syd (scot %da wen) ~] + %f %exec our ~ [her syd %da wen] %tabl + ^- (list (pair silk silk)) + %+ turn ins |= [pax=path mis=miso] - ?> ?=(%del -.mis) - pax - :: - %+ turn ink - |= [pax=path mis=miso] - ^- (pair path cage) ?> ?=(%ins -.mis) + :- [%$ %path -:!>(*path) pax] =+ =>((flop pax) ?~(. %$ i)) - [pax - [%atom %t] ((hard ,@t) +>.q.q.p.mis)] - :: - ~ - :: - %- mo + [%cast - [%$ p.mis]] + == + :* hen %pass + [%diffing (scot %p her) syd (scot %da wen) ~] + %f %exec our ~ [her syd %da wen] %tabl + ^- (list (pair silk silk)) %+ turn dif |= [pax=path mis=miso] ?> ?=(%dif -.mis) - [pax p.mis] - :: - ~ - :: - %- mo + =+ (need (need (read-x:ze let.dom pax))) + ?> ?=(%& -<) + :- [%$ %path -:!>(*path) pax] + [%pact [%$ p.-] [%$ p.mis]] + == + :* hen %pass + [%castifying (scot %p her) syd (scot %da wen) ~] + %f %exec our ~ [her syd %da wen] %tabl + ^- (list (pair silk silk)) %+ turn mut |= [pax=path mis=miso] ?> ?=(%mut -.mis) - [pax p.mis] - :: - ~ - :: - ~ - :: - %- mo ^- (list (pair path mime)) - ;: welp - ^- (list (pair path mime)) - %+ murn ins - |= [pax=path mis=miso] - ^- (unit (pair path mime)) - ?> ?=(%ins -.mis) - ?. ?=(%mime p.p.mis) - ~ - `[pax ((hard mime) q.q.p.mis)] - :: - ^- (list (pair path mime)) - %+ murn ink - |= [pax=path mis=miso] - ^- (unit (pair path mime)) - ?> ?=(%ins -.mis) - ?> ?=(%mime p.p.mis) - `[pax ((hard mime) q.q.p.mis)] - :: - ^- (list (pair path mime)) - %+ murn mut - |= [pax=path mis=miso] - ^- (unit (pair path mime)) - ?> ?=(%mut -.mis) - ?. ?=(%mime p.p.mis) - ~ - `[pax ((hard mime) q.q.p.mis)] - == + :- [%$ %path -:!>(*path) pax] + =+ (lobe-to-mark:ze (~(got by q:(aeon-to-yaki:ze let.dom)) pax)) + [%cast - [%$ p.mis]] == - == - ^- (list move) - :~ :* hen %pass - [%inserting (scot %p her) syd (scot %da wen) ~] - %f %exec our ~ [her syd %da wen] %tabl - ^- (list (pair silk silk)) - %+ turn ins + == + %_ +>.$ + dok + :- ~ + :* (turn del |=([pax=path mis=miso] ?>(?=(%del -.mis) pax))) + :: + %+ turn ink + |= [pax=path mis=miso] + ^- (pair path cage) + ?> ?=(%ins -.mis) + =+ =>((flop pax) ?~(. %$ i)) + [pax - [%atom %t] ((hard ,@t) +>.q.q.p.mis)] + :: + ~ + :: + (mo (turn dif |=([pax=path mis=miso] ?>(?=(%dif -.mis) [pax p.mis])))) + :: + ~ + :: + (mo (turn mut |=([pax=path mis=miso] ?>(?=(%mut -.mis) [pax p.mis])))) + :: + ~ + :: + ~ + :: + %- mo ^- (list (pair path mime)) + ;: welp + ^- (list (pair path mime)) + %+ murn ins |= [pax=path mis=miso] + ^- (unit (pair path mime)) ?> ?=(%ins -.mis) - :- [%$ %path -:!>(*path) pax] - =+ =>((flop pax) ?~(. %$ i)) - [%cast - [%$ p.mis]] - == - :* hen %pass - [%diffing (scot %p her) syd (scot %da wen) ~] - %f %exec our ~ [her syd %da wen] %tabl - ^- (list (pair silk silk)) - %+ turn dif + ?. ?=(%mime p.p.mis) + ~ + `[pax ((hard mime) q.q.p.mis)] + :: + ^- (list (pair path mime)) + %+ murn ink |= [pax=path mis=miso] - ?> ?=(%dif -.mis) - =+ (need (need (read-x:ze let.dom pax))) - ?> ?=(%& -<) - :- [%$ %path -:!>(*path) pax] - [%pact [%$ p.-] [%$ p.mis]] - == - :* hen %pass - [%castifying (scot %p her) syd (scot %da wen) ~] - %f %exec our ~ [her syd %da wen] %tabl - ^- (list (pair silk silk)) - %+ turn mut + ^- (unit (pair path mime)) + ?> ?=(%ins -.mis) + ?> ?=(%mime p.p.mis) + `[pax ((hard mime) q.q.p.mis)] + :: + ^- (list (pair path mime)) + %+ murn mut |= [pax=path mis=miso] + ^- (unit (pair path mime)) ?> ?=(%mut -.mis) - :- [%$ %path -:!>(*path) pax] - =+ (lobe-to-mark:ze (~(got by q:(aeon-to-yaki:ze let.dom)) pax)) - [%cast - [%$ p.mis]] - == + ?. ?=(%mime p.p.mis) + ~ + `[pax ((hard mime) q.q.p.mis)] + == + == == :: ++ silkify @@ -691,8 +666,7 @@ %+ turn cat |= [pax=path cay=cage] [pax (page-to-lobe:ze [p q.q]:cay)] - =- %_(+>.$ tag [- tag]) - ^- move + %- emit :* hen %pass [%mutating (scot %p her) syd (scot %da wen) ~] %f %exec our ~ [her syd %da wen] %tabl @@ -733,11 +707,8 @@ ^+ +> :: ~& %taking-patch ?: ?=(%| -.res) - %_ +>.$ - dok ~ - yel - [[hen %note '!' %rose [" " "" ""] leaf/"clay patch failed" p.res] yel] - == + =. dok ~ + (print-to-dill '!' %rose [" " "" ""] leaf/"clay patch failed" p.res) :: ~& %editing =+ ^- sim=(list (pair path misu)) ?~ dok @@ -795,38 +766,31 @@ =+ can=(mo sim) :: ~& %forming-ergo :: =- ~& %formed-ergo - - %_ +>.$ - dok ~ - tag - :_ tag - :* hen %pass [%ergoing (scot %p her) syd ~] %f - %exec our ~ [her syd %da now] %tabl - ^- (list (pair silk silk)) - %+ turn (~(tap in sum)) - |= a=path - ^- (pair silk silk) - :- [%$ %path !>(a)] - =+ b=(~(got by can) a) - ?: ?=(%del -.b) - [%$ %null !>(~)] - =+ (~(get by mim.u.dok) a) - ?^ - [%$ %mime !>(u.-)] - :+ %cast %mime - =+ (need (need (read-x:ze let.dom a))) - ?: ?=(%& -<) - [%$ p.-] - (lobe-to-silk:ze a p.-) - == + %- emit(dok ~) + :* hen %pass [%ergoing (scot %p her) syd ~] %f + %exec our ~ [her syd %da now] %tabl + ^- (list (pair silk silk)) + %+ turn (~(tap in sum)) + |= a=path + ^- (pair silk silk) + :- [%$ %path !>(a)] + =+ b=(~(got by can) a) + ?: ?=(%del -.b) + [%$ %null !>(~)] + =+ (~(get by mim.u.dok) a) + ?^ - [%$ %mime !>(u.-)] + :+ %cast %mime + =+ (need (need (read-x:ze let.dom a))) + ?: ?=(%& -<) + [%$ p.-] + (lobe-to-silk:ze a p.-) == :: ++ take-ergo |= res=gage ^+ +> ?: ?=(%| -.res) - %_ +>.$ - yel - [[hen %note '!' %rose [" " "" ""] leaf/"clay ergo failed" p.res] yel] - == + (print-to-dill '!' %rose [" " "" ""] leaf/"clay ergo failed" p.res) ?~ hez ~|(%no-sync-duct !!) =+ ^- can=(map path (unit mime)) %- mo ^- mode @@ -839,33 +803,27 @@ ~ `((hard mime) q.q.mim) =+ mus=(must-ergo (turn (~(tap by can)) head)) - %= +>.$ - reg - %- welp :_ reg - %+ turn (~(tap by mus)) - |= [pot=term len=@ud pak=(set path)] - :* u.hez %ergo pot - %+ turn (~(tap in pak)) - |= pax=path - [(slag len pax) (~(got by can) pax)] - == + %- emil + %+ turn (~(tap by mus)) + |= [pot=term len=@ud pak=(set path)] + :* u.hez %give %ergo pot + %+ turn (~(tap in pak)) + |= pax=path + [(slag len pax) (~(got by can) pax)] == :: ++ checkout-ankh |= hat=(map path lobe) ^+ +> - %_ +>.$ - tag - :_ tag - :* hen %pass [%patching (scot %p her) syd ~] %f - %exec our :^ ~ [her syd %da now] %tabl - ^- (list (pair silk silk)) - %+ turn (~(tap by hat)) - |= [a=path b=lobe] - ^- (pair silk silk) - :- [%$ %path-hash !>([a b])] - (lobe-to-silk:ze a b) - == + %- emit + :* hen %pass [%patching (scot %p her) syd ~] %f + %exec our :^ ~ [her syd %da now] %tabl + ^- (list (pair silk silk)) + %+ turn (~(tap by hat)) + |= [a=path b=lobe] + ^- (pair silk silk) + :- [%$ %path-hash !>([a b])] + (lobe-to-silk:ze a b) == :: ++ apply-foreign-update :: apply subscription @@ -1016,34 +974,10 @@ !! == :: - ++ rand-to-rant - |= rut=rand - ^+ +> - ~| [%x-over-network-not-implemented [p q -.r]:rut hen] !! - :: =- %_(+>.$ tag [- tag]) - :: :* hen - :: [%foreign-plops (scot %p our) (scot %p her) syd ~] - :: %f %exec our ~ %tabl - :: ^- (list (pair silk silk)) - :: %+ turn (~(tap in pop)) - :: |= a=plop - :: ?- -.a - :: %delta - :: :- [%$ %blob !>([%delta p.a q.a *cage])] - :: [%vale p.r.a q.r.a] - :: :: - :: %direct - :: :- [%$ %blob !>([%direct p.a *cage])] - :: [%vale p.q.a q.q.a] - :: :: - :: %indirect ~| %foreign-indirect-not-implemented !! - :: == - :: == - :: ++ validate-x |= [car=care cas=case pax=path peg=page] ^+ +> - =- %_(+>.$ tag [- tag]) + %- emit :* hen %pass [%foreign-x (scot %p our) (scot %p her) syd car (scot cas) pax] %f %exec our ~ [her syd cas] @@ -1065,8 +999,8 @@ ++ validate-plops |= [cas=case lem=(unit ,@da) pop=(set plop)] ^+ +> - =- %_(+>.$ tag [- tag]) =+ lum=(scot %da (fall lem *@da)) + %- emit :* hen %pass [%foreign-plops (scot %p our) (scot %p her) syd lum ~] %f %exec our ~ [her syd cas] %tabl @@ -1074,15 +1008,8 @@ %+ turn (~(tap in pop)) |= a=plop ?- -.a - %delta - :- [%$ %blob !>([%delta p.a q.a *page])] - [%vale p.r.a q.r.a] - :: - %direct - :- [%$ %blob !>([%direct p.a *page])] - [%vale p.q.a q.q.a] - :: - %indirect ~| %foreign-indirect-not-implemented !! + %delta [[%$ %blob !>([%delta p.a q.a *page])] [%vale p.r.a q.r.a]] + %direct [[%$ %blob !>([%direct p.a *page])] [%vale p.q.a q.q.a]] == == :: @@ -1101,7 +1028,6 @@ ?- -.bol %delta [-.bol p.bol q.bol p.cay q.q.cay] %direct [-.bol p.bol p.cay q.q.cay] - %indirect ~| %plop-indirect-not-implemented !! == %^ apply-foreign-update lem @@ -1219,6 +1145,15 @@ (bleb p.i.xiq +(u.nab) ?:(p.q.i.xiq ~ `[u.nab u.huy])) == == + ++ drop-me + ^+ . + ?~ mer + . + %- emit(mer ~) ^- move :* + hen.u.mer %give %mere %| %user-interrupt + >sor.u.mer< >our< >cas.u.mer< >gem.u.mer< ~ + == + :: ++ ze |% ++ aeon-to-tako ~(got by hit.dom) @@ -1231,7 +1166,6 @@ ?- - %delta p.q %direct p.q - %indirect p.q == ++ lobe-to-silk :: XX maybe move hoo{n,k} stuff here |= [pax=path lob=lobe] @@ -1249,7 +1183,6 @@ =+ bol=(~(got by lat.ran) lob) ?- -.bol %direct [%volt q.bol] - %indirect [%volt q.bol] %delta ~| delta/q.q.bol [%pact $(lob q.q.bol) [%volt r.bol]] == @@ -1482,7 +1415,6 @@ ?- -.gar %direct (~(put in far) lob) %delta (~(put in $(lob q.q.gar)) lob) - %indirect (~(put in $(lob r.gar)) lob) == :: ++ data-twixt-takos @@ -1530,6 +1462,15 @@ ~ ```[%null [%atom %n] ~] :: + ++ read-v + |= [yon=aeon pax=path] + ^- (unit (unit ,[%dome (hypo dome)])) + ?: (lth yon let.dom) + ~ + ?: (gth yon let.dom) + `~ + ``[%dome -:!>(*dome) dom] + :: ++ read-x |= [yon=aeon pax=path] ^- (unit (unit (each cage lobe))) @@ -1556,8 +1497,6 @@ =+ bol=(lobe-to-blob u.lob) ?: ?=(%direct -.bol) ((hard ,@t) q.q.bol) - ?: ?=(%indirect -.bol) - ((hard ,@t) q.q.bol) ?> ?=(%delta -.bol) =+ txt=$(u.lob q.q.bol) ?> ?=(%txt-diff p.r.bol) @@ -1611,6 +1550,8 @@ ?^(r.mun [~ ~] [~ ~ %& %aeon !>(yon)]) ?: ?=(%u p.mun) (read-u yon r.mun) + ?: ?=(%v p.mun) + (bind (read-v yon r.mun) (curr bind (cury same %&))) ?: ?=(%x p.mun) (read-x yon r.mun) ?: ?=(%y p.mun) @@ -1645,7 +1586,7 @@ :: %- ~(run by hat) :: |= a=lobe :: =+ (lobe-to-blob a) - :: ?-(-.- %direct q.-, %indirect q.-, %delta !!) + :: ?-(-.- %direct q.-, %delta !!) ::`+>.$(ank.dom (checkout-ankh -), let.dom yon) :: ++ update-lat :: update-lat:ze @@ -1716,7 +1657,17 @@ ^+ ..me ?: don ..me(mer `dat) - ..me(mer ~, reg :_(reg [hen %mere gon.dat])) + =. mer ~ + => (emit hen.dat %give %mere gon.dat) + ..me + :: + ++ emit + |= move + %_(+> ..ze (^emit +<)) + :: + ++ emil + |= (list move) + %_(+> ..ze (^emil +<)) :: ++ route |= [sat=term res=(each riot gage)] @@ -1759,7 +1710,7 @@ :: ++ fetch-ali ^+ . - =- %_(+ tag [- tag], wat.dat %ali) + %- emit(wat.dat %ali) :* hen %pass [%merge (scot %p p.bob) q.bob (scot %p p.ali) q.ali %ali ~] %c %warp [p.bob p.ali] q.ali @@ -1937,7 +1888,7 @@ ++ diff-bas |= [nam=term yak=yaki oth=(trel ship desk case) yuk=yaki] ^+ +> - =- %_(+>.$ tag [- tag]) + %- emit :* hen %pass =+ (cat 3 %diff- nam) [%merge (scot %p p.bob) q.bob (scot %p p.ali) q.ali - ~] @@ -1982,15 +1933,18 @@ |= [pax=path lob=lobe] (~(has by q.bas.dat) pax) =. cal.dal.dat - %- mo - %+ skim (~(tap by q.bas.dat)) + %- mo ^- (list (pair path lobe)) + %+ murn (~(tap by q.bas.dat)) |= [pax=path lob=lobe] + ^- (unit (pair path lobe)) =+ a=(~(get by q.ali.dat) pax) =+ b=(~(get by q.bob.dat) pax) - ?& ?=(^ a) - !=([~ lob] a) - =([~ lob] b) - == + ?. ?& ?=(^ a) + !=([~ lob] a) + =([~ lob] b) + == + ~ + `[pax +.a] =. can.dal.dat p.can =. old.dal.dat %- mo ^- (list ,[path ~]) @@ -2022,15 +1976,18 @@ |= [pax=path lob=lobe] (~(has by q.bas.dat) pax) =. cal.dob.dat - %- mo - %+ skim (~(tap by q.bas.dat)) + %- mo ^- (list (pair path lobe)) + %+ murn (~(tap by q.bas.dat)) |= [pax=path lob=lobe] + ^- (unit (pair path lobe)) =+ a=(~(get by q.ali.dat) pax) =+ b=(~(get by q.bob.dat) pax) - ?& ?=(^ b) - !=([~ lob] b) - =([~ lob] a) - == + ?. ?& ?=(^ b) + !=([~ lob] b) + =([~ lob] a) + == + ~ + `[pax +.b] =. can.dob.dat p.can =. old.dob.dat %- mo ^- (list ,[path ~]) @@ -2046,7 +2003,7 @@ |- ^+ +.$ ?+ gem.dat ~| [%merge-weird-gem gem.dat] !! ?(%mate %meld) - =- %_(+.$ tag [- tag], wat.dat %merge) + %- emit(wat.dat %merge) :* hen %pass [%merge (scot %p p.bob) q.bob (scot %p p.ali) q.ali %merge ~] %f %exec p.bob ~ [p.bob q.bob da/now] %tabl @@ -2080,7 +2037,7 @@ :: ++ build ^+ . - =- %_(+ tag [- tag], wat.dat %build) + %- emit(wat.dat %build) :* hen %pass [%merge (scot %p p.bob) q.bob (scot %p p.ali) q.ali %build ~] %f %exec p.bob ~ [p.bob q.bob da/now] %tabl @@ -2119,7 +2076,7 @@ %- ~(urn by con) |= [pax=path *] (~(got by q.bas.dat) pax) - =. con :: add/del conflict + =. con :: change/del conflict %- ~(uni by con) %- mo ^- (list ,[path *]) %+ skim (~(tap by old.dal.dat)) @@ -2128,7 +2085,7 @@ ~| %strange-add-and-del !! (~(has by can.dob.dat) pax) - =. con :: add/del conflict + =. con :: change/del conflict %- ~(uni by con) %- mo ^- (list ,[path *]) %+ skim (~(tap by old.dob.dat)) @@ -2175,6 +2132,13 @@ [(lobe-to-mark u.-) u.-] [p q.q]:cay [(~(put by hat) pax p.bol) (~(put by lat) p.bol bol)] + :: ~& old=(~(run by old) mug) + :: ~& newdal=(~(run by new.dal.dat) mug) + :: ~& newdob=(~(run by new.dob.dat) mug) + :: ~& caldal=(~(run by cal.dal.dat) mug) + :: ~& caldob=(~(run by cal.dob.dat) mug) + :: ~& hot=(~(run by hot) mug) + :: ~& cas=(~(run by cas) mug) =+ ^- hat=(map path lobe) :: all the content %- ~(uni by old) %- ~(uni by new.dal.dat) @@ -2183,6 +2147,7 @@ %- ~(uni by cal.dob.dat) %- ~(uni by hot) cas + :: ~& > hat=(~(run by hat) mug) =+ ^- del=(map path ,?) (~(run by (~(uni by old.dal.dat) old.dob.dat)) |=(~ %|)) =. gon.dat [%& (sa (turn (~(tap by con)) head))] @@ -2201,11 +2166,11 @@ :: ++ checkout ^+ . - =- %_(+ tag [- tag], wat.dat %checkout) =+ ^- val=beak ?: ?=(%init gem.dat) [p.ali q.ali cas.dat] [p.bob q.bob da/now] + %- emit(wat.dat %checkout) :* hen %pass [%merge (scot %p p.bob) q.bob (scot %p p.ali) q.ali %checkout ~] %f %exec p.bob ~ val %tabl @@ -2244,7 +2209,6 @@ :: ++ ergo ^+ . - =- %_(+ tag [- tag], wat.dat %ergo) =+ ^- sum=(set path) =+ (must-ergo (turn (~(tap by erg.dat)) head)) =+ (turn (~(tap by -)) (corl tail tail)) @@ -2256,6 +2220,7 @@ ?: ?=(%init gem.dat) [p.ali q.ali cas.dat] [p.bob q.bob da/now] + %- emit(wat.dat %ergo) :* hen %pass [%merge (scot %p p.bob) q.bob (scot %p p.ali) q.ali %ergo ~] %f %exec p.bob ~ val %tabl @@ -2292,17 +2257,15 @@ (error:he %ergo-no-hez ~) ?: ?=(%| -.gon.dat) +>.$ - %* done he - reg - =+ mus=(must-ergo (turn (~(tap by erg.dat)) head)) - %- welp :_ reg - %+ turn (~(tap by mus)) - |= [pot=term len=@ud pak=(set path)] - :* u.hez %ergo pot - %+ turn (~(tap in pak)) - |= pax=path - [(slag len pax) (~(got by can) pax)] - == + =+ mus=(must-ergo (turn (~(tap by erg.dat)) head)) + =< done:he + %- emil + %+ turn (~(tap by mus)) + |= [pot=term len=@ud pak=(set path)] + :* u.hez %give %ergo pot + %+ turn (~(tap in pak)) + |= pax=path + [(slag len pax) (~(got by can) pax)] == :: ++ he @@ -2350,7 +2313,6 @@ =+ bol=(~(got by lat.ran) lob) ?- -.bol %direct [%volt q.bol] - %indirect [%volt q.bol] %delta [%pact $(lob q.q.bol) [%volt r.bol]] == :: @@ -2408,6 +2370,20 @@ %boat :_ ..^$ [hen %give %hill (turn (~(tap by mon.ruf)) head)]~ + :: + %drop + =^ mos ruf + =+ den=((de now hen ruf) [. .]:p.q.hic q.q.hic) + abet:drop-me:den + [mos ..^$] + :: + %info + ?: =(%$ q.q.hic) + [~ ..^$] + =^ mos ruf + =+ den=((de now hen ruf) [. .]:p.q.hic q.q.hic) + abet:(exec:den now r.q.hic) + [mos ..^$] :: %init :_ %_ ..^$ @@ -2422,14 +2398,6 @@ :: ~ == - :: - %info - ?: =(%$ q.q.hic) - [~ ..^$] - =^ mos ruf - =+ den=((de now hen ruf) [. .]:p.q.hic q.q.hic) - abet:(exec:den now r.q.hic) - [mos ..^$] :: %into =. hez.ruf `hen diff --git a/arvo/dill.hoon b/arvo/dill.hoon index 42c21e764..e5ce33127 100644 --- a/arvo/dill.hoon +++ b/arvo/dill.hoon @@ -216,6 +216,7 @@ =. +> (sync %home our %base) =. +> ?. ?=(?(%king %czar) can) +> (sync %kids our %base) + =. +> autoload =. +> peer |- ^+ +>+ ?~ myt +>+ @@ -255,7 +256,18 @@ %_ +>.$ moz :_ moz - [hen %pass ~ %g %deal [our our] ram %poke %hood-sync -:!>(syn) syn] + :* hen %pass /sync %g %deal [our our] + ram %poke %hood-sync -:!>(syn) syn + == + == + :: + ++ autoload + %_ . + moz + :_ moz + :* hen %pass /autoload %g %deal [our our] + ram %poke %kiln-start-autoload [%cube ~ [%atom %n]] ~ + == == :: ++ pump :: send diff ack diff --git a/arvo/gall.hoon b/arvo/gall.hoon index 05664dd45..645ec68be 100644 --- a/arvo/gall.hoon +++ b/arvo/gall.hoon @@ -1122,6 +1122,7 @@ %deal `%g %exec `%f %flog `%d + %drop `%c %info `%c %merg `%c %mont `%c diff --git a/arvo/zuse.hoon b/arvo/zuse.hoon index f6d71674f..08b2e31ae 100644 --- a/arvo/zuse.hoon +++ b/arvo/zuse.hoon @@ -1836,7 +1836,6 @@ ++ blob :: fs blob $% [%delta p=lobe q=[p=mark q=lobe] r=page] :: delta on q [%direct p=lobe q=page] :: immediate - [%indirect p=lobe q=page r=lobe s=page] :: both == :: ++ boat (map (pair bone wire) (trel bean ship path)) :: outgoing subs ++ boon :: fort output @@ -2360,6 +2359,7 @@ == :: ++ kiss-clay :: in request ->$ $% [%boat ~] :: pier rebooted + [%drop p=@p q=@tas] :: cancel pending merge [%info p=@p q=@tas r=nori] :: internal edit [%init p=@p] :: report install [%into p=@tas q=? r=mode] :: external edit diff --git a/gen/hood/autoload.hoon b/gen/hood/autoload.hoon new file mode 100644 index 000000000..5476276a1 --- /dev/null +++ b/gen/hood/autoload.hoon @@ -0,0 +1,13 @@ +:: +:::: /hoon/autoload/hood/gen + :: +/? 314 +:: +:::: + !: +:- %say +|= $: [now=@da eny=@uvI bec=beak] + [arg=?(~ [? ~]) ~] + == +:- %kiln-autoload +`(unit ,?)`?~(arg ~ `-.arg) diff --git a/lib/kiln.hoon b/lib/kiln.hoon index 44c022ded..54d21eda7 100644 --- a/lib/kiln.hoon +++ b/lib/kiln.hoon @@ -10,6 +10,7 @@ ++ kiln-pith :: $: rem=(map desk kiln-desk) :: syn=(map kiln-sync ,[let=@ud ust=bone]) :: + autoload=? :: == :: ++ kiln-desk :: per-desk state $: auto=? :: escalate on failure @@ -54,6 +55,7 @@ => |% :: arvo structures ++ card :: $% [%exec wire @p ~ [beak silk]] :: + [%drop wire @p @tas] :: [%info wire @p @tas nori] :: [%mont wire @tas @p @tas path] :: [%ogre wire $|(@tas beam)] :: @@ -64,6 +66,8 @@ ++ pear :: poke fruit $% [%talk-command command:talk] :: [%kiln-merge kiln-merge] :: + [%helm-reload (list term)] :: + [%helm-reset ~] :: == :: ++ move (pair bone card) :: user-level move -- @@ -118,6 +122,10 @@ |= kiln-merge abet:abet:(merge:(work syd) ali sud gim) :: +++ poke-cancel + |= syd=desk + abet:(emit %drop /cancel our syd) +:: ++ do-info |= [mez=tape tor=toro] abet:(emit:(spam leaf/mez ~) %info /kiln our tor) @@ -148,6 +156,25 @@ =+ old=;;((map ,@da cord) (fall (file where) ~)) (foal where %sched !>((~(put by old) tym eve))) :: +++ poke-autoload + |= lod=(unit ,?) + ?^ lod + abet(autoload u.lod) + =< abet(autoload !autoload) + (spam leaf/"turning autoload o{?:(autoload "ff" "n")}" ~) +:: +++ poke-start-autoload + |= ~ + =< abet + %- emil + %+ turn + `(list term)`~[%ames %behn %clay %dill %eyre %ford %gall %zuse %hoon] + |= syd=term + ^- card + :* %warp /kiln/autoload/[syd] [our our] %home ~ + %next %y da/now /arvo/[syd]/hoon + == +:: ++ take |=(way=wire ?>(?=([@ ~] way) (work i.way))) :: general handler ++ take-mere :: |= [way=wire are=(each (set path) (pair term tang))] @@ -171,7 +198,7 @@ == abet:abet:(mere:(auto hos) mes) :: -++ take-writ :: +++ take-writ-sync :: |= [way=wire rot=riot] ?> ?=([@ @ @ ~] way) =+ ^- hos=kiln-sync @@ -181,6 +208,24 @@ == abet:abet:(writ:(auto hos) rot) :: +++ take-writ-autoload + |= [way=wire rot=riot] + ?> ?=([@ ~] way) + ?> ?=(^ rot) + =+ syd=(slav %tas i.way) + =. +>.$ + ?. autoload + +>.$ + ?: ?=(%hoon syd) + (emit %poke /kiln/reload/[syd] [our %hood] %helm-reset ~) + (emit %poke /kiln/reload/[syd] [our %hood] %helm-reload ~[syd]) + =. +>.$ + %- emit :* + %warp /kiln/autoload/[syd] [our our] %home ~ + %next %y da/now /arvo/[syd]/hoon + == + abet +:: ++ spam |= mes=(list tank) ((slog mes) ..spam) @@ -244,7 +289,7 @@ ?+ p.p.mes :* (render "sync failed" sud her syd) leaf/"please manually merge the desks with" - leaf/":+merge %{(trip syd)} {(scow %p her)} %{(trip sud)}" + leaf/"|merge %{(trip syd)} {(scow %p her)} %{(trip sud)}" leaf/"" leaf/"error code: {}" q.p.mes @@ -457,7 +502,7 @@ """ done setting up scratch space in {<[-]>} please resolve the following conflicts and run - :+merge {} our {<[-]>} + |merge {} our {<[-]>} """ %^ tanks-if-any "annotated conflicts in:" annotated diff --git a/pub/doc/arvo/clay/architecture.md b/pub/doc/arvo/clay/architecture.md new file mode 100644 index 000000000..ed65ccd26 --- /dev/null +++ b/pub/doc/arvo/clay/architecture.md @@ -0,0 +1,415 @@ +# clay + +## high-level + +clay is the primary filesystem for the arvo operating system, +which is the core of an urbit. The architecture of clay is +intrinsically connected with arvo, but we assume no knowledge of +either arvo or urbit. We will point out only those features of +arvo that are necessary for an understanding of clay, and we will +do so only when they arise. + +The first relevant feature of arvo is that it is a deterministic +system where input and output are defined as a series of events +and effects. The state of arvo is simply a function of its event +log. None of the effects from an event are emitted until the +event is entered in the log and persisted, either to disk or +another trusted source of persistence, such as a Kafka cluster. +Consequently, arvo is a single-level store: everything in its +state is persistent. + +In a more traditional OS, everything in RAM can be erased at any +time by power failure, and is always erased on reboot. Thus, a +primary purpose of a filesystem is to ensure files persist across +power failures and reboots. In arvo, both power failures and +reboots are special cases of suspending computation, which is +done safely since our event log is already persistent. Therefore, +clay is not needed in arvo for persistence. Why, then, do we have a +filesystem? There are two answers to this question. + +First, clay provides a filesystem tree, which is a convenient +user interface for some applications. Unix has the useful concept +of virtual filesystems, which are used for everything from direct +access to devices, to random number generators, to the /proc +tree. It is easy and intuitive to read from and write to a +filesystem tree. + +Second, clay has a distributed revision control system baked into +it. Traditional filesystems are not revision controlled, so +userspace software -- such as git -- is written on top of them to +do so. clay natively provides the same functionality as modern +DVCSes, and more. + +clay has two other unique properties that we'll cover later on: +it supports typed data and is referentially transparent. + +### Revision Control + +Every urbit has one or more "desks", which are independently +revision-controlled branches. Each desk contains its own mark +definitions, apps, doc, and so forth. + +Traditionally, an urbit has at least a base and a home desk. The +base desk has all the system software from the distribution. the +home desk is a fork of base with all the stuff specific to the +user of the urbit. + +A desk is a series of numbered commits, the most recent of which +represents the current state of the desk. A commit is composed of +(1) an absolute time when it was created, (2) a list of zero or +more parents, and (3) a map from paths to data. + +Most commits have exactly one parent, but the initial commit on a +desk may have zero parents, and merge commits have more than one +parent. + +The non-meta data is stored in the map of paths to data. It's +worth noting that no constraints are put on this map, so, for +example, both /a/b and /a/b/c could have data. This is impossible +in a traditional Unix filesystem since it means that /a/b is both +a file and a directory. Conventionally, the final element in the +path is its mark -- much like a filename extension in Unix. Thus, +/doc/readme.md in Unix is stored as /doc/readme/md in urbit. + +The data is not stored directly in the map; rather, a hash of the +data is stored, and we maintain a master blob store. Thus, if the +same data is referred to in multiple commits (as, for example, +when a file doesn't change between commits), only the hash is +duplicated. + +In the master blob store, we either store the data directly, or +else we store a diff against another blob. The hash is dependent +only on the data within and not on whether or not it's stored +directly, so we may on occasion rearrange the contents of the +blob store for performance reasons. + +Recall that a desk is a series of numbered commits. Not every +commit in a desk must be numbered. For example, if the base desk +has had 50 commits since home was forked from it, then a merge +from base to home will only add a single revision number to home, +although the full commit history will be accessible by traversing +the parentage of the individual commits. + +We do guarantee that the first commit is numbered 1, commits are +numbered consecutively after that (i.e. there are no "holes"), +the topmost commit is always numbered, and every numbered commit +is an ancestor of every later numbered commit. + +There are three ways to refer to particular commits in the +revision history. Firstly, one can use the revision number. +Secondly, one can use any absolute time between the one numbered +commit and the next (inclusive of the first, exclusive of the +second). Thirdly, every desk has a map of labels to revision +numbers. These labels may be used to refer to specific commits. + +Additionally, clay is a global filesystem, so data on other urbit +is easily accessible the same way as data on our local urbit. In +general, the path to a particular revision of a desk is +/~urbit-name/desk-name/revision. Thus, to get /try/readme/md +from revision 5 of the home desk on ~sampel-sipnym, we refer to +/~sampel-sipnym/home/5/try/readme/md. Clay's namespace is thus +global and referentially transparent. + +XXX reactivity here? + +### A Typed Filesystem + +Since clay is a general filesystem for storing data of arbitrary +types, in order to revision control correctly it needs to be +aware of types all the way through. Traditional revision control +does an excellent job of handling source code, so for source code +we act very similar to traditional revision control. The +challenge is to handle other data similarly well. + +For example, modern VCSs generally support "binary files", which +are files for which the standard textual diffing, patching, and +merging algorithms are not helpful. A "diff" of two binary files +is just a pair of the files, "patching" this diff is just +replacing the old file with the new one, and "merging" +non-identical diffs is always a conflict, which can't even be +helpfully annotated. Without knowing anything about the structure +of a blob of data, this is the best we can do. + +Often, though, "binary" files have some internal structure, and +it is possible to create diff, patch, and merge algorithms that +take advantage of this structure. An image may be the result of a +base image with some set of operations applied. With algorithms +aware of this set of operations, not only can revision control +software save space by not having to save every revision of the +image individually, these transformations can be made on parallel +branches and merged at will. + +Suppose Alice is tasked with touching up a picture, improving the +color balance, adjusting the contrast, and so forth, while Bob +has the job of cropping the picture to fit where it's needed and +adding textual overlay. Without type-aware revision control, +these changes must be made serially, requiring Alice and Bob to +explicitly coordinate their efforts. With type-aware revision +control, these operations may be performed in parallel, and then +the two changesets can be merged programmatically. + +Of course, even some kinds of text files may be better served by +diff, patch, and merge algorithms aware of the structure of the +files. Consider a file containing a pretty-printed JSON object. +Small changes in the JSON object may result in rather significant +changes in how the object is pretty-printed (for example, by +addding an indentation level, splitting a single line into +multiple lines). + +A text file wrapped at 80 columns also reacts suboptimally with +unadorned Hunt-McIlroy diffs. A single word inserted in a +paragraph may push the final word or two of the line onto the +next line, and the entire rest of the paragraph may be flagged as +a change. Two diffs consisting of a single added word to +different sentences may be flagged as a conflict. In general, +prose should be diffed by sentence, not by line. + +As far as the author is aware, clay is the first generalized, +type-aware revision control system. We'll go into the workings +of this system in some detail. + +### Marks + +Central to a typed filesystem is the idea of types. In clay, we +call these "marks". A mark is a file that defines a type, +conversion routines to and from the mark, and diff, patch, and +merge routines. + +For example, a `%txt` mark may be a list of lines of text, and it +may include conversions to `%mime` to allow it to be serialized +and sent to a browswer or to the unix filesystem. It will also +include Hunt-McIlroy diff, patch, and merge algorithms. + +A `%json` mark would be defined as a json object in the code, and +it would have a parser to convert from `%txt` and a printer to +convert back to `%txt`. The diff, patch, and merge algorithms are +fairly straightforward for json, though they're very different +from the text ones. + +More formally, a mark is a core with three arms, `++grab`, +`++grow`, and `++grad`. In `++grab` is a series of functions to +convert from other marks to the given mark. In `++grow` is a +series of functions to convert from the given mark to other +marks. In `++grad` is `++diff`, `++pact`, `++join`, and `++mash`. + +The types are as follows, in an informal pseudocode: + + ++ grab: + ++ mime: -> + ++ txt: -> + ... + ++ grow: + ++ mime: -> + ++ txt: -> + ... + ++ grad + ++ diff: (, ) -> + ++ pact: (, ) -> + ++ join: (, ) -> or NULL + ++ mash: (, ) -> + +These types are basically what you would expect. Not every mark +has each of these functions defined -- all of them are optional +in the general case. + +In general, for a particular mark, the `++grab` and `++grow` entries +(if they exist) should be inverses of each other. + +In `++grad`, `++diff` takes two instances of a mark and produces +a diff of them. `++pact` takes an instance of a mark and patches +it with the given diff. `++join` takes two diffs and attempts to +merge them into a single diff. If there are conflicts, it +produces null. `++mash` takes two diffs and forces a merge, +annotating any conflicts. + +In general, if `++diff` called with A and B produces diff D, then +`++pact` called with A and D should produce B. Also, if `++join` +of two diffs does not produce null, then `++mash` of the same +diffs should produce the same result. + +Alternately, instead of `++diff`, `++pact`, `++join`, and +`++mash`, a mark can provide the same functionality by defining +`++sted` to be the name of another mark to which we wish to +delegate the revision control responsibilities. Then, before +running any of those functions, clay will convert to the other +mark, and convert back afterward. For example, the `%hoon` mark +is revision-controlled in the same way as `%txt`, so its `++grad` +is simply `++sted %txt`. Of course, `++txt` must be defined in +`++grow` and `++grab` as well. + +Every file in clay has a mark, and that mark must have a +fully-functioning `++grad`. Marks are used for more than just +clay, and other marks don't need a `++grad`, but if a piece of +data is to be saved to clay, we must know how to revision-control +it. + +Additionally, if a file is to be synced out to unix, then it must +have conversion routines to and from the `%mime` mark. + +##Using clay + +### Reading and Subscribing + +When reading from Clay, there are three types of requests. A +`%sing` request asks for data at single revsion. A `%next` +request asks to be notified the next time there's a change to +given file. A `%many` request asks to be notified on every +change in a desk for a range of changes. + +For `%sing` and `%next`, there are generally three things to be +queried. A `%u` request simply checks for the existence of a +file at a path. A `%x` request gets the data in the file at a +path. A `%y` request gets a hash of the data in the file at the +path combined with all its children and their data. Thus, `%y` +of a node changes if it or any of its children change. + +A `%sing` request is fulfilled immediately if possible. If the +requested revision is in the future, or is on another ship for +which we don't have the result cached, we don't respond +immediately. If the requested revision is in the future, we wait +until the revision happens before we respond to the request. If +the request is for data on another ship, we pass on the request +to the other ship. In general, Clay subscriptions, like most +things in Urbit, aren't guaranteed to return immediately. +They'll return when they can, and they'll do so in a +referentially transparent manner. + +A `%next` request checks query at the given revision, and it +produces the result of the query the next time it changes, along +with the revsion number when it changes. Thus, a `%next` of a +`%u` is triggered when a file is added or deleted, a `%next of a +`%x` is triggered when a file is added, deleted, or changed, and +a `%next` of a `%y` is triggered when a file or any of its +children is added, deleted, or changed. + +A `%many` request is triggered every time the given desk has a +new revision. Unlike a `%next`, a `%many` has both a start and +an end revsion, after which it stops returning. For `%next`, a +single change is reported, and if the caller wishes to hear of +the next change, it must resubscribe. For `%many`, every revsion +from the start to the end triggers a response. Since a `%many` +request doesn't ask for any particular data, there aren't `%u`, +`%x`, and `%y` versions for it. + +### Unix sync + +One of the primary functions of clay is as a convenient user +interface. While tools exist to use clay from within urbit, it's +often useful to be able to treat clay like any other filesystem +from the Unix perspective -- to "mount" it, as it were. + +From urbit, you can run `|mount /path/to/directory %mount-point`, +and this will mount the given clay directory to the mount-point +directory in Unix. Every file is converted to `%mime` before it's +written to Unix, and converted back when read from Unix. The +entire directory is watched (a la Dropbox), and every change is +auto-committed to clay. + +### Merging + +Merging is a fundamental operation for a distributed revision +control system. At their root, clay's merges are similar to +git's, but with some additions to accomodate typed data. There +are seven different merge strategies. + +Throughout our discussion, we'll say that the merge is from +Alice's desk to Bob's. Recall that a commit is a date (for all +new commits this will be the current date), a list of parents, +and the data itself. + +A `%init` merge should be used iff it's the first commit to a +desk. The head of Alice's desk is used as the number 1 commit to +Bob's desk. Obviously, the ancestry remains intact through +traversing the parentage of the commit even though previous +commits are not numbered for Bob's desk. + +A `%this` merge means to keep what's in Bob's desk, but join the +ancestry. Thus, the new commit has the head of each desk as +parents, but the data is exactly what's in Bob's desk. For those +following along in git, this is the 'ours' merge strategy, not +the '--ours' option to the 'recursive' merge strategy. In other +words, even if Alice makes a change that does not conflict with +Bob, we throw it away. It's Bob's way or the highway. + +A `%that` merge means to take what's in Alice's desk, but join +the ancestry. This is the reverse of `%this`. + +A `%fine` merge is a "fast-forward" merge. This succeeds iff one +head is in the ancestry of the other. In this case, we use the +descendant as our new head. + +For `%meet`, `%mate`, and `%meld` merges, we first find the most +recent common ancestor to use as our merge base. If we have no +common ancestors, then we fail. If we have more than one most +recent common ancestor, then we have a criss-cross situation, +which should be handled delicately. At present, we delicately +throw up our hands and give up, but something akin to git's +'recursive' strategy should be implemented in the future. + +There's a functional inclusion ordering on `%fine`, `%meet`, +`%mate`, and `%meld` such that if an earlier strategy would have +succeeded, then every later strategy will produce the same +result. Put another way, every earlier strategy is the same as +every later strategy except with a restricted domain. + +A `%meet` merge only succeeds if the changes from the merge base +to Alice's head (hereafter, "Alice's changes") are in different +files than Bob's changes. In this case, the parents are both +Alice's and Bob's heads, and the data is the merge base plus +Alice's changed files plus Bob's changed files. + +A `%mate` merge attempts to merge changes to the same file when +both Alice and bob change it. If the merge is clean, we use it; +otherwise, we fail. A merge between different types of changes -- +for example, deleting a file vs changing it -- is always a +conflict. If we succeed, the parents are both Alice's and Bob's +heads, and the data is the merge base plus Alice's changed files +plus Bob's changed files plus the merged files. + +A `%meld` merge will succeed even if there are conflicts. If +there are conflicts in a file, then we use the merge base's +version of that file, and we produce a set of files with +conflicts. The parents are both Alice's and Bob's heads, and the +data is the merge base plus Alice's changed files plus Bob's +changed files plus the successfully merged files plus the merge +base's version of the conflicting files. + +That's the extent of the merge options in clay proper. In +userspace there's a final option `%auto`, which is the most +common. `%auto` checks to see if Bob's desk exists, and if it +doesn't we use a `%init` merge. Otherwise, we progressively try +`%fine`, `%meet`, and `%mate` until one succeeds. + +If none succeed, we merge Bob's desk into a scratch desk. Then, +we merge Alice's desk into the scratch desk with the `%meld` +option to force the merge. For each file in the produced set of +conflicting files, we call the `++mash` function for the +appropriate mark, which annotates the conflicts if we know how. + +Finally, we display a message to the user informing them of the +scratch desk's existence, which files have annotated conflicts, +and which files have unannotated conflicts. When the user has +resolved the conflicts, they can merge the scratch desk back into +Bob's desk. This will be a `%fine` merge since Bob's head is in +the ancestry of the scratch desk. + +### Autosync + +Tracking and staying in sync with another desk is another +fundamental operation. We call this "autosync". This doesn't mean +simply mirroring a desk, since that wouldn't allow local changes. +We simply want to apply changes as they are made upstream, as +long as there are no conflicts with local changes. + +This is implemented by watching the other desk, and, when it has +changes, merging these changes into our desk with the usual merge +strategies. + +Note that it's quite reasonable for two desks to be autosynced to +each other. This results in any change on one desk being mirrored +to the other and vice versa. + +Additionally, it's fine to set up an autosync even if one desk, +the other desk, or both desks do not exist. The sync will be +activated when the upstream desk comes into existence and will +create the downstream desk if needed.