src/eric7/Plugins/VcsPlugins/vcsMercurial/FastexportExtension/fastexport.py

Tue, 03 Dec 2024 14:21:36 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Tue, 03 Dec 2024 14:21:36 +0100
branch
eric7
changeset 11075
282fc28b44ee
child 11076
2989645b2618
permissions
-rw-r--r--

Mercurial Interface
- Added support for the `fastexport` extension.

# -*- coding: utf-8 -*-

# Copyright (c) 2025 Detlev Offenbach <detlev@die-offenbachs.de>
#

"""
Module implementing the fastexport extension interface.
"""

import os

from PyQt6.QtCore import QProcess, pyqtSlot
from PyQt6.QtWidgets import QDialog

from eric7.EricWidgets import EricMessageBox
from eric7.EricWidgets.EricProgressDialog import EricProgressDialog

from ..HgExtension import HgExtension
from ..HgUtilities import getHgExecutable


class Fastexport(HgExtension):
    """
    Class implementing the fastexport extension interface.
    """

    def __init__(self, vcs, ui=None):
        """
        Constructor

        @param vcs reference to the Mercurial vcs object
        @type Hg
        @param ui reference to a UI widget (defaults to None)
        @type QWidget
        """
        super().__init__(vcs, ui=ui)

        self.__process = None
        self.__progress = None

    def hgFastexport(self, revisions=None):
        """
        Public method to export the repository as a git fast-import stream.

        @param revisions list of revisions to be exported
        @type list of str
        """
        from .HgFastexportConfigDialog import HgFastexportConfigDialog

        dlg = HgFastexportConfigDialog(revisions=revisions, parent=self.ui)
        if dlg.exec() == QDialog.DialogCode.Accepted:
            outputFile, revisions, authormap, importMarks, exportMarks = dlg.getData()

            if os.path.exists(outputFile):
                overwrite = EricMessageBox.yesNo(
                    self.ui,
                    self.tr("Mercurial Fastexport"),
                    self.tr(
                        "<p>The output file <b>{0}</b> exists already. Overwrite it?"
                        "</p>"
                    ).format(outputFile),
                )
                if not overwrite:
                    return

            repoPath = self.vcs.getClient().getRepository()
            hgExecutable = getHgExecutable()

            args = self.vcs.initCommand("fastexport")
            args.extend(["--config", "progress.assume-tty=True"])
            args.extend(["--config", "progress.format=topic number estimate"])
            if authormap:
                args.extend(["--authormap", authormap])
            if importMarks:
                args.extend(["--import-marks", importMarks])
            if exportMarks:
                args.extend(["--export-marks", exportMarks])
            for revision in revisions:
                args.extend(["--rev", revision])

            self.__progress = None

            self.__process = QProcess(parent=self)
            self.__process.setStandardOutputFile(outputFile)
            self.__process.setWorkingDirectory(repoPath)
            self.__process.readyReadStandardError.connect(self.__readStderr)
            self.__process.finished.connect(self.__processFinished)
            self.__process.start(hgExecutable, args)

    @pyqtSlot()
    def __readStderr(self):
        """
        Private slot to handle the readyReadStandardError signal.
        """
        if self.__process is not None:
            output = str(
                self.__process.readAllStandardError(), self.vcs.getEncoding(), "replace"
            )
            if output.lstrip().startswith("exporting "):
                msg = output.splitlines()[-1]
                topic, number, estimate = msg.split(None, 2)
                value, maximum = number.split("/", 1)
                if self.__progress is None:
                    self.__progress = EricProgressDialog(
                        labelText="",
                        cancelButtonText=self.tr("Cancel"),
                        minimum=0,
                        maximum=int(maximum),
                        labelFormat=self.tr("%v/%m Changesets"),
                        parent=self.ui,
                    )
                    self.__progress.setWindowTitle(self.tr("Mercurial Fastexport"))
                    self.__progress.show()
                self.__progress.setLabelText(
                    self.tr("Exporting repository (time remaining: {0}) ...").format(
                        estimate
                    )
                )
                self.__progress.setValue(int(value))

                if self.__progress.wasCanceled() and self.__process is not None:
                    self.__process.terminate()

            else:
                if (
                    self.__progress
                    and not self.__progress.wasCanceled()
                    and self.output.strip()
                ):
                    EricMessageBox.warning(
                        self.ui,
                        self.tr("Mercurial Fastexport"),
                        self.tr(
                            "<p>The repository fastexport process sent an error"
                            " message.</p><p>{0}</p>"
                        ).format(output.strip()),
                    )

    @pyqtSlot(int, QProcess.ExitStatus)
    def __processFinished(self, exitCode, exitStatus):
        """
        Private slot to handle the process finished signal.

        @param exitCode exit code of the process
        @type int
        @param exitStatus exit status
        @type QProcess.ExitStatus
        """
        if self.__progress is not None:
            self.__progress.hide()
            self.__progress.deleteLater()
            self.__progress = None

        if exitStatus == QProcess.ExitStatus.NormalExit:
            if exitCode == 0:
                EricMessageBox.information(
                    self.ui,
                    self.tr("Mercurial Fastexport"),
                    self.tr(
                        "<p>The repository fastexport process finished"
                        " successfully.</p>"
                    ),
                )
            elif exitCode == 255:
                EricMessageBox.warning(
                    self.ui,
                    self.tr("Mercurial Fastexport"),
                    self.tr("<p>The repository fastexport process was cancelled.</p>"),
                )
            else:
                EricMessageBox.warning(
                    self.ui,
                    self.tr("Mercurial Fastexport"),
                    self.tr(
                        "<p>The repository fastexport process finished"
                        " with exit code <b>{0}</b>.</p>"
                    ).format(exitCode),
                )
        else:
            EricMessageBox.critical(
                self.ui,
                self.tr("Mercurial Fastexport"),
                self.tr("<p>The repository fastexport process crashed.</p>"),
            )

        self.__process.deleteLater()
        self.__process = None

eric ide

mercurial