a +b<@sdddlmZddlZddlZddlmZddlmZmZddl m Z ddZ dd d Z dddZ dS))absolute_importN)_)errorpycompat) stringutilc#s|sdSttjtjiddfddt|fddfdd fd d fd d }}|dkr|ttjvr}q|dkrdgffVd7}q||dkr&ttj\}}t|}td|D]"}dgffVd7qq||dvr|dkr@}||\}}|g}|dkrx|\}}| |qRfdd|D}d|ffVd7q||dkr|\}} | q||dkr|\}} | <d| ffVq||dkr|\}} d| fVq||dkr}|dkrhd} }|dvr\| |7} }q@d | fVn||\}} d!| fVq||d"kr|dvr }qq||d#krd}q||dkrdSd} d}|dkr|d$kr| |7} |d7}}qt t d%| q|dS)&a#parses a DAG from a concise textual description; generates events "+n" is a linear run of n nodes based on the current default parent "." is a single node based on the current default parent "$" resets the default parent to -1 (implied at the start); otherwise the default parent is always the last node created ">> len(list(parsedag(b""" ... ... +3 # 3 nodes in linear run ... :forkhere # a label for the last of the 3 nodes from above ... +5 # 5 more nodes on one branch ... :mergethis # label again ... >> list(parsedag(b"")) [] A simple linear run: >>> list(parsedag(b"+3")) [('n', (0, [-1])), ('n', (1, [0])), ('n', (2, [1]))] Some non-standard ways to define such runs: >>> list(parsedag(b"+1+2")) [('n', (0, [-1])), ('n', (1, [0])), ('n', (2, [1]))] >>> list(parsedag(b"+1*1*")) [('n', (0, [-1])), ('n', (1, [0])), ('n', (2, [1]))] >>> list(parsedag(b"*")) [('n', (0, [-1]))] >>> list(parsedag(b"...")) [('n', (0, [-1])), ('n', (1, [0])), ('n', (2, [1]))] A fork and a join, using numeric back references: >>> list(parsedag(b"+2*2*/2")) [('n', (0, [-1])), ('n', (1, [0])), ('n', (2, [0])), ('n', (3, [2, 1]))] >>> list(parsedag(b"+2<2+1/2")) [('n', (0, [-1])), ('n', (1, [0])), ('n', (2, [0])), ('n', (3, [2, 1]))] Placing a label: >>> list(parsedag(b"+1 :mylabel +1")) [('n', (0, [-1])), ('l', (0, 'mylabel')), ('n', (1, [0]))] An empty label (silly, really): >>> list(parsedag(b"+1:+1")) [('n', (0, [-1])), ('l', (0, '')), ('n', (1, [0]))] Fork and join, but with labels instead of numeric back references: >>> list(parsedag(b"+1:f +1:p2 *f */p2")) [('n', (0, [-1])), ('l', (0, 'f')), ('n', (1, [0])), ('l', (1, 'p2')), ('n', (2, [0])), ('n', (3, [2, 1]))] >>> list(parsedag(b"+1:f +1:p2 >> list(parsedag(b"+1 $ +1")) [('n', (0, [-1])), ('n', (1, [-1]))] Annotations, which are meant to introduce sticky state for subsequent nodes: >>> list(parsedag(b"+1 @ann +1")) [('n', (0, [-1])), ('a', 'ann'), ('n', (1, [0]))] >>> list(parsedag(b'+1 @"my annotation" +1')) [('n', (0, [-1])), ('a', 'my annotation'), ('n', (1, [0]))] Commands, which are meant to operate on the most recently created node: >>> list(parsedag(b"+1 !cmd +1")) [('n', (0, [-1])), ('c', 'cmd'), ('n', (1, [0]))] >>> list(parsedag(b'+1 !"my command" +1')) [('n', (0, [-1])), ('c', 'my command'), ('n', (1, [0]))] >>> list(parsedag(b'+1 !!my command line\n +1')) [('n', (0, [-1])), ('C', 'my command line'), ('n', (1, [0]))] Comments, which extend to the end of the line: >>> list(parsedag(b'+1 # comment\n+1')) [('n', (0, [-1])), ('n', (1, [0]))] Error: >>> try: list(parsedag(b'+1 bad')) ... except Exception as e: print(pycompat.sysstr(bytes(e))) invalid character in dag description: bad... Nrcs4|sS|dttjvr(t|S|SdS)Nr)rbytestrstringdigitsint)ref)labelsp1r9/usr/lib64/python3.9/site-packages/mercurial/dagparser.pyresolves  zparsedag..resolvecs tdS)N)nextr)chiterrrnextchszparsedag..nextchcs$d}||vr||7}}q||fSNr)cZallowsrrrnextruns zparsedag..nextruncs4d}||kr*||kr}||7}}q|fSrr)rlimitescaperrrr nextdelimitedszparsedag..nextdelimitedcs$|dkrddS|SdS)N"\r)r)rr r wordcharsrr nextstringszparsedag..nextstringr.nr+s*/*/csg|] }|qSrr).0r )rrr rzparsedag..<:l@a!rs Cc#$ s+invalid character in dag description: %s...) rr r ascii_lettersr Z iterbytestrZ whitespacer ZxrangeappendrAbortr)Zdescr$rZdigsniZprefprefspsr nametextcmdrr) rrrr rrrrr#rparsedags                              rATFFc #sddfdd}d} |D]\} | dkrF| r| Vd} q*t| t| |krf| Vd} n|r~| r~| dkr~| d7} | | 7} q*| r| Vd S) z$generates single lines for dagtext()cSs,td|r|Sd|dddddS)Ns ^[0-9a-z]*$r!r"s\\)rematchreplace)r?rrr wrapstring.s z dagtextlines..wrapstringc 3si}d}d}d}D]h\}}|dkr|\}}||krNttd||f|sZdg}n(|D]"}||kr^ttd||fq^|d7}|d} t|dkr|ddkr|r|rd|Vd}rd Vd Vd} nd }t|dkr|d| krrd Vn|d7}n|r"d|Vd}r.d Vg} |D]H}|| krP| d n,||vrj| ||n| d||q6dd| Vq|rd|Vd}|dkr|\} } | || <d| Vr~d Vq|dkrd|Vr~d Vq|dkrd|Vd Vq|dkr@r0d Vd|Vq|dkr\d|Vd Vqttdt|t|fq|rd|VdS)NrFr&sexpected id %i, got %irs)parent id %i is larger than current id %irs+%d r5Tr%rs%dr(r)r.r-r3r1r2s!!r0r/r4s'invalid event type in dag: ('%s', '%s'))rr9rlenr8joinrZ escapestr) rrunZwantrZneedrootkinddatarr=prr<Zridr>eventsusedotswrapannotations wrapcommands wraplabels wrapnonlinearrFrrgen3s                zdagtextlines..genrrGr% N)rH) rO addspacesrSrQrRrTrP maxlinewidthrUlinepartrrNr dagtextlines"s ^  r[c Csdt||||||||S)agenerates lines of a textual representation for a dag event stream events should generate what parsedag() does, so: ('n', (id, [parentids])) for node creation ('l', (id, labelname)) for labels on nodes ('a', text) for annotations ('c', text) for commands ('C', text) for line commands ('!!') ('#', text) for comment lines Parent nodes must come before child nodes. Examples -------- Linear run: >>> dagtext([(b'n', (0, [-1])), (b'n', (1, [0]))]) '+2' Two roots: >>> dagtext([(b'n', (0, [-1])), (b'n', (1, [-1]))]) '+1 $ +1' Fork and join: >>> dagtext([(b'n', (0, [-1])), (b'n', (1, [0])), (b'n', (2, [0])), ... (b'n', (3, [2, 1]))]) '+2 *2 */2' Fork and join with labels: >>> dagtext([(b'n', (0, [-1])), (b'l', (0, b'f')), (b'n', (1, [0])), ... (b'l', (1, b'p2')), (b'n', (2, [0])), (b'n', (3, [2, 1]))]) '+1 :f +1 :p2 *f */p2' Annotations: >>> dagtext([(b'n', (0, [-1])), (b'a', b'ann'), (b'n', (1, [0]))]) '+1 @ann +1' >>> dagtext([(b'n', (0, [-1])), ... (b'a', b'my annotation'), ... (b'n', (1, [0]))]) '+1 @"my annotation" +1' Commands: >>> dagtext([(b'n', (0, [-1])), (b'c', b'cmd'), (b'n', (1, [0]))]) '+1 !cmd +1' >>> dagtext([(b'n', (0, [-1])), ... (b'c', b'my command'), ... (b'n', (1, [0]))]) '+1 !"my command" +1' >>> dagtext([(b'n', (0, [-1])), ... (b'C', b'my command line'), ... (b'n', (1, [0]))]) '+1 !!my command line\n+1' Comments: >>> dagtext([(b'n', (0, [-1])), (b'#', b' comment'), (b'n', (1, [0]))]) '+1 # comment\n+1' >>> dagtext([]) '' Combining parsedag and dagtext: >>> dagtext(parsedag(b'+1 :f +1 :p2 *f */p2')) '+1 :f +1 :p2 *f */p2' rG)rIr[)ZdagrWrSrQrRrTrPrXrrrdagtextsWr\)TFFFFFrB)TFFFFFrB)Z __future__rrCr Zi18nrrrZutilsrrAr[r\rrrrs2