obslog: make content and description patches available to templater
The code was repeatedly calling fm.write() with the same field
("patch" and "descdiff"). I think that led to the value constantly
getting replaced, so when it was used in a template (as {patch} or
{descdiff}), it would only get the last value, which was always an
empty string.
This patch fixes it by writing the full patch to a temporary buffer
and then assigning the whole patch to the formatter field.
$."$TESTDIR/testlib/topic_setup.sh"Initialsetup$cat<<EOF>>$HGRCPATH>[ui]>logtemplate={rev}{branch} \{{get(namespaces,"topics")}}{phase}{desc|firstline}\n>[experimental]>evolution=all>EOF$hginitmain$cdmain$hgtopicothermarkedworkingdirectoryastopic:other$echoaaa>aaa$hgaddaaa$hgcommit-mc_aactivetopic'other'grewitsfirstchangeset(see'hg help topics'formoreinformation)$echoaaa>bbb$hgaddbbb$hgcommit-mc_b$hgtopicfoo$echoaaa>ccc$hgaddccc$hgcommit-mc_cactivetopic'foo'grewitsfirstchangeset(see'hg help topics'formoreinformation)$echoaaa>ddd$hgaddddd$hgcommit-mc_d$echoaaa>eee$hgaddeee$hgcommit-mc_e$echoaaa>fff$hgaddfff$hgcommit-mc_f$hglog-G@5default{foo}draftc_f|o4default{foo}draftc_e|o3default{foo}draftc_d|o2default{foo}draftc_c|o1default{other}draftc_b|o0default{other}draftc_aCheckthattopicwithoutanyparentdoesnotcrash--list---------------------------------------------------------$hgupotherswitchingtotopicother0filesupdated,0filesmerged,4filesremoved,0filesunresolved$hgtopic--list ### topic: other ### target: default (branch)s2@c_b(current)s1:c_a$hgphase--public'topic("other")'activetopic'other'isnowempty(use'hg topic --clear'toclearitifneeded)Afterchangingthephaseofallthechangesetsin"other"topublic,thetopicshouldstillbeactive,butisempty.Weshouldbebetteratinformatingtheuseraboutitanddisplayinggooddatainthiscase.$hgtopicfoo(4changesets)*other(0changesets)$hgstack###topic:other ### target: default (branch)(stackisempty)s0^c_b(basecurrent)$hgupfooswitchingtotopicfoo4filesupdated,0filesmerged,0filesremoved,0filesunresolvedSimpletest-----------'hg stack'listallchangesetinthetopic$hgtopic*foo(4changesets)$hgstack###topic:foo ### target: default (branch)s4@c_f(current)s3:c_es2:c_ds1:c_cs0^c_b(base)$hgstack-v ### topic: foo ### target: default (branch)s4(6559e6d93aea)@c_f(current)s3(0f9ac936c87d):c_es2(e629654d7050):c_ds1(8522f9e3fee9):c_cs0(ea705abc4f51)^c_b(base)$hgstack-Tjson|python-mjson.tool[{"desc":"c_f","isentry":true,"node":"6559e6d93aeadba940874f54f106c61931b5b8cf","stack_index":4,"state":["current"],"symbol":"@"},{"desc":"c_e","isentry":true,"node":"0f9ac936c87d1d991011862aff4e86d0c3300a89","stack_index":3,"state":["clean"],"symbol":":"},{"desc":"c_d","isentry":true,"node":"e629654d70505107cca3d12782d9c5a50d8fb9c8","stack_index":2,"state":["clean"],"symbol":":"},{"desc":"c_c","isentry":true,"node":"8522f9e3fee92d4ec4e688ac3fbd2ee0f8fd5036","stack_index":1,"state":["clean"],"symbol":":"},{"desc":"c_b","isentry":false,"node":"ea705abc4f51e26d356ed94b3443e8c19b76cedf","stack_index":0,"state":["base"],"symbol":"^"}]$hgstack-v-Tjson|python-mjson.tool[{"desc":"c_f","isentry":true,"node":"6559e6d93aeadba940874f54f106c61931b5b8cf","stack_index":4,"state":["current"],"symbol":"@"},{"desc":"c_e","isentry":true,"node":"0f9ac936c87d1d991011862aff4e86d0c3300a89","stack_index":3,"state":["clean"],"symbol":":"},{"desc":"c_d","isentry":true,"node":"e629654d70505107cca3d12782d9c5a50d8fb9c8","stack_index":2,"state":["clean"],"symbol":":"},{"desc":"c_c","isentry":true,"node":"8522f9e3fee92d4ec4e688ac3fbd2ee0f8fd5036","stack_index":1,"state":["clean"],"symbol":":"},{"desc":"c_b","isentry":false,"node":"ea705abc4f51e26d356ed94b3443e8c19b76cedf","stack_index":0,"state":["base"],"symbol":"^"}]$hgstack-T'{rev}: [{branch}] [{topic}] {desc}\n'5:[default][foo]c_f4:[default][foo]c_e3:[default][foo]c_d2:[default][foo]c_c1:[default][]c_bcheckthattopicsandstackareavailableevenifui.strict=true$hgtopics*foo(4changesets)$hgstack###topic:foo ### target: default (branch)s4@c_f(current)s3:c_es2:c_ds1:c_cs0^c_b(base)$hgtopics--configui.strict=true*foo(4changesets)$hgstack--configui.strict=true ### topic: foo ### target: default (branch)s4@c_f(current)s3:c_es2:c_ds1:c_cs0^c_b(base)mergecase(displayinginfoaboutexternal)-------------------------------------------$hgupdefault0filesupdated,0filesmerged,4filesremoved,0filesunresolved$hgtopicszzzmarkedworkingdirectoryastopic:zzz$echozzz>zzz$hgaddzzz$hgcommit-mzzz_aactivetopic'zzz'grewitsfirstchangeset(see'hg help topics'formoreinformation)$hgmergefoo4filesupdated,0filesmerged,0filesremoved,0filesunresolved(branchmerge,don't forget to commit) $ hg commit -m "merged foo"stack -m display data about child $ hg stack foo ### topic: foo ### target: default (branch) s4: c_f s3: c_e s2: c_d s1: c_c s0^ c_b (base) $ hg stack foo --children ### topic: foo ### target: default (branch) s4: c_f (external-children) s3: c_e s2: c_d s1: c_c s0^ c_b (base)error case, nothing to list $ hg strip --config extensions.strip= t1 --no-backup 0 files updated, 0 files merged, 5 files removed, 0 files unresolved $ hg up foo switching to topic foo 4 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg topic --clear $ hg stack ### target: default (branch) (stack is empty) s0^ c_f (base current)Test "t#" reference------------------- $ hg up s2 abort: cannot resolve "s2": branch "default" has only 0 non-public changesets [255] $ hg topic foo marked working directory as topic: foo $ hg up t42 abort: cannot resolve "t42": topic "foo" has only 4 changesets [255] $ hg up s42 abort: cannot resolve "s42": topic "foo" has only 4 changesets [255] $ hg up s2 0 files updated, 0 files merged, 2 files removed, 0 files unresolved $ hg summary parent: 3:e629654d7050 c_d branch: default commit: (clean) update: 2 new changesets (update) phases: 4 draft topic: fooCase with some of the topic unstable------------------------------------ $ echo bbb > ddd $ hg commit --amend 2 new orphan changesets $ hg log -G @ 6 default {foo} draft c_d | | * 5 default {foo} draft c_f | | | * 4 default {foo} draft c_e | | | x 3 default {foo} draft c_d |/ o 2 default {foo} draft c_c | o 1 default {} public c_b | o 0 default {} public c_a $ hg topic --list ### topic: foo ### target: default (branch) s4$ c_f (orphan) s3$ c_e (orphan) s2@ c_d (current) s1: c_c s0^ c_b (base) $ hg up s3 2 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg topic --list ### topic: foo ### target: default (branch) s4$ c_f (orphan) s3@ c_e (current orphan) s2: c_d s1: c_c s0^ c_b (base) $ hg topic --list --color=debug [stack.summary.topic|### topic: [topic.active|foo]] [stack.summary.branches|### target: default (branch)] [stack.index stack.index.orphan|s4][stack.state stack.state.orphan|$] [stack.desc stack.desc.orphan|c_f][stack.state stack.state.orphan| (orphan)] [stack.index stack.index.current stack.index.orphan|s3][stack.state stack.state.current stack.state.orphan|@] [stack.desc stack.desc.current stack.desc.orphan|c_e][stack.state stack.state.current stack.state.orphan| (current orphan)] [stack.index stack.index.clean|s2][stack.state stack.state.clean|:] [stack.desc stack.desc.clean|c_d] [stack.index stack.index.clean|s1][stack.state stack.state.clean|:] [stack.desc stack.desc.clean|c_c] [stack.index stack.index.base|s0][stack.state stack.state.base|^] [stack.desc stack.desc.base|c_b][stack.state stack.state.base| (base)] $ hg up s2 1 files updated, 0 files merged, 1 files removed, 0 files unresolvedAlso test the revset: $ hg log -r 'stack()' 2 default {foo} draft c_c 6 default {foo} draft c_d 4 default {foo} draft c_e 5 default {foo} draft c_f $ hg log -r 'stack(foo)' hg: parse error: stack takes no arguments, it works on current topic [255] $ hg log -r 'stack(foobar)' hg: parse error: stack takes no arguments, it works on current topic [255]Stack relation subscript: $ hg log -r 'foo#stack[0]' 1 default {} public c_b $ hg log -r 's0andfoo#stack[0]' 1 default {} public c_b $ hg log -r 'foo#stack[4]' 5 default {foo} draft c_f $ hg log -r 's4andfoo#stack[4]' 5 default {foo} draft c_fCase with multiple heads on the topic-------------------------------------Make things linear again $ hg rebase -s 'desc(c_e)' -d 'desc(c_d)-obsolete()' rebasing 4:0f9ac936c87d "c_e" (foo) rebasing 5:6559e6d93aea "c_f" (foo) $ hg log -G o 8 default {foo} draft c_f | o 7 default {foo} draft c_e | @ 6 default {foo} draft c_d | o 2 default {foo} draft c_c | o 1 default {} public c_b | o 0 default {} public c_aCreate the second branch $ hg up 'desc(c_d)' 0 files updated, 0 files merged, 0 files removed, 0 files unresolved $ echo aaa > ggg $ hg add ggg $ hg commit -m c_g $ echo aaa > hhh $ hg add hhh $ hg commit -m c_h $ hg log -G @ 10 default {foo} draft c_h | o 9 default {foo} draft c_g | | o 8 default {foo} draft c_f | | | o 7 default {foo} draft c_e |/ o 6 default {foo} draft c_d | o 2 default {foo} draft c_c | o 1 default {} public c_b | o 0 default {} public c_aTest output $ hg top -l ### topic: foo (2 heads) ### target: default (branch) s6@ c_h (current) s5: c_g s2^ c_d (base) s4: c_f s3: c_e s2: c_d s1: c_c s0^ c_b (base)Case with multiple heads on the topic with unstability involved---------------------------------------------------------------We amend the message to make sure the display base pick the right changeset $ hg up 'desc(c_d)' 0 files updated, 0 files merged, 2 files removed, 0 files unresolved $ echo ccc > ddd $ hg commit --amend -m 'c_D' 4 new orphan changesets $ hg rebase -d . -s 'desc(c_g)' rebasing 9:81264ae8a36a "c_g" (foo) rebasing 10:fde5f5941642 "c_h" (foo) $ hg log -G o 13 default {foo} draft c_h | o 12 default {foo} draft c_g | @ 11 default {foo} draft c_D | | * 8 default {foo} draft c_f | | | * 7 default {foo} draft c_e | | | x 6 default {foo} draft c_d |/ o 2 default {foo} draft c_c | o 1 default {} public c_b | o 0 default {} public c_a $ hg topic --list ### topic: foo (2 heads) ### target: default (branch) s6: c_h s5: c_g s2^ c_D (base current) s4$ c_f (orphan) s3$ c_e (orphan) s2@ c_D (current) s1: c_c s0^ c_b (base)Trying to list non existing topic $ hg stack thisdoesnotexist abort: cannot resolve "thisdoesnotexist": no such topic found [255] $ hg topic --list thisdoesnotexist abort: cannot resolve "thisdoesnotexist": no such topic found [255]Complex cases where commits with same topic are not consecutive but are linear============================================================================== $ hg log --graph o 13 default {foo} draft c_h | o 12 default {foo} draft c_g | @ 11 default {foo} draft c_D | | * 8 default {foo} draft c_f | | | * 7 default {foo} draft c_e | | | x 6 default {foo} draft c_d |/ o 2 default {foo} draft c_c | o 1 default {} public c_b | o 0 default {} public c_aConverting into a linear chain $ hg rebase -s 'desc("c_e")-obsolete()' -d 'desc("c_h")-obsolete()' rebasing 7:215bc359096a "c_e" (foo) rebasing 8:ec9267b3f33f "c_f" (foo) $ hg log -G o 15 default {foo} draft c_f | o 14 default {foo} draft c_e | o 13 default {foo} draft c_h | o 12 default {foo} draft c_g | @ 11 default {foo} draft c_D | o 2 default {foo} draft c_c | o 1 default {} public c_b | o 0 default {} public c_aChanging topics on some commits in between $ hg topic foobar -r 'desc(c_e)+desc(c_D)' switching to topic foobar 4 new orphan changesets changed topic on 2 changesets to "foobar" $ hg log -G @ 17 default {foobar} draft c_D | | * 16 default {foobar} draft c_e | | | | * 15 default {foo} draft c_f | | | | | x 14 default {foo} draft c_e | |/ | * 13 default {foo} draft c_h | | | * 12 default {foo} draft c_g | | | x 11 default {foo} draft c_D |/ o 2 default {foo} draft c_c | o 1 default {} public c_b | o 0 default {} public c_a $ hg rebase -s 'desc("c_f")-obsolete()' -d 'desc("c_e")-obsolete()' rebasing 15:77082e55de88 "c_f" (foo) switching to topic foo 1 new orphan changesets switching to topic foobar $ hg rebase -s 'desc("c_g")-obsolete()' -d 'desc("c_D")-obsolete()' rebasing 12:0c3e8aed985d "c_g" (foo) switching to topic foo rebasing 13:b9e4f3709bc5 "c_h" (foo) rebasing 16:4bc813530301 "c_e" (foobar) switching to topic foobar rebasing 18:4406ea4be852 "c_f" (tip foo) switching to topic foo switching to topic foobar $ hg up 3 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg log --graph o 22 default {foo} draft c_f | @ 21 default {foobar} draft c_e | o 20 default {foo} draft c_h | o 19 default {foo} draft c_g | o 17 default {foobar} draft c_D | o 2 default {foo} draft c_c | o 1 default {} public c_b | o 0 default {} public c_aXXX: The following should show single headsXXX: The behind count is weird, because the topic are interleaved. $ hg stack ### topic: foobar ### target: default (branch), 3 behind s2@ c_e (current) ^ c_h s1: c_D s0^ c_c (base) $ hg stack -v ### topic: foobar ### target: default (branch), 3 behind s2(ea0f882ce093)@ c_e (current) ^ c_h s1(d2f548af67ab): c_D s0(8522f9e3fee9)^ c_c (base) $ hg stack --debug ### topic: foobar ### target: default (branch), 3 behind s2(ea0f882ce093a2ad63db49083c5cb98a24a9470e)@ c_e (current) ^ c_h s1(d2f548af67ab55b08452a3e00a539319490fcd5b): c_D s0(8522f9e3fee92d4ec4e688ac3fbd2ee0f8fd5036)^ c_c (base) $ hg stack foo ### topic: foo ### target: default (branch), ambiguous rebase destination - topic 'foo' has 3 heads s4: c_f ^ c_e s3: c_h s2: c_g ^ c_D s1: c_c s0^ c_b (base)case involving a merge---------------------- $ cd .. $ hg init stack-gap-merge $ cd stack-gap-merge $ echo aaa > aaa $ hg commit -Am 'c_A' adding aaa $ hg topic red marked working directory as topic: red $ echo bbb > bbb $ hg commit -Am 'c_B' adding bbb active topic 'red' grew its first changeset (see 'hghelptopics' for more information) $ echo ccc > ccc $ hg commit -Am 'c_C' adding ccc $ hg topic blue $ echo ddd > ddd $ hg commit -Am 'c_D' adding ddd active topic 'blue' grew its first changeset (see 'hghelptopics' for more information) $ hg up 'desc("c_B")' switching to topic red 0 files updated, 0 files merged, 2 files removed, 0 files unresolved $ echo eee > eee $ hg commit -Am 'c_E' adding eee $ echo fff > fff $ hg commit -Am 'c_F' adding fff $ hg topic blue $ echo ggg > ggg $ hg commit -Am 'c_G' adding ggg $ hg up 'desc("c_D")' 2 files updated, 0 files merged, 3 files removed, 0 files unresolved $ hg topic red $ hg merge 'desc("c_G")' 3 files updated, 0 files merged, 0 files removed, 0 files unresolved (branch merge, don'tforgettocommit)$hgcommit-Am'c_H'$hgtopicblue$echoiii>iii$hgci-Am'c_I'addingiii$hglog-G@8default{blue}draftc_I|o7default{red}draftc_H|\|o6default{blue}draftc_G|||o5default{red}draftc_F|||o4default{red}draftc_E||o|3default{blue}draftc_D||o|2default{red}draftc_C|/o1default{red}draftc_B|o0default{}draftc_A$hgstackred###topic:red ### target: default (branch), 6 behinds5:c_H^c_G^c_Ds4:c_Cs1^c_B(base)s3:c_Fs2:c_Es1:c_Bs0^c_A(base)$hgstackblue###topic:blue ### target: default (branch), ambiguous rebase destination - topic 'blue' has 3 headss3@c_I(current)^c_Hs2:c_D^c_Cs1:c_Gs0^c_F(base)Evenwithsomeobsoleteandorphanchangesets(theorderingofeachbranchof"blue"changebecausetheirhashchange.weshouldstabilizethiseventuelly)$hgup'desc("c_B")'switchingtotopicred0filesupdated,0filesmerged,6filesremoved,0filesunresolved$hgcommit--amend--usertest27neworphanchangesets$hgup'desc("c_C")'1filesupdated,0filesmerged,0filesremoved,0filesunresolved$hgcommit--amend--usertest2$hgup'desc("c_D")'switchingtotopicblue1filesupdated,0filesmerged,0filesremoved,0filesunresolved$hgcommit--amend--usertest2$hglog-G--rev'sort(all(), "topo")'@11default{blue}draftc_D||*8default{blue}draftc_I|||*7default{red}draftc_H||\||*6default{blue}draftc_G|||||*5default{red}draftc_F|||||*4default{red}draftc_E||||x|3default{blue}draftc_D|//x/2default{red}draftc_C|/|*10default{red}draftc_C|/x1default{red}draftc_B||o9default{red}draftc_B|/o0default{}draftc_A$hgstackred###topic:red ### target: default (branch), 7 behinds5$c_H(orphan)^c_G^c_Ds4$c_C(orphan)s1^c_B(base)s3$c_F(orphan)s2$c_E(orphan)s1:c_Bs0^c_A(base)$hgstackblue###topic:blue ### target: default (branch), ambiguous rebase destination - topic 'blue' has 3 headss3$c_I(orphan)^c_Hs2$c_G(orphan)^c_Fs1@c_D(currentorphan)s0^c_C(baseorphan)moreobsolescence$hgup'max(desc("c_H"))'switchingtotopicred3filesupdated,0filesmerged,0filesremoved,0filesunresolved$hgcommit--amend--usertest3$hgup'max(desc("c_G"))'switchingtotopicblue0filesupdated,0filesmerged,2filesremoved,0filesunresolved$hgcommit--amend--usertest3$hgup'max(desc("c_B"))'switchingtotopicred0filesupdated,0filesmerged,3filesremoved,0filesunresolved$hgcommit--amend--usertest3$hgup'max(desc("c_C"))'1filesupdated,0filesmerged,0filesremoved,0filesunresolved$hgcommit--amend--usertest3$hgup'max(desc("c_D"))'switchingtotopicblue1filesupdated,0filesmerged,0filesremoved,0filesunresolved$hgcommit--amend--usertest3$hglog-G--rev'sort(all(), "topo")'@16default{blue}draftc_D||*13default{blue}draftc_G||||*12default{red}draftc_H|||\||||*8default{blue}draftc_I|||||||+---x7default{red}draftc_H||||/|+---x6default{blue}draftc_G||||*|5default{red}draftc_F||||*|4default{red}draftc_E|||+---x3default{blue}draftc_D||x|2default{red}draftc_C|/|*15default{red}draftc_C|/x1default{red}draftc_B||o14default{red}draftc_B|/o0default{}draftc_A$hgstackred###topic:red ### target: default (branch), 7 behinds5$c_H(orphan)^c_G^c_Ds4$c_F(orphan)s3$c_E(orphan)s1^c_B(base)s2$c_C(orphan)s1:c_Bs0^c_A(base)$hgstackblue###topic:blue ### target: default (branch), ambiguous rebase destination - topic 'blue' has 3 headss3$c_I(orphan)^c_Hs2$c_G(orphan)^c_Fs1@c_D(currentorphan)s0^c_C(baseorphan)Teststackbehaviorwithasplit--------------------------------getthingslinearagain$hgrebase-rs1-ddefaultrebasing16:1d84ec948370"c_D"(tipblue)switchingtotopicblue$hgrebase-rs2-ds1rebasing13:3ab2eedae500"c_G"(blue)$hgrebase-rs3-ds2rebasing8:3bfe800e0486"c_I"(blue)$hgstack ### topic: blue ### target: default (branch)s3:c_Is2:c_Gs1@c_D(current)s0^c_A(base)makingasplit(firstgetsomethingtosplit)$hgups21filesupdated,0filesmerged,0filesremoved,0filesunresolved$hgstatus--change.Aggg$echozzz>Z$hgaddZ$hgcommit--amend1neworphanchangesets$hgstatus--change.AZAggg$hgstack ### topic: blue ### target: default (branch)s3$c_I(orphan)s2@c_G(current)s1:c_Ds0^c_A(base)$hg--configextensions.evolve=--configui.interactive=yessplit<<EOF>y>y>n>c>EOF0filesupdated,0filesmerged,2filesremoved,0filesunresolvedaddingZaddinggggdiff--gita/Zb/Znewfilemode100644examinechangesto'Z'?(enter?forhelp)[Ynesfdaq?]y@@-0,0+1,1@@+zzzrecordchange1/2to'Z'?(enter?forhelp)[Ynesfdaq?]ydiff--gita/gggb/gggnewfilemode100644examinechangesto'ggg'?(enter?forhelp)[Ynesfdaq?]ncontinuesplitting?[Ycdq?]c$hg--configextensions.evolve=obslog--allodde94df880e9(21)c_G||@e7ea874afbd5(22)c_G|/xb24bab30ac12(20)c_G|rewritten(parent,content)asdde94df880e9,e7ea874afbd5usingsplitbytest(ThuJan0100:00:001970+0000)|x907f7d3c2333(18)c_G|rewritten(content)asb24bab30ac12usingamendbytest(ThuJan0100:00:001970+0000)|x3ab2eedae500(13)c_G|rewritten(parent)as907f7d3c2333usingrebasebytest(ThuJan0100:00:001970+0000)|xc7d60a180d05(6)c_Grewritten(user)as3ab2eedae500usingamendbytest(ThuJan0100:00:001970+0000)$hgexport. # HG changeset patch # User test3 # Date 0 0 # Thu Jan 01 00:00:00 1970 +0000 # Node ID e7ea874afbd5c17aeee366d39a828dbcb01682ce # Parent dde94df880e97f4a1ee8c5408254b429b3d90204 # EXP-Topic bluec_Gdiff-rdde94df880e9-re7ea874afbd5ggg---/dev/nullThuJan0100:00:001970+0000+++b/gggThuJan0100:00:001970+0000@@-0,0+1,1@@+ggg$hgexport.^ # HG changeset patch # User test3 # Date 0 0 # Thu Jan 01 00:00:00 1970 +0000 # Node ID dde94df880e97f4a1ee8c5408254b429b3d90204 # Parent f3328cd199dc389b850ca952f65a15a8e6dbc79b # EXP-Topic bluec_Gdiff-rf3328cd199dc-rdde94df880e9Z---/dev/nullThuJan0100:00:001970+0000+++b/ZThuJan0100:00:001970+0000@@-0,0+1,1@@+zzzCheckthatstackouputstillmakesense$hgstack ### topic: blue ### target: default (branch)s4$c_I(orphan)s3@c_G(current)s2:c_Gs1:c_Ds0^c_A(base)