2 // ConsoleLogger.cs: Outputs to the console
5 // Marek Sieradzki (marek.sieradzki@gmail.com)
7 // (C) 2005 Marek Sieradzki
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System.Runtime.InteropServices;
32 using System.Collections;
33 using System.Collections.Generic;
36 using System.Security;
38 using Microsoft.Build.Framework;
40 namespace Microsoft.Build.BuildEngine {
41 public class ConsoleLogger : ILogger {
45 LoggerVerbosity verbosity;
46 WriteHandler writeHandler;
50 bool performanceSummary;
52 bool skipProjectStartedText;
53 List<string> errors, warnings;
55 ConsoleColor errorColor, warningColor, eventColor, messageColor, highMessageColor;
57 ColorResetter colorReset;
58 IEventSource eventSource;
59 bool no_message_color, use_colors;
60 bool noItemAndPropertyList;
62 List<BuildEvent> events;
63 Dictionary<string, List<string>> errorsTable;
64 Dictionary<string, List<string>> warningsTable;
65 SortedDictionary<string, PerfInfo> targetPerfTable, tasksPerfTable;
66 string current_events_string;
68 public ConsoleLogger ()
69 : this (LoggerVerbosity.Normal, null, null, null)
73 public ConsoleLogger (LoggerVerbosity verbosity)
74 : this (LoggerVerbosity.Normal, null, null, null)
78 public ConsoleLogger (LoggerVerbosity verbosity,
81 ColorResetter colorReset)
83 this.verbosity = verbosity;
86 this.warningCount = 0;
88 this.writeHandler += new WriteHandler (WriteHandlerFunction);
90 this.writeHandler += write;
91 this.performanceSummary = false;
92 this.showSummary = true;
93 this.skipProjectStartedText = false;
94 errors = new List<string> ();
95 warnings = new List<string> ();
96 this.colorSet = colorSet;
97 this.colorReset = colorReset;
99 events = new List<BuildEvent> ();
100 errorsTable = new Dictionary<string, List<string>> ();
101 warningsTable = new Dictionary<string, List<string>> ();
102 targetPerfTable = new SortedDictionary<string, PerfInfo> ();
103 tasksPerfTable = new SortedDictionary<string, PerfInfo> ();
106 errorColor = ConsoleColor.DarkRed;
107 warningColor = ConsoleColor.DarkYellow;
108 eventColor = ConsoleColor.DarkCyan;
109 messageColor = ConsoleColor.DarkGray;
110 highMessageColor = ConsoleColor.White;
112 // if message color is not set via the env var,
113 // then don't use any color for it.
114 no_message_color = true;
117 if (colorSet == null || colorReset == null)
121 string config = Environment.GetEnvironmentVariable ("XBUILD_COLORS");
122 if (config == null) {
127 if (config == "disable")
131 string [] pairs = config.Split (new char[] {','}, StringSplitOptions.RemoveEmptyEntries);
132 foreach (string pair in pairs) {
133 string [] parts = pair.Split (new char[] {'='}, StringSplitOptions.RemoveEmptyEntries);
134 if (parts.Length != 2)
137 if (parts [0] == "errors")
138 TryParseConsoleColor (parts [1], ref errorColor);
139 else if (parts [0] == "warnings")
140 TryParseConsoleColor (parts [1], ref warningColor);
141 else if (parts [0] == "events")
142 TryParseConsoleColor (parts [1], ref eventColor);
143 else if (parts [0] == "messages") {
144 if (TryParseConsoleColor (parts [1], ref messageColor)) {
145 highMessageColor = GetBrightColorFor (messageColor);
146 no_message_color = false;
152 bool TryParseConsoleColor (string color_str, ref ConsoleColor color)
154 switch (color_str.ToLower ()) {
155 case "black": color = ConsoleColor.Black; break;
157 case "blue": color = ConsoleColor.DarkBlue; break;
158 case "green": color = ConsoleColor.DarkGreen; break;
159 case "cyan": color = ConsoleColor.DarkCyan; break;
160 case "red": color = ConsoleColor.DarkRed; break;
161 case "magenta": color = ConsoleColor.DarkMagenta; break;
162 case "yellow": color = ConsoleColor.DarkYellow; break;
163 case "grey": color = ConsoleColor.DarkGray; break;
165 case "brightgrey": color = ConsoleColor.Gray; break;
166 case "brightblue": color = ConsoleColor.Blue; break;
167 case "brightgreen": color = ConsoleColor.Green; break;
168 case "brightcyan": color = ConsoleColor.Cyan; break;
169 case "brightred": color = ConsoleColor.Red; break;
170 case "brightmagenta": color = ConsoleColor.Magenta; break;
171 case "brightyellow": color = ConsoleColor.Yellow; break;
174 case "brightwhite": color = ConsoleColor.White; break;
175 default: return false;
181 ConsoleColor GetBrightColorFor (ConsoleColor color)
184 case ConsoleColor.DarkBlue: return ConsoleColor.Blue;
185 case ConsoleColor.DarkGreen: return ConsoleColor.Green;
186 case ConsoleColor.DarkCyan: return ConsoleColor.Cyan;
187 case ConsoleColor.DarkRed: return ConsoleColor.Red;
188 case ConsoleColor.DarkMagenta: return ConsoleColor.Magenta;
189 case ConsoleColor.DarkYellow: return ConsoleColor.Yellow;
190 case ConsoleColor.DarkGray: return ConsoleColor.Gray;
191 case ConsoleColor.Gray: return ConsoleColor.White;
193 default: return color;
197 public void ApplyParameter (string parameterName,
198 string parameterValue)
200 // FIXME: what we should do here? in msbuild it isn't
201 // changing "parameters" property
204 public virtual void Initialize (IEventSource eventSource)
206 this.eventSource = eventSource;
208 eventSource.BuildStarted += BuildStartedHandler;
209 eventSource.BuildFinished += BuildFinishedHandler;
211 eventSource.ProjectStarted += PushEvent;
212 eventSource.ProjectFinished += PopEvent;
214 eventSource.TargetStarted += PushEvent;
215 eventSource.TargetFinished += PopEvent;
217 eventSource.TaskStarted += PushEvent;
218 eventSource.TaskFinished += PopEvent;
220 eventSource.MessageRaised += MessageHandler;
221 eventSource.WarningRaised += WarningHandler;
222 eventSource.ErrorRaised += ErrorHandler;
225 public void BuildStartedHandler (object sender, BuildStartedEventArgs args)
227 if (IsVerbosityGreaterOrEqual (LoggerVerbosity.Normal)) {
228 WriteLine (String.Empty);
229 WriteLine (String.Format ("Build started {0}.", args.Timestamp));
230 WriteLine ("__________________________________________________");
232 buildStart = args.Timestamp;
237 public void BuildFinishedHandler (object sender, BuildFinishedEventArgs args)
239 if (!IsVerbosityGreaterOrEqual (LoggerVerbosity.Normal)) {
244 TimeSpan timeElapsed = args.Timestamp - buildStart;
245 if (performanceSummary || verbosity == LoggerVerbosity.Diagnostic)
246 DumpPerformanceSummary ();
248 if (args.Succeeded == true && !projectFailed) {
249 WriteLine ("Build succeeded.");
251 WriteLine ("Build FAILED.");
253 if (warnings.Count > 0) {
254 WriteLine (Environment.NewLine + "Warnings:");
255 SetColor (warningColor);
257 WriteLine (String.Empty);
258 foreach (KeyValuePair<string, List<string>> pair in warningsTable) {
259 if (!String.IsNullOrEmpty (pair.Key))
260 WriteLine (pair.Key);
262 string indent_str = String.IsNullOrEmpty (pair.Key) ? String.Empty : "\t";
263 foreach (string msg in pair.Value)
264 WriteLine (String.Format ("{0}{1}", indent_str, msg));
266 WriteLine (String.Empty);
272 if (errors.Count > 0) {
273 WriteLine ("Errors:");
274 SetColor (errorColor);
276 WriteLine (String.Empty);
277 foreach (KeyValuePair<string, List<string>> pair in errorsTable) {
278 if (!String.IsNullOrEmpty (pair.Key))
279 WriteLine (pair.Key);
281 string indent_str = String.IsNullOrEmpty (pair.Key) ? String.Empty : "\t";
282 foreach (string msg in pair.Value)
283 WriteLine (String.Format ("{0}{1}", indent_str, msg));
285 WriteLine (String.Empty);
290 if (showSummary == true){
291 WriteLine (String.Format ("\t {0} Warning(s)", warningCount));
292 WriteLine (String.Format ("\t {0} Error(s)", errorCount));
293 WriteLine (String.Empty);
294 WriteLine (String.Format ("Time Elapsed {0}", timeElapsed));
300 public void ProjectStartedHandler (object sender, ProjectStartedEventArgs args)
302 if (IsVerbosityGreaterOrEqual (LoggerVerbosity.Normal)) {
303 SetColor (eventColor);
304 WriteLine (String.Format ("Project \"{0}\" ({1} target(s)):", args.ProjectFile,
305 String.IsNullOrEmpty (args.TargetNames) ? "default" : args.TargetNames));
307 DumpProperties (args.Properties);
308 DumpItems (args.Items);
312 public void ProjectFinishedHandler (object sender, ProjectFinishedEventArgs args)
314 if (IsVerbosityGreaterOrEqual (LoggerVerbosity.Normal)) {
317 SetColor (eventColor);
318 WriteLine (String.Format ("Done building project \"{0}\".{1}", args.ProjectFile,
319 args.Succeeded ? String.Empty : "-- FAILED"));
321 WriteLine (String.Empty);
324 // no project has failed yet, so update the flag
325 projectFailed = !args.Succeeded;
328 public void TargetStartedHandler (object sender, TargetStartedEventArgs args)
330 if (IsVerbosityGreaterOrEqual (LoggerVerbosity.Normal)) {
332 SetColor (eventColor);
333 WriteLine (String.Empty);
334 WriteLine (String.Format ("Target {0}:",args.TargetName));
339 public void TargetFinishedHandler (object sender, TargetFinishedEventArgs args)
341 if (IsVerbosityGreaterOrEqual (LoggerVerbosity.Detailed) ||
342 (!args.Succeeded && IsVerbosityGreaterOrEqual (LoggerVerbosity.Normal))) {
343 SetColor (eventColor);
344 WriteLine (String.Format ("Done building target \"{0}\" in project \"{1}\".{2}",
345 args.TargetName, args.ProjectFile,
346 args.Succeeded ? String.Empty : "-- FAILED"));
348 WriteLine (String.Empty);
353 public void TaskStartedHandler (object sender, TaskStartedEventArgs args)
355 if (IsVerbosityGreaterOrEqual (LoggerVerbosity.Detailed)) {
356 SetColor (eventColor);
357 WriteLine (String.Format ("Task \"{0}\"",args.TaskName));
363 public void TaskFinishedHandler (object sender, TaskFinishedEventArgs args)
366 if (IsVerbosityGreaterOrEqual (LoggerVerbosity.Detailed) ||
367 (!args.Succeeded && IsVerbosityGreaterOrEqual (LoggerVerbosity.Normal))) {
368 SetColor (eventColor);
370 WriteLine (String.Format ("Done executing task \"{0}\"", args.TaskName));
372 WriteLine (String.Format ("Task \"{0}\" execution -- FAILED", args.TaskName));
377 public void MessageHandler (object sender, BuildMessageEventArgs args)
379 if (IsMessageOk (args)) {
380 if (no_message_color) {
381 ExecutePendingEventHandlers ();
382 WriteLine (args.Message);
384 ExecutePendingEventHandlers ();
385 SetColor (args.Importance == MessageImportance.High ? highMessageColor : messageColor);
386 WriteLine (args.Message);
392 public void WarningHandler (object sender, BuildWarningEventArgs args)
394 string msg = FormatWarningEvent (args);
395 if (IsVerbosityGreaterOrEqual (LoggerVerbosity.Quiet)) {
396 ExecutePendingEventHandlers ();
397 SetColor (warningColor);
398 WriteLineWithoutIndent (msg);
403 List<string> list = null;
404 if (!warningsTable.TryGetValue (EventsAsString, out list))
405 warningsTable [EventsAsString] = list = new List<string> ();
411 public void ErrorHandler (object sender, BuildErrorEventArgs args)
413 string msg = FormatErrorEvent (args);
414 if (IsVerbosityGreaterOrEqual (LoggerVerbosity.Quiet)) {
415 ExecutePendingEventHandlers ();
416 SetColor (errorColor);
417 WriteLineWithoutIndent (msg);
422 List<string> list = null;
423 if (!errorsTable.TryGetValue (EventsAsString, out list))
424 errorsTable [EventsAsString] = list = new List<string> ();
430 public void CustomEventHandler (object sender, CustomBuildEventArgs args)
434 private void WriteLine (string message)
437 StringBuilder sb = new StringBuilder ();
438 for (int i = 0; i < indent; i++)
442 writeHandler (sb.ToString ());
444 writeHandler (message);
448 void PushEvent<T> (object sender, T args) where T: BuildStatusEventArgs
453 void PushEvent<T> (T args) where T: BuildStatusEventArgs
455 BuildEvent be = new BuildEvent {
457 StartHandlerHasExecuted = false,
462 current_events_string = null;
465 void PopEvent<T> (object sender, T finished_args) where T: BuildStatusEventArgs
467 PopEvent (finished_args);
470 void PopEvent<T> (T finished_args) where T: BuildStatusEventArgs
472 if (events.Count == 0)
473 throw new InvalidOperationException ("INTERNAL ERROR: Trying to pop from an empty events stack");
475 BuildEvent be = events [events.Count - 1];
476 if (performanceSummary || verbosity == LoggerVerbosity.Diagnostic) {
477 var args = be.EventArgs;
478 TargetStartedEventArgs tgt_args = args as TargetStartedEventArgs;
479 if (tgt_args != null) {
480 AddPerfInfo (tgt_args.TargetName, args.Timestamp, targetPerfTable);
482 TaskStartedEventArgs tsk_args = args as TaskStartedEventArgs;
483 if (tsk_args != null)
484 AddPerfInfo (tsk_args.TaskName, args.Timestamp, tasksPerfTable);
488 be.ExecuteFinishedHandler (finished_args);
489 events.RemoveAt (events.Count - 1);
490 current_events_string = null;
493 void ExecutePendingEventHandlers ()
495 foreach (var be in events)
496 be.ExecuteStartedHandler ();
499 string EventsToString ()
501 StringBuilder sb = new StringBuilder ();
503 string last_imported_target_file = String.Empty;
504 for (int i = 0; i < events.Count; i ++) {
505 var args = events [i].EventArgs;
506 ProjectStartedEventArgs pargs = args as ProjectStartedEventArgs;
508 sb.AppendFormat ("{0} ({1}) ->\n", pargs.ProjectFile,
509 String.IsNullOrEmpty (pargs.TargetNames) ?
512 last_imported_target_file = String.Empty;
516 TargetStartedEventArgs targs = args as TargetStartedEventArgs;
518 if (targs.TargetFile != targs.ProjectFile && targs.TargetFile != last_imported_target_file)
519 // target from an imported file,
520 // and it hasn't been mentioned as yet
521 sb.AppendFormat ("{0} ", targs.TargetFile);
523 last_imported_target_file = targs.TargetFile;
524 sb.AppendFormat ("({0} target) ->\n", targs.TargetName);
528 return sb.ToString ();
531 void AddPerfInfo (string name, DateTime start, IDictionary<string, PerfInfo> perf_table)
534 if (!perf_table.TryGetValue (name, out pi)) {
535 pi = new PerfInfo ();
536 perf_table [name] = pi;
539 pi.Time += DateTime.Now - start;
543 void DumpPerformanceSummary ()
545 SetColor (eventColor);
546 WriteLine ("Target perfomance summary:");
549 foreach (var pi in targetPerfTable.OrderBy (pair => pair.Value.Time))
550 WriteLine (String.Format ("{0,10:0.000} ms {1,-50} {2,5} calls", pi.Value.Time.TotalMilliseconds, pi.Key, pi.Value.NumberOfCalls));
552 WriteLine (String.Empty);
554 SetColor (eventColor);
555 WriteLine ("Tasks perfomance summary:");
558 foreach (var pi in tasksPerfTable.OrderBy (pair => pair.Value.Time))
559 WriteLine (String.Format ("{0,10:0.000} ms {1,-50} {2,5} calls", pi.Value.Time.TotalMilliseconds, pi.Key, pi.Value.NumberOfCalls));
561 WriteLine (String.Empty);
564 private void WriteLineWithoutIndent (string message)
566 writeHandler (message);
569 private void WriteHandlerFunction (string message)
571 Console.WriteLine (message);
574 void SetColor (ConsoleColor color)
586 private void ParseParameters ()
588 string[] splittedParameters = parameters.Split (';');
589 foreach (string s in splittedParameters ) {
591 case "PerformanceSummary":
592 this.performanceSummary = true;
595 this.showSummary = false;
597 case "NoItemAndPropertyList":
598 this.noItemAndPropertyList = true;
601 throw new ArgumentException ("Invalid parameter : " + s);
606 public virtual void Shutdown ()
608 if (eventSource == null)
611 eventSource.BuildStarted -= BuildStartedHandler;
612 eventSource.BuildFinished -= BuildFinishedHandler;
614 eventSource.ProjectStarted -= PushEvent;
615 eventSource.ProjectFinished -= PopEvent;
617 eventSource.TargetStarted -= PushEvent;
618 eventSource.TargetFinished -= PopEvent;
620 eventSource.TaskStarted -= PushEvent;
621 eventSource.TaskFinished -= PopEvent;
623 eventSource.MessageRaised -= MessageHandler;
624 eventSource.WarningRaised -= WarningHandler;
625 eventSource.ErrorRaised -= ErrorHandler;
628 static bool InEmacs = Environment.GetEnvironmentVariable ("EMACS") == "t";
630 private string FormatErrorEvent (BuildErrorEventArgs args)
632 // For some reason we get an 1-char empty string as Subcategory somtimes.
633 string subprefix = args.Subcategory == null || args.Subcategory == "" || args.Subcategory == " " ? "" : " ";
634 string subcat = subprefix == "" ? "" : args.Subcategory;
636 if (args.LineNumber != 0){
637 if (args.ColumnNumber != 0 && !InEmacs)
638 return String.Format ("{0}({1},{2}): {3}{4}error {5}: {6}",
639 args.File, args.LineNumber, args.ColumnNumber,
640 subprefix, subcat, args.Code, args.Message);
642 return String.Format ("{0}({1}): {2}{3}error {4}: {5}",
643 args.File, args.LineNumber,
644 subprefix, subcat, args.Code, args.Message);
646 return String.Format ("{0}: {1}{2}error {3}: {4}", args.File, subprefix, subcat, args.Code,
651 private string FormatWarningEvent (BuildWarningEventArgs args)
653 // For some reason we get an 1-char empty string as Subcategory somtimes.
654 string subprefix = args.Subcategory == null || args.Subcategory == "" || args.Subcategory == " " ? "" : " ";
655 string subcat = subprefix == "" ? "" : args.Subcategory;
657 // FIXME: show more complicated args
658 if (args.LineNumber != 0){
660 if (args.ColumnNumber != 0 && !InEmacs) {
661 return String.Format ("{0}({1},{2}): {3}{4}warning {5}: {6}",
662 args.File, args.LineNumber, args.ColumnNumber,
663 subprefix, subcat, args.Code, args.Message);
665 return String.Format ("{0}({1}): {2}{3}warning {4}: {5}",
666 args.File, args.LineNumber,
667 subprefix, subcat, args.Code, args.Message);
669 return String.Format ("{0}: {1} warning {2}: {3}", args.File, args.Subcategory, args.Code,
674 private bool IsMessageOk (BuildMessageEventArgs bsea)
676 if (bsea.Importance == MessageImportance.High && IsVerbosityGreaterOrEqual (LoggerVerbosity.Minimal)) {
678 } else if (bsea.Importance == MessageImportance.Normal && IsVerbosityGreaterOrEqual (LoggerVerbosity.Normal)) {
680 } else if (bsea.Importance == MessageImportance.Low && IsVerbosityGreaterOrEqual (LoggerVerbosity.Detailed)) {
686 private bool IsVerbosityGreaterOrEqual (LoggerVerbosity v)
688 if (v == LoggerVerbosity.Diagnostic) {
689 return LoggerVerbosity.Diagnostic <= verbosity;
690 } else if (v == LoggerVerbosity.Detailed) {
691 return LoggerVerbosity.Detailed <= verbosity;
692 } else if (v == LoggerVerbosity.Normal) {
693 return LoggerVerbosity.Normal <= verbosity;
694 } else if (v == LoggerVerbosity.Minimal) {
695 return LoggerVerbosity.Minimal <= verbosity;
696 } else if (v == LoggerVerbosity.Quiet) {
702 void DumpProperties (IEnumerable properties)
704 if (noItemAndPropertyList || !IsVerbosityGreaterOrEqual (LoggerVerbosity.Diagnostic))
707 SetColor (eventColor);
708 WriteLine (String.Empty);
709 WriteLine ("Initial Properties:");
712 if (properties == null)
715 var dict = new SortedDictionary<string, string> ();
716 foreach (DictionaryEntry de in properties)
717 dict [(string)de.Key] = (string)de.Value;
719 foreach (KeyValuePair<string, string> pair in dict)
720 WriteLine (String.Format ("{0} = {1}", pair.Key, pair.Value));
723 void DumpItems (IEnumerable items)
725 if (noItemAndPropertyList || !IsVerbosityGreaterOrEqual (LoggerVerbosity.Diagnostic) || items == null)
728 SetColor (eventColor);
729 WriteLine (String.Empty);
730 WriteLine ("Initial Items:");
735 var items_table = new SortedDictionary<string, List<ITaskItem>> ();
736 foreach (DictionaryEntry de in items) {
737 string key = (string)de.Key;
738 if (!items_table.ContainsKey (key))
739 items_table [key] = new List<ITaskItem> ();
741 items_table [key].Add ((ITaskItem) de.Value);
744 foreach (string name in items_table.Keys) {
747 foreach (ITaskItem item in items_table [name])
748 WriteLine (item.ItemSpec);
753 public string Parameters {
759 throw new ArgumentNullException ();
761 if (parameters != String.Empty)
766 string EventsAsString {
768 if (current_events_string == null)
769 current_events_string = EventsToString ();
770 return current_events_string;
774 public bool ShowSummary {
775 get { return showSummary; }
776 set { showSummary = value; }
779 public bool SkipProjectStartedText {
780 get { return skipProjectStartedText; }
781 set { skipProjectStartedText = value; }
784 public LoggerVerbosity Verbosity {
785 get { return verbosity; }
786 set { verbosity = value; }
789 protected WriteHandler WriteHandler {
790 get { return writeHandler; }
791 set { writeHandler = value; }
796 public BuildStatusEventArgs EventArgs;
797 public bool StartHandlerHasExecuted;
798 public ConsoleLogger ConsoleLogger;
800 public void ExecuteStartedHandler ()
802 if (StartHandlerHasExecuted)
805 if (EventArgs is ProjectStartedEventArgs)
806 ConsoleLogger.ProjectStartedHandler (null, (ProjectStartedEventArgs)EventArgs);
807 else if (EventArgs is TargetStartedEventArgs)
808 ConsoleLogger.TargetStartedHandler (null, (TargetStartedEventArgs)EventArgs);
809 else if (EventArgs is TaskStartedEventArgs)
810 ConsoleLogger.TaskStartedHandler (null, (TaskStartedEventArgs)EventArgs);
811 else if (!(EventArgs is BuildStartedEventArgs))
812 throw new InvalidOperationException ("Unexpected event on the stack, type: " + EventArgs.GetType ());
814 StartHandlerHasExecuted = true;
817 public void ExecuteFinishedHandler (BuildStatusEventArgs finished_args)
819 if (!StartHandlerHasExecuted)
822 if (EventArgs is ProjectStartedEventArgs)
823 ConsoleLogger.ProjectFinishedHandler (null, finished_args as ProjectFinishedEventArgs);
824 else if (EventArgs is TargetStartedEventArgs)
825 ConsoleLogger.TargetFinishedHandler (null, finished_args as TargetFinishedEventArgs);
826 else if (EventArgs is TaskStartedEventArgs)
827 ConsoleLogger.TaskFinishedHandler (null, finished_args as TaskFinishedEventArgs);
828 else if (!(EventArgs is BuildStartedEventArgs))
829 throw new InvalidOperationException ("Unexpected event on the stack, type: " + EventArgs.GetType ());
834 public TimeSpan Time;
835 public int NumberOfCalls;