add: #executeCommand:inputFrom:outputTo:errorTo:auxFrom:inDirectory:lineWise:onError:
--- a/AbstractOperatingSystem.st Tue Mar 04 08:59:01 2003 +0100
+++ b/AbstractOperatingSystem.st Tue Mar 04 09:00:26 2003 +0100
@@ -961,6 +961,199 @@
"Modified: / 10.11.1998 / 20:54:37 / cg"
!
+executeCommand:aCommandString inputFrom:anInStream outputTo:anOutStream errorTo:anErrStream auxFrom:anAuxStream inDirectory:dirOrNil lineWise:lineWise onError:aBlock
+ "execute the unix command specified by the argument, aCommandString.
+ The commandString is passed to a shell for execution - see the description of
+ 'sh -c' in your UNIX manual.
+ Return true if successful.
+ If not successfull, aBlock is called with an OsProcessStatus
+ (containing the exit status) as argument.
+ The given in, out and err streams may be arbitrary (Smalltalk-) streams;
+ if any is not an external stream (which is required by the command),
+ extra pipes and shuffler processes are created, which stuff the data into
+ those internal stream(s).
+ Nil stream args will execute the command connected to ST/X's standard input, output or
+ error resp. - i.e. usually, i/o will be from/to the terminal"
+
+ |pid exitStatus sema pIn pOut pErr pAux externalInStream externalOutStream externalErrStream externalAuxStream
+ shuffledInStream shuffledOutStream shuffledErrStream shuffledAuxStream
+ inputShufflerProcess outputShufflerProcess errorShufflerProcess auxShufflerProcess stopShufflers
+ inStreamToClose outStreamToClose errStreamToClose auxStreamToClose terminateLock|
+
+ terminateLock := Semaphore forMutualExclusion.
+ ((externalInStream := anInStream) notNil
+ and:[externalInStream isExternalStream not]) ifTrue:[
+ pIn := ExternalStream makePipe.
+ inStreamToClose := externalInStream := pIn at:1.
+ shuffledInStream := pIn at:2.
+ lineWise ifTrue:[shuffledInStream buffered:false].
+
+ "/ start a reader process, shuffling data from the given
+ "/ inStream to the pipe (which is connected to the commands input)
+ inputShufflerProcess := [
+ [
+ [anInStream atEnd] whileFalse:[
+ self shuffleFrom:anInStream to:shuffledInStream lineWise:lineWise.
+ shuffledInStream flush
+ ]
+ ] ensure:[
+ shuffledInStream close
+ ]
+ ] forkNamed:'cmd input shuffler'.
+ ].
+ ((externalOutStream := anOutStream) notNil
+ and:[externalOutStream isExternalStream not]) ifTrue:[
+ pOut := ExternalStream makePipe.
+ shuffledOutStream := (pOut at:1).
+ outStreamToClose := externalOutStream := pOut at:2.
+ lineWise ifTrue:[shuffledOutStream buffered:false].
+ outputShufflerProcess :=
+ [
+ self shuffleAllFrom:shuffledOutStream to:anOutStream lineWise:lineWise lockWith:terminateLock.
+ ] forkNamed:'cmd output shuffler'.
+ ].
+ (externalErrStream := anErrStream) notNil ifTrue:[
+ anErrStream == anOutStream ifTrue:[
+ externalErrStream := externalOutStream
+ ] ifFalse:[
+ anErrStream isExternalStream ifFalse:[
+ pErr := ExternalStream makePipe.
+ shuffledErrStream := (pErr at:1).
+ errStreamToClose := externalErrStream := pErr at:2.
+
+ lineWise ifTrue:[shuffledErrStream buffered:false].
+ errorShufflerProcess :=
+ [
+ self shuffleAllFrom:shuffledErrStream to:anErrStream lineWise:lineWise lockWith:terminateLock.
+ ] forkNamed:'cmd err-output shuffler'.
+ ]
+ ]
+ ].
+ ((externalAuxStream := anAuxStream) notNil
+ and:[externalAuxStream isExternalStream not]) ifTrue:[
+ pAux := ExternalStream makePipe.
+ auxStreamToClose := externalAuxStream := pAux at:1.
+ shuffledAuxStream := pAux at:2.
+
+ "/ start a reader process, shuffling data from the given
+ "/ auxStream to the pipe (which is connected to the commands aux)
+ auxShufflerProcess := [
+ [
+ [anAuxStream atEnd] whileFalse:[
+ self shuffleFrom:anAuxStream to:shuffledAuxStream lineWise:false.
+ shuffledAuxStream flush
+ ]
+ ] ensure:[
+ shuffledAuxStream close
+ ]
+ ] forkNamed:'cmd aux shuffler'.
+ ].
+
+ sema := Semaphore new name:'OS command wait'.
+ pid := Processor
+ monitor:[
+ self
+ startProcess:aCommandString
+ inputFrom:externalInStream
+ outputTo:externalOutStream
+ errorTo:externalErrStream
+ auxFrom:externalAuxStream
+ inDirectory:dirOrNil
+ ]
+ action:[:status |
+ status stillAlive ifFalse:[
+ exitStatus := status.
+ sema signal.
+ self closePid:pid
+ ]
+ ].
+
+ inStreamToClose notNil ifTrue:[
+ inStreamToClose close
+ ].
+ errStreamToClose notNil ifTrue:[
+ errStreamToClose close
+ ].
+ outStreamToClose notNil ifTrue:[
+ outStreamToClose close
+ ].
+ auxStreamToClose notNil ifTrue:[
+ auxStreamToClose close
+ ].
+
+ stopShufflers := [
+ inputShufflerProcess notNil ifTrue:[
+ terminateLock critical:[inputShufflerProcess terminate].
+ inputShufflerProcess waitUntilTerminated
+ ].
+ auxShufflerProcess notNil ifTrue:[
+ terminateLock critical:[auxShufflerProcess terminate].
+ auxShufflerProcess waitUntilTerminated
+ ].
+ outputShufflerProcess notNil ifTrue:[
+ terminateLock critical:[outputShufflerProcess terminate].
+ outputShufflerProcess waitUntilTerminated.
+ self shuffleRestFrom:shuffledOutStream to:anOutStream lineWise:lineWise.
+ shuffledOutStream close.
+ ].
+ errorShufflerProcess notNil ifTrue:[
+ terminateLock critical:[errorShufflerProcess terminate].
+ errorShufflerProcess waitUntilTerminated.
+ self shuffleRestFrom:shuffledErrStream to:anErrStream lineWise:lineWise.
+ shuffledErrStream close.
+ ].
+ ].
+
+ pid notNil ifTrue:[
+ [
+ sema wait.
+ ] ifCurtailed:[
+ "/ terminate the os-command (and all of its forked commands)
+ self terminateProcessGroup:pid.
+ self terminateProcess:pid.
+ self closePid:pid.
+ stopShufflers value.
+ ]
+ ] ifFalse:[
+ exitStatus := self osProcessStatusClass processCreationFailure
+ ].
+ stopShufflers value.
+ exitStatus success ifFalse:[
+ ^ aBlock value:exitStatus
+ ].
+ ^ true
+
+ "
+ |outStream errStream|
+
+ outStream := '' writeStream.
+
+ OperatingSystem executeCommand:'ls -l'
+ inputFrom:'abc' readStream
+ outputTo:outStream
+ errorTo:nil
+ inDirectory:nil
+ lineWise:true
+ onError:[:exitStatus | ^ false].
+ outStream contents
+ "
+
+ "
+ |outStream errStream|
+
+ outStream := '' writeStream.
+
+ OperatingSystem executeCommand:'gpg -s --batch --no-tty --passphrase-fd 0 /tmp/passwd'
+ inputFrom:'bla' readStream
+ outputTo:outStream
+ errorTo:nil
+ inDirectory:nil
+ lineWise:true
+ onError:[:exitStatus | false].
+ outStream contents
+ "
+!
+
executeCommand:aCommandString inputFrom:anInStream outputTo:anOutStream errorTo:anErrStream inDirectory:dirOrNil lineWise:lineWise onError:aBlock
"execute the unix command specified by the argument, aCommandString.
The commandString is passed to a shell for execution - see the description of
@@ -4283,7 +4476,7 @@
!AbstractOperatingSystem class methodsFor:'documentation'!
version
- ^ '$Header: /cvs/stx/stx/libbasic/AbstractOperatingSystem.st,v 1.86 2003-03-03 20:09:17 stefan Exp $'
+ ^ '$Header: /cvs/stx/stx/libbasic/AbstractOperatingSystem.st,v 1.87 2003-03-04 08:00:26 ca Exp $'
! !
AbstractOperatingSystem initialize!