Loading

gdc.d

  1. void main(){}
  2.     import core.sys.posix.unistd;
  3. import std.path;
  4. import std.stdio;
  5. // =============================================================================
  6. // Functions and classes for process management.
  7. // =============================================================================
  8.  
  9.  
  10. /**
  11. Spawns a new _process, optionally assigning it an arbitrary set of standard
  12. input, output, and error streams.
  13.  
  14. The function returns immediately, leaving the child _process to execute
  15. in parallel with its parent.  It is recommended to always call $(LREF wait)
  16. on the returned $(LREF Pid), as detailed in the documentation for $(D wait).
  17.  
  18. Command_line:
  19. There are four overloads of this function.  The first two take an array
  20. of strings, $(D args), which should contain the program name as the
  21. zeroth element and any command-line arguments in subsequent elements.
  22. The third and fourth versions are included for convenience, and may be
  23. used when there are no command-line arguments.  They take a single string,
  24. $(D program), which specifies the program name.
  25.  
  26. Unless a directory is specified in $(D args[0]) or $(D program),
  27. $(D spawnProcess) will search for the program in a platform-dependent
  28. manner.  On POSIX systems, it will look for the executable in the
  29. directories listed in the PATH environment variable, in the order
  30. they are listed.  On Windows, it will search for the executable in
  31. the following sequence:
  32. $(OL
  33.     $(LI The directory from which the application loaded.)
  34.     $(LI The current directory for the parent process.)
  35.     $(LI The 32-bit Windows system directory.)
  36.     $(LI The 16-bit Windows system directory.)
  37.     $(LI The Windows directory.)
  38.     $(LI The directories listed in the PATH environment variable.)
  39. )
  40. ---
  41. // Run an executable called "prog" located in the current working
  42. // directory:
  43. auto pid = spawnProcess("./prog");
  44. scope(exit) wait(pid);
  45. // We can do something else while the program runs.  The scope guard
  46. // ensures that the process is waited for at the end of the scope.
  47. ...
  48.  
  49. // Run DMD on the file "myprog.d", specifying a few compiler switches:
  50. auto dmdPid = spawnProcess(["dmd", "-O", "-release", "-inline", "myprog.d" ]);
  51. if (wait(dmdPid) != 0)
  52.     writeln("Compilation failed!");
  53. ---
  54.  
  55. Environment_variables:
  56. By default, the child process inherits the environment of the parent
  57. process, along with any additional variables specified in the $(D env)
  58. parameter.  If the same variable exists in both the parent's environment
  59. and in $(D env), the latter takes precedence.
  60.  
  61. If the $(LREF Config.newEnv) flag is set in $(D config), the child
  62. process will $(I not) inherit the parent's environment.  Its entire
  63. environment will then be determined by $(D env).
  64. ---
  65. wait(spawnProcess("myapp", ["foo" : "bar"], Config.newEnv));
  66. ---
  67.  
  68. Standard_streams:
  69. The optional arguments $(D stdin), $(D stdout) and $(D stderr) may
  70. be used to assign arbitrary $(XREF stdio,File) objects as the standard
  71. input, output and error streams, respectively, of the child process.  The
  72. former must be opened for reading, while the latter two must be opened for
  73. writing.  The default is for the child process to inherit the standard
  74. streams of its parent.
  75. ---
  76. // Run DMD on the file myprog.d, logging any error messages to a
  77. // file named errors.log.
  78. auto logFile = File("errors.log", "w");
  79. auto pid = spawnProcess(["dmd", "myprog.d"],
  80.                         std.stdio.stdin,
  81.                         std.stdio.stdout,
  82.                         logFile);
  83. if (wait(pid) != 0)
  84.     writeln("Compilation failed. See errors.log for details.");
  85. ---
  86.  
  87. Note that if you pass a $(D File) object that is $(I not)
  88. one of the standard input/output/error streams of the parent process,
  89. that stream will by default be $(I closed) in the parent process when
  90. this function returns.  See the $(LREF Config) documentation below for
  91. information about how to disable this behaviour.
  92.  
  93. Beware of buffering issues when passing $(D File) objects to
  94. $(D spawnProcess).  The child process will inherit the low-level raw
  95. read/write offset associated with the underlying file descriptor, but
  96. it will not be aware of any buffered data.  In cases where this matters
  97. (e.g. when a file should be aligned before being passed on to the
  98. child process), it may be a good idea to use unbuffered streams, or at
  99. least ensure all relevant buffers are flushed.
  100.  
  101. Params:
  102. args    = An array which contains the program name as the zeroth element
  103.           and any command-line arguments in the following elements.
  104. stdin   = The standard input stream of the child process.
  105.           This can be any $(XREF stdio,File) that is opened for reading.
  106.           By default the child process inherits the parent's input
  107.           stream.
  108. stdout  = The standard output stream of the child process.
  109.           This can be any $(XREF stdio,File) that is opened for writing.
  110.           By default the child process inherits the parent's output stream.
  111. stderr  = The standard error stream of the child process.
  112.           This can be any $(XREF stdio,File) that is opened for writing.
  113.           By default the child process inherits the parent's error stream.
  114. env     = Additional environment variables for the child process.
  115. config  = Flags that control process creation. See $(LREF Config)
  116.           for an overview of available flags.
  117. workDir = The working directory for the new process.
  118.           By default the child process inherits the parent's working
  119.           directory.
  120.  
  121. Returns:
  122. A $(LREF Pid) object that corresponds to the spawned process.
  123.  
  124. Throws:
  125. $(LREF ProcessException) on failure to start the process.$(BR)
  126. $(XREF stdio,StdioException) on failure to pass one of the streams
  127.     to the child process (Windows only).$(BR)
  128. $(CXREF exception,RangeError) if $(D args) is empty.
  129. */
  130. Pid spawnProcess(char[][] args)
  131. {
  132. alias args2 = args;
  133.     return spawnProcessImpl(args2);
  134. }
  135.  
  136. Pid spawnProcessImpl(char[][] )
  137. {
  138.     auto id = fork;
  139.         return new Pid(id);
  140. }
  141.  
  142. /**
  143. Flags that control the behaviour of $(LREF spawnProcess) and
  144. $(LREF spawnShell).
  145.  
  146. Use bitwise OR to combine flags.
  147.  
  148. Example:
  149. ---
  150. auto logFile = File("myapp_error.log", "w");
  151.  
  152. // Start program, suppressing the console window (Windows only),
  153. // redirect its error stream to logFile, and leave logFile open
  154. // in the parent process as well.
  155. auto pid = spawnProcess("myapp", stdin, stdout, logFile,
  156.                         Config.retainStderr | Config.suppressConsole);
  157. scope(exit)
  158. {
  159.     auto exitCode = wait(pid);
  160.     logFile.writeln("myapp exited with code ", exitCode);
  161.     logFile.close();
  162. }
  163. ---
  164. */
  165. enum Config
  166. {
  167.     none }
  168.  
  169.  
  170. class Pid
  171. {
  172.         this(int )         {
  173.         }
  174. }
  175.  
  176.  
  177. Pipe pipe() {
  178.     Pipe p;
  179.     return p;
  180. }
  181. /// An interface to a pipe created by the $(LREF pipe) function.
  182. struct Pipe
  183. {
  184.     /// The write end of the pipe.
  185.     @property writeEnd() { return _write; }
  186.  
  187.  
  188.     File _read, _write;
  189. }
  190.  
  191. /// ditto
  192. ProcessPipes pipeProcess(in char[] program,
  193.                          Redirect redirect ,
  194.                          Config = Config.none,
  195. char[] = null)
  196. {
  197.     return pipeProcessImpl!spawnProcess(program, redirect);
  198. }
  199.  
  200. ProcessPipes pipeProcessImpl(alias spawnFunc, Cmd)
  201.                                     (Cmd ,
  202.                                      Redirect redirectFlags)
  203. {
  204.     File childStdin, childStdout;
  205.     ProcessPipes pipes;
  206.     if (redirectFlags )
  207.     {
  208.         auto p = pipe;
  209.         childStdout = p.writeEnd;
  210.     }
  211.     return pipes;
  212. }
  213.  
  214.  
  215. /**
  216. Flags that can be passed to $(LREF pipeProcess) and $(LREF pipeShell)
  217. to specify which of the child process' standard streams are redirected.
  218. Use bitwise OR to combine flags.
  219. */
  220. enum Redirect
  221. {
  222.     /// Redirect the standard input, output or error streams, respectively.
  223.     stdin }
  224.  
  225. void assertThrown(T : Throwable = Exception, E)
  226.                  (lazy E expression,
  227.                   string msg = null,
  228.                   string file = __FILE__,
  229.                   size_t line = __LINE__)
  230. {
  231.     import core.exception : AssertError;
  232.  
  233.     try
  234.         expression();
  235.     catch (T)
  236.         return;
  237.     throw new AssertError("assertThrown failed: No " ~ T.stringof ~ " was thrown"
  238.                                  ~ (msg.length == 0 ? "." : ": ") ~ msg,
  239.                           file, line);
  240. }
  241.  
  242. unittest
  243. {
  244.     TestScript prog ;
  245.     auto p = pipeProcess(prog.path, Redirect.stdin);
  246.     assertThrown!Error(p.stdin);
  247. }
  248.  
  249. /**
  250. Object which contains $(XREF stdio,File) handles that allow communication
  251. with a child process through its standard streams.
  252. */
  253. struct ProcessPipes
  254. {
  255.     /**
  256.     An $(XREF stdio,File) that allows writing to the child process'
  257.     standard input stream.
  258.  
  259.     Throws:
  260.     $(OBJECTREF Error) if the child process' standard input stream hasn't
  261.     been redirected.
  262.     */
  263.     @property stdin()     {
  264.             throw new Error("Child process' standard input stream hasn't "
  265. );
  266.         return _stdin;
  267.     }
  268.  
  269.     File _stdin;
  270. }
  271.  
  272.  
  273.  
  274. struct TestScript
  275. {
  276.     string path;
  277. }