1 /**
2   Includes a utility class for unix-pipe chaining of system processes.
3 */
4 module dcord.util.process;
5 
6 import std.algorithm.iteration,
7        std.array;
8 
9 static import std.stdio,
10               std.process;
11 
12 /**
13   Represents a single running process in the chain.
14 */
15 struct Process {
16   std.process.Pid pid;
17   std.process.Pipe _stdout;
18   std.process.Pipe _stderr;
19 
20   /**
21    Creates a new process (and spawns it).
22 
23     Params:
24       args = args for the process
25       upstream = file object used as stdin for the process
26   */
27   this(string[] args, std.stdio.File upstream) {
28     this._stdout = std.process.pipe();
29     this._stderr = std.process.pipe();
30     this.pid = std.process.spawnProcess(args, upstream, this._stdout.writeEnd, this._stderr.writeEnd);
31   }
32 
33   /**
34     Creates a new process (and spawns it)
35 
36     Params:
37       args = args for the process
38   */
39   this(string[] args) {
40     this(args, std.stdio.stdin);
41   }
42 
43   /// Waits for this process to complete and returns the exit code.
44   int wait() {
45     return std.process.wait(this.pid);
46   }
47 
48   /// File object of this processes stdout
49   @property std.stdio.File stdout() {
50     return this._stdout.readEnd;
51   }
52 
53   /// File object of this processes stderr
54   @property std.stdio.File stderr() {
55     return this._stderr.readEnd;
56   }
57 }
58 
59 /**
60   Represents a chain of processes with each member piping its stdout into the
61   next members stdin.
62 */
63 class ProcessChain {
64   Process*[] members;
65 
66   /// Adds a new process in the chain.
67   ProcessChain run(string[] args) {
68     members ~= new Process(args,
69       this.members.length ? this.members[$-1]._stdout.readEnd : std.stdio.stdin);
70     return this;
71   }
72 
73   /// Waits for all processes in the chain to exit and returns an array of exit codes.
74   int[] wait() {
75     assert(this.members.length);
76     return this.members.map!((p) => p.wait()).array;
77   }
78 
79   /// Returns stdout for the last process in the chain.
80   std.stdio.File end() {
81     assert(this.members.length);
82     return this.members[$-1]._stdout.readEnd;
83   }
84 }