PageRenderTime 39ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/src/sys/dotnet/fan/sys/Process.cs

https://bitbucket.org/bedlaczech/fan-1.0
C# | 254 lines | 182 code | 37 blank | 35 comment | 35 complexity | 50d6fa38c68484b79da07f8fc0eb6628 MD5 | raw file
Possible License(s): CC-BY-SA-3.0
  1. //
  2. // Copyright (c) 2008, Brian Frank and Andy Frank
  3. // Licensed under the Academic Free License version 3.0
  4. //
  5. // History:
  6. // 6 Feb 08 Andy Frank Creation
  7. //
  8. using System;
  9. using System.Collections;
  10. using System.Text;
  11. namespace Fan.Sys
  12. {
  13. /// <summary>
  14. /// Process
  15. /// </summary>
  16. public class Process : FanObj
  17. {
  18. //////////////////////////////////////////////////////////////////////////
  19. // Construction
  20. //////////////////////////////////////////////////////////////////////////
  21. public static Process make()
  22. {
  23. return new Process(new List(Sys.StrType), null);
  24. }
  25. public static Process make(List command)
  26. {
  27. return new Process(command, null);
  28. }
  29. public static Process make(List command, File dir)
  30. {
  31. return new Process(command, dir);
  32. }
  33. private Process(List command, File dir)
  34. {
  35. this.command(command);
  36. this.dir(dir);
  37. }
  38. //////////////////////////////////////////////////////////////////////////
  39. // Identity
  40. //////////////////////////////////////////////////////////////////////////
  41. public override Type @typeof()
  42. {
  43. return Sys.ProcessType;
  44. }
  45. //////////////////////////////////////////////////////////////////////////
  46. // Configuration
  47. //////////////////////////////////////////////////////////////////////////
  48. public List command() { return m_command; }
  49. public void command(List v) { this.m_command = v; }
  50. public File dir() { return m_dir; }
  51. public void dir(File v)
  52. {
  53. checkRun();
  54. if (v != null && (!v.exists() || !v.isDir()))
  55. throw ArgErr.make("Invalid working directory: " + v).val;
  56. this.m_dir = v;
  57. }
  58. public Map env()
  59. {
  60. if (m_env == null)
  61. {
  62. m_env = new Map(Sys.StrType, Sys.StrType);
  63. IDictionaryEnumerator en =
  64. (IDictionaryEnumerator)new System.Diagnostics.Process().
  65. StartInfo.EnvironmentVariables.GetEnumerator();
  66. while (en.MoveNext())
  67. {
  68. string key = (string)en.Key;
  69. string val = (string)en.Value;
  70. m_env.set(key, val);
  71. }
  72. }
  73. return m_env;
  74. }
  75. public bool mergeErr() { return m_mergeErr; }
  76. public void mergeErr(bool v) { checkRun(); m_mergeErr = v; }
  77. public OutStream @out() { return m_out; }
  78. public void @out(OutStream @out) { checkRun(); this.m_out = @out; }
  79. public OutStream err() { return m_err; }
  80. public void err(OutStream err) { checkRun(); this.m_err = err; }
  81. public InStream @in() { return m_in; }
  82. public void @in(InStream @in) { checkRun(); this.m_in = @in; }
  83. //////////////////////////////////////////////////////////////////////////
  84. // Lifecycle
  85. //////////////////////////////////////////////////////////////////////////
  86. public Process run()
  87. {
  88. checkRun();
  89. try
  90. {
  91. // arguments
  92. string fileName = m_command.get(0) as string;
  93. StringBuilder args = new StringBuilder();
  94. for (int i=1; i<m_command.sz(); i++)
  95. {
  96. if (i > 1) args.Append(" ");
  97. args.Append(m_command.get(i) as string);
  98. }
  99. // create process
  100. m_proc = new System.Diagnostics.Process();
  101. m_proc.StartInfo.UseShellExecute = false;
  102. m_proc.StartInfo.FileName = fileName;
  103. m_proc.StartInfo.Arguments = args.ToString();
  104. // environment
  105. if (m_env != null)
  106. {
  107. IDictionaryEnumerator en = m_env.pairsIterator();
  108. while (en.MoveNext())
  109. {
  110. string key = (string)en.Key;
  111. string val = (string)en.Value;
  112. m_proc.StartInfo.EnvironmentVariables[key] = val;
  113. }
  114. }
  115. // working directory
  116. if (m_dir != null)
  117. m_proc.StartInfo.WorkingDirectory = ((LocalFile)m_dir).m_file.FullName;
  118. // streams
  119. if (m_in != null) m_proc.StartInfo.RedirectStandardInput = true;
  120. m_proc.StartInfo.RedirectStandardOutput = true;
  121. m_proc.StartInfo.RedirectStandardError = true;
  122. m_proc.OutputDataReceived += new System.Diagnostics.DataReceivedEventHandler(outHandler);
  123. m_proc.ErrorDataReceived += new System.Diagnostics.DataReceivedEventHandler(errHandler);
  124. // start it
  125. m_proc.Start();
  126. // start async read/writes
  127. if (m_in != null)
  128. {
  129. new System.Threading.Thread(
  130. new System.Threading.ThreadStart(inHandler)).Start();
  131. }
  132. m_proc.BeginOutputReadLine();
  133. m_proc.BeginErrorReadLine();
  134. return this;
  135. }
  136. catch (System.Exception e)
  137. {
  138. m_proc = null;
  139. throw Err.make(e).val;
  140. }
  141. }
  142. public long join()
  143. {
  144. if (m_proc == null) throw Err.make("Process not running").val;
  145. try
  146. {
  147. m_proc.WaitForExit();
  148. return m_proc.ExitCode;
  149. }
  150. catch (System.Exception e)
  151. {
  152. throw Err.make(e).val;
  153. }
  154. }
  155. public Process kill()
  156. {
  157. if (m_proc == null) throw Err.make("Process not running").val;
  158. m_proc.Kill();
  159. return this;
  160. }
  161. private void checkRun()
  162. {
  163. if (m_proc != null) throw Err.make("Process already run").val;
  164. }
  165. //////////////////////////////////////////////////////////////////////////
  166. // Handlers
  167. //////////////////////////////////////////////////////////////////////////
  168. private void inHandler()
  169. {
  170. System.IO.Stream input = SysInStream.dotnet(m_in);
  171. System.IO.Stream output = m_proc.StandardInput.BaseStream;
  172. byte[] temp = new byte[256];
  173. while (!m_proc.HasExited)
  174. {
  175. try
  176. {
  177. int n = input.Read(temp, 0, temp.Length);
  178. if (n < 0) break;
  179. output.Write(temp, 0, n);
  180. output.Flush();
  181. }
  182. catch (System.Exception e)
  183. {
  184. Err.dumpStack(e);
  185. }
  186. }
  187. }
  188. private void outHandler(object sender, System.Diagnostics.DataReceivedEventArgs args)
  189. {
  190. if (String.IsNullOrEmpty(args.Data)) return;
  191. if (m_out != null) m_out.printLine(args.Data);
  192. }
  193. private void errHandler(object sender, System.Diagnostics.DataReceivedEventArgs args)
  194. {
  195. if (String.IsNullOrEmpty(args.Data)) return;
  196. if (m_mergeErr)
  197. {
  198. if (m_out != null) m_out.printLine(args.Data);
  199. }
  200. else
  201. {
  202. if (m_err != null) m_err.printLine(args.Data);
  203. }
  204. }
  205. //////////////////////////////////////////////////////////////////////////
  206. // Fields
  207. //////////////////////////////////////////////////////////////////////////
  208. private List m_command;
  209. private File m_dir;
  210. private Map m_env;
  211. private bool m_mergeErr = true;
  212. private OutStream m_out = Env.cur().@out();
  213. private OutStream m_err = Env.cur().err();
  214. private InStream m_in = null;
  215. private volatile System.Diagnostics.Process m_proc;
  216. }
  217. }