#BUGFIX by cg
authorClaus Gittinger <cg@exept.de>
Fri, 27 Apr 2018 15:13:16 +0200
changeset 4639 3e5713fe4685
parent 4638 4d145bdadcf8
child 4640 84130c41071a
#BUGFIX by cg class: TerminalSession added: #closeDownShell: removed: #killShell comment/format in: #closeDownShell #defineWindowSizeLines:columns: #startCommand:in:environment:setupTerminalWith:terminatedAction: changed: #outputFromAction:prompt:timeout:to: #readerProcessLoop #startReaderProcess #stopReaderProcess class: TerminalSession class added: #examples comment/format in: #documentation #initialize
TerminalSession.st
--- a/TerminalSession.st	Thu Apr 26 10:17:02 2018 +0200
+++ b/TerminalSession.st	Fri Apr 27 15:13:16 2018 +0200
@@ -1,3 +1,5 @@
+"{ Encoding: utf8 }"
+
 "
  COPYRIGHT (c) 2013 by eXept Software AG
               All Rights Reserved
@@ -43,6 +45,8 @@
 
 documentation
 "
+    This is basically a TerminalView without a view.
+
     This keeps the state and API to interact with another program
     via a terminal session. Under Unix, a pseudo-tty connection
     is used; other operating systems might use other mechanisms.
@@ -67,6 +71,37 @@
     inStream    - the controlled program's input (a pty-half)
     errStream   - the controlled program's output (a pty-half)
 "
+!
+
+examples
+"
+    |session|
+
+    session := TerminalSession new.
+    session startReaderProcess.
+    session 
+        pluggableProcessInputAction:[:buffer :n |
+            Transcript show:(buffer copyTo:n).
+            Transcript endEntry.
+        ].
+    session 
+        startCommand:'ls -l' in:'~' 
+        environment:nil 
+        setupTerminalWith:[] 
+        terminatedAction:[ Transcript showCR:'finished' ].
+
+    session 
+        startCommand:'(cd ~/work/cg/schemeNew ; make)' in:'~' 
+        environment:nil 
+        setupTerminalWith:[] 
+        terminatedAction:[ Transcript showCR:'finished' ].
+
+    session 
+        startCommand:'(ls ~/work/cg/schemeNew)' in:'~' 
+        environment:nil 
+        setupTerminalWith:[] 
+        terminatedAction:[ Transcript showCR:'finished' ].
+"
 ! !
 
 !TerminalSession class methodsFor:'initialization'!
@@ -77,6 +112,7 @@
 
     "
      self initialize
+     Debug := true.
     "
 ! !
 
@@ -144,19 +180,32 @@
 closeDownShell
     "shut down my shell process"
 
-    |pid|
+    self closeDownShell:1
+!
+
+closeDownShell:waitTimeInSeconds
+    "shut down my shell process"
+
+    |pid waitTime|
 
     (pid := shellPid) notNil ifTrue:[
+        Logger info:'killing shell pid=%1' with:shellPid.
         Debug ifTrue:[
-            Transcript show:'killing shell pid='; showCR:pid.
+            Logger info:'killing shell pid=%1' with:pid.
         ].
-        OperatingSystem isMSWINDOWSlike ifFalse:[
-            OperatingSystem terminateProcessGroup:pid.
-        ].    
+        OperatingSystem terminateProcessGroup:pid.
         OperatingSystem terminateProcess:pid.
-        Delay waitForSeconds:0.2.
+
+        waitTime := 0.
+        [shellPid notNil and:[waitTime < waitTimeInSeconds]] whileTrue:[
+            Delay waitForSeconds:0.1.
+            waitTime := waitTime + 0.1
+        ].
+        Logger info:'shell pid after SIGTERM=%1' with:shellPid.
+
+        "/ still not dead?
         shellPid notNil ifTrue:[
-            "/ Delay waitForSeconds:1.
+            Logger info:'stil not dead after %1' with:waitTimeInSeconds.
             OperatingSystem isMSWINDOWSlike ifFalse:[
                 OperatingSystem killProcessGroup:pid.
             ].
@@ -256,29 +305,6 @@
     ].
 !
 
-killShell
-    "shut down my shell process and stop the background reader thread."
-
-    |pid|
-
-    (pid := shellPid) notNil ifTrue:[
-        Debug ifTrue:[
-            Transcript show:'killing shell pid='; showCR:pid.
-        ].
-        OperatingSystem terminateProcessGroup:pid.
-        OperatingSystem terminateProcess:pid.
-        Delay waitForSeconds:1.
-        shellPid notNil ifTrue:[
-            OperatingSystem isMSWINDOWSlike ifFalse:[
-                OperatingSystem killProcessGroup:pid.
-            ].
-            OperatingSystem killProcess:pid.
-            shellPid := nil.
-        ].
-        OperatingSystem closePid:pid.
-    ].
-!
-
 reinitialize
     shellPid := nil.
     inStream := outStream := errStream := nil.
@@ -328,8 +354,7 @@
     shellPid := Processor
                monitor:[
                   Debug ifTrue:[
-                      Transcript show:'exec:'; show:shell.
-                      Transcript show:' args:'; showCR:args.
+                      Logger info:'exec: "%1" args: "%2"' with:shell with:args.
                   ].
                   OperatingSystem
                       exec:shell
@@ -343,10 +368,10 @@
                ]
                action:[:status |
                     Debug ifTrue:[
-                        Transcript show:'pid:'; showCR:status pid.
-                        Transcript show:'status:'; showCR:status status.
-                        Transcript show:'code:'; showCR:status code.
-                        Transcript show:'core:'; showCR:status core.
+                        Logger info:'pid: %1' with:status pid.
+                        Logger info:'status %1:' with:status status.
+                        Logger info:'code: %1' with:status code.
+                        Logger info:'core %1:' with:status core.
                     ].
                     status stillAlive ifFalse:[
                         exitStatus := status.
@@ -356,6 +381,8 @@
                     ].
                ].
 
+    Logger info:'started shell pid: %1' with:shellPid.
+
     "close the slave side of the pty/pipes (only used by the child)"
     pty notNil ifTrue:[
         (pty at:2) close.
@@ -437,10 +464,7 @@
 !
 
 defineWindowSizeLines:numberOfLines columns:numberOfColumns
-    | delta prevNumCols prevNumLines|
-
     "/ any idea, how to do this under windows ?
-
     OperatingSystem isUNIXlike ifTrue:[
         "/
         "/ tell the pty;
@@ -450,14 +474,14 @@
         and:[inStream isExternalStream
         and:[inStream isOpen]]) ifTrue:[
             Debug ifTrue:[
-                Transcript showCR:'TerminalSession [info]: changed len to ', numberOfLines printString.
+                Logger info:'TerminalSession [info]: changed len to %1' with:numberOfLines.
             ].
             (OperatingSystem 
                 setWindowSizeOnFileDescriptor:inStream fileDescriptor
                 width:numberOfColumns
                 height:numberOfLines) ifFalse:[
                 Debug ifTrue:[
-                    Transcript showCR:'TerminalSession [warning]: cannot change windowSize'.
+                    Logger info:'TerminalSession [warning]: cannot change windowSize'.
                 ].
             ].
 
@@ -534,9 +558,9 @@
         (gotPrompt := (sema waitWithTimeout:seconds) notNil) ifFalse:[
             newSize := collectedOutput size.
             self debuggingCodeFor:#cg is:[
-                Transcript show:'timeout - output size is: '; showCR:newSize.
+                Logger info:'timeout - output size is: %1' with:newSize.
                 (newSize between:1 and:1000) ifTrue:[
-                    Transcript show:'output is: '; showCR:collectedOutput contents.
+                    Logger info:'output is: "%1"' with:collectedOutput contents.
                 ].
             ].
 
@@ -759,30 +783,33 @@
                 |n sensor|
 
                 readerDelay notNil ifTrue:[ Delay waitForSeconds:readerDelay].
-                outStream isNil ifTrue:[^ self].
-                outStream readWait.
+                outStream isNil ifTrue:[
+                    Delay waitForSeconds:0.1
+                ] ifFalse:[
+                    outStream readWait.
 
-                (pluggableCheckBeforeReadAction isNil
-                or:[pluggableCheckBeforeReadAction value]) ifTrue:[
-                    n := self readAnyAvailableData.
-                    n == 0 ifTrue:[
-                        "/ Windows IPC has a bug - it always
-                        "/ returns 0 (when the command is idle)
-                        "/ and says it's at the end (sigh)
+                    (pluggableCheckBeforeReadAction isNil
+                    or:[pluggableCheckBeforeReadAction value]) ifTrue:[
+                        n := self readAnyAvailableData.
+                        n == 0 ifTrue:[
+                            "/ Windows IPC has a bug - it always
+                            "/ returns 0 (when the command is idle)
+                            "/ and says it's at the end (sigh)
 
-                        OperatingSystem isMSWINDOWSlike ifTrue:[
-                            Delay waitForSeconds:0.1
-                        ] ifFalse:[
-                            outStream atEnd ifTrue:[
-                                outStream close. outStream := nil.
-                                inStream close.  inStream := nil.
-                                Processor activeProcess terminate.
+                            OperatingSystem isMSWINDOWSlike ifTrue:[
+                                Delay waitForSeconds:0.1
                             ] ifFalse:[
-                                "/ this should not happen.
+                                outStream atEnd ifTrue:[
+                                    outStream close. outStream := nil.
+                                    inStream close.  inStream := nil.
+                                    Processor activeProcess terminate.
+                                ] ifFalse:[
+                                    "/ this should not happen.
 
-                                Delay waitForSeconds:0.1
-                            ]
-                        ].
+                                    Delay waitForSeconds:0.1
+                                ]
+                            ].
+                        ]
                     ]
                 ]
             ]
@@ -794,6 +821,7 @@
     "Start a reader process, which looks for the commands output,
      and sends me #processInput:n: events whenever something arrives."
 
+    Logger info:'start reader'.
     readerProcess isNil ifTrue:[
         readerProcess := [
             [
@@ -818,6 +846,7 @@
 
     |p|
 
+    Logger info:'stop reader'.
     (p := readerProcess) notNil ifTrue:[
         readerProcess := nil.
         p terminate.