Project/Project.py

branch
make_support
changeset 6254
88cb0838c90d
parent 6252
5e5e57bf09ed
child 6265
56bd09c4c297
diff -r 5e5e57bf09ed -r 88cb0838c90d Project/Project.py
--- a/Project/Project.py	Sun Apr 15 12:04:17 2018 +0200
+++ b/Project/Project.py	Tue Apr 17 19:53:46 2018 +0200
@@ -22,7 +22,7 @@
 import zipfile
 
 from PyQt5.QtCore import pyqtSlot, QFile, QFileInfo, pyqtSignal, \
-    QCryptographicHash, QIODevice, QByteArray, QObject, Qt
+    QCryptographicHash, QIODevice, QByteArray, QObject, Qt, QProcess
 from PyQt5.QtGui import QCursor, QKeySequence
 from PyQt5.QtWidgets import QLineEdit, QToolBar, QDialog, QInputDialog, \
     QApplication, QMenu, QAction
@@ -179,6 +179,7 @@
         }
         
         self.vcsMenu = None
+        self.__makeProcess = None
         
         self.__initProjectTypes()
         
@@ -4155,7 +4156,8 @@
             """<p>This questions 'make', if a rebuild of the configured"""
             """ target is necessary.</p>"""
         ))
-        self.makeTestAct.triggered.connect(self.__questionMake)
+        self.makeTestAct.triggered.connect(
+            lambda: self.__executeMake(questionOnly=True))
         self.actions.append(self.makeTestAct)
 
         self.closeAct.setEnabled(False)
@@ -5407,32 +5409,6 @@
         """
         self.showMenu.emit("Make", self.makeMenu)
     
-    @pyqtSlot()
-    def executeMake(self):
-        """
-        Public slot to execute a project specific make run (auto-run).
-        """
-        self.__executeMake(automatic=True)
-    
-    @pyqtSlot()
-    def __executeMake(self, automatic=False):
-        """
-        Private method to execute a project specific make run.
-        
-        @param automatic flag indicating a non-user invoked execution
-        @type bool
-        """
-        # TODO: implement this
-        pass
-    
-    @pyqtSlot()
-    def __questionMake(self):
-        """
-        Private method to question make for changes.
-        """
-        # TODO: implement this
-        pass
-    
     def hasDefaultMakeParameters(self):
         """
         Private method to test, if the project contains the default make
@@ -5458,3 +5434,149 @@
         @rtype bool
         """
         return self.pdata["MAKEPARAMS"]["MakeEnabled"]
+    
+    @pyqtSlot()
+    def executeMake(self):
+        """
+        Public slot to execute a project specific make run (auto-run)
+        (execute or question).
+        """
+        self.__executeMake(
+            questionOnly=self.pdata["MAKEPARAMS"]["MakeTestOnly"],
+            interactive=False)
+    
+    @pyqtSlot()
+    def __executeMake(self, questionOnly=False, interactive=True):
+        """
+        Private method to execute a project specific make run.
+        
+        @param questionOnly flag indicating to ask make for changes only
+        @type bool
+        @param interactive flag indicating an interactive invocation (i.e.
+            through a menu action)
+        @type bool
+        """
+        if not self.pdata["MAKEPARAMS"]["MakeEnabled"] or \
+           self.__makeProcess is not None:
+            return
+        
+        if self.pdata["MAKEPARAMS"]["MakeExecutable"]:
+            prog = self.pdata["MAKEPARAMS"]["MakeExecutable"]
+        else:
+            prog = Project.DefaultMake
+        
+        args = []
+        if self.pdata["MAKEPARAMS"]["MakeParameters"]:
+            args.extend(Utilities.parseOptionString(
+                self.pdata["MAKEPARAMS"]["MakeParameters"]))
+        
+        if self.pdata["MAKEPARAMS"]["MakeFile"]:
+            args.append("--makefile={0}".format(
+                self.pdata["MAKEPARAMS"]["MakeFile"]))
+        
+        if questionOnly:
+            args.append("--question")
+        
+        if self.pdata["MAKEPARAMS"]["MakeTarget"]:
+            args.append(self.pdata["MAKEPARAMS"]["MakeTarget"])
+        
+        self.__makeProcess = QProcess(self)
+        self.__makeProcess.readyReadStandardOutput.connect(
+            self.__makeReadStdOut)
+        self.__makeProcess.readyReadStandardError.connect(
+            self.__makeReadStdErr)
+        self.__makeProcess.finished.connect(
+            lambda exitCode, exitStatus: self.__makeFinished(
+                exitCode, exitStatus, questionOnly, interactive))
+        self.__makeProcess.setWorkingDirectory(self.getProjectPath())
+        self.__makeProcess.start(prog, args)
+        
+        if not self.__makeProcess.waitForStarted():
+            E5MessageBox.critical(
+                self.ui,
+                self.tr("Execute Make"),
+                self.tr("""The make process did not start."""))
+            
+            self.__cleanupMake()
+    
+    @pyqtSlot()
+    def __makeReadStdOut(self):
+        """
+        Private slot to process process output received via stdout.
+        """
+        if self.__makeProcess is not None:
+            output = str(self.__makeProcess.readAllStandardOutput(),
+                         Preferences.getSystem("IOEncoding"),
+                         'replace')
+            self.appendStdout.emit(output)
+    
+    @pyqtSlot()
+    def __makeReadStdErr(self):
+        """
+        Private slot to process process output received via stderr.
+        """
+        if self.__makeProcess is not None:
+            error = str(self.__makeProcess.readAllStandardError(),
+                        Preferences.getSystem("IOEncoding"),
+                        'replace')
+            self.appendStderr.emit(error)
+    
+    def __makeFinished(self, exitCode, exitStatus, questionOnly,
+                       interactive=True):
+        """
+        Private slot handling the make process finished signal.
+        
+        @param exitCode exit code of the make process
+        @type int
+        @param exitStatus exit status of the make process
+        @type QProcess.ExitStatus
+        @param questionOnly flag indicating a test only run
+        @type bool
+        @param interactive flag indicating an interactive invocation (i.e.
+            through a menu action)
+        @type bool
+        """
+        if exitStatus == QProcess.CrashExit:
+            E5MessageBox.critical(
+                self.ui,
+                self.tr("Execute Make"),
+                self.tr("""The make process crashed."""))
+        else:
+            if questionOnly and exitCode == 1:
+                # a rebuild is needed
+                title = self.tr("Test for Changes")
+                
+                if self.pdata["MAKEPARAMS"]["MakeTarget"]:
+                    message = self.tr(
+                        """<p>There are changes that require the configured"""
+                        """ make target <b>{0}</b> to be rebuilt.</p>""")\
+                    .format(self.pdata["MAKEPARAMS"]["MakeTarget"])
+                else:
+                    message = self.tr(
+                        """<p>There are changes that require the default"""
+                        """ make target to be rebuilt.</p>""")
+                
+                if self.ui.notificationsEnabled() and not interactive:
+                    self.ui.showNotification(
+                        UI.PixmapCache.getPixmap("makefile48.png"),
+                        title,
+                        message)
+                else:
+                    E5MessageBox.information(self.ui, title, message)
+            elif exitCode > 1:
+                E5MessageBox.critical(
+                    self.ui,
+                    self.tr("Execute Make"),
+                    self.tr("""The makefile contains errors."""))
+        
+        self.__cleanupMake()
+    
+    def __cleanupMake(self):
+        """
+        Private method to clean up make related stuff.
+        """
+        self.__makeProcess.readyReadStandardOutput.disconnect()
+        self.__makeProcess.readyReadStandardError.disconnect()
+        self.__makeProcess.finished.disconnect()
+        self.__makeProcess.deleteLater()
+        self.__makeProcess = None

eric ide

mercurial