Merge pull request #3613 from kloun/patch-4
[mono.git] / mcs / class / Microsoft.Build.Utilities / Microsoft.Build.Utilities / ProcessService.cs
1
2 using System;
3 using System.IO;
4 using System.Collections;
5 using System.Collections.Generic;
6 using System.Diagnostics;
7
8 namespace Microsoft.Build.Utilities
9 {
10         internal static class ProcessService {
11                 static Dictionary<string, string> globalEnvironmentVariablesOverride;
12
13                 public static Dictionary<string, string> GlobalEnvironmentVariblesOverride {
14                         get {
15                                 if (globalEnvironmentVariablesOverride == null)
16                                         globalEnvironmentVariablesOverride = new Dictionary<string, string> (StringComparer.InvariantCultureIgnoreCase);
17                                 return globalEnvironmentVariablesOverride;
18                         }
19                 }
20
21                 public static ProcessWrapper StartProcess (string command, string arguments, string workingDirectory, EventHandler exited)
22                 {
23                         return StartProcess (command, arguments, workingDirectory, (ProcessEventHandler)null, (ProcessEventHandler)null, exited);
24                 }
25
26                 public static ProcessWrapper StartProcess (string command, string arguments, string workingDirectory, ProcessEventHandler outputStreamChanged, ProcessEventHandler errorStreamChanged)
27                 {
28                         return StartProcess (command, arguments, workingDirectory, outputStreamChanged, errorStreamChanged, null);
29                 }
30
31                 public static ProcessWrapper StartProcess (string command, string arguments, string workingDirectory, TextWriter outWriter, TextWriter errorWriter, EventHandler exited)
32                 {
33                         return StartProcess (command, arguments, workingDirectory, outWriter, errorWriter, exited, false);
34                 }
35
36                 public static ProcessWrapper StartProcess (string command, string arguments, string workingDirectory, TextWriter outWriter, TextWriter errorWriter, EventHandler exited, bool redirectStandardInput)
37                 {
38                         ProcessEventHandler wout = OutWriter.GetWriteHandler (outWriter);
39                         ProcessEventHandler werr = OutWriter.GetWriteHandler (errorWriter);
40                         return StartProcess (command, arguments, workingDirectory, wout, werr, exited, redirectStandardInput);
41                 }
42
43                 public static ProcessWrapper StartProcess (string command, string arguments, string workingDirectory, ProcessEventHandler outputStreamChanged, ProcessEventHandler errorStreamChanged, EventHandler exited)
44                 {
45                         return StartProcess (command, arguments, workingDirectory, outputStreamChanged, errorStreamChanged, exited, false);
46                 }
47
48                 public static ProcessWrapper StartProcess (string command, string arguments, string workingDirectory, ProcessEventHandler outputStreamChanged, ProcessEventHandler errorStreamChanged, EventHandler exited, bool redirectStandardInput)
49                 {
50                         return StartProcess (CreateProcessStartInfo (command, arguments, workingDirectory, redirectStandardInput),
51                                 outputStreamChanged, errorStreamChanged, exited, null);
52                 }
53
54                 public static ProcessWrapper StartProcess (ProcessStartInfo startInfo, TextWriter outWriter, TextWriter errorWriter, EventHandler exited)
55                 {
56                         return StartProcess (startInfo, outWriter, errorWriter, exited, null);
57                 }
58
59                 public static ProcessWrapper StartProcess (ProcessStartInfo startInfo, TextWriter outWriter, TextWriter errorWriter, EventHandler exited, Dictionary<string, string> environmentOverride)
60                 {
61                         ProcessEventHandler wout = OutWriter.GetWriteHandler (outWriter);
62                         ProcessEventHandler werr = OutWriter.GetWriteHandler (errorWriter);
63                         return StartProcess (startInfo, wout, werr, exited, environmentOverride);
64                 }
65
66                 // @environmentOverride overrides even the global override values
67                 public static ProcessWrapper StartProcess (ProcessStartInfo startInfo, ProcessEventHandler outputStreamChanged, ProcessEventHandler errorStreamChanged, EventHandler exited, Dictionary<string, string> environmentOverride)
68                 {
69                         if (startInfo == null)
70                                 throw new ArgumentException ("startInfo");
71
72                         ProcessWrapper p = new ProcessWrapper();
73
74                         if (outputStreamChanged != null) {
75                                 p.OutputStreamChanged += outputStreamChanged;
76                         }
77
78                         if (errorStreamChanged != null)
79                                 p.ErrorStreamChanged += errorStreamChanged;
80
81                         if (exited != null)
82                                 p.Exited += exited;
83
84                         p.StartInfo = startInfo;
85                         ProcessEnvironmentVariableOverrides (p.StartInfo, environmentOverride);
86
87                         // WORKAROUND for "Bug 410743 - wapi leak in System.Diagnostic.Process"
88                         // Process leaks when an exit event is registered
89                         // instead we use another thread to monitor I/O and wait for exit
90                         // p.EnableRaisingEvents = true;
91
92                         p.Start ();
93                         return p;
94                 }
95
96                 public static ProcessStartInfo CreateProcessStartInfo (string command, string arguments, string workingDirectory, bool redirectStandardInput)
97                 {
98                         if (command == null)
99                                 throw new ArgumentNullException("command");
100
101                         if (command.Length == 0)
102                                 throw new ArgumentException("command");
103
104                         ProcessStartInfo startInfo = null;
105                         if(String.IsNullOrEmpty (arguments))
106                                 startInfo = new ProcessStartInfo (command);
107                         else
108                                 startInfo = new ProcessStartInfo (command, arguments);
109
110                         if(workingDirectory != null && workingDirectory.Length > 0)
111                                 startInfo.WorkingDirectory = workingDirectory;
112
113                         startInfo.RedirectStandardOutput = true;
114                         startInfo.RedirectStandardError = true;
115                         startInfo.RedirectStandardInput = redirectStandardInput;
116                         startInfo.UseShellExecute = false;
117                         startInfo.CreateNoWindow = true;
118
119                         return startInfo;
120                 }
121
122                 public static void ProcessEnvironmentVariableOverrides (ProcessStartInfo info, Dictionary<string, string> environmentOverride)
123                 {
124                         if (globalEnvironmentVariablesOverride != null)
125                                 foreach (var entry in globalEnvironmentVariablesOverride)
126                                         ProcessEnvironmentVariable (info, (string)entry.Key, (string)entry.Value);
127
128                         if (environmentOverride != null)
129                                 foreach (var entry in environmentOverride)
130                                         ProcessEnvironmentVariable (info, (string)entry.Key, (string)entry.Value);
131                 }
132
133                 static void ProcessEnvironmentVariable (ProcessStartInfo info, string name, string value)
134                 {
135                         if (value == null && info.EnvironmentVariables.ContainsKey (name))
136                                 info.EnvironmentVariables.Remove (name);
137                         else
138                                 info.EnvironmentVariables[name] = value;
139                 }
140
141         }
142
143         class OutWriter
144         {
145                 TextWriter writer;
146
147                 public OutWriter (TextWriter writer)
148                 {
149                         this.writer = writer;
150                 }
151
152                 public void WriteOut (object sender, string s)
153                 {
154                         writer.Write (s);
155                 }
156
157                 public static ProcessEventHandler GetWriteHandler (TextWriter tw)
158                 {
159                         return tw != null ? new ProcessEventHandler(new OutWriter (tw).WriteOut) : null;
160                 }
161         }
162 }
163