def _dograft()

in eden/scm/edenscm/mercurial/commands/__init__.py [0:0]


def _dograft(ui, repo, *revs, **opts):
    if revs and opts.get("rev"):
        ui.warn(
            _(
                "warning: inconsistent use of --rev might give unexpected "
                "revision ordering!\n"
            )
        )

    revs = list(revs)
    revs.extend(opts.get("rev"))

    if not opts.get("user") and opts.get("currentuser"):
        opts["user"] = ui.username()
    if not opts.get("date") and opts.get("currentdate"):
        opts["date"] = "%d %d" % util.makedate()

    editor = cmdutil.getcommiteditor(editform="graft", **opts)

    cont = False
    if opts.get("continue") or opts.get("abort"):
        if revs and opts.get("continue"):
            raise error.Abort(_("can't specify --continue and revisions"))
        if revs and opts.get("abort"):
            raise error.Abort(_("can't specify --abort and revisions"))

        # read in unfinished revisions
        try:
            nodes = repo.localvfs.readutf8("graftstate").splitlines()
            revs = [repo[node].rev() for node in nodes]
        except IOError as inst:
            if inst.errno != errno.ENOENT:
                raise
            cmdutil.wrongtooltocontinue(repo, _("graft"))

        if opts.get("continue"):
            cont = True
        if opts.get("abort"):
            return update(ui, repo, node=".", clean=True)
    else:
        cmdutil.checkunfinished(repo)
        cmdutil.bailifchanged(repo)
        if not revs:
            raise error.Abort(_("no revisions specified"))
        revs = scmutil.revrange(repo, revs)

    skipped = set()
    # check for merges
    for rev in repo.revs("%ld and merge()", revs):
        ui.warn(_("skipping ungraftable merge revision %d\n") % rev)
        skipped.add(rev)
    revs = [r for r in revs if r not in skipped]
    if not revs:
        raise error.Abort(_("empty revision set was specified"))

    # Don't check in the --continue case, in effect retaining --force across
    # --continues. That's because without --force, any revisions we decided to
    # skip would have been filtered out here, so they wouldn't have made their
    # way to the graftstate. With --force, any revisions we would have otherwise
    # skipped would not have been filtered out, and if they hadn't been applied
    # already, they'd have been in the graftstate.
    if not (cont or opts.get("force")):
        # check for ancestors of dest branch
        crev = repo["."].rev()
        ancestors = repo.changelog.ancestors([crev], inclusive=True)
        # XXX make this lazy in the future
        # don't mutate while iterating, create a copy
        for rev in list(revs):
            if rev in ancestors:
                ui.warn(_("skipping ancestor revision %s\n") % (repo[rev]))
                # XXX remove on list is slow
                revs.remove(rev)

        if not revs:
            return -1

    for pos, ctx in enumerate(repo.set("%ld", revs)):
        desc = '%s "%s"' % (ctx, ctx.description().split("\n", 1)[0])
        names = repo.nodebookmarks(ctx.node())
        if names:
            desc += " (%s)" % " ".join(names)
        ui.status(_("grafting %s\n") % desc)
        if opts.get("dry_run"):
            continue

        source = ctx.extra().get("source")
        extra = {}
        if source:
            extra["source"] = source
            extra["intermediate-source"] = ctx.hex()
        else:
            extra["source"] = ctx.hex()
        user = ctx.user()
        if opts.get("user"):
            user = opts["user"]
        date = ctx.date()
        if opts.get("date"):
            date = opts["date"]
        message = ctx.description()
        if opts.get("log"):
            message += "\n(grafted from %s)" % ctx.hex()

        # we don't merge the first commit when continuing
        if not cont:
            # perform the graft merge with p1(rev) as 'ancestor'
            try:
                # ui.forcemerge is an internal variable, do not document
                repo.ui.setconfig("ui", "forcemerge", opts.get("tool", ""), "graft")
                stats = mergemod.graft(repo, ctx, ctx.p1(), ["local", "graft"])
            finally:
                repo.ui.setconfig("ui", "forcemerge", "", "graft")
            # report any conflicts
            if stats and stats[3] > 0:
                # write out state for --continue
                nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
                repo.localvfs.writeutf8("graftstate", "".join(nodelines))
                extra = ""
                if opts.get("user"):
                    extra += " --user %s" % util.shellquote(opts["user"])
                if opts.get("date"):
                    extra += " --date %s" % util.shellquote(opts["date"])
                if opts.get("log"):
                    extra += " --log"
                hint = _("use 'hg resolve' and 'hg graft --continue%s'") % extra
                raise error.Abort(_("unresolved conflicts, can't continue"), hint=hint)
        else:
            cont = False

        # commit
        node = repo.commit(
            text=message, user=user, date=date, extra=extra, editor=editor
        )
        if node is None:
            ui.warn(_("note: graft of %s created no changes to commit\n") % (ctx))

    # remove state when we complete successfully
    if not opts.get("dry_run"):
        repo.localvfs.unlinkpath("graftstate", ignoremissing=True)

    return 0