Wed, 31 Aug 2011 18:44:04 +0200
Continued implementing an interface to the Mercurial command server.
Modified part 2 of the queues extension and the status monitor thread.
--- a/Plugins/VcsPlugins/vcsMercurial/HgStatusMonitorThread.py Tue Aug 30 19:39:52 2011 +0200 +++ b/Plugins/VcsPlugins/vcsMercurial/HgStatusMonitorThread.py Wed Aug 31 18:44:04 2011 +0200 @@ -10,6 +10,7 @@ from PyQt4.QtCore import QProcess from VCS.StatusMonitorThread import VcsStatusMonitorThread +from .HgClient import HgClient import Preferences @@ -30,6 +31,9 @@ VcsStatusMonitorThread.__init__(self, interval, project, vcs, parent) self.__ioEncoding = Preferences.getSystem("IOEncoding") + + self.__client = None + self.__useCommandLine = False def _performMonitor(self): """ @@ -54,66 +58,103 @@ """ self.shouldUpdate = False - process = QProcess() + if self.__client is None and not self.__useCommandLine: + if self.vcs.versionStr >= "1.9": + client = HgClient(self.projectDir, "utf-8") + ok, err = client.startServer() + if ok: + self.__client = client + else: + self.__useCommandLine = True + else: + self.__useCommandLine = True + + # step 1: get overall status args = [] args.append('status') args.append('--noninteractive') args.append('--all') - process.setWorkingDirectory(self.projectDir) - process.start('hg', args) - procStarted = process.waitForStarted() - if procStarted: - finished = process.waitForFinished(300000) - if finished and process.exitCode() == 0: - output = \ - str(process.readAllStandardOutput(), self.__ioEncoding, 'replace') - states = {} - for line in output.splitlines(): - if not line.startswith(" "): - flag, name = line.split(" ", 1) - if flag in "AMR": - if flag == "R": - status = "O" - else: - status = flag - states[name] = status - - args = [] - args.append('resolve') - args.append('--list') - process.setWorkingDirectory(self.projectDir) - process.start('hg', args) - procStarted = process.waitForStarted() - if procStarted: - finished = process.waitForFinished(300000) - if finished and process.exitCode() == 0: - output = str( - process.readAllStandardOutput(), self.__ioEncoding, 'replace') - for line in output.splitlines(): - flag, name = line.split(" ", 1) - if flag == "U": - states[name] = "Z" # conflict - - for name in states: - try: - if self.reportedStates[name] != states[name]: - self.statusList.append("{0} {1}".format(states[name], name)) - except KeyError: - self.statusList.append("{0} {1}".format(states[name], name)) - for name in self.reportedStates.keys(): - if name not in states: - self.statusList.append(" {0}".format(name)) - self.reportedStates = states - return True, \ - self.trUtf8("Mercurial status checked successfully") + + output = "" + error = "" + if self.__client: + output, error = self.__client.runcommand(args) + else: + process = QProcess() + process.setWorkingDirectory(self.projectDir) + process.start('hg', args) + procStarted = process.waitForStarted() + if procStarted: + finished = process.waitForFinished(300000) + if finished and process.exitCode() == 0: + output = \ + str(process.readAllStandardOutput(), self.__ioEncoding, 'replace') + else: + process.kill() + process.waitForFinished() + error = \ + str(process.readAllStandardError(), self.__ioEncoding, 'replace') else: process.kill() process.waitForFinished() - return False, \ - str(process.readAllStandardError(), - Preferences.getSystem("IOEncoding"), - 'replace') + error = self.trUtf8("Could not start the Mercurial process.") + + if error: + return False, error + + states = {} + for line in output.splitlines(): + if not line.startswith(" "): + flag, name = line.split(" ", 1) + if flag in "AMR": + if flag == "R": + status = "O" + else: + status = flag + states[name] = status + + # step 2: get conflicting changes + args = [] + args.append('resolve') + args.append('--list') + + output = "" + error = "" + if self.__client: + output, error = self.__client.runcommand(args) else: - process.kill() - process.waitForFinished() - return False, self.trUtf8("Could not start the Mercurial process.") + process.setWorkingDirectory(self.projectDir) + process.start('hg', args) + procStarted = process.waitForStarted() + if procStarted: + finished = process.waitForFinished(300000) + if finished and process.exitCode() == 0: + output = str( + process.readAllStandardOutput(), self.__ioEncoding, 'replace') + + for line in output.splitlines(): + flag, name = line.split(" ", 1) + if flag == "U": + states[name] = "Z" # conflict + + # step 3: collect the status to be reported back + for name in states: + try: + if self.reportedStates[name] != states[name]: + self.statusList.append("{0} {1}".format(states[name], name)) + except KeyError: + self.statusList.append("{0} {1}".format(states[name], name)) + for name in self.reportedStates.keys(): + if name not in states: + self.statusList.append(" {0}".format(name)) + self.reportedStates = states + + return True, \ + self.trUtf8("Mercurial status checked successfully") + + def _shutdown(self): + """ + Protected method performing shutdown actions. + """ + if self.__client: + self.__client.stopServer()
--- a/Plugins/VcsPlugins/vcsMercurial/QueuesExtension/HgQueuesListDialog.py Tue Aug 30 19:39:52 2011 +0200 +++ b/Plugins/VcsPlugins/vcsMercurial/QueuesExtension/HgQueuesListDialog.py Wed Aug 31 18:44:04 2011 +0200 @@ -39,6 +39,7 @@ self.process = QProcess() self.vcs = vcs + self.__hgClient = vcs.getClient() self.patchesList.header().setSortIndicator(0, Qt.AscendingOrder) @@ -110,23 +111,40 @@ if missing: args.append('--missing') - self.process.kill() - self.process.setWorkingDirectory(self.__repodir) - - self.process.start('hg', args) - procStarted = self.process.waitForStarted() - if not procStarted: + if self.__hgClient: self.inputGroup.setEnabled(False) self.inputGroup.hide() - E5MessageBox.critical(self, - self.trUtf8('Process Generation Error'), - self.trUtf8( - 'The process {0} could not be started. ' - 'Ensure, that it is in the search path.' - ).format('hg')) + + out, err = self.__hgClient.runcommand(args) + if err: + self.__showError(err) + if out: + for line in out.splitlines(): + self.__processOutputLine(line) + if self.__mode == "qseries": + self.__getSeries(True) + elif self.__mode == "missing": + self.__getTop() + else: + self.__finish() else: - self.inputGroup.setEnabled(True) - self.inputGroup.show() + self.process.kill() + self.process.setWorkingDirectory(self.__repodir) + + self.process.start('hg', args) + procStarted = self.process.waitForStarted() + if not procStarted: + self.inputGroup.setEnabled(False) + self.inputGroup.hide() + E5MessageBox.critical(self, + self.trUtf8('Process Generation Error'), + self.trUtf8( + 'The process {0} could not be started. ' + 'Ensure, that it is in the search path.' + ).format('hg')) + else: + self.inputGroup.setEnabled(True) + self.inputGroup.show() def __getTop(self): """ @@ -137,23 +155,35 @@ args = [] args.append('qtop') - self.process.kill() - self.process.setWorkingDirectory(self.__repodir) - - self.process.start('hg', args) - procStarted = self.process.waitForStarted() - if not procStarted: + if self.__hgClient: self.inputGroup.setEnabled(False) self.inputGroup.hide() - E5MessageBox.critical(self, - self.trUtf8('Process Generation Error'), - self.trUtf8( - 'The process {0} could not be started. ' - 'Ensure, that it is in the search path.' - ).format('hg')) + + out, err = self.__hgClient.runcommand(args) + if err: + self.__showError(err) + if out: + for line in out.splitlines(): + self.__processOutputLine(line) + self.__finish() else: - self.inputGroup.setEnabled(True) - self.inputGroup.show() + self.process.kill() + self.process.setWorkingDirectory(self.__repodir) + + self.process.start('hg', args) + procStarted = self.process.waitForStarted() + if not procStarted: + self.inputGroup.setEnabled(False) + self.inputGroup.hide() + E5MessageBox.critical(self, + self.trUtf8('Process Generation Error'), + self.trUtf8( + 'The process {0} could not be started. ' + 'Ensure, that it is in the search path.' + ).format('hg')) + else: + self.inputGroup.setEnabled(True) + self.inputGroup.show() def __finish(self): """ @@ -191,7 +221,11 @@ if button == self.buttonBox.button(QDialogButtonBox.Close): self.close() elif button == self.buttonBox.button(QDialogButtonBox.Cancel): - self.__finish() + self.__mode = "" + if self.__hgClient: + self.__hgClient.cancel() + else: + self.__finish() def __procFinished(self, exitCode, exitStatus): """ @@ -292,23 +326,31 @@ s = str(self.process.readLine(), Preferences.getSystem("IOEncoding"), 'replace').strip() - if self.__mode == "qtop": - self.__markTopItem(s) + self.__processOutputLine(s) + + def __processOutputLine(self, line): + """ + Private method to process the lines of output. + + @param line output line to be processed (string) + """ + if self.__mode == "qtop": + self.__markTopItem(line) + else: + l = line.split(": ", 1) + if len(l) == 1: + data, summary = l[0][:-1], "" else: - l = s.split(": ", 1) - if len(l) == 1: - data, summary = l[0][:-1], "" - else: - data, summary = l[0], l[1] - l = data.split(None, 2) - if len(l) == 2: - # missing entry - index, status, name = -1, l[0], l[1] - elif len(l) == 3: - index, status, name = l[:3] - else: - continue - self.__generateItem(index, status, name, summary) + data, summary = l[0], l[1] + l = data.split(None, 2) + if len(l) == 2: + # missing entry + index, status, name = -1, l[0], l[1] + elif len(l) == 3: + index, status, name = l[:3] + else: + return + self.__generateItem(index, status, name, summary) def __readStderr(self): """ @@ -318,12 +360,20 @@ error pane. """ if self.process is not None: - self.errorGroup.show() s = str(self.process.readAllStandardError(), Preferences.getSystem("IOEncoding"), 'replace') - self.errors.insertPlainText(s) - self.errors.ensureCursorVisible() + self.__showError(s) + + def __showError(self, out): + """ + Private slot to show some error. + + @param out error to be shown (string) + """ + self.errorGroup.show() + self.errors.insertPlainText(out) + self.errors.ensureCursorVisible() def on_passwordCheckBox_toggled(self, isOn): """
--- a/Plugins/VcsPlugins/vcsMercurial/QueuesExtension/HgQueuesListGuardsDialog.py Tue Aug 30 19:39:52 2011 +0200 +++ b/Plugins/VcsPlugins/vcsMercurial/QueuesExtension/HgQueuesListGuardsDialog.py Wed Aug 31 18:44:04 2011 +0200 @@ -35,6 +35,7 @@ self.process = QProcess() self.vcs = vcs + self.__hgClient = vcs.getClient() self.patchSelector.addItems([""] + patchesList) @@ -80,35 +81,41 @@ self.guardsList.clear() self.patchNameLabel.setText("") - ioEncoding = Preferences.getSystem("IOEncoding") - process = QProcess() args = [] args.append("qguard") if patch: args.append(patch) - process.setWorkingDirectory(self.__repodir) - process.start('hg', args) - procStarted = process.waitForStarted() - if procStarted: - finished = process.waitForFinished(30000) - if finished and process.exitCode() == 0: - output = \ - str(process.readAllStandardOutput(), ioEncoding, 'replace').strip() - if output: - patchName, guards = output.split(":", 1) - self.patchNameLabel.setText(patchName) - guardsList = guards.strip().split() - for guard in guardsList: - if guard.startswith("+"): - icon = UI.PixmapCache.getIcon("plus.png") - guard = guard[1:] - elif guard.startswith("-"): - icon = UI.PixmapCache.getIcon("minus.png") - guard = guard[1:] - else: - icon = None - guard = self.trUtf8("Unguarded") - itm = QListWidgetItem(guard, self.guardsList) - if icon: - itm.setIcon(icon) + output = "" + if self.__hgClient: + output = self.__hgClient.runcommand(args)[0].strip() + else: + ioEncoding = Preferences.getSystem("IOEncoding") + process = QProcess() + process.setWorkingDirectory(self.__repodir) + process.start('hg', args) + procStarted = process.waitForStarted() + if procStarted: + finished = process.waitForFinished(30000) + if finished and process.exitCode() == 0: + output = \ + str(process.readAllStandardOutput(), + ioEncoding, 'replace').strip() + + if output: + patchName, guards = output.split(":", 1) + self.patchNameLabel.setText(patchName) + guardsList = guards.strip().split() + for guard in guardsList: + if guard.startswith("+"): + icon = UI.PixmapCache.getIcon("plus.png") + guard = guard[1:] + elif guard.startswith("-"): + icon = UI.PixmapCache.getIcon("minus.png") + guard = guard[1:] + else: + icon = None + guard = self.trUtf8("Unguarded") + itm = QListWidgetItem(guard, self.guardsList) + if icon: + itm.setIcon(icon)
--- a/Plugins/VcsPlugins/vcsMercurial/QueuesExtension/HgQueuesQueueManagementDialog.py Tue Aug 30 19:39:52 2011 +0200 +++ b/Plugins/VcsPlugins/vcsMercurial/QueuesExtension/HgQueuesQueueManagementDialog.py Wed Aug 31 18:44:04 2011 +0200 @@ -24,7 +24,7 @@ NAME_INPUT = 1 QUEUE_INPUT = 2 - def __init__(self, mode, title, suppressActive, repodir, parent=None): + def __init__(self, mode, title, suppressActive, repodir, vcs, parent=None): """ Constructor @@ -35,6 +35,7 @@ @param suppressActive flag indicating to not show the name of the active queue (boolean) @param repodir name of the repository directory (string) + @param vcs reference to the vcs object @param parent reference to the parent widget (QWidget) """ super().__init__(parent) @@ -48,6 +49,7 @@ self.__mode = mode self.__repodir = repodir self.__suppressActive = suppressActive + self.__hgClient = vcs.getClient() self.inputFrame.setHidden(mode != HgQueuesQueueManagementDialog.NAME_INPUT) self.selectLabel.setHidden(mode != HgQueuesQueueManagementDialog.QUEUE_INPUT) @@ -81,26 +83,31 @@ queuesList = [] activeQueue = "" - ioEncoding = Preferences.getSystem("IOEncoding") - process = QProcess() args = [] args.append("qqueue") args.append("--list") - process.setWorkingDirectory(self.__repodir) - process.start('hg', args) - procStarted = process.waitForStarted() - if procStarted: - finished = process.waitForFinished(30000) - if finished and process.exitCode() == 0: - output = \ - str(process.readAllStandardOutput(), ioEncoding, 'replace') - for queue in output.splitlines(): - queue = queue.strip() - if queue.endswith(")"): - queue = queue.rsplit(None, 1)[0] - activeQueue = queue - queuesList.append(queue) + output = "" + if self.__hgClient: + output = self.__hgClient.runcommand(args)[0] + else: + ioEncoding = Preferences.getSystem("IOEncoding") + process = QProcess() + process.setWorkingDirectory(self.__repodir) + process.start('hg', args) + procStarted = process.waitForStarted() + if procStarted: + finished = process.waitForFinished(30000) + if finished and process.exitCode() == 0: + output = \ + str(process.readAllStandardOutput(), ioEncoding, 'replace') + + for queue in output.splitlines(): + queue = queue.strip() + if queue.endswith(")"): + queue = queue.rsplit(None, 1)[0] + activeQueue = queue + queuesList.append(queue) if self.__suppressActive: if activeQueue in queuesList:
--- a/Plugins/VcsPlugins/vcsMercurial/QueuesExtension/queues.py Tue Aug 30 19:39:52 2011 +0200 +++ b/Plugins/VcsPlugins/vcsMercurial/QueuesExtension/queues.py Wed Aug 31 18:44:04 2011 +0200 @@ -754,7 +754,7 @@ else: title = self.trUtf8("Rename Active Queue") dlg = HgQueuesQueueManagementDialog(HgQueuesQueueManagementDialog.NAME_INPUT, - title, False, repodir) + title, False, repodir, self.vcs) if dlg.exec_() == QDialog.Accepted: queueName = dlg.getData() if queueName: @@ -825,7 +825,7 @@ raise ValueError("illegal value for operation") dlg = HgQueuesQueueManagementDialog(HgQueuesQueueManagementDialog.QUEUE_INPUT, - title, True, repodir) + title, True, repodir, self.vcs) if dlg.exec_() == QDialog.Accepted: queueName = dlg.getData() if queueName: @@ -887,5 +887,5 @@ self.queuesListQueuesDialog = HgQueuesQueueManagementDialog( HgQueuesQueueManagementDialog.NO_INPUT, self.trUtf8("Available Queues"), - False, repodir) + False, repodir, self.vcs) self.queuesListQueuesDialog.show()
--- a/VCS/StatusMonitorThread.py Tue Aug 30 19:39:52 2011 +0200 +++ b/VCS/StatusMonitorThread.py Wed Aug 31 18:44:04 2011 +0200 @@ -94,6 +94,7 @@ self.monitorCondition.wait(self.monitorMutex, self.interval * 1000) self.monitorMutex.unlock() + self._shutdown() self.exit() def setInterval(self, interval): @@ -185,3 +186,11 @@ a status message in case of non successful operation (string) """ raise RuntimeError('Not implemented') + + def _shutdown(self): + """ + Protected method performing shutdown actions. + + The default implementation does nothing. + """ + pass