summaryrefslogtreecommitdiff
path: root/mcs/class/Microsoft.Build.Utilities/Microsoft.Build.Utilities/ProcessService.cs
blob: 3de49797724445ed39a605db3e25215d4049b7d3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#if NET_2_0

using System;
using System.IO;
using System.Collections;
using System.Collections.Specialized;
using System.Diagnostics;

using SCS = System.Collections.Specialized;

namespace Microsoft.Build.Utilities
{
	internal static class ProcessService {
		static SCS.ProcessStringDictionary globalEnvironmentVariablesOverride;

		public static StringDictionary GlobalEnvironmentVariblesOverride {
			get {
				if (globalEnvironmentVariablesOverride == null)
					globalEnvironmentVariablesOverride = new SCS.ProcessStringDictionary ();
				return globalEnvironmentVariablesOverride;
			}
		}

		public static ProcessWrapper StartProcess (string command, string arguments, string workingDirectory, EventHandler exited)
		{
			return StartProcess (command, arguments, workingDirectory, (ProcessEventHandler)null, (ProcessEventHandler)null, exited);
		}

		public static ProcessWrapper StartProcess (string command, string arguments, string workingDirectory, ProcessEventHandler outputStreamChanged, ProcessEventHandler errorStreamChanged)
		{
			return StartProcess (command, arguments, workingDirectory, outputStreamChanged, errorStreamChanged, null);
		}

		public static ProcessWrapper StartProcess (string command, string arguments, string workingDirectory, TextWriter outWriter, TextWriter errorWriter, EventHandler exited)
		{
			return StartProcess (command, arguments, workingDirectory, outWriter, errorWriter, exited, false);
		}

		public static ProcessWrapper StartProcess (string command, string arguments, string workingDirectory, TextWriter outWriter, TextWriter errorWriter, EventHandler exited, bool redirectStandardInput)
		{
			ProcessEventHandler wout = OutWriter.GetWriteHandler (outWriter);
			ProcessEventHandler werr = OutWriter.GetWriteHandler (errorWriter);
			return StartProcess (command, arguments, workingDirectory, wout, werr, exited, redirectStandardInput);
		}

		public static ProcessWrapper StartProcess (string command, string arguments, string workingDirectory, ProcessEventHandler outputStreamChanged, ProcessEventHandler errorStreamChanged, EventHandler exited)
		{
			return StartProcess (command, arguments, workingDirectory, outputStreamChanged, errorStreamChanged, exited, false);
		}

		public static ProcessWrapper StartProcess (string command, string arguments, string workingDirectory, ProcessEventHandler outputStreamChanged, ProcessEventHandler errorStreamChanged, EventHandler exited, bool redirectStandardInput)
		{
			return StartProcess (CreateProcessStartInfo (command, arguments, workingDirectory, redirectStandardInput),
				outputStreamChanged, errorStreamChanged, exited, null);
		}

		public static ProcessWrapper StartProcess (ProcessStartInfo startInfo, TextWriter outWriter, TextWriter errorWriter, EventHandler exited)
		{
			return StartProcess (startInfo, outWriter, errorWriter, exited, null);
		}

		public static ProcessWrapper StartProcess (ProcessStartInfo startInfo, TextWriter outWriter, TextWriter errorWriter, EventHandler exited, StringDictionary environmentOverride)
		{
			ProcessEventHandler wout = OutWriter.GetWriteHandler (outWriter);
			ProcessEventHandler werr = OutWriter.GetWriteHandler (errorWriter);
			return StartProcess (startInfo, wout, werr, exited, environmentOverride);
		}

		// @environmentOverride overrides even the global override values
		public static ProcessWrapper StartProcess (ProcessStartInfo startInfo, ProcessEventHandler outputStreamChanged, ProcessEventHandler errorStreamChanged, EventHandler exited, StringDictionary environmentOverride)
		{
			if (startInfo == null)
				throw new ArgumentException ("startInfo");

			ProcessWrapper p = new ProcessWrapper();

			if (outputStreamChanged != null) {
				p.OutputStreamChanged += outputStreamChanged;
			}

			if (errorStreamChanged != null)
				p.ErrorStreamChanged += errorStreamChanged;

			if (exited != null)
				p.Exited += exited;

			p.StartInfo = startInfo;
			ProcessEnvironmentVariableOverrides (p.StartInfo, environmentOverride);

			// WORKAROUND for "Bug 410743 - wapi leak in System.Diagnostic.Process"
			// Process leaks when an exit event is registered
			// instead we use another thread to monitor I/O and wait for exit
			// p.EnableRaisingEvents = true;

			p.Start ();
			return p;
		}

		public static ProcessStartInfo CreateProcessStartInfo (string command, string arguments, string workingDirectory, bool redirectStandardInput)
		{
			if (command == null)
				throw new ArgumentNullException("command");

			if (command.Length == 0)
				throw new ArgumentException("command");

			ProcessStartInfo startInfo = null;
			if(String.IsNullOrEmpty (arguments))
				startInfo = new ProcessStartInfo (command);
			else
				startInfo = new ProcessStartInfo (command, arguments);

			if(workingDirectory != null && workingDirectory.Length > 0)
				startInfo.WorkingDirectory = workingDirectory;

			startInfo.RedirectStandardOutput = true;
			startInfo.RedirectStandardError = true;
			startInfo.RedirectStandardInput = redirectStandardInput;
			startInfo.UseShellExecute = false;

			return startInfo;
		}

		public static void ProcessEnvironmentVariableOverrides (ProcessStartInfo info, StringDictionary environmentOverride)
		{
			if (globalEnvironmentVariablesOverride != null)
				foreach (DictionaryEntry entry in globalEnvironmentVariablesOverride)
					ProcessEnvironmentVariable (info, (string)entry.Key, (string)entry.Value);

			if (environmentOverride != null)
				foreach (DictionaryEntry entry in environmentOverride)
					ProcessEnvironmentVariable (info, (string)entry.Key, (string)entry.Value);
                }

		static void ProcessEnvironmentVariable (ProcessStartInfo info, string name, string value)
		{
			if (value == null && info.EnvironmentVariables.ContainsKey (name))
				info.EnvironmentVariables.Remove (name);
			else
				info.EnvironmentVariables[name] = value;
		}

	}

	class OutWriter
	{
		TextWriter writer;

		public OutWriter (TextWriter writer)
		{
			this.writer = writer;
		}

		public void WriteOut (object sender, string s)
		{
			writer.Write (s);
		}

		public static ProcessEventHandler GetWriteHandler (TextWriter tw)
		{
			return tw != null ? new ProcessEventHandler(new OutWriter (tw).WriteOut) : null;
		}
	}
}

#endif