Added stdout/stderr separation limitation and coloration
authoretisserant
Mon, 13 Aug 2007 17:22:39 +0200
changeset 7 e20fa7257d41
parent 6 97d73990053d
child 8 56bae4ff53c4
Added stdout/stderr separation limitation and coloration
Beremiz.py
--- a/Beremiz.py	Thu Aug 09 18:05:09 2007 +0200
+++ b/Beremiz.py	Mon Aug 13 17:22:39 2007 +0200
@@ -32,6 +32,9 @@
 sys.path.append(os.path.join(base_folder, "plcopeneditor"))
 sys.path.append(os.path.join(base_folder, "CanFestival-3", "objdictgen"))
 
+iec2cc_path = os.path.join(base_folder, "matiec", "iec2cc")
+ieclib_path = os.path.join(base_folder, "matiec", "lib")
+
 from PLCOpenEditor import PLCOpenEditor, ProjectDialog
 from PLCControler import PLCControler
 
@@ -78,13 +81,32 @@
 class LogPseudoFile:
     """ Base class for file like objects to facilitate StdOut for the Shell."""
     def __init__(self, output = None):
+        self.red_white = wx.TextAttr("RED", "WHITE")
+        self.red_yellow = wx.TextAttr("RED", "YELLOW")
+        self.black_white = wx.TextAttr("BLACK", "WHITE")
+        self.default_style = None
         self.output = output
 
     def writelines(self, l):
         map(self.write, l)
 
     def write(self, s):
-        self.output.SetValue(self.output.GetValue() + s) 
+        if self.default_style != self.black_white: 
+            self.output.SetDefaultStyle(self.black_white)
+            self.default_style = self.black_white
+        self.output.AppendText(s) 
+
+    def write_warning(self, s):
+        if self.default_style != self.red_white: 
+            self.output.SetDefaultStyle(self.red_white)
+            self.default_style = self.red_white
+        self.output.AppendText(s) 
+
+    def write_error(self, s):
+        if self.default_style != self.red_yellow: 
+            self.output.SetDefaultStyle(self.red_yellow)
+            self.default_style = self.red_yellow
+        self.output.AppendText(s) 
 
     def flush(self):
         self.output.SetValue("")
@@ -261,7 +283,7 @@
         
         self.LogConsole = wx.TextCtrl(id=ID_BEREMIZLOGCONSOLE, value='',
               name='LogConsole', parent=self, pos=wx.Point(0, 0),
-              size=wx.Size(0, 0), style=wx.TE_MULTILINE)
+              size=wx.Size(0, 0), style=wx.TE_MULTILINE|wx.TE_RICH2)
         
         self.EditPLCButton = wx.Button(id=ID_BEREMIZEDITPLCBUTTON, label='Edit\nPLC',
               name='EditPLCButton', parent=self, pos=wx.Point(0, 0),
@@ -617,25 +639,59 @@
             self.PLCEditor.RefreshToolBar()
             self.PLCEditor.Show()
 
+    def LogCommand(self, Command, sz_limit = 100):
+
+        import os, popen2, fcntl, select, signal
+        
+        child = popen2.Popen3(Command, 1) # capture stdout and stderr from command
+        child.tochild.close()             # don't need to talk to child
+        outfile = child.fromchild 
+        outfd = outfile.fileno()
+        errfile = child.childerr
+        errfd = errfile.fileno()
+        outdata = errdata = ''
+        outeof = erreof = 0
+        outlen = errlen = 0
+        while 1:
+            ready = select.select([outfd,errfd],[],[]) # wait for input
+            if outfd in ready[0]:
+                outchunk = outfile.readline()
+                if outchunk == '': outeof = 1
+                outdata += outchunk
+                outlen += 1
+                self.Log.write(outchunk)
+            if errfd in ready[0]:
+                errchunk = errfile.readline()
+                if errchunk == '': erreof = 1
+                errdata += errchunk
+                errlen += 1
+                self.Log.write_warning(errchunk)
+            if outeof and erreof : break
+            if errlen > sz_limit or outlen > sz_limit : 
+                os.kill(child.pid, signal.SIGTERM)
+                self.Log.write_error("Output size reached limit -- killed\n")
+                break
+        err = child.wait()
+        return (err, outdata, errdata)
+
     def BuildAutom(self):
         if self.PLCManager:
             self.TargetDir = os.path.join(self.CurrentProjectPath, "build")
             if not os.path.exists(self.TargetDir):
                 os.mkdir(self.TargetDir)
             self.Log.flush()
-            sys.stdout = self.Log
+            #sys.stdout = self.Log
             try:
-                print "Building ST Program..."
+                self.Log.write("Building ST Program...\n")
                 plc_file = os.path.join(self.TargetDir, "plc.st")
                 result = self.PLCManager.GenerateProgram(plc_file)
                 if not result:
-                    raise Exception
-                print "Compiling ST Program in to C Program..."
-                status, result = commands.getstatusoutput("../matiec/iec2cc %s -I ../matiec/lib %s"%(plc_file, self.TargetDir))
+                    raise Exception, "ST/IL/SFC code generator returned %d"%result
+                self.Log.write("Compiling ST Program in to C Program...\n")
+                status, result, err_result = self.LogCommand("%s %s -I %s %s"%(iec2cc_path, plc_file, ieclib_path, self.TargetDir))
                 if status:
-                    print result
-                    raise Exception
-                print "Extracting Located Variables..."
+                    raise Exception, "IEC2C compiler returned %d"%status
+                self.Log.write("Extracting Located Variables...\n")
                 location_file = open(os.path.join(self.TargetDir,"LOCATED_VARIABLES.h"))
                 locations = []
                 lines = [line.strip() for line in location_file.readlines()]
@@ -643,21 +699,23 @@
                     result = LOCATED_MODEL.match(line)
                     if result:
                         locations.append(result.groups())
-                print "Generating Network Configurations..."
+                self.Log.write("Generating Network Configurations...\n")
                 for bus_id, bus_infos in self.BusManagers.items():
                     if bus_infos["Type"] == "CanFestival":
                         master = config_utils.GenerateConciseDCF(locations, bus_id, bus_infos["NodeList"])
                         result = gen_cfile.GenerateFile("%s.c"%os.path.join(self.TargetDir, gen_cfile.FormatName(bus_infos["Name"])), master)
                         if result:
                             raise Exception
-                print "Generating Makefiles..."
+                self.Log.write("Generating Makefiles...\n")
                 
-                print "Compiling Project..."
+                self.Log.write("Compiling Project...\n")
                 
-                print "\nBuild Project completed"
+                self.Log.write("\nBuild Project completed\n")
             except Exception, message:
+                self.Log.write_error("\nBuild Failed\n")
+                self.Log.write(str(message))
                 pass
-            sys.stdout = sys.__stdout__
+            #sys.stdout = sys.__stdout__
                 
 #-------------------------------------------------------------------------------
 #                             Add Bus Dialog