1
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
2
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
4
// activate this define to see the build worker window
8
using System.Collections.Generic;
9
using System.Diagnostics;
11
using System.Runtime.Serialization;
12
using System.Threading;
14
using ICSharpCode.SharpDevelop.Interprocess;
15
using Microsoft.Build.Framework;
17
namespace ICSharpCode.SharpDevelop.BuildWorker
21
static HostProcess host;
23
bool requestCancellation;
26
internal static void Main(string[] args)
28
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(AppDomain_CurrentDomain_UnhandledException);
30
if (args.Length == 3 && args[0] == "worker") {
32
host = new HostProcess(args[1], args[2]);
33
host.Run(new Program().DataReceived);
34
} catch (Exception ex) {
35
ShowMessageBox(ex.ToString());
38
Console.WriteLine("ICSharpCode.SharpDevelop.BuildWorker.exe is used to compile " +
39
"MSBuild projects inside SharpDevelop.");
40
Console.WriteLine("If you want to compile projects on the command line, use " +
41
"MSBuild.exe (part of the .NET Framework)");
45
readonly MSBuildWrapper buildWrapper = new MSBuildWrapper();
47
void DataReceived(string command, BinaryReader reader)
51
StartBuild(BuildJob.ReadFrom(reader));
57
throw new InvalidOperationException("Unknown command");
61
static void AppDomain_CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
63
ShowMessageBox(e.ExceptionObject.ToString());
66
#if RELEASE && WORKERDEBUG
67
#error WORKERDEBUG must not be defined if RELEASE is defined
70
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1300:SpecifyMessageBoxOptions")]
71
internal static void ShowMessageBox(string text)
73
System.Windows.Forms.MessageBox.Show(text, "SharpDevelop Build Worker Process");
76
[Conditional("DEBUG")]
77
internal static void Log(string text)
79
Debug.WriteLine(text);
81
DateTime now = DateTime.Now;
82
Console.WriteLine(now.ToString() + "," + now.Millisecond.ToString("d3") + " " + text);
86
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
87
public void StartBuild(BuildJob job)
90
throw new ArgumentNullException("job");
92
if (currentJob != null)
93
throw new InvalidOperationException("Already running a job");
95
requestCancellation = false;
98
Console.Title = "BuildWorker - " + Path.GetFileName(job.ProjectFileName);
100
Program.Log("Got job:");
101
Program.Log(job.ToString());
102
Program.Log("Start build thread");
103
Thread thread = new Thread(RunThread);
104
thread.Name = "Build thread";
105
thread.SetApartmentState(ApartmentState.STA);
109
public void CancelBuild()
111
Program.Log("CancelBuild()");
113
if (!requestCancellation) {
114
requestCancellation = true;
115
buildWrapper.Cancel();
120
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
123
Program.Log("In build thread");
124
bool success = false;
126
if (File.Exists(currentJob.ProjectFileName)) {
127
success = buildWrapper.DoBuild(currentJob, new ForwardingLogger(this));
130
HostReportEvent(new BuildErrorEventArgs(null, null, currentJob.ProjectFileName, 0, 0, 0, 0, "Project file '" + Path.GetFileName(currentJob.ProjectFileName) + "' not found", null, null));
132
} catch (Exception ex) {
133
host.Writer.Write("ReportException");
134
host.Writer.Write(ex.ToString());
136
Program.Log("BuildDone");
139
Console.Title = "BuildWorker - no job";
140
DisplayEventCounts();
146
// in the moment we call BuildDone, we can get the next job
147
host.Writer.Write("BuildDone");
148
host.Writer.Write(success);
152
void HostReportEvent(BuildEventArgs e)
154
host.Writer.Write("ReportEvent");
155
EventSource.EncodeEvent(host.Writer, e);
158
sealed class ForwardingLogger : ILogger
162
public ForwardingLogger(Program program)
164
this.program = program;
167
IEventSource eventSource;
169
public LoggerVerbosity Verbosity { get; set; }
170
public string Parameters { get; set; }
172
public void Initialize(IEventSource eventSource)
174
this.eventSource = eventSource;
175
EventTypes eventMask = program.currentJob.EventMask;
176
if ((eventMask & EventTypes.Message) != 0)
177
eventSource.MessageRaised += OnEvent;
178
if ((eventMask & EventTypes.Error) != 0)
179
eventSource.ErrorRaised += OnEvent;
180
if ((eventMask & EventTypes.Warning) != 0)
181
eventSource.WarningRaised += OnEvent;
182
if ((eventMask & EventTypes.BuildStarted) != 0)
183
eventSource.BuildStarted += OnEvent;
184
if ((eventMask & EventTypes.BuildFinished) != 0)
185
eventSource.BuildFinished += OnEvent;
186
if ((eventMask & EventTypes.ProjectStarted) != 0)
187
eventSource.ProjectStarted += OnEvent;
188
if ((eventMask & EventTypes.ProjectFinished) != 0)
189
eventSource.ProjectFinished += OnEvent;
190
if ((eventMask & EventTypes.TargetStarted) != 0)
191
eventSource.TargetStarted += OnEvent;
192
if ((eventMask & EventTypes.TargetFinished) != 0)
193
eventSource.TargetFinished += OnEvent;
194
if ((eventMask & EventTypes.TaskStarted) != 0)
195
eventSource.TaskStarted += OnEvent;
197
eventSource.TaskStarted += OnTaskStarted;
198
if ((eventMask & EventTypes.TaskFinished) != 0)
199
eventSource.TaskFinished += OnEvent;
201
eventSource.TaskFinished += OnTaskFinished;
202
if ((eventMask & EventTypes.Custom) != 0)
203
eventSource.CustomEventRaised += OnEvent;
204
if ((eventMask & EventTypes.Unknown) != 0)
205
eventSource.AnyEventRaised += OnUnknownEventRaised;
208
eventSource.AnyEventRaised += CountEvent;
212
public void Shutdown()
214
EventTypes eventMask = program.currentJob.EventMask;
215
if ((eventMask & EventTypes.Message) != 0)
216
eventSource.MessageRaised -= OnEvent;
217
if ((eventMask & EventTypes.Error) != 0)
218
eventSource.ErrorRaised -= OnEvent;
219
if ((eventMask & EventTypes.Warning) != 0)
220
eventSource.WarningRaised -= OnEvent;
221
if ((eventMask & EventTypes.BuildStarted) != 0)
222
eventSource.BuildStarted -= OnEvent;
223
if ((eventMask & EventTypes.BuildFinished) != 0)
224
eventSource.BuildFinished -= OnEvent;
225
if ((eventMask & EventTypes.ProjectStarted) != 0)
226
eventSource.ProjectStarted -= OnEvent;
227
if ((eventMask & EventTypes.ProjectFinished) != 0)
228
eventSource.ProjectFinished -= OnEvent;
229
if ((eventMask & EventTypes.TargetStarted) != 0)
230
eventSource.TargetStarted -= OnEvent;
231
if ((eventMask & EventTypes.TargetFinished) != 0)
232
eventSource.TargetFinished -= OnEvent;
233
if ((eventMask & EventTypes.TaskStarted) != 0)
234
eventSource.TaskStarted -= OnEvent;
236
eventSource.TaskStarted -= OnTaskStarted;
237
if ((eventMask & EventTypes.TaskFinished) != 0)
238
eventSource.TaskFinished -= OnEvent;
240
eventSource.TaskFinished -= OnTaskFinished;
241
if ((eventMask & EventTypes.Custom) != 0)
242
eventSource.CustomEventRaised -= OnEvent;
243
if ((eventMask & EventTypes.Unknown) != 0)
244
eventSource.AnyEventRaised -= OnUnknownEventRaised;
247
eventSource.AnyEventRaised -= CountEvent;
251
// used for all events that should be forwarded
252
void OnEvent(object sender, BuildEventArgs e)
254
program.HostReportEvent(e);
257
// registered for AnyEventRaised to forward unknown events
258
void OnUnknownEventRaised(object sender, BuildEventArgs e)
260
if (EventSource.GetEventType(e) == EventTypes.Unknown)
264
// registered when only specific tasks should be forwarded
265
void OnTaskStarted(object sender, TaskStartedEventArgs e)
267
if (program.currentJob.InterestingTaskNames.Contains(e.TaskName))
271
// registered when only specific tasks should be forwarded
272
void OnTaskFinished(object sender, TaskFinishedEventArgs e)
274
if (program.currentJob.InterestingTaskNames.Contains(e.TaskName))
280
void CountEvent(object sender, BuildEventArgs e)
282
Program.CountEvent(EventSource.GetEventType(e));
288
static Dictionary<EventTypes, int> eventCounts = new Dictionary<EventTypes, int>();
290
static void CountEvent(EventTypes e)
292
if (eventCounts.ContainsKey(e))
298
static void DisplayEventCounts()
300
foreach (var pair in eventCounts) {
301
Console.WriteLine(" " + pair.Key.ToString() + ": " + pair.Value.ToString());