o ]Lb<@sddlmZddlZddlZddlmZddlmZmZddl m Z ddZ dd d Z dddZ dS))absolute_importN)_)errorpycompat) stringutilc#sB|sdSttjtjiddfddt|fddfdd fd d fd d }}|dkr|ttjvrW}|ttjvsL|dkrndgffVd7}n+|dkrttj\}}t|}td|D]}dgffVd7qn|dvr|dkr}||\}}|g}|dkr|\}}| ||dksfdd|D}d|ffVd7n|dkr|\}} | n|dkr|\}} | <d| ffVn|dkr|\}} d| fVn|dkrH}|dkr|d#krfd}n3|dkrmdSd} d}|dkr|d$kr| |7} |d7}}|dkr|d$ks{t t d%| |dksDdSdS)&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... Nrcs0|sS|dttjvrt|S|S)Nr)rbytestrstringdigitsint)ref)labelsp1r5/usr/lib/python3/dist-packages/mercurial/dagparser.pyresolves  zparsedag..resolvecs tdS)N)nextr)chiterrrnextchs zparsedag..nextchcs*d}||vr||7}}||vs||fSNr)callowsrrrnextruns zparsedag..nextruncs:d}||kr||kr }||7}}||ks|fSrr)rlimitescaperrrr nextdelimiteds zparsedag..nextdelimitedcs |dkr ddS|S)N"\r)r)rr!r wordcharsrr nextstrings zparsedag..nextstringr.nr+s*/*/csg|]}|qSrr).0r )rrr szparsedag..<:l@a!rs Cc#$ s+invalid character in dag description: %s...) rr r ascii_lettersr iterbytestr whitespacer xrangeappendrAbortr)descr%rdigsniprefprefspsr nametextcmdrr) rrrr!rrrrr$rparsedags                          rHTFFc #sddfdd}d} |D].} | dkr$| r#| Vd} qt| t| |kr4| Vd} n |r@| r@| dkr@| d7} | | 7} q| rL| Vd Sd S) z$generates single lines for dagtext()cSs,td|r|Sd|dddddS)Ns ^[0-9a-z]*$r"r#s\\)rematchreplace)rFrrr wrapstring.s z dagtextlines..wrapstringc 3szi}d}d}d}D]$\}}|dkr|\}}||kr'ttd||f|s-dg}n|D]}||kr@ttd||fq/|d7}|d} t|dkrm|ddkrm|rk|r`d|Vd}red Vd Vd} nd }t|dkr|d| krrd Vq |d7}q |rd|Vd}rd Vg} |D]!}|| kr| d q||vr| ||q| d||qdd| Vq |rd|Vd}|dkr|\} } | || <d| Vrd Vq |dkrd|Vrd Vq |dkrd|Vd Vq |dkrr d Vd|Vq |dkr d|Vd Vq ttdt|t|f|r;d|VdSdS)NrFr'sexpected id %i, got %irs)parent id %i is larger than current id %irs+%d r6Tr&rs%dr)r*r/r.r4r2r3s!!r1r0r5s'invalid event type in dag: ('%s', '%s'))rr=rlenr<joinr escapestr) rrunwantrneedrootkinddatarrDprrCridrEeventsusedotswrapannotations wrapcommands wraplabels wrapnonlinearrMrrgen3s          zdagtextlines..genrrNr& N)rO) rZ addspacesr^r\r]r_r[ maxlinewidthr`linepartrrYr dagtextlines"s& ^   rfc 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' rN)rPrf)dagrbr^r\r]r_r[rcrrrdagtextsWrh)TFFFFFrI) __future__rrJr i18nrrrutilsrrHrfrhrrrrs4