OsPipeline
An instance of <OsPipeline> represents a sequenceable collection of vast subprocesses wired together such that the output of one flows into the input of the next. This allows for a 'pipeline' style of concurrency, and the pipeline object is designed to be polymorphic with an <OsVastSubprocess>.
A user should use an <OsPipelineStarter> to construct an instance of an <OsPipeline>. @see the class comments of <OsPipelineStarter> for more information on how to do this.
Process Enumeration A pipeline can answer a sequenceable collection of all its processes, as well as providing simple accessors to the first and last in the pipeline. The first process is called the 'initial' process, while the last process is called the 'terminal' process.
For more information, see the method comments from the following methods in OsPipeline:
initialProcess, processes, terminalProcess
Standard I/O A pipeline can answer its stdin, stdout and stderr streams. A pipeline is an abstract concept relating to how real processes are linked together in a pipelined fashion, but we can still map these standard I/O concepts in a way that makes sense.
Asking for the inputStream of a pipeline is the same as asking for the inputStream of its initial process,
since that serves as the entry point for input. Asking for the output or error stream of a pipeline is the
same as asking for the output or error stream of its terminal process.
 
For more information, see the method comments from the following methods in OsPipeline:
closeStreams, errorStream, inputStream, outputStream
Lifecycle Status and Notification A pipeline is considered complete when ALL of its processes are also complete.
A pipeline has an exitCode that is determined by the exitCode of the terminal process.
 
VAST can sign up to be notified when a pipeline exits using VAST's futures framework.
 
For more information, see the method comments from the following methods in OsPipeline:
exitCode, isComplete, onCompletion, waitForCompletion, waitForCompletion:
Command and Control A pipeline can be terminated by sending either terminate (for graceful termination) or kill (for hard termination).
The pipeline will forward this request to all of its processes. Once all of them are successfully terminated, then the
pipeline will answer that isComplete.
 
For more information, see the method comments from the following methods in OsPipeline:
kill, terminate
Class Methods
new
  Answer a new initialized instance

     Answers:
        <OsPipeline>
Instance Methods
closeStreams
  Close all stdio streams from all processes in the pipeline.
     Ignore any exceptions

     Answers:
        <OsProcessStream>
commandLine
  Answer the resolved and quoted command line that
     will passed on to the native process start logic.

     By default, this is expressed in the current code page

     A primitive failure will occur if the name is not
     a byte object
     A primitive failure will occur if the args is not
     nil or an Array

     Answers:
        <String>
errorStream
  A pipeline error stream is a null stream.
     The inputStream is the inputStream of the first process
     The outputStream is the outputStream of the last process
     And errorStream would need to represent the errorStreams of
     all the processes.
     Instead, the OsPipelineStarter can be configured to append all
     error out to a file (redirectErrorToFile:), or error can be merged with
     the output (#redirectErrorToOutput).

     Answers:
        <OsNullReadPipeStream>
exitCode
  Answer an integer representing the exitCode of the last
     process in the pipeline.  If the last process has not completed,
     then answer nil. 
     Note: This is operating system dependent.

     Answers:
        <Integer>
initialProcess
  Answer the initial process in the pipeline.

     Answers:
        <OsVastSubprocess>
inputStream
  Answer the stdin stream of the pipeline (which is the stdin stream
     of the first process in the pipeline).

     Answers:
        <OsProcessStream>
isComplete
  Answer true if the receiver process has completed, false otherwise.
     A pipeline is complete when all of its processes are complete

     Answers:
        <Boolean>
kill
  Kill the pipeline immediatley, bypassing any graceful shutdown
     that may be offerred by the OS.

     This semantics of 'kill' vs 'terminate' are OS dependent.
         Windows - terminate and kill are equivalent
         Unix - SIGKILL is used here.  (SIGTERM for terminate)

     @see OsPipeline>>terminate: for further details.

     Answers:
        <Boolean> true if all processes were successfully terminated, false otherwise
onCompletion
  Answer a future that represents the
     eventual completion of this pipeline, as
     well as retrieving the result.
     A pipeline is considered complete when
     all of its processes are complete

     Answers:
        <EsFuture>
outputStream
  Answer the stdout stream of the pipeline (which is the stdout stream
     of the last process in the pipeline).

     Answers:
        <OsProcessStream>
pids
  Answer a keyed collection describing all the process ids
     in the pipeline, with their associated processes

     Answers
        <KeyedCollection>
processes
  Answers the collection of <OsVastSubprocess>s

     Answers:
        <SequenceableCollection>
terminalProcess
  Answer the final process in the pipeline.

     Answers:
        <OsVastSubprocess>
terminate
  Terminate the process, gracefully if the OS supports it.
     @see OsPipeline>>terminate: for further details

     This semantics of 'kill' vs 'terminate' are OS dependent.
         Windows - terminate and kill are equivalent
         Unix - SIGTERM is used here.  (SIGKILL for kill)
     Answers:
        <Boolean> true if all processes were successfully terminated, false otherwise
uids
  Answer a keyed collection describing all the vast unique ids
     in the pipeline, with their associated processes

     Answers
        <KeyedCollection>
utf8CommandLine
  Answer the resolved and quoted command line that
     will passed on to the native process start logic.

     This is expressed in UTF-8, which is the native internal
     representation that is used for the subprocess module.

     A primitive failure will occur if the name is not
     a byte object
     A primitive failure will occur if the args is not
     nil or an Array

     Answers:
        <String>
waitForCompletion
  Wait until all processes in the pipeline complete.
     The calling smalltalk process will block until the pipeline completes

     Answers:
        <Integer> - exit code of the last process in the pipeline
waitForCompletion:
  Wait until all processes in the pipeline complete and answer the exit code of the last process.
     The calling smalltalk process will block until all processes complete or the
     wait duration (@aDurationOrMs) elapses.
     Answers the <Integer> exit code if the pipeline completes before the elapsed time.
     Otherwise, answer nil if the duration time elapses

     Arguments:
        aDurationOrMs - <Duration>duration object
                                    <Integer> duration in milliseconds
     Answers:   
        <Integer> - exit code of the last process in the pipeline
        <UndefinedObject> - nil if the duration elapsed before the pipeline exited
Last modified date: 02/23/2021