##// END OF EJS Templates
copies: expand `_chain` variable name to make the function easier to read...
copies: expand `_chain` variable name to make the function easier to read This came up while explaining what the function is about. I find the function easier to follow that way.

File last commit:

r43803:6d001f45 default
r44176:b0f5d8eb default
Show More
dagparser.py
516 lines | 15.0 KiB | text/x-python | PythonLexer
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 # dagparser.py - parser and generator for concise description of DAGs
#
# Copyright 2010 Peter Arrenbrecht <peter@arrenbrecht.ch>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
Gregory Szorc
dagparser: use absolute_import
r25941 from __future__ import absolute_import
import re
import string
from .i18n import _
Yuya Nishihara
py3: drop use of str() in dagparser.py
r34207 from . import (
error,
Yuya Nishihara
py3: wrap string constants in dagparser.py with bytestr()
r34208 pycompat,
Yuya Nishihara
stringutil: bulk-replace call sites to point to new module...
r37102 )
Augie Fackler
formatting: blacken the codebase...
r43346 from .utils import stringutil
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335
def parsedag(desc):
'''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
"<p" sets the default parent to the backref p
"*p" is a fork at parent p, where p is a backref
"*p1/p2/.../pn" is a merge of parents p1..pn, where the pi are backrefs
"/p2/.../pn" is a merge of the preceding node and p2..pn
":name" defines a label for the preceding node; labels can be redefined
"@text" emits an annotation event for text
"!command" emits an action event for the current node
"!!my command\n" is like "!", but to the end of the line
"#...\n" is a comment up to the end of the line
Whitespace between the above elements is ignored.
A backref is either
* a number n, which references the node curr-n, where curr is the current
node, or
* the name of a label you placed earlier using ":name", or
* empty to denote the default parent.
All string valued-elements are either strictly alphanumeric, or must
be enclosed in double quotes ("..."), with "\" as escape character.
Generates sequence of
('n', (id, [parentids])) for node creation
('l', (id, labelname)) for labels on nodes
('a', text) for annotations
('c', command) for actions (!)
('C', command) for line actions (!!)
Examples
--------
Example of a complex graph (output not shown for brevity):
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> len(list(parsedag(b"""
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 ...
... +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
timeless@mozdev.org
en-us: labeled
r17500 ... <forkhere # set default parent to labeled fork node
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 ... +10 # 10 more nodes on a parallel branch
... @stable # following nodes will be annotated as "stable"
... +5 # 5 nodes in stable
... !addfile # custom command; could trigger new file in next node
... +2 # two more nodes
timeless@mozdev.org
en-us: labeled
r17500 ... /mergethis # merge last node with labeled node
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 ... +4 # 4 more nodes descending from merge node
...
... """)))
34
Empty list:
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> list(parsedag(b""))
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 []
A simple linear run:
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> list(parsedag(b"+3"))
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 [('n', (0, [-1])), ('n', (1, [0])), ('n', (2, [1]))]
Some non-standard ways to define such runs:
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> list(parsedag(b"+1+2"))
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 [('n', (0, [-1])), ('n', (1, [0])), ('n', (2, [1]))]
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> list(parsedag(b"+1*1*"))
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 [('n', (0, [-1])), ('n', (1, [0])), ('n', (2, [1]))]
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> list(parsedag(b"*"))
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 [('n', (0, [-1]))]
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> list(parsedag(b"..."))
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 [('n', (0, [-1])), ('n', (1, [0])), ('n', (2, [1]))]
A fork and a join, using numeric back references:
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> list(parsedag(b"+2*2*/2"))
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 [('n', (0, [-1])), ('n', (1, [0])), ('n', (2, [0])), ('n', (3, [2, 1]))]
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> list(parsedag(b"+2<2+1/2"))
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 [('n', (0, [-1])), ('n', (1, [0])), ('n', (2, [0])), ('n', (3, [2, 1]))]
Placing a label:
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> list(parsedag(b"+1 :mylabel +1"))
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 [('n', (0, [-1])), ('l', (0, 'mylabel')), ('n', (1, [0]))]
An empty label (silly, really):
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> list(parsedag(b"+1:+1"))
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 [('n', (0, [-1])), ('l', (0, '')), ('n', (1, [0]))]
Fork and join, but with labels instead of numeric back references:
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> list(parsedag(b"+1:f +1:p2 *f */p2"))
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 [('n', (0, [-1])), ('l', (0, 'f')), ('n', (1, [0])), ('l', (1, 'p2')),
('n', (2, [0])), ('n', (3, [2, 1]))]
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> list(parsedag(b"+1:f +1:p2 <f +1 /p2"))
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 [('n', (0, [-1])), ('l', (0, 'f')), ('n', (1, [0])), ('l', (1, 'p2')),
('n', (2, [0])), ('n', (3, [2, 1]))]
Restarting from the root:
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> list(parsedag(b"+1 $ +1"))
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 [('n', (0, [-1])), ('n', (1, [-1]))]
Annotations, which are meant to introduce sticky state for subsequent nodes:
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> list(parsedag(b"+1 @ann +1"))
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 [('n', (0, [-1])), ('a', 'ann'), ('n', (1, [0]))]
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> list(parsedag(b'+1 @"my annotation" +1'))
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 [('n', (0, [-1])), ('a', 'my annotation'), ('n', (1, [0]))]
Commands, which are meant to operate on the most recently created node:
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> list(parsedag(b"+1 !cmd +1"))
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 [('n', (0, [-1])), ('c', 'cmd'), ('n', (1, [0]))]
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> list(parsedag(b'+1 !"my command" +1'))
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 [('n', (0, [-1])), ('c', 'my command'), ('n', (1, [0]))]
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> list(parsedag(b'+1 !!my command line\\n +1'))
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 [('n', (0, [-1])), ('C', 'my command line'), ('n', (1, [0]))]
Comments, which extend to the end of the line:
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> list(parsedag(b'+1 # comment\\n+1'))
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 [('n', (0, [-1])), ('n', (1, [0]))]
Error:
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> try: list(parsedag(b'+1 bad'))
Yuya Nishihara
doctest: upgrade old-style "except" clause
r34140 ... except Exception as e: print(pycompat.sysstr(bytes(e)))
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 invalid character in dag description: bad...
'''
if not desc:
return
Augie Fackler
dagparser: suppress some pytype errors around pycompat.bytestring...
r43803 wordchars = pycompat.bytestr(
string.ascii_letters + string.digits
) # pytype: disable=wrong-arg-types
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335
labels = {}
p1 = -1
r = 0
def resolve(ref):
if not ref:
return p1
Augie Fackler
dagparser: suppress some pytype errors around pycompat.bytestring...
r43803 elif ref[0] in pycompat.bytestr(
string.digits
): # pytype: disable=wrong-arg-types
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 return r - int(ref)
else:
return labels[ref]
Yuya Nishihara
py3: iterate bytes as a byte string in dagparser.py
r34209 chiter = pycompat.iterbytestr(desc)
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335
def nextch():
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return next(chiter, b'\0')
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335
def nextrun(c, allow):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 s = b''
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 while c in allow:
s += c
c = nextch()
return c, s
def nextdelimited(c, limit, escape):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 s = b''
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 while c != limit:
if c == escape:
c = nextch()
s += c
c = nextch()
return nextch(), s
def nextstring(c):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if c == b'"':
return nextdelimited(nextch(), b'"', b'\\')
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 else:
return nextrun(c, wordchars)
c = nextch()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 while c != b'\0':
Augie Fackler
dagparser: suppress some pytype errors around pycompat.bytestring...
r43803 while c in pycompat.bytestr(
string.whitespace
): # pytype: disable=wrong-arg-types
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 c = nextch()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if c == b'.':
yield b'n', (r, [p1])
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 p1 = r
r += 1
c = nextch()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 elif c == b'+':
Augie Fackler
dagparser: suppress some pytype errors around pycompat.bytestring...
r43803 c, digs = nextrun(
nextch(), pycompat.bytestr(string.digits)
) # pytype: disable=wrong-arg-types
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 n = int(digs)
Gregory Szorc
global: use pycompat.xrange()...
r38806 for i in pycompat.xrange(0, n):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 yield b'n', (r, [p1])
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 p1 = r
r += 1
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 elif c in b'*/':
if c == b'*':
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 c = nextch()
c, pref = nextstring(c)
prefs = [pref]
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 while c == b'/':
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 c, pref = nextstring(nextch())
prefs.append(pref)
ps = [resolve(ref) for ref in prefs]
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 yield b'n', (r, ps)
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 p1 = r
r += 1
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 elif c == b'<':
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 c, ref = nextstring(nextch())
p1 = resolve(ref)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 elif c == b':':
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 c, name = nextstring(nextch())
labels[name] = p1
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 yield b'l', (p1, name)
elif c == b'@':
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 c, text = nextstring(nextch())
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 yield b'a', text
elif c == b'!':
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 c = nextch()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if c == b'!':
cmd = b''
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 c = nextch()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 while c not in b'\n\r\0':
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 cmd += c
c = nextch()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 yield b'C', cmd
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 else:
c, cmd = nextstring(c)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 yield b'c', cmd
elif c == b'#':
while c not in b'\n\r\0':
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 c = nextch()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 elif c == b'$':
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 p1 = -1
c = nextch()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 elif c == b'\0':
Augie Fackler
formatting: blacken the codebase...
r43346 return # in case it was preceded by whitespace
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 s = b''
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 i = 0
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 while c != b'\0' and i < 10:
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 s += c
i += 1
c = nextch()
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.Abort(
Martin von Zweigbergk
cleanup: join string literals that are already on one line...
r43387 _(b'invalid character in dag description: %s...') % s
Augie Fackler
formatting: blacken the codebase...
r43346 )
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335
Augie Fackler
formatting: blacken the codebase...
r43346 def dagtextlines(
events,
addspaces=True,
wraplabels=False,
wrapannotations=False,
wrapcommands=False,
wrapnonlinear=False,
usedots=False,
maxlinewidth=70,
):
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 '''generates single lines for dagtext()'''
def wrapstring(text):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if re.match(b"^[0-9a-z]*$", text):
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 return text
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return b'"' + text.replace(b'\\', b'\\\\').replace(b'"', b'\"') + b'"'
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335
def gen():
labels = {}
run = 0
wantr = 0
needroot = False
for kind, data in events:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if kind == b'n':
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 r, ps = data
# sanity check
if r != wantr:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.Abort(_(b"expected id %i, got %i") % (wantr, r))
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 if not ps:
ps = [-1]
else:
for p in ps:
if p >= r:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.Abort(
_(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"parent id %i is larger than "
b"current id %i"
Augie Fackler
formatting: blacken the codebase...
r43346 )
% (p, r)
)
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 wantr += 1
# new root?
p1 = r - 1
if len(ps) == 1 and ps[0] == -1:
if needroot:
if run:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 yield b'+%d' % run
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 run = 0
if wrapnonlinear:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 yield b'\n'
yield b'$'
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 p1 = -1
else:
needroot = True
if len(ps) == 1 and ps[0] == p1:
if usedots:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 yield b"."
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 else:
run += 1
else:
if run:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 yield b'+%d' % run
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 run = 0
if wrapnonlinear:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 yield b'\n'
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 prefs = []
for p in ps:
if p == p1:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 prefs.append(b'')
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 elif p in labels:
prefs.append(labels[p])
else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 prefs.append(b'%d' % (r - p))
yield b'*' + b'/'.join(prefs)
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 else:
if run:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 yield b'+%d' % run
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 run = 0
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if kind == b'l':
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 rid, name = data
labels[rid] = name
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 yield b':' + name
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 if wraplabels:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 yield b'\n'
elif kind == b'c':
yield b'!' + wrapstring(data)
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 if wrapcommands:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 yield b'\n'
elif kind == b'C':
yield b'!!' + data
yield b'\n'
elif kind == b'a':
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 if wrapannotations:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 yield b'\n'
yield b'@' + wrapstring(data)
elif kind == b'#':
yield b'#' + data
yield b'\n'
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 else:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.Abort(
Martin von Zweigbergk
cleanup: join string literals that are already on one line...
r43387 _(b"invalid event type in dag: ('%s', '%s')")
Augie Fackler
formatting: blacken the codebase...
r43346 % (
stringutil.escapestr(kind),
stringutil.escapestr(data),
)
)
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 if run:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 yield b'+%d' % run
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 line = b''
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 for part in gen():
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if part == b'\n':
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 if line:
yield line
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 line = b''
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 else:
if len(line) + len(part) >= maxlinewidth:
yield line
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 line = b''
elif addspaces and line and part != b'.':
line += b' '
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 line += part
if line:
yield line
Augie Fackler
formatting: blacken the codebase...
r43346
def dagtext(
dag,
addspaces=True,
wraplabels=False,
wrapannotations=False,
wrapcommands=False,
wrapnonlinear=False,
usedots=False,
maxlinewidth=70,
):
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 '''generates 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:
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> dagtext([(b'n', (0, [-1])), (b'n', (1, [0]))])
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 '+2'
Two roots:
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> dagtext([(b'n', (0, [-1])), (b'n', (1, [-1]))])
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 '+1 $ +1'
Fork and join:
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> dagtext([(b'n', (0, [-1])), (b'n', (1, [0])), (b'n', (2, [0])),
... (b'n', (3, [2, 1]))])
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 '+2 *2 */2'
Fork and join with labels:
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> 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]))])
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 '+1 :f +1 :p2 *f */p2'
Annotations:
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> dagtext([(b'n', (0, [-1])), (b'a', b'ann'), (b'n', (1, [0]))])
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 '+1 @ann +1'
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> dagtext([(b'n', (0, [-1])),
... (b'a', b'my annotation'),
... (b'n', (1, [0]))])
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 '+1 @"my annotation" +1'
Commands:
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> dagtext([(b'n', (0, [-1])), (b'c', b'cmd'), (b'n', (1, [0]))])
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 '+1 !cmd +1'
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> dagtext([(b'n', (0, [-1])),
... (b'c', b'my command'),
... (b'n', (1, [0]))])
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 '+1 !"my command" +1'
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> dagtext([(b'n', (0, [-1])),
... (b'C', b'my command line'),
... (b'n', (1, [0]))])
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 '+1 !!my command line\\n+1'
Comments:
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> dagtext([(b'n', (0, [-1])), (b'#', b' comment'), (b'n', (1, [0]))])
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 '+1 # comment\\n+1'
>>> dagtext([])
''
Combining parsedag and dagtext:
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> dagtext(parsedag(b'+1 :f +1 :p2 *f */p2'))
Peter Arrenbrecht
dagparser: parses and formats DAGs as concise text...
r11335 '+1 :f +1 :p2 *f */p2'
'''
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return b"\n".join(
Augie Fackler
formatting: blacken the codebase...
r43346 dagtextlines(
dag,
addspaces,
wraplabels,
wrapannotations,
wrapcommands,
wrapnonlinear,
usedots,
maxlinewidth,
)
)