OsProcessStarter
This class is to help configure and start an operating system processes.
This class uses a builder design pattern, so configurations for starting the process are being stored internally, and then the OsProcessStarter>>start method can be repeatedly used to spawn new processes with the same configuration.
Its important to note that the external process is running in parallel to the VAST process which is why an asynchronous programming style is preferred when deciding to take action after the external process completes. Many of the examples below will request an onCompletion future and then perform an action when the future notifies that its complete.
EXAMPLES:
"Run `dir` and print the results on the transcript once the process completes"
(OsProcessStarter startShell: 'dir') onCompletion
then: [:proc | Transcript show: proc outputStream upToEnd ; cr].
 
"Run `dir /b` and print the results on the transcript once the process completes"
(OsProcessStarter startShell: \#('dir' '/b')) onCompletion
then: [:proc | Transcript show: proc outputStream upToEnd; cr].
 
"Run `dir /b` in a particular working directory."
((OsProcessStarter shell: \#('dir' '/b'))
workingDirectory: 'C:\Temp';
start) onCompletion then: [:proc | Transcript show: proc outputStream upToEnd; cr].
 
"Run `dir` redirecting stderr to stdout and redirecting stdout to Nul.
Block the current Smalltalk process until the external process completes."
((OsProcessStarter shell: \#('dir' '/b'))
redirectErrorToOutput;
redirectOutputToNull;
start) waitForCompletion.
Class Methods
command:
  Set the os program and arguments
     and answer the new starter.

     @progAndArgs is a <SequenceableCollection>,
     where the first element is the program name
     and any remaining elements will be the arguments.

     Arguments:
        progAndArgs - <SequenceableCollection>
     Answers:
        <OsProcessStarter>
new
  Answer a new initialized instance of this process starter.

     Answers:
        <OsProcessStarter>
shell:
  Set the os program and arguments
     and answer the new starter configured
     to run @progAndArgs in the system shell

     @progAndArgs is a <SequenceableCollection>,
     where the first element is the program name
     and any remaining elements will be the arguments.

     Arguments:
        progAndArgs - <SequenceableCollection>
     Answers:
        <OsProcessStarter>
start:
  Set the os program and arguments
     and start a new native subprocess.
     The new subprocess will have stdio connected
     to VAST with pipes streams

     @progAndArgs is a <SequenceableCollection>,
     where the first element is the program name
     and any remaining elements will be the arguments.

     Examples:
        The following would run the command
        >ls -la
        using the current working directory and env of the current process:
            p := OsProcessStarter start: #('ls' '-la')
     Arguments:
        progAndArgs - <SequenceableCollection>
     Answers:
        <OsVastSubprocess>

startShell:
  Set the os program and arguments
     and start a new native subprocess spawned using
     the system shell.
     The new subprocess will have stdio connected
     to VAST with pipes streams

     @progAndArgs is a <SequenceableCollection>,
     where the first element is the program name
     and any remaining elements will be the arguments.

     Examples:
        The following would run the command within a shell environment
        >/bin/sh -c ls -la
        using the current working directory and env of the current process:
            p := OsProcessStarter startShell: #('ls' '-la')
     Arguments:
        progAndArgs - <SequenceableCollection>
     Answers:
        <OsVastSubprocess>

Instance Methods
&&
  Answer a conditional sequence pipeline chain.
     aSequenceableStarter will start as soon as this process starter finishes
     IF the exit code from this process is considered success (by default, an exitcode of 0)

     Arguments: 
        aSequenceableStarter - <OsProcessStarter | OsPipelineStarter | OsPipelineChainStarter>
     Answers:   
        <OsPipelineChainStarter>
=>
  Answer a sequence pipeline chain.
     aSequenceableStarter will start as soon as this process starter finishes

     Arguments: 
        aSequenceableStarter - <OsProcessStarter | OsPipelineStarter | OsPipelineChainStarter>
     Answers:   
        <OsPipelineChainStarter>
|
  Answer a pipeline, or pipeline chain, that is configured to feed the output from this
     starter into the input of @aPipelineableStarter.
     The execution of this pipeline will perform the starters in parallel

     Arguments: 
        aPipelineableStarter - <OsProcessStarter | OsPipelineStarter | OsPipelineChainStarter>
     Answers:   
        <OsProcessStarter | OsPipelineStarter | OsPipelineChainStarter>
||
  Answer a conditional sequence process.
     aSequenceableStarter will start as soon as this process starter finishes
     IF the exit code from this process is considered a failure code (by default, an exitcode ~= 0)

     Arguments: 
        aSequenceableStarter - <OsProcessStarter | OsPipelineStarter | OsPipelineChainStarter>
     Answers:   
        <OsPipelineChainStarter>
autoFillError:
  Set to true to automatically pull data from internal os pipes to the stderr smalltalk pipe stream.
     This will activate the `deadlock avoidance` process which will attempt to fill the smalltalk pipe stream
     with available data in the os pipe every interval (default: 100ms).
     This will also enable the policy that whenever a write, or batch of writes, is about to occur to the stdin smalltalk pipe stream,
     then the stderr smalltalk pipe stream will attempt to be filled.

     Note: 'autoFill' only applies when the error has been redirected to pipe streams
     @see #redirectErrorToPipe

     @see #tuneForDeadlockAvoidance which uses this feature to avoid the situation where both sides (smalltalk and the os process)
     are blocked waiting for each other to fill or flush the os pipes.

     Arguments:
        aBoolean - <Boolean>
autoFillOutput:
  Set to true to automatically pull data from internal os pipes to the stdout smalltalk pipe stream.
     This will activate the `deadlock avoidance` process which will attempt to fill the smalltalk pipe stream
     with available data in the os pipe every interval (default: 100ms).
     This will also enable the policy that whenever a write, or batch of writes, is about to occur to the stdin smalltalk pipe stream,
     then the stdout smalltalk pipe stream will attempt to be filled.

     Note: 'autoFill' only applies when the output has been redirected to pipe streams
     @see #redirectOutputToPipe

     @see #tuneForDeadlockAvoidance which uses this feature to avoid the situation where both sides (smalltalk and the os process)
     are blocked waiting for each other to fill or flush the os pipes.

     Arguments:
        aBoolean - <Boolean>
autoFlushInput:
  Set true if any writes to the #inputStream of the process should be immediately flushed,
     false for normal bufferring behavior. This is useful for interactive scenarios where any
     request or response should be immediatley sent to the native process, instead of sitting
     in a buffer until the buffer is full.

     Note: 'autoFlush' only applies when the input has been redirected to pipe streams
     @see #redirectInputToPipe

     @see #tuneForInteractive which uses this feature, in conjuctions with 'autoFill' for the
     output/error streams, to create favorable conditions for 2-way conversations between this
     process and the native OS Process.

     Arguments:
        aBoolean - <Boolean>
command
  Answer the builder's Os program and arguments
     which are, by default, converted from UTF-8 to the
     current code page.  An exception to this are ByteArray
     program or arguments, which are assumed to already
     be in UTF-8 format and pass through with no conversion

     Answers:
        <SequenceableCollection> of <String | ByteArray> 
command:
  Set the builder's Os program and arguments.
     All program and arguments, if required, will
     be converted into UTF-8 from the current code page

     @note: Any element in @progAndArgs that is a <ByteArray>
     will not be converted, as <ByteArray>s are assumed to already
     be in UTF-8 format.

     @progAndArgs is a <SequenceableCollection>,
     where the first element is the program name
     and any remaining elements will be the arguments.

     @progAndArgs can also be a <String | ByteArray>, which is treated
     as the program name with no arguments.

     Arguments:
        progAndArgs - <String | ByteArray> program name (no arguments)
                                <SequenceableCollection> of <String | ByteArray>   program and arg names
     Answers:
        <OsProcessStarter>
detached
  Answer true if the process should run in 'detached' mode, false otherwise.
     A detached process is one that will keep running even after VAST exits.
     Default: A non-detached process is one whose lifecycle is connected to VAST.
     If VAST exits, then a non-detached process closes along with all its contained
     processes.

     Answers:
        <Boolean>
detached:
  Set true if the process should run in 'detached' mode, false otherwise.
     A detached process is one that will keep running even after VAST exits.
     Default: A non-detached process is one whose lifecycle is connected to VAST.
     If VAST exits, then a non-detached process closes along with all its contained
     processes.

     Answers:
        <Boolean>
engine
  Answer the identifier of the execution engine to be used to spawn new subprocesses
     @see OsProcessStarter>>engine: for a detail description

     Identifier: 
        OsProcessConstants::ProcEngineDefault
        OsProcessConstants::ProcEngineFork
        OsProcessConstants::ProcEngineVFork
        OsProcessConstants::ProcEnginePosixSpawn
        OsProcessConstants::ProcEngineCreateProcess
        OsProcessConstants::ProcEngineUnixProcCompat
        nil (alias for OsProcessConstants::ProcEngineDefault)

     Answers:
        <Integer>
engine:
  Set the execution engine to be used to spawn new subprocesses.
     @anEngine can be one of 
        OsProcessConstants::ProcEngineDefault
        OsProcessConstants::ProcEngineFork
        OsProcessConstants::ProcEngineVFork
        OsProcessConstants::ProcEnginePosixSpawn
        OsProcessConstants::ProcEngineCreateProcess
        OsProcessConstants::ProcEngineUnixProcCompat
        nil (alias for OsProcessConstants::ProcEngineDefault)

      All Platforms:
        ProcEngineDefault - Use the default engine for the platform
        Windows Default: ProcEngineCreateProcess
        Unix Default: ProcEnginePosixSpawn

      Windows:
        ProcEngineCreateProcess - Uses the CreateProcess API to spawn new subprocesses

      Unix:
        ProcEngineFork - Uses fork()/exec() to spawn new subprocesses
        ProcEngineVFork - Uses vfork()/exec() to spawn new subprocesses
        ProcEnginePosixSpawn - Uses posix_spawn() to spawn new subprocesses
        ProcEngineUnixProcCompat - Internal: Used by deprecated UnixProcess for compatibility

     Arguments:
        anEngine - <Integer> @see OsProcessConstants::ProcEngine*
     Raises:
        <Exception> invalid execution engine
environment
  Answer an <OsProcessEnvironment> key=value view of the process builder's environment
     This is initially a copy of the current process environment.
     Processes started from this builder will use this as the environment

     Answers:
        <OsProcessEnvironment>
environment:
  Set a key=value view of the process builder's environment
     This is initially a copy of the current process environment.
     Processes started from this builder will use this as the environment

     Arguments:
        envVariables - <OsProcessEnvironment> instance
                             - <KeyedCollection> of key <String> value <String>
                             - <SequenceableCollection> of <String> 'key=value'
                             - nil if using current process env
     Answers:
        <OsProcessStarter>
errorBufferSize:
  Set the number of bytes to buffer for error (stderr) pipe streams.
     This setting is only used if redirecting error to its own pipe.
     If errors are being redirected to output pipes (#redirectErrorToOutput), 
     then the value of #outputPipeBufferSize will be used.
     In all other cases, this value will be ignored

     Arguments: 
        anInteger - number of bytes.  Buffering is disabled if anInteger is 0
     Answers:
        <OsProcessStarter>
inheritError
  Inherit error from the parent VAST process stderr.

     Answers:
        <OsProcessStarter>
inheritInput
  Inherit input from the parent VAST process stdin

     Answers:
        <OsProcessStarter>
inheritIO
  Inherit input, output and error from the parent VAST process stdin, stdout, stderr

     Answers:
        <OsProcessStarter>
inheritOutput
  Inherit output from the parent VAST process stdout

     Answers:
        <OsProcessStarter>
inputBufferSize:
  Set the number of bytes to buffer for input (stdin) pipe streams.
     This setting is only used if redirecting input to pipes,
     otherwise it is ignored.


     Arguments: 
        anInteger - number of bytes.  Buffering is disabled if anInteger is 0
     Answers:
        <OsProcessStarter>
outputBufferSize:
  Set the number of bytes to buffer for output (stdout) pipe streams.
     This setting is only used if redirecting output to pipes,
     otherwise it is ignored.

     Arguments: 
        anInteger - number of bytes.  Buffering is disabled if anInteger is 0
     Answers:
        <OsProcessStarter>
processClass
  Answer the process class to use when starting new processes
     It should be compatible with OsVastSubprocess

     Arguments:
        aProcessClass - <Object>
processClass:
  Set the process class to use.
     @aProcessClass is intended to be a subclass of OsVastSubprocess.
     However, it is not required and the custom process class just needs
     to implement the required methods.

     @see OsProcessStarter>>start method for required API impl

     Arguments:
        aProcessClass - <Object>
redirectErrorToFile:
  Redirect errors to @aFilenameOrPath.
     The file will be created or truncated if it exists
     If @aFilenameOrPath is a ByteArray, then it will pass right through
     with no UTF-8 conversion.
     Otherwise, we get pass in the string converted form that will be converted
     to UTF-8.

     Arguments:
        aFilenameOrPath - <String> or <CfsPath> file on the filesysystem
     Answers:
        <OsProcessStarter>
redirectErrorToFile:append:
  Redirect errors to @aFilenameOrPath.
     If @aFilenameOrPath is a ByteArray, then it will pass right through
     with no UTF-8 conversion.
     Otherwise, we get pass in the string converted form that will be converted
     to UTF-8.

     If append is true
        The file will be opened in atomic append mode
     If append is false
        The file will be created or truncated if it exists
        and opened for writing

    Answers:
        <OsProcessStarter>
redirectErrorToNull
  Redirect errors to the OS-specific null bucket
     Do this to ignore errors

     Answers:
        <OsProcessStarter>
redirectErrorToOutput
  Merge errors with output so they both
     are redirected to the same location

     Answers:
        <OsProcessStarter>
redirectErrorToPipe
  Redirect errors to a pipe connected to, and accessible from,
     OsVastSubprocess>>errorStream

     Answers:
        <OsProcessStarter>
redirectInputToFile:
  Redirect input to @aFilenameOrPath.
     If @aFilenameOrPath is a ByteArray, then it will pass right through
     with no UTF-8 conversion.
     Otherwise, we get pass in the string converted form that will be converted
     to UTF-8.

     Arguments:
        aFilenameOrPath - <String> or <CfsPath> file on the filesysystem
     Answers:
        <OsProcessStarter>
redirectInputToNull
  Redirect input to the OS-specific null bucket
     Do this to ignore input

     Answers:
        <OsProcessStarter>
redirectInputToPipe
  Redirect input to a pipe connected to, and accessible from,
     OsVastSubprocess>>inputStream

     Answers:
        <OsProcessStarter>
redirectIOToNull
  Redirect input, output and error to the special NULL descriptor
     Do this to ignore all input and output (including error)

     Answers:
        <OsProcessStarter>
redirectIOToPipes
  Redirect input, output and error to pipes connected to the
     Smalltalk process object
     Use this if you wish to capture all input and output (including error)
     as streams that you can programmatically read and write to.
     These streams will be available on the OsVastSubprocess object

     Answers:
        <OsProcessStarter>
redirectOutputToFile:
  Redirect output to @aFilenameOrPath.
     The file will be created or truncated if it exists
     If @aFilenameOrPath is a ByteArray, then it will pass right through
     with no UTF-8 conversion.
     Otherwise, we get pass in the string converted form that will be converted
     to UTF-8.

     Arguments:
        aFilenameOrPath - <String> or <CfsPath> file on the filesysystem
     Answers:
        <OsProcessStarter>
redirectOutputToFile:append:
  Redirect ouptut to @aFilenameOrPath.
     If @aFilenameOrPath is a ByteArray, then it will pass right through
     with no UTF-8 conversion.
     Otherwise, we get pass in the string converted form that will be converted
     to UTF-8.

     If append is true
        The file will be opened in atomic append mode
     If append is false
        The file will be created or truncated if it exists
        and opened for writing

    Answers:
        <OsProcessStarter>
redirectOutputToNull
  Redirect output to the OS-specific null bucket
     Do this to ignore output

     Answers:
        <OsProcessStarter>
redirectOutputToPipe
  Redirect output to a pipe connected to, and accessible from,
     OsVastSubprocess>>outputStream

     Answers:
        <OsProcessStarter>
runInShell
  Answer true if the command will be spawned using the selected system shell,
     false otherwise

     Answers:
        <Boolean>
runInShell:
  Set true if this command should run using the system's shell, false otherwise
     The default shell for the system is selected.  Use #shell: to customize which
     shell to use.

     Arguments:
        aBoolean - <Boolean> true to use shell, false otherwise
shellMode
  Answer the identifier of the shell to be used for running 
     commands in the new subprocesses.
     @see OsProcessStarter>>shellMode: for a detail description

     Identifier: 
        OsProcessConstants::ProcShellNone
        OsProcessConstants::ProcShellDefault
        OsProcessConstants::ProcShellCmd
        OsProcessConstants::ProcShellPowershell
        OsProcessConstants::ProcShellSh
        OsProcessConstants::ProcShellBash
        OsProcessConstants::ProcShellCsh
        OsProcessConstants::ProcShellTcsh
        OsProcessConstants::ProcShellKsh
        OsProcessConstants::ProcShellZsh
        nil (alias for OsProcessConstants::ProcEngineNone)

     Answers:
        <Integer>
shellMode:
  Set the shell to use for running commands in the new subprocesses.
     @aShell can be one of 
        OsProcessConstants::ProcShellNone
        OsProcessConstants::ProcShellDefault
        OsProcessConstants::ProcShellCmd
        OsProcessConstants::ProcShellPowershell
        OsProcessConstants::ProcShellSh
        OsProcessConstants::ProcShellBash
        OsProcessConstants::ProcShellCsh
        OsProcessConstants::ProcShellTcsh
        OsProcessConstants::ProcShellKsh
        OsProcessConstants::ProcShellZsh
        nil (alias for OsProcessConstants::ProcEngineNone)

      All Platforms:
        ProcShellNone - Do not use shell with command
        ProcEngineDefault - Use the default shell for the platform
        Windows Default: ProcShellCmd
        Unix Default: ProcShellSh

      Windows:
        ProcShellCmd - cmd.exe
        ProcShellPowershell - powershell.exe

      Unix:
        ProcShellSh -Bourne Shell (/bin/sh)
        ProcShellBash - Bourne-again Shell  (/bin/bash)
        ProcShellCsh - C Shell  (/bin/csh)
        ProcShellTcsh - TENEX C Shell  (/bin/tcsh)
        ProcShellKsh - Korn Shell  (/bin/ksh)
        ProcShellZsh - Z Shell  (/bin/zsh)

     Arguments:
        aShell - <Integer> @see OsProcessConstants::ProcShell*
     Raises:
        <Exception> invalid shell
start
  Starts a new process by invoking the @command in the
     working directory (@workingDirectory), with the associated
     @environment and stdio specifications.

     A new subprocess object will be immediatley answered which
     is the handle to the subprocess that has started execution.

     @Note: Direct instvar refs are to ensure we pass the UTF-8
     form of the instance field without conversion

     Answers:
        <OsVastSubprocess>
     Raises:
        <OsProcessException>
tracingEnabled
  Answer true if process execution tracing is enabled, false otherwise

     Answers:
        <Boolean>
tracingEnabled:
  Set true if process execution tracing should be enabled, false otherwise

     Arguments:
        aBoolean - <Boolean>
tuneForDeadlockAvoidance
  Set stdout and stderr with the 'autoFill' flag.

     This has the following impact:
        1. Stdout and stderr buffers are filled just prior to a write to stdin via smalltalk pipe streams
        2. A deadlock avoidance ST process is created to fill stdout, stderr in a polling manner.

     Note: This only impacts stdout and/or stderr that are redirected to smalltalk pipe streams
tuneForInteractive
  Set stdin with the 'autoFlush' flag.

     This has the following impact:
        1. The bytes written to smalltalk pipe streams are immediately flushed to stdin.
            * For interactive conversations, we don't want to buffer up conversations into
            * the smalltalk buffers.  We want them to go straight to stdin to get the desired impact.
        2. @see #tuneForDeadlockAvoidance for additional impacts.

     Note: This only impacts stdin, stdout and stderr that are redirected to smalltalk pipe streams
workingDirectory
  Answer the process builder's working directory
     This will be used as the working directory of subprocesses
     started by this builder.
     By default, this value is converted from UTF-8 to the
     current code page.  An exception to this is if the directory
     is a ByteArray, which is assumed to already
     be in UTF-8 format and pass through with no conversion

     Answers:
        <String | ByteArray> - process builder's working directory
        <UndefinedObject> - nil if using CWD of the processs
workingDirectory:
  Set the process starter's working directory
     This will be used as the working directory of subprocesses
     started by this starter.

     Arguments:
        aDirectoryPath - <String> process starter's working dir string
                                 - <UndefinedObject> - nil if current working directory should be used
     Answers:
        <OsProcessStarter>
Last modified date: 02/23/2021