diff --git a/pkg/arvo/gen/hood/story-init.hoon b/pkg/arvo/gen/hood/story-init.hoon index 47a9c69c2..b0be3e79f 100644 --- a/pkg/arvo/gen/hood/story-init.hoon +++ b/pkg/arvo/gen/hood/story-init.hoon @@ -9,13 +9,13 @@ :: :: Create a story file for a given desk :: -=/ our p.bec +=/ our p.bec =? desk =(*^desk desk) q.bec :: use current desk if user didn't provide -=/ existing-story .^(? %cu /(scot %p our)/[desk]/(scot %da now)/story) +=/ existing-story .^(? %cu /(scot %p our)/[desk]/(scot %da now)/story) ?: ?&(existing-story !overwrite) - ~& >> "Error: {}/story already exists. Set the optional parameter `overwrite` to `%.y` to forcibly wipe" + ~& >> "Error: /{(trip (slav %tas desk))}/story already exists. Set the optional parameter `overwrite` to `%.y` to forcibly overwrite." :: XX could use a better way to noop - :- %helm-pass [%d %noop ~] + helm-pass+[%d %noop ~] =| tale=story :- %helm-pass [%c [%info desk %& [/story %ins story+!>(tale)]~]] \ No newline at end of file diff --git a/pkg/arvo/gen/hood/story-remove.hoon b/pkg/arvo/gen/hood/story-remove.hoon index 9296cd524..1059403f6 100644 --- a/pkg/arvo/gen/hood/story-remove.hoon +++ b/pkg/arvo/gen/hood/story-remove.hoon @@ -4,15 +4,20 @@ /- *story :- %say |= $: [now=@da eny=@uvJ bec=beak] - [[syd=desk =aeon:clay ~] ~] + [[syd=desk ~] cas=case ~] == :: -:: Remove a commit message to a given case on a given desk +:: Remove any commit message(s) for a given case and desk :: -=/ our p.bec -:: XX should `base` here be syd or q.bec -=/ tak .^(tako:clay %cs /(scot %p our)/base/(scot %ud aeon)/tako/~) -=/ tale=story .^(story %cx /(scot %p our)/[syd]/(scot %da now)/story) -=. tale (~(del ju tale) tak) +:: XX: story set and story init both have desk and case as optional. +:: however, it seems a bit odd to allow both optional here +:: since we're dealing with a more hazardous operation. +:: should we allow a bare `|story-remove` to remove the last commit message on the current desk? +:: leaning towards no, and potentially even making the case non-optional +=/ our p.bec +=? cas =(*case cas) da+now :: use current commit if cas not provided +=/ tak .^(tako:clay %cs /(scot %p our)/[syd]/(scot cas)/tako/~) +=/ tale=story .^(story %cx /(scot %p our)/[syd]/(scot %da now)/story) +=. tale (~(del ju tale) tak) :- %helm-pass [%c [%info syd %& [/story %ins story+!>(tale)]~]] \ No newline at end of file diff --git a/pkg/arvo/gen/hood/story-set.hoon b/pkg/arvo/gen/hood/story-set.hoon index cf4d138cf..cb587ec1f 100644 --- a/pkg/arvo/gen/hood/story-set.hoon +++ b/pkg/arvo/gen/hood/story-set.hoon @@ -4,15 +4,16 @@ /- *story :- %say |= $: [now=@da eny=@uvJ bec=beak] - [[syd=desk =prose ~] cas=case ~] + [[=prose ~] =desk cas=case ~] == :: -:: Add a commit message to a given case on a given desk (modifies in place) +:: Add a commit message to a given case on a given desk. Stores conflicting messages. :: -=/ our p.bec -=? cas =(*case cas) [%da now] :: set current commit when cas not provided -=/ tak .^(tako:clay %cs /(scot %p our)/[syd]/(scot cas)/tako/~) -=/ tale=story .^(story %cx /(scot %p our)/[syd]/(scot %da now)/story) -=. tale (~(put ju tale) tak prose) +=/ our p.bec +=? desk =(*^desk desk) q.bec :: use current desk if user didn't provide +=? cas =(*case cas) da+now :: use current commit if cas not provided +=/ tak .^(tako:clay %cs /(scot %p our)/[desk]/(scot cas)/tako/~) +=/ tale=story .^(story %cx /(scot %p our)/[desk]/(scot %da now)/story) +=. tale (~(put ju tale) tak prose) :- %helm-pass -[%c [%info syd %& [/story %ins story+!>(tale)]~]] \ No newline at end of file +[%c [%info desk %& [/story %ins story+!>(tale)]~]] \ No newline at end of file diff --git a/pkg/arvo/gen/story-list.hoon b/pkg/arvo/gen/story-list.hoon index 2e8dd9320..ce3c570a4 100644 --- a/pkg/arvo/gen/story-list.hoon +++ b/pkg/arvo/gen/story-list.hoon @@ -7,13 +7,13 @@ [[syd=desk ~] ~] == :: -:: List all commit messages for the given desk +:: (Internal) List all commit messages for the given desk, +:: including orphans (i.e. ones that have no connection to the file graph) :: -:: TODO remove this outdated generator, superseded by story-log -=/ our p.bec -=/ tale=story .^(story %cx /(scot %p our)/[syd]/(scot %da now)/story) +=/ our p.bec +=/ tale=story .^(story %cx /(scot %p our)/[syd]/(scot %da now)/story) =/ story-to-mime .^($-(story mime) %cf /(scot %p our)/[syd]/(scot %da now)/story/mime) -=/ tale-mime (story-to-mime tale) -=/ tale-text `@t`q.q.tale-mime +=/ tale-mime (story-to-mime tale) +=/ tale-text `@t`q.q.tale-mime :- %tang [tale-text ~] \ No newline at end of file diff --git a/pkg/arvo/gen/story-log.hoon b/pkg/arvo/gen/story-log.hoon index 99e584f4d..64caa3e1a 100644 --- a/pkg/arvo/gen/story-log.hoon +++ b/pkg/arvo/gen/story-log.hoon @@ -5,17 +5,100 @@ /+ lib=story :- %say |= $: [now=@da eny=@uvJ bec=beak] - [[syd=desk ~] ~] + [[~] =desk ~] == |^ -=/ our p.bec -=/ cas `case`[%da now] -=/ tale .^(story %cx /(scot %p our)/[syd]/(scot %da now)/story) -=/ current-tako .^(tako:clay %cs /(scot %p our)/[syd]/(scot cas)/tako/~) -=/ current-yaki .^(yaki:clay %cs /(scot %p our)/base/(scot cas)/yaki/(scot %uv current-tako)) +=/ our p.bec +=? desk =(*^desk desk) q.bec :: use current desk if user didn't provide +=/ cas=case da+now +=/ tale .^(story %cx /(scot %p our)/[desk]/(scot %da now)/story) +=/ current-tako .^(tako:clay %cs /(scot %p our)/[desk]/(scot cas)/tako/~) +=/ current-yaki .^(yaki:clay %cs /(scot %p our)/[desk]/(scot cas)/yaki/(scot %uv current-tako)) :- %tang -(story-log current-yaki tale) +(story-log [our desk] current-yaki tale) +:::: +:: Remarks: :: +:: There are two recursions in the log file: +:: 1. the outer loop, `commit-loop` which threads downwards into each commit by ancestor +:: 2. the inner loop, `ancestor-loop`, which threads left-to-right on reverse-ancestors +:::: +++ story-log + |= [[our=ship syd=^desk] current-commit=yaki:clay tale=story] + ^- tang + =/ cas=case da+now + :: + %- flop :: least-recent-first -> most-recent-first + %- head :: result from state + =| state=[result=tang mergebase=(unit tako:clay)] + |- + ^- _state + =* commit-loop $ + =/ reverse-ancestors (flop p.current-commit) + |- + =* ancestor-loop $ + ?- reverse-ancestors + ~ + :: stop here and return the current message + =/ msg=(unit cord) (msg-from-commit current-commit tale) + [?~(msg result.state [u.msg result.state]) mergebase=~] + :: + [tako:clay ~] + =/ parent=tako:clay i.reverse-ancestors + =/ parent-commit .^(yaki:clay %cs /(scot %p our)/[syd]/(scot cas)/yaki/(scot %uv parent)) + =/ msg (msg-from-commit current-commit tale) + :: If there is a mergebase and we are visting it right now: + :: stop here and clear the mergebase. + :: skip adding the mergebase's msg itself because it will be added through the other branch + :: Otherwise, record the current message if exists + ?: ?&(?=(^ mergebase.state) =(u.mergebase.state r.current-commit)) + [result=result.state mergebase=~] + commit-loop(current-commit parent-commit, state [?~(msg result.state [u.msg result.state]) mergebase.state]) + :: + [tako:clay tako:clay ~] + :: + :: mainline: ultimate base chain + :: nowline: relative mainline + :: sideline: side-chain, featurebranch + :: + :: From the context of e, commit c is on its relative mainline, or nowline, while commit d is on its sideline + :: %base a--b-------------X :: mainline + :: %new \--c------e--/ :: nowline + :: %new2 \--d--/ :: sideline + :: + :: + =/ sideline=tako:clay i.reverse-ancestors + =/ mainline=tako:clay i.t.reverse-ancestors + =/ mergebases .^((list tako:clay) %cs /(scot %p our)/[syd]/(scot cas)/base-tako/(scot %uv mainline)/(scot %uv sideline)) :: XX base-tako ignores beak + =/ next-mergebase=(unit tako:clay) ?~(mergebases ~ (some i.mergebases)) :: take the first valid mergebase (by convention) if exists, else none + =/ sideline-commit=yaki:clay .^(yaki:clay %cs /(scot %p our)/[syd]/(scot cas)/yaki/(scot %uv sideline)) + =/ mainline-commit=yaki:clay .^(yaki:clay %cs /(scot %p our)/[syd]/(scot cas)/yaki/(scot %uv mainline)) + =/ msg=(unit cord) (msg-from-commit current-commit tale) + :: + :: 1 - process current commit + :: 2 - recur and queue processing on all commits on the sideline + :: 3 - recur and queue processing on all commits on the mainline + :: + :: Because mainline messages are cons'd to result last, they are + :: (by definition) towards the less recent side of the resulting flopped list + :: + =. state [result=?~(msg result.state [u.msg result.state]) mergebase=next-mergebase] :: 1 + =. state commit-loop(current-commit sideline-commit) :: 2 + =. state commit-loop(current-commit mainline-commit) :: 3 + state + :: + [tako:clay tako:clay tako:clay *] + ~& "in 3+ ancestor commit" + =/ sideline=tako:clay i.reverse-ancestors + =/ nowline=tako:clay i.t.reverse-ancestors + =/ mergebases .^((list tako:clay) %cs /(scot %p our)/[syd]/(scot cas)/base-tako/(scot %uv nowline)/(scot %uv sideline)) + =/ next-mergebase=(unit tako:clay) ?~(mergebases ~ (some i.mergebases)) :: take the first valid mergebase (by convention) if exists, else none + =/ sideline-commit=yaki:clay .^(yaki:clay %cs /(scot %p our)/[syd]/(scot cas)/yaki/(scot %uv sideline)) + =. mergebase.state next-mergebase + =. state commit-loop(current-commit sideline-commit) :: traverse downwards + =. state ancestor-loop(reverse-ancestors t.reverse-ancestors) :: traverse rightwards + state + == ++ msg-from-commit |= [commit=yaki:clay tale=story] ^- (unit cord) @@ -27,88 +110,5 @@ (tako-to-text:lib r.commit) (proses-to-text:lib u.proses) == -:::: -:: Remarks: :: -:: There are two recursions in the log file: -:: 1. the outer loop, `commit-loop` which threads downwards into each commit by ancestor -:: 2. the inner loop, `ancestor-loop`, which threads left-to-right on reverse-ancestors -:::: -++ story-log - |= [current-commit=yaki:clay tale=story] - ^- tang - =/ our p.bec - =/ cas=case [%da now] - %- flop - %- head - =| state=[result=tang mergebase=(unit tako:clay)] - |- - ^- _state - =* commit-loop $ - =/ reverse-ancestors (flop p.current-commit) - |- - =* ancestor-loop $ - ?- reverse-ancestors - ~ - :: stop here and return the current message - =/ msg=(unit cord) (msg-from-commit current-commit tale) - [?~(msg result.state [u.msg result.state]) mergebase=~] - :: - [tako:clay ~] - =/ parent=tako:clay i.reverse-ancestors - =/ parent-commit .^(yaki:clay %cs /(scot %p our)/base/(scot cas)/yaki/(scot %uv parent)) - =/ msg (msg-from-commit current-commit tale) - :: proper logic is: if there is a mergebase and the current commit is the mergebase, stop. otherwise, continue - ?: ?&(?=(^ mergebase.state) =(u.mergebase.state r.current-commit)) - :: stop here and clear mergebase. we skip adding the mergebase's msg itself because it will be added through the other branch - [result=result.state mergebase=~] - commit-loop(current-commit parent-commit, state [?~(msg result.state [u.msg result.state]) mergebase.state]) - :: - [tako:clay tako:clay ~] - :: - :: mainline: ultimate base chain - :: nextline: relative mainline - :: sideline: side-chain, featurebranch - :: - :: From the context of e, commit c is on its relative mainline, or nowline, while commit d is on its sideline - :: %base a--b-------------X :: mainline - :: %new \--c------e--/ :: nowline - :: %new2 \--d--/ :: sideline - :: - :: - ~& "in merge commit" - =/ sideline=tako:clay i.reverse-ancestors - =/ mainline=tako:clay i.t.reverse-ancestors - =/ mergebases .^((list tako:clay) %cs /(scot %p our)/base/(scot cas)/base-tako/(scot %uv mainline)/(scot %uv sideline)) - =/ next-mergebase=(unit tako:clay) ?~(mergebases ~ (some i.mergebases)) :: take the first valid mergebase (by convention) if exists, else none - =/ sideline-commit=yaki:clay .^(yaki:clay %cs /(scot %p our)/base/(scot cas)/yaki/(scot %uv sideline)) - =/ mainline-commit=yaki:clay .^(yaki:clay %cs /(scot %p our)/base/(scot cas)/yaki/(scot %uv mainline)) - =/ msg=(unit cord) (msg-from-commit current-commit tale) - :: - :: 1 - process current commit - :: 2 - recur and queue processing on all commits on the sideline - :: 3 - recur and queue processing on all commits on the mainline - :: - :: Because mainline messages are cons'd to result last, they are - :: (by definition) towards the less recent side of the (resulting, flopped) list - :: - =. state [result=?~(msg result.state [u.msg result.state]) mergebase=next-mergebase] :: 1 - =. state commit-loop(current-commit sideline-commit) :: 2 - =. state commit-loop(current-commit mainline-commit) :: 3 - state - :: - [tako:clay tako:clay tako:clay *] - ~& "in 3+ ancestor commit" - :: take the first two (sideline/mainline). calculate that mergebase - :: recur through sideline (state-b). but instead of state-c line for mainline, - =/ sideline=tako:clay i.reverse-ancestors - =/ nowline=tako:clay i.t.reverse-ancestors - =/ mergebases .^((list tako:clay) %cs /(scot %p our)/base/(scot cas)/base-tako/(scot %uv nowline)/(scot %uv sideline)) - =/ next-mergebase=(unit tako:clay) ?~(mergebases ~ (some i.mergebases)) :: take the first valid mergebase (by convention) if exists, else none - =/ sideline-commit=yaki:clay .^(yaki:clay %cs /(scot %p our)/base/(scot cas)/yaki/(scot %uv sideline)) - =. mergebase.state next-mergebase - =. state commit-loop(current-commit sideline-commit) - =. state ancestor-loop(reverse-ancestors t.reverse-ancestors) - state - == -- \ No newline at end of file diff --git a/pkg/arvo/sys/vane/clay.hoon b/pkg/arvo/sys/vane/clay.hoon index 912920a99..2e13a67e6 100644 --- a/pkg/arvo/sys/vane/clay.hoon +++ b/pkg/arvo/sys/vane/clay.hoon @@ -4074,9 +4074,10 @@ =/ tako-b (slav %uv i.t.t.pax) =/ yaki-a (~(got by hut.ran) tako-a) =/ yaki-b (~(got by hut.ran) tako-b) - %+ turn ~(tap in (find-merge-points yaki-a yaki-b)) + %+ turn ~(tap in (find-merge-points yaki-a yaki-b)) |= =yaki r.yaki + :: %base ?> ?=(^ t.t.pax) :^ ~ ~ %uvs !>