in eden/scm/edenscm/mercurial/drawdag.py [0:0]
def _drawdagintransaction(repo, text, tr, **opts):
# parse the graph and make sure len(parents) <= 2 for each node
edges = _parseasciigraph(text)
for k, v in edges.items():
if len(v) > 2:
raise error.Abort(_("%s: too many parents: %s") % (k, " ".join(v)))
# parse comments to get extra file content instructions
files = collections.defaultdict(dict) # {(name, path): content}
comments = list(_getcomments(text))
commenttext = "\n".join(comments)
filere = re.compile(r"^(\w+)/([\w/]+)\s*=\s*(.*)$", re.M)
for name, path, content in filere.findall(commenttext):
content = content.replace(r"\n", "\n").replace(r"\1", "\1")
files[name][path] = content
# parse commits like "X has date 1 0" to specify dates
dates = {}
datere = re.compile(r"^(\w+) has date\s*[= ]([0-9 ]+)$", re.M)
for name, date in datere.findall(commenttext):
dates[name] = date
# do not create default files? (ex. commit A has file "A")
defaultfiles = not any("drawdag.defaultfiles=false" in c for c in comments)
committed = {None: nullid} # {name: node}
existed = {None}
# for leaf nodes, try to find existing nodes in repo
for name, parents in edges.items():
if len(parents) == 0:
try:
committed[name] = scmutil.revsingle(repo, name).node()
existed.add(name)
except error.RepoLookupError:
pass
# parse mutation comments like amend: A -> B -> C
tohide = set()
mutations = {}
for comment in comments:
args = comment.split(":", 1)
if len(args) <= 1:
continue
cmd = args[0].strip()
arg = args[1].strip()
if cmd in ("replace", "rebase", "amend"):
nodes = [n.strip() for n in arg.split("->")]
for i in range(len(nodes) - 1):
pred, succ = nodes[i], nodes[i + 1]
if succ in mutations:
raise error.Abort(
_("%s: multiple mutations: from %s and %s")
% (succ, pred, mutations[succ][0])
)
mutations[succ] = ([pred], cmd, None)
tohide.add(pred)
elif cmd in ("split",):
pred, succs = arg.split("->")
pred = pred.strip()
succs = [s.strip() for s in succs.split(",")]
for succ in succs:
if succ in mutations:
raise error.Abort(
_("%s: multiple mutations: from %s and %s")
% (succ, pred, mutations[succ][0])
)
for i in range(len(succs) - 1):
parent = succs[i]
child = succs[i + 1]
if child not in edges or parent not in edges[child]:
raise error.Abort(
_("%s: split targets must be a stack: %s is not a parent of %s")
% (pred, parent, child)
)
mutations[succs[-1]] = ([pred], cmd, succs[:-1])
tohide.add(pred)
elif cmd in ("fold",):
preds, succ = arg.split("->")
preds = [p.strip() for p in preds.split(",")]
succ = succ.strip()
if succ in mutations:
raise error.Abort(
_("%s: multiple mutations: from %s and %s")
% (succ, ", ".join(preds), mutations[succ][0])
)
for i in range(len(preds) - 1):
parent = preds[i]
child = preds[i + 1]
if child not in edges or parent not in edges[child]:
raise error.Abort(
_("%s: fold sources must be a stack: %s is not a parent of %s")
% (succ, parent, child)
)
mutations[succ] = (preds, cmd, None)
tohide.update(preds)
elif cmd in ("prune",):
for n in arg.split(","):
n = n.strip()
tohide.add(n)
elif cmd in ("revive",):
for n in arg.split(","):
n = n.strip()
tohide -= {n}
# Only record mutations if mutation is enabled.
mutationedges = {}
mutationpreds = set()
if mutation.enabled(repo):
# For mutation recording to work, we must include the mutations
# as extra edges when walking the DAG.
for succ, (preds, cmd, split) in mutations.items():
succs = {succ}
mutationpreds.update(preds)
if split:
succs.update(split)
for s in succs:
mutationedges.setdefault(s, set()).update(preds)
else:
mutationedges = {}
mutations = {}
# commit in topological order
for name, parents in _walkgraph(edges, mutationedges):
if name in committed:
continue
pctxs = [repo[committed[n]] for n in parents]
pctxs.sort(key=lambda c: c.node())
added = {}
if len(parents) > 1:
# If it's a merge, take the files and contents from the parents
for f in pctxs[1].manifest():
if f not in pctxs[0].manifest():
added[f] = pycompat.decodeutf8(pctxs[1][f].data())
else:
# If it's not a merge, add a single file, if defaultfiles is set
if defaultfiles:
added[name] = name
# add extra file contents in comments
for path, content in files.get(name, {}).items():
added[path] = content
commitmutations = None
if name in mutations:
preds, cmd, split = mutations[name]
if split is not None:
split = [repo[committed[s]] for s in split]
commitmutations = ([repo[committed[p]] for p in preds], cmd, split)
date = dates.get(name, "0 0")
ctx = simplecommitctx(repo, name, pctxs, added, commitmutations, date)
n = ctx.commit()
committed[name] = n
if name not in mutationpreds and opts.get("bookmarks"):
bookmarks.addbookmarks(repo, tr, [name], hex(n), True, True)
# parse commits like "bookmark book_A=A" to specify bookmarks
dates = {}
bookmarkre = re.compile(r"^bookmark (\S+)\s*=\s*(\w+)$", re.M)
for book, name in bookmarkre.findall(commenttext):
node = committed.get(name)
if node:
bookmarks.addbookmarks(repo, tr, [book], hex(node), True, True)
# update visibility (hide commits)
hidenodes = [committed[n] for n in tohide]
visibility.remove(repo, hidenodes)
del committed[None]
if opts.get("print"):
for name, n in sorted(committed.items()):
if name:
repo.ui.write("%s %s\n" % (short(n), name))
if opts.get("write_env"):
path = opts.get("write_env")
with open(path, "w") as f:
for name, n in sorted(committed.items()):
if name and name not in existed:
f.write("%s=%s\n" % (name, hex(n)))