def commitctx()

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


    def commitctx(self, ctx, error=False):
        """Add a new revision to current repository.
        Revision information is passed via the context argument.
        """

        tr = None
        p1, p2 = ctx.p1(), ctx.p2()
        user = ctx.user()

        descriptionlimit = self.ui.configbytes("commit", "description-size-limit")
        if descriptionlimit:
            descriptionlen = len(ctx.description())
            if descriptionlen > descriptionlimit:
                raise errormod.Abort(
                    _("commit message length (%s) exceeds configured limit (%s)")
                    % (descriptionlen, descriptionlimit)
                )

        extraslimit = self.ui.configbytes("commit", "extras-size-limit")
        if extraslimit:
            extraslen = sum(len(k) + len(v) for k, v in pycompat.iteritems(ctx.extra()))
            if extraslen > extraslimit:
                raise errormod.Abort(
                    _("commit extras total size (%s) exceeds configured limit (%s)")
                    % (extraslen, extraslimit)
                )

        isgit = git.isgitformat(self)
        lock = self.lock()
        try:
            tr = self.transaction("commit")
            trp = weakref.proxy(tr)

            if ctx.manifestnode():
                # reuse an existing manifest revision
                mn = ctx.manifestnode()
                files = ctx.files()
            elif ctx.files():
                m1ctx = p1.manifestctx()
                m2ctx = p2.manifestctx()
                mctx = m1ctx.copy()

                m = mctx.read()
                m1 = m1ctx.read()
                m2 = m2ctx.read()

                # Validate that the files that are checked in can be interpreted
                # as utf8. This is to protect against potential crashes as we
                # move to utf8 file paths. Changing encoding is a beast on top
                # of storage format.
                try:
                    for f in ctx.added():
                        if isinstance(f, bytes):
                            f.decode("utf-8")
                except UnicodeDecodeError as inst:
                    raise errormod.Abort(
                        _("invalid file name encoding: %s!") % inst.object
                    )

                # check in files
                added = []
                changed = []

                removed = []
                drop = []

                def handleremove(f):
                    if f in m1 or f in m2:
                        removed.append(f)
                        if f in m:
                            del m[f]
                            drop.append(f)

                for f in ctx.removed():
                    handleremove(f)
                for f in sorted(ctx.modified() + ctx.added()):
                    if ctx[f] is None:
                        # in memctx this means removal
                        handleremove(f)
                    else:
                        added.append(f)

                linkrev = len(self)
                self.ui.note(_("committing files:\n"))

                if not isgit:
                    # Prefetch rename data, since _filecommit will look for it.
                    # (git does not need this step)
                    if util.safehasattr(self.fileslog, "metadatastore"):
                        keys = []
                        for f in added:
                            fctx = ctx[f]
                            if fctx.filenode() is not None:
                                keys.append((fctx.path(), fctx.filenode()))
                        self.fileslog.metadatastore.prefetch(keys)
                for f in added:
                    self.ui.note(f + "\n")
                    try:
                        fctx = ctx[f]
                        if isgit:
                            filenode = self._filecommitgit(fctx)
                        else:
                            filenode = self._filecommit(
                                fctx, m1, m2, linkrev, trp, changed
                            )
                        m[f] = filenode
                        m.setflag(f, fctx.flags())
                    except OSError:
                        self.ui.warn(_("trouble committing %s!\n") % f)
                        raise
                    except IOError as inst:
                        errcode = getattr(inst, "errno", errno.ENOENT)
                        if error or errcode and errcode != errno.ENOENT:
                            self.ui.warn(_("trouble committing %s!\n") % f)
                        raise

                # update manifest
                self.ui.note(_("committing manifest\n"))
                removed = sorted(removed)
                drop = sorted(drop)
                if added or drop:
                    if isgit:
                        mn = mctx.writegit()
                    else:
                        mn = (
                            mctx.write(
                                trp,
                                linkrev,
                                p1.manifestnode(),
                                p2.manifestnode(),
                                added,
                                drop,
                            )
                            or p1.manifestnode()
                        )
                else:
                    mn = p1.manifestnode()
                files = changed + removed
            else:
                mn = p1.manifestnode()
                files = []

            # update changelog
            self.ui.note(_("committing changelog\n"))
            self.changelog.delayupdate(tr)
            extra = ctx.extra().copy()
            n = self.changelog.add(
                mn,
                files,
                ctx.description(),
                trp,
                p1.node(),
                p2.node(),
                user,
                ctx.date(),
                extra,
            )
            xp1, xp2 = p1.hex(), p2 and p2.hex() or ""
            self.hook("pretxncommit", throw=True, node=hex(n), parent1=xp1, parent2=xp2)
            # set the new commit is proper phase
            targetphase = phases.newcommitphase(self.ui)
            if targetphase:
                # retract boundary do not alter parent changeset.
                # if a parent have higher the resulting phase will
                # be compliant anyway
                #
                # if minimal phase was 0 we don't need to retract anything
                phases.registernew(self, tr, targetphase, [n])
            # Newly committed commits should be visible.
            if targetphase > phases.public:
                visibility.add(self, [n])
            mutinfo = ctx.mutinfo()
            if mutinfo is not None:
                entry = mutation.createentry(n, mutinfo)
                mutation.recordentries(self, [entry], skipexisting=False)
            tr.close()

            # Generate and log interesting data.
            loginfo = ctx.loginfo()
            path = os.path.commonprefix([os.path.dirname(p) for p in files])
            if len(path) > 0:
                loginfo.update({"common_directory_path": path})

            diffnumber = diffprops.parserevfromcommitmsg(ctx.description())
            if diffnumber is not None:
                loginfo.update({"phabricator_diff_number": diffnumber})

            self.ui.log("commit_info", node=hex(n), author=user, **loginfo)
            return n
        finally:
            if tr:
                tr.release()
            lock.release()