OSProcess.st
changeset 647 7a142099a1ad
parent 583 4233a808de0e
equal deleted inserted replaced
646:52bc49856f76 647:7a142099a1ad
       
     1 "
       
     2  Copyright (c) 2007-2010 Jan Vrany
       
     3  Copyright (c) 2009-2010 eXept Software AG
       
     4 
       
     5  Permission is hereby granted, free of charge, to any person
       
     6  obtaining a copy of this software and associated documentation
       
     7  files (the 'Software'), to deal in the Software without
       
     8  restriction, including without limitation the rights to use,
       
     9  copy, modify, merge, publish, distribute, sublicense, and/or sell
       
    10  copies of the Software, and to permit persons to whom the
       
    11  Software is furnished to do so, subject to the following
       
    12  conditions:
       
    13 
       
    14  The above copyright notice and this permission notice shall be
       
    15  included in all copies or substantial portions of the Software.
       
    16 
       
    17  THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
       
    18  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
       
    19  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
       
    20  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
       
    21  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
       
    22  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
       
    23  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
       
    24  OTHER DEALINGS IN THE SOFTWARE.
       
    25 "
       
    26 "{ Package: 'stx:libsvn' }"
       
    27 
     1 "{ NameSpace: SVN }"
    28 "{ NameSpace: SVN }"
     2 "{ Package: 'stx:libsvn' }"
       
     3 
    29 
     4 Object subclass:#OSProcess
    30 Object subclass:#OSProcess
     5 	instanceVariableNames:'executable arguments environment workdir stdin stdout stderr
    31         instanceVariableNames:'executable arguments environment workdir stdin stdout stderr
     6 		exitValue runningLock'
    32                 exitValue runningLock'
     7 	classVariableNames:''
    33         classVariableNames:''
     8 	poolDictionaries:''
    34         poolDictionaries:''
     9 	category:'OS-Support'
    35         category:'OS-Support'
    10 !
    36 !
    11 
    37 
       
    38 !OSProcess class methodsFor:'documentation'!
       
    39 
       
    40 copyright
       
    41 "
       
    42  Copyright (c) 2007-2010 Jan Vrany
       
    43  Copyright (c) 2009-2010 eXept Software AG
       
    44 
       
    45  Permission is hereby granted, free of charge, to any person
       
    46  obtaining a copy of this software and associated documentation
       
    47  files (the 'Software'), to deal in the Software without
       
    48  restriction, including without limitation the rights to use,
       
    49  copy, modify, merge, publish, distribute, sublicense, and/or sell
       
    50  copies of the Software, and to permit persons to whom the
       
    51  Software is furnished to do so, subject to the following
       
    52  conditions:
       
    53 
       
    54  The above copyright notice and this permission notice shall be
       
    55  included in all copies or substantial portions of the Software.
       
    56 
       
    57  THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
       
    58  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
       
    59  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
       
    60  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
       
    61  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
       
    62  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
       
    63  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
       
    64  OTHER DEALINGS IN THE SOFTWARE.
       
    65 
       
    66 "
       
    67 ! !
    12 
    68 
    13 !OSProcess class methodsFor:'private'!
    69 !OSProcess class methodsFor:'private'!
    14 
    70 
    15 asShellQuotedArgument: anObject
    71 asShellQuotedArgument: anObject
    16 
    72 
    17     | aString unquotedStream quotedStream |
    73     | aString unquotedStream quotedStream |
    18     aString := anObject asString.
    74     aString := anObject asString.
    19 
    75 
    20     (aString first = $' and: [aString last = $'])
    76     (aString first = $' and: [aString last = $'])
    21 	ifTrue:[^aString].
    77         ifTrue:[^aString].
    22 
    78 
    23     (aString first = $" and: [aString last = $"])
    79     (aString first = $" and: [aString last = $"])
    24 	ifTrue:[^aString].
    80         ifTrue:[^aString].
    25 
    81 
    26     (aString allSatisfy:
    82     (aString allSatisfy:
    27 	[:char|char isSeparator not and: [(#($" $< $> $& $# $; $\) includes: char) not]])
    83         [:char|char isSeparator not and: [(#($" $< $> $& $# $; $\) includes: char) not]])
    28 	    ifTrue:[^aString].
    84             ifTrue:[^aString].
    29 
    85 
    30     unquotedStream := aString readStream.
    86     unquotedStream := aString readStream.
    31     quotedStream := (String new: aString size + 10) writeStream.
    87     quotedStream := (String new: aString size + 10) writeStream.
    32     quotedStream nextPut: $".
    88     quotedStream nextPut: $".
    33     [ unquotedStream atEnd ] whileFalse:
    89     [ unquotedStream atEnd ] whileFalse:
    34 	[|char|
    90         [|char|
    35 	char := unquotedStream next.
    91         char := unquotedStream next.
    36 	(#($" $\) includes: char) ifTrue:[quotedStream nextPut: $\].
    92         (#($" $\) includes: char) ifTrue:[quotedStream nextPut: $\].
    37 	quotedStream nextPut: char].
    93         quotedStream nextPut: char].
    38     quotedStream nextPut: $".
    94     quotedStream nextPut: $".
    39     ^quotedStream contents.
    95     ^quotedStream contents.
    40 
    96 
    41     "
    97     "
    42 	OSProcess asShellQuotedArgument: 'Hello' .
    98         OSProcess asShellQuotedArgument: 'Hello' .
    43 	OSProcess asShellQuotedArgument: 'Hello world'
    99         OSProcess asShellQuotedArgument: 'Hello world'
    44 	OSProcess asShellQuotedArgument: 'Hello'' world'
   100         OSProcess asShellQuotedArgument: 'Hello'' world'
    45 	OSProcess asShellQuotedArgument: 'Hello
   101         OSProcess asShellQuotedArgument: 'Hello
    46 	World'
   102         World'
    47     "
   103     "
    48 
   104 
    49     "Created: / 10-10-2008 / 12:32:18 / Jan Vrany <vranyj1@fel.cvut.cz>"
   105     "Created: / 10-10-2008 / 12:32:18 / Jan Vrany <vranyj1@fel.cvut.cz>"
    50     "Modified: / 02-06-2009 / 19:41:05 / Jan Vrany <vranyj1@fel.cvut.cz>"
   106     "Modified: / 02-06-2009 / 19:41:05 / Jan Vrany <vranyj1@fel.cvut.cz>"
    51 ! !
   107 ! !
   152 
   208 
   153     | cmdStream |
   209     | cmdStream |
   154     cmdStream := String new writeStream.
   210     cmdStream := String new writeStream.
   155     cmdStream nextPutAll:self executable.
   211     cmdStream nextPutAll:self executable.
   156     self arguments do:
   212     self arguments do:
   157 	[:arg|
   213         [:arg|
   158 	cmdStream space.
   214         cmdStream space.
   159 	cmdStream nextPutAll:(self asShellQuotedArgument: arg)].
   215         cmdStream nextPutAll:(self asShellQuotedArgument: arg)].
   160 
   216 
   161     ^cmdStream contents utf8Encoded
   217     ^cmdStream contents utf8Encoded
   162 
   218 
   163     "Created: / 19-03-2008 / 12:34:59 / janfrog"
   219     "Created: / 19-03-2008 / 12:34:59 / janfrog"
   164     "Modified: / 31-03-2008 / 14:09:05 / janfrog"
   220     "Modified: / 31-03-2008 / 14:09:05 / janfrog"
   168 !OSProcess methodsFor:'operations'!
   224 !OSProcess methodsFor:'operations'!
   169 
   225 
   170 execute
   226 execute
   171     "
   227     "
   172     self synchronized:
   228     self synchronized:
   173 	[runningLock
   229         [runningLock
   174 	    ifNotNil:[self error:'Process already running']
   230             ifNotNil:[self error:'Process already running']
   175 	    ifNil:[runningLock := Semaphore new:0]].
   231             ifNil:[runningLock := Semaphore new:0]].
   176     [["
   232     [["
   177 	(OperatingSystem
   233 
   178 	    executeCommand: self asShellCommandString
   234         OperatingSystem isMSWINDOWSlike"false"
   179 	    inputFrom: self stdin
   235             ifTrue: [self executeOnStupidPlatform]
   180 	    outputTo: self stdout
   236             ifFalse:[self executeOnReasonablePlatform]
   181 	    errorTo: self stderr
   237      "
   182 	    auxFrom: nil
   238 
   183 	    environment: nil
   239         (OperatingSystem
   184 	    inDirectory: self workdir asString
   240             executeCommand: self asShellCommandString
   185 	    lineWise: (self stdout = self stderr)
   241             inputFrom: self stdin
   186 	    onError:[:value|exitValue := value code.false])
   242             outputTo: self stdout
   187 	    ifTrue:[exitValue := 0]
   243             errorTo: self stderr
   188     "
   244             auxFrom: nil
       
   245             environment: nil
       
   246             inDirectory: self workdir asString
       
   247             lineWise: (self stdout = self stderr)
       
   248             onError:[:value|exitValue := value code.false])
       
   249             ifTrue:[exitValue := 0]
       
   250     "
       
   251 
   189     ] ensure:[runningLock signalForAll. runningLock := nil]] fork
   252     ] ensure:[runningLock signalForAll. runningLock := nil]] fork
   190     "
   253     "
   191 
   254 
   192     "Created: / 15-03-2008 / 18:11:20 / janfrog"
   255     "Created: / 15-03-2008 / 18:11:20 / janfrog"
   193     "Modified: / 19-03-2008 / 12:35:05 / janfrog"
   256     "Modified: / 19-03-2008 / 12:35:05 / janfrog"
   194     "Modified: / 08-06-2008 / 19:15:45 / Jan Vrany <vranyj1@fel.cvut.cz>"
   257     "Modified: / 08-06-2008 / 19:15:45 / Jan Vrany <vranyj1@fel.cvut.cz>"
       
   258     "Modified: / 11-04-2010 / 13:04:54 / Jan Vrany <jan.vrany@fit.cvut.cz>"
   195 !
   259 !
   196 
   260 
   197 waitFor
   261 waitFor
   198 
   262 
   199     "| lock |
   263     "| lock |
   200     self synchronized:
   264     self synchronized:
   201 	[runningLock
   265         [runningLock
   202 	    ifNil:[^self]
   266             ifNil:[^self]
   203 	    ifNotNil:[lock := runningLock]].
   267             ifNotNil:[lock := runningLock]].
   204     lock wait"
   268     lock wait"
   205 
   269 
   206     "Created: / 15-03-2008 / 18:32:41 / janfrog"
   270     "Created: / 15-03-2008 / 18:32:41 / janfrog"
   207     "Modified: / 08-06-2008 / 19:15:22 / Jan Vrany <vranyj1@fel.cvut.cz>"
   271     "Modified: / 08-06-2008 / 19:15:22 / Jan Vrany <vranyj1@fel.cvut.cz>"
   208 ! !
   272 ! !
   211 
   275 
   212 asShellQuotedArgument:arg
   276 asShellQuotedArgument:arg
   213     ^ self class asShellQuotedArgument:arg
   277     ^ self class asShellQuotedArgument:arg
   214 
   278 
   215     "Created: / 10-10-2008 / 12:32:18 / Jan Vrany <vranyj1@fel.cvut.cz>"
   279     "Created: / 10-10-2008 / 12:32:18 / Jan Vrany <vranyj1@fel.cvut.cz>"
       
   280 !
       
   281 
       
   282 executeOnReasonablePlatform
       
   283     "
       
   284     self synchronized:
       
   285         [runningLock 
       
   286             ifNotNil:[self error:'Process already running']
       
   287             ifNil:[runningLock := Semaphore new:0]].
       
   288     [["
       
   289         (OperatingSystem
       
   290             executeCommand: self asShellCommandString
       
   291             inputFrom: self stdin
       
   292             outputTo: self stdout
       
   293             errorTo: self stderr
       
   294             auxFrom: nil
       
   295             environment: nil
       
   296             inDirectory: self workdir asString
       
   297             lineWise: (self stdout = self stderr)
       
   298             onError:[:value|exitValue := value code.false])
       
   299             ifTrue:[exitValue := 0]        
       
   300     "
       
   301     ] ensure:[runningLock signalForAll. runningLock := nil]] fork
       
   302     "
       
   303 
       
   304     "Modified: / 19-03-2008 / 12:35:05 / janfrog"
       
   305     "Modified: / 08-06-2008 / 19:15:45 / Jan Vrany <vranyj1@fel.cvut.cz>"
       
   306     "Created: / 11-04-2010 / 12:49:15 / Jan Vrany <jan.vrany@fit.cvut.cz>"
       
   307 !
       
   308 
       
   309 executeOnStupidPlatform
       
   310 
       
   311     "i.e., on MS Windows. For some reasons sometimes part
       
   312      of stdout bytes are lost. Arghh.
       
   313      To workaround it, redirect output to file and then
       
   314      read that file. Stupid & complicated kludge, sigh."
       
   315 
       
   316     | extStdoutF extStdout extStderrF extStderr |
       
   317     [extStdout := (extStdoutF := Filename newTemporary) writeStream.
       
   318     extStderr := (extStderrF := Filename newTemporary) writeStream.        
       
   319     (OperatingSystem
       
   320             executeCommand: self asShellCommandString
       
   321             inputFrom: self stdin
       
   322             outputTo: extStdout
       
   323             errorTo: extStderr
       
   324             auxFrom: nil
       
   325             environment: nil
       
   326             inDirectory: self workdir asString
       
   327             lineWise: (self stdout = self stderr)
       
   328             onError:[:value|exitValue := value code.false])
       
   329             ifTrue:[exitValue := 0]    
       
   330     ] ensure: [
       
   331         extStdout close. extStderr close.
       
   332         stdout nextPutAll: extStdoutF contentsAsString.
       
   333         stderr nextPutAll: extStderrF contentsAsString.
       
   334         "Windows are really stupid!! Sometimes they lock files
       
   335          longer than needed. Even same process is not allowed
       
   336          to work with them. Sigh sigh sigh..."
       
   337         [ extStdoutF remove ] on: Error do:
       
   338             [Delay waitForMilliseconds: 10.
       
   339             [ extStdoutF remove ] on: Error do:
       
   340                 [Delay waitForMilliseconds: 20.
       
   341                 extStdoutF remove]].
       
   342         "Same for stderr"
       
   343         [ extStderrF remove ] on: Error do:
       
   344             [Delay waitForMilliseconds: 10.
       
   345             [ extStderrF remove ] on: Error do:
       
   346                 [Delay waitForMilliseconds: 20.
       
   347                 extStderrF remove]]]
       
   348 
       
   349     "Created: / 11-04-2010 / 12:50:57 / Jan Vrany <jan.vrany@fit.cvut.cz>"
       
   350     "Modified: / 04-09-2010 / 23:41:37 / Jan Vrany <jan.vrany@fit.cvut.cz>"
   216 ! !
   351 ! !
   217 
   352 
   218 !OSProcess class methodsFor:'documentation'!
   353 !OSProcess class methodsFor:'documentation'!
   219 
   354 
   220 version
   355 version
   224 version_CVS
   359 version_CVS
   225     ^ '$Header$'
   360     ^ '$Header$'
   226 !
   361 !
   227 
   362 
   228 version_SVN
   363 version_SVN
   229     ^'§Id: OSProcess.st 88 2009-06-15 12:12:29Z vranyj1 §'
   364     ^ '§Id: SVN__OSProcess.st 350 2011-07-07 18:42:56Z vranyj1 §'
   230 ! !
   365 ! !