def _drawdagintransaction()

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)))