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.
29 using System.Runtime.InteropServices;
30 using System.Collections;
31 using System.Collections.Generic;
34 using System.Security;
36 using Microsoft.Build.Framework;
38 #if MICROSOFT_BUILD_DLL
39 namespace Microsoft.Build.Logging
41 namespace Microsoft.Build.BuildEngine
44 public class ConsoleLogger : ILogger {
47 LoggerVerbosity verbosity;
48 WriteHandler writeHandler;
49 bool skipProjectStartedText;
50 ConsoleColor errorColor, warningColor, eventColor, messageColor, highMessageColor;
52 ColorResetter colorReset;
53 IEventSource eventSource;
54 bool no_message_color, use_colors;
55 ConsoleLoggerParameter config = new ConsoleLoggerParameter ();
57 public ConsoleLogger ()
58 : this (LoggerVerbosity.Normal, null, null, null)
62 public ConsoleLogger (LoggerVerbosity verbosity)
63 : this (verbosity, null, null, null)
67 public ConsoleLogger (LoggerVerbosity verbosity,
70 ColorResetter colorReset)
72 this.verbosity = verbosity;
74 this.writeHandler += new WriteHandler (WriteHandlerFunction);
76 this.writeHandler += write;
77 this.skipProjectStartedText = false;
78 this.colorSet = colorSet;
79 this.colorReset = colorReset;
82 errorColor = ConsoleColor.DarkRed;
83 warningColor = ConsoleColor.DarkYellow;
84 eventColor = ConsoleColor.DarkCyan;
85 messageColor = ConsoleColor.DarkGray;
86 highMessageColor = ConsoleColor.White;
88 // if message color is not set via the env var,
89 // then don't use any color for it.
90 no_message_color = true;
93 if (colorSet == null || colorReset == null)
97 string config = Environment.GetEnvironmentVariable ("XBUILD_COLORS");
103 if (config == "disable")
107 string [] pairs = config.Split (new char[] {','}, StringSplitOptions.RemoveEmptyEntries);
108 foreach (string pair in pairs) {
109 string [] parts = pair.Split (new char[] {'='}, StringSplitOptions.RemoveEmptyEntries);
110 if (parts.Length != 2)
113 if (parts [0] == "errors")
114 TryParseConsoleColor (parts [1], ref errorColor);
115 else if (parts [0] == "warnings")
116 TryParseConsoleColor (parts [1], ref warningColor);
117 else if (parts [0] == "events")
118 TryParseConsoleColor (parts [1], ref eventColor);
119 else if (parts [0] == "messages") {
120 if (TryParseConsoleColor (parts [1], ref messageColor)) {
121 highMessageColor = GetBrightColorFor (messageColor);
122 no_message_color = false;
128 private void WriteHandlerFunction (string message)
130 Console.WriteLine (message);
133 bool TryParseConsoleColor (string color_str, ref ConsoleColor color)
135 switch (color_str.ToLowerInvariant ()) {
136 case "black": color = ConsoleColor.Black; break;
138 case "blue": color = ConsoleColor.DarkBlue; break;
139 case "green": color = ConsoleColor.DarkGreen; break;
140 case "cyan": color = ConsoleColor.DarkCyan; break;
141 case "red": color = ConsoleColor.DarkRed; break;
142 case "magenta": color = ConsoleColor.DarkMagenta; break;
143 case "yellow": color = ConsoleColor.DarkYellow; break;
144 case "grey": color = ConsoleColor.DarkGray; break;
146 case "brightgrey": color = ConsoleColor.Gray; break;
147 case "brightblue": color = ConsoleColor.Blue; break;
148 case "brightgreen": color = ConsoleColor.Green; break;
149 case "brightcyan": color = ConsoleColor.Cyan; break;
150 case "brightred": color = ConsoleColor.Red; break;
151 case "brightmagenta": color = ConsoleColor.Magenta; break;
152 case "brightyellow": color = ConsoleColor.Yellow; break;
155 case "brightwhite": color = ConsoleColor.White; break;
156 default: return false;
162 ConsoleColor GetBrightColorFor (ConsoleColor color)
165 case ConsoleColor.DarkBlue: return ConsoleColor.Blue;
166 case ConsoleColor.DarkGreen: return ConsoleColor.Green;
167 case ConsoleColor.DarkCyan: return ConsoleColor.Cyan;
168 case ConsoleColor.DarkRed: return ConsoleColor.Red;
169 case ConsoleColor.DarkMagenta: return ConsoleColor.Magenta;
170 case ConsoleColor.DarkYellow: return ConsoleColor.Yellow;
171 case ConsoleColor.DarkGray: return ConsoleColor.Gray;
172 case ConsoleColor.Gray: return ConsoleColor.White;
174 default: return color;
178 class ConsoleLoggerParameter
180 public ConsoleLoggerParameter ()
184 public bool PerformanceSummary { get; set; }
185 public bool ShowSummary { get; set; }
186 public bool NoItemAndPropertyList { get; set; }
189 public void ApplyParameter (string parameterName,
190 string parameterValue)
192 switch (parameterName) {
193 case "PerformanceSummary":
194 config.PerformanceSummary = true;
197 config.ShowSummary = true;
200 config.ShowSummary = false;
202 case "NoItemAndPropertyList":
203 config.NoItemAndPropertyList = true;
206 if (parameterName.StartsWith ("Verbosity="))
207 ParseVerbosity (parameterName);
212 void ParseVerbosity (string s)
215 if (!TrySplitKeyValuePair (s, out key, out value))
216 throw new LoggerException ("Unknown Verbosity, should be set as 'Verbosity=<verbosity>'");
221 Verbosity = LoggerVerbosity.Quiet;
225 Verbosity = LoggerVerbosity.Minimal;
229 Verbosity = LoggerVerbosity.Normal;
233 Verbosity = LoggerVerbosity.Detailed;
237 Verbosity = LoggerVerbosity.Diagnostic;
240 throw new LoggerException (String.Format ("Unknown verbosity - '{0}'", s));
244 bool TrySplitKeyValuePair (string pair, out string key, out string value)
247 string[] parts = pair.Split ('=');
248 if (parts.Length != 2)
256 public virtual void Initialize (IEventSource eventSource)
258 this.eventSource = eventSource;
260 eventSource.BuildStarted += BuildStartedHandler;
261 eventSource.BuildFinished += BuildFinishedHandler;
263 eventSource.ProjectStarted += PushEvent;
264 eventSource.ProjectFinished += PopEvent;
266 eventSource.TargetStarted += PushEvent;
267 eventSource.TargetFinished += PopEvent;
269 eventSource.TaskStarted += PushEvent;
270 eventSource.TaskFinished += PopEvent;
272 eventSource.MessageRaised += MessageHandler;
273 eventSource.WarningRaised += WarningHandler;
274 eventSource.ErrorRaised += ErrorHandler;
276 if (!String.IsNullOrEmpty (parameters))
280 Dictionary<object,BuildRecord> build_records = new Dictionary<object, BuildRecord> ();
282 object dummy_key = new object ();
284 BuildRecord GetBuildRecord (object sender)
287 // FIXME: our Microsoft.Build.Engine shouldn't give different "sender" object for each event
288 // during the same build run. But it actually does.
289 // It is problematic for parallel build because it is impossible to determine right "ongoing build"
290 // record for the event without correct sender object.
291 // Hence we expect sender as a valid object only if it is IBuildEngine4 -
292 // only Microsoft.Build.Internal.BuildEngine4 implements it so far.
293 var key = sender as IBuildEngine4 ?? dummy_key;
294 if (!build_records.TryGetValue (key, out r)) {
295 r = new BuildRecord (this);
296 build_records.Add (key, r);
301 public void BuildStartedHandler (object sender, BuildStartedEventArgs args)
303 GetBuildRecord (sender).BuildStartedHandler (sender, args);
306 public void BuildFinishedHandler (object sender, BuildFinishedEventArgs args)
308 GetBuildRecord (sender).BuildFinishedHandler (args);
309 build_records.Remove (sender);
312 void PushEvent<T> (object sender, T args) where T: BuildStatusEventArgs
314 GetBuildRecord (sender).PushEvent (sender, args);
316 void PopEvent<T> (object sender, T args) where T: BuildStatusEventArgs
318 GetBuildRecord (sender).PopEvent (args);
320 public void ProjectStartedHandler (object sender, ProjectStartedEventArgs args)
322 GetBuildRecord (sender).ProjectStartedHandler (args);
324 public void ProjectFinishedHandler (object sender, ProjectFinishedEventArgs args)
326 GetBuildRecord (sender).ProjectFinishedHandler (args);
328 public void TargetStartedHandler (object sender, TargetStartedEventArgs args)
330 GetBuildRecord (sender).TargetStartedHandler (args);
332 public void TargetFinishedHandler (object sender, TargetFinishedEventArgs args)
334 GetBuildRecord (sender).TargetFinishedHandler (args);
336 public void TaskStartedHandler (object sender, TaskStartedEventArgs args)
338 GetBuildRecord (sender).TaskStartedHandler (args);
340 public void TaskFinishedHandler (object sender, TaskFinishedEventArgs args)
342 GetBuildRecord (sender).TaskFinishedHandler (args);
344 public void MessageHandler (object sender, BuildMessageEventArgs args)
346 GetBuildRecord (sender).MessageHandler (args);
348 public void WarningHandler (object sender, BuildWarningEventArgs args)
350 GetBuildRecord (sender).WarningHandler (args);
352 public void ErrorHandler (object sender, BuildErrorEventArgs args)
354 GetBuildRecord (sender).ErrorHandler (args);
358 public void CustomEventHandler (object sender, CustomBuildEventArgs args)
360 build_records [sender].CustomHandler (args);
363 void SetColor (ConsoleColor color)
375 private void ParseParameters ()
377 string[] splittedParameters = parameters.Split (';');
378 foreach (string s in splittedParameters )
379 ApplyParameter (s, null);
382 public virtual void Shutdown ()
384 if (eventSource == null)
387 eventSource.BuildStarted -= BuildStartedHandler;
388 eventSource.BuildFinished -= BuildFinishedHandler;
390 eventSource.ProjectStarted -= PushEvent;
391 eventSource.ProjectFinished -= PopEvent;
393 eventSource.TargetStarted -= PushEvent;
394 eventSource.TargetFinished -= PopEvent;
396 eventSource.TaskStarted -= PushEvent;
397 eventSource.TaskFinished -= PopEvent;
399 eventSource.MessageRaised -= MessageHandler;
400 eventSource.WarningRaised -= WarningHandler;
401 eventSource.ErrorRaised -= ErrorHandler;
404 public string Parameters {
410 throw new ArgumentNullException ();
416 public bool ShowSummary {
417 get { return config.ShowSummary; }
418 set { config.ShowSummary = value; }
421 public bool SkipProjectStartedText {
422 get { return skipProjectStartedText; }
423 set { skipProjectStartedText = value; }
426 public LoggerVerbosity Verbosity {
427 get { return verbosity; }
428 set { verbosity = value; }
431 protected WriteHandler WriteHandler {
432 get { return writeHandler; }
433 set { writeHandler = value; }
438 readonly ConsoleLogger parent;
440 readonly List<BuildEvent> events;
441 readonly Dictionary<string, List<string>> errorsTable;
442 readonly Dictionary<string, List<string>> warningsTable;
443 readonly SortedDictionary<string, PerfInfo> targetPerfTable, tasksPerfTable;
444 List<string> errors, warnings;
451 string current_events_string;
453 ConsoleColor eventColor {
454 get { return parent.eventColor; }
456 LoggerVerbosity verbosity {
457 get { return parent.Verbosity; }
460 public BuildRecord (ConsoleLogger parent)
462 this.parent = parent;
466 this.warningCount = 0;
467 errors = new List<string> ();
468 warnings = new List<string> ();
469 events = new List<BuildEvent> ();
470 errorsTable = new Dictionary<string, List<string>> ();
471 warningsTable = new Dictionary<string, List<string>> ();
472 targetPerfTable = new SortedDictionary<string, PerfInfo> ();
473 tasksPerfTable = new SortedDictionary<string, PerfInfo> ();
476 internal void PushEvent<T> (object sender, T args) where T: BuildStatusEventArgs
478 BuildEvent be = new BuildEvent {
481 StartHandlerHasExecuted = false,
482 ConsoleLogger = this.parent
486 current_events_string = null;
489 void PopEvent<T> (object sender, T finished_args) where T: BuildStatusEventArgs
491 PopEvent (finished_args);
494 internal void PopEvent<T> (T finished_args) where T: BuildStatusEventArgs
496 if (events.Count == 0)
497 throw new InvalidOperationException ("INTERNAL ERROR: Trying to pop from an empty events stack");
499 BuildEvent be = events [events.Count - 1];
500 if (parent.config.PerformanceSummary || verbosity == LoggerVerbosity.Diagnostic) {
501 var args = be.EventArgs;
502 TargetStartedEventArgs tgt_args = args as TargetStartedEventArgs;
503 if (tgt_args != null) {
504 AddPerfInfo (tgt_args.TargetName, args.Timestamp, targetPerfTable);
506 TaskStartedEventArgs tsk_args = args as TaskStartedEventArgs;
507 if (tsk_args != null)
508 AddPerfInfo (tsk_args.TaskName, args.Timestamp, tasksPerfTable);
512 be.ExecuteFinishedHandler (finished_args);
513 events.RemoveAt (events.Count - 1);
514 current_events_string = null;
517 public void ResetBuildState ()
521 errorsTable.Clear ();
522 warningsTable.Clear ();
523 targetPerfTable.Clear ();
524 tasksPerfTable.Clear ();
531 projectFailed = false;
534 void AddPerfInfo (string name, DateTime start, IDictionary<string, PerfInfo> perf_table)
537 if (!perf_table.TryGetValue (name, out pi)) {
538 pi = new PerfInfo ();
539 perf_table [name] = pi;
542 pi.Time += DateTime.Now - start;
546 public void BuildStartedHandler (object sender, BuildStartedEventArgs args)
548 if (IsVerbosityGreaterOrEqual (LoggerVerbosity.Normal)) {
549 WriteLine (String.Empty);
550 WriteLine (String.Format ("Build started {0}.", args.Timestamp));
551 WriteLine ("__________________________________________________");
553 buildStart = args.Timestamp;
555 PushEvent (sender, args);
558 public void BuildFinishedHandler (BuildFinishedEventArgs args)
560 BuildFinishedHandlerActual (args);
565 void BuildFinishedHandlerActual (BuildFinishedEventArgs args)
567 if (!IsVerbosityGreaterOrEqual (LoggerVerbosity.Normal)) {
572 TimeSpan timeElapsed = args.Timestamp - buildStart;
573 if (parent.config.PerformanceSummary || verbosity == LoggerVerbosity.Diagnostic)
574 DumpPerformanceSummary ();
576 if (args.Succeeded == true && !projectFailed) {
577 WriteLine ("Build succeeded.");
579 WriteLine ("Build FAILED.");
581 if (warnings.Count > 0) {
582 WriteLine (Environment.NewLine + "Warnings:");
583 SetColor (parent.warningColor);
585 WriteLine (String.Empty);
586 foreach (KeyValuePair<string, List<string>> pair in warningsTable) {
587 if (!String.IsNullOrEmpty (pair.Key))
588 WriteLine (pair.Key);
590 string indent_str = String.IsNullOrEmpty (pair.Key) ? String.Empty : "\t";
591 foreach (string msg in pair.Value)
592 WriteLine (String.Format ("{0}{1}", indent_str, msg));
594 WriteLine (String.Empty);
600 if (errors.Count > 0) {
601 WriteLine ("Errors:");
602 SetColor (parent.errorColor);
604 WriteLine (String.Empty);
605 foreach (KeyValuePair<string, List<string>> pair in errorsTable) {
606 if (!String.IsNullOrEmpty (pair.Key))
607 WriteLine (pair.Key);
609 string indent_str = String.IsNullOrEmpty (pair.Key) ? String.Empty : "\t";
610 foreach (string msg in pair.Value)
611 WriteLine (String.Format ("{0}{1}", indent_str, msg));
613 WriteLine (String.Empty);
618 if (parent.ShowSummary == true){
619 WriteLine (String.Format ("\t {0} Warning(s)", warningCount));
620 WriteLine (String.Format ("\t {0} Error(s)", errorCount));
621 WriteLine (String.Empty);
622 WriteLine (String.Format ("Time Elapsed {0}", timeElapsed));
628 public void ProjectStartedHandler (ProjectStartedEventArgs args)
630 if (IsVerbosityGreaterOrEqual (LoggerVerbosity.Normal)) {
631 SetColor (eventColor);
632 WriteLine (String.Format ("Project \"{0}\" ({1} target(s)):", args.ProjectFile,
633 String.IsNullOrEmpty (args.TargetNames) ? "default" : args.TargetNames));
635 DumpProperties (args.Properties);
636 DumpItems (args.Items);
640 public void ProjectFinishedHandler (ProjectFinishedEventArgs args)
642 if (IsVerbosityGreaterOrEqual (LoggerVerbosity.Normal)) {
645 SetColor (eventColor);
646 WriteLine (String.Format ("Done building project \"{0}\".{1}", args.ProjectFile,
647 args.Succeeded ? String.Empty : "-- FAILED"));
649 WriteLine (String.Empty);
652 // no project has failed yet, so update the flag
653 projectFailed = !args.Succeeded;
656 public void TargetStartedHandler (TargetStartedEventArgs args)
658 if (IsVerbosityGreaterOrEqual (LoggerVerbosity.Normal)) {
660 SetColor (eventColor);
661 WriteLine (String.Empty);
662 WriteLine (String.Format ("Target {0}:",args.TargetName));
667 public void TargetFinishedHandler (TargetFinishedEventArgs args)
669 if (IsVerbosityGreaterOrEqual (LoggerVerbosity.Detailed) ||
670 (!args.Succeeded && IsVerbosityGreaterOrEqual (LoggerVerbosity.Normal))) {
671 SetColor (eventColor);
672 WriteLine (String.Format ("Done building target \"{0}\" in project \"{1}\".{2}",
673 args.TargetName, args.ProjectFile,
674 args.Succeeded ? String.Empty : "-- FAILED"));
676 WriteLine (String.Empty);
681 public void TaskStartedHandler (TaskStartedEventArgs args)
683 if (IsVerbosityGreaterOrEqual (LoggerVerbosity.Detailed)) {
684 SetColor (eventColor);
685 WriteLine (String.Format ("Task \"{0}\"",args.TaskName));
691 public void TaskFinishedHandler (TaskFinishedEventArgs args)
694 if (IsVerbosityGreaterOrEqual (LoggerVerbosity.Detailed) ||
695 (!args.Succeeded && IsVerbosityGreaterOrEqual (LoggerVerbosity.Normal))) {
696 SetColor (eventColor);
698 WriteLine (String.Format ("Done executing task \"{0}\"", args.TaskName));
700 WriteLine (String.Format ("Task \"{0}\" execution -- FAILED", args.TaskName));
705 public void MessageHandler (BuildMessageEventArgs args)
707 if (IsMessageOk (args)) {
708 if (parent.no_message_color) {
709 ExecutePendingEventHandlers ();
710 WriteLine (args.Message);
712 ExecutePendingEventHandlers ();
713 SetColor (args.Importance == MessageImportance.High ? parent.highMessageColor : parent.messageColor);
714 WriteLine (args.Message);
720 public void WarningHandler (BuildWarningEventArgs args)
722 string msg = FormatWarningEvent (args);
723 if (IsVerbosityGreaterOrEqual (LoggerVerbosity.Quiet)) {
724 ExecutePendingEventHandlers ();
725 SetColor (parent.warningColor);
726 WriteLineWithoutIndent (msg);
731 List<string> list = null;
732 if (!warningsTable.TryGetValue (EventsAsString, out list))
733 warningsTable [EventsAsString] = list = new List<string> ();
739 public void ErrorHandler (BuildErrorEventArgs args)
741 string msg = FormatErrorEvent (args);
742 if (IsVerbosityGreaterOrEqual (LoggerVerbosity.Quiet)) {
743 ExecutePendingEventHandlers ();
744 SetColor (parent.errorColor);
745 WriteLineWithoutIndent (msg);
750 List<string> list = null;
751 if (!errorsTable.TryGetValue (EventsAsString, out list))
752 errorsTable [EventsAsString] = list = new List<string> ();
757 public void CustomHandler (CustomBuildEventArgs args)
761 private bool IsVerbosityGreaterOrEqual (LoggerVerbosity v)
763 if (v == LoggerVerbosity.Diagnostic) {
764 return LoggerVerbosity.Diagnostic <= verbosity;
765 } else if (v == LoggerVerbosity.Detailed) {
766 return LoggerVerbosity.Detailed <= verbosity;
767 } else if (v == LoggerVerbosity.Normal) {
768 return LoggerVerbosity.Normal <= verbosity;
769 } else if (v == LoggerVerbosity.Minimal) {
770 return LoggerVerbosity.Minimal <= verbosity;
771 } else if (v == LoggerVerbosity.Quiet) {
777 void DumpItems (IEnumerable items)
779 if (parent.config.NoItemAndPropertyList || !IsVerbosityGreaterOrEqual (LoggerVerbosity.Diagnostic) || items == null)
782 SetColor (eventColor);
783 WriteLine (String.Empty);
784 WriteLine ("Initial Items:");
789 var items_table = new SortedDictionary<string, List<ITaskItem>> ();
790 foreach (DictionaryEntry de in items) {
791 string key = (string)de.Key;
792 if (!items_table.ContainsKey (key))
793 items_table [key] = new List<ITaskItem> ();
795 items_table [key].Add ((ITaskItem) de.Value);
798 foreach (string name in items_table.Keys) {
801 foreach (ITaskItem item in items_table [name])
802 WriteLine (item.ItemSpec);
807 string EventsAsString {
809 if (current_events_string == null)
810 current_events_string = EventsToString ();
811 return current_events_string;
815 private bool IsMessageOk (BuildMessageEventArgs bsea)
817 if (bsea.Importance == MessageImportance.High && IsVerbosityGreaterOrEqual (LoggerVerbosity.Minimal)) {
819 } else if (bsea.Importance == MessageImportance.Normal && IsVerbosityGreaterOrEqual (LoggerVerbosity.Normal)) {
821 } else if (bsea.Importance == MessageImportance.Low && IsVerbosityGreaterOrEqual (LoggerVerbosity.Detailed)) {
827 void DumpProperties (IEnumerable properties)
829 if (parent.config.NoItemAndPropertyList || !IsVerbosityGreaterOrEqual (LoggerVerbosity.Diagnostic))
832 SetColor (eventColor);
833 WriteLine (String.Empty);
834 WriteLine ("Initial Properties:");
837 if (properties == null)
840 var dict = new SortedDictionary<string, string> ();
841 foreach (DictionaryEntry de in properties)
842 dict [(string)de.Key] = (string)de.Value;
844 foreach (KeyValuePair<string, string> pair in dict)
845 WriteLine (String.Format ("{0} = {1}", pair.Key, pair.Value));
848 private void WriteLine (string message)
851 StringBuilder sb = new StringBuilder ();
852 for (int i = 0; i < indent; i++)
855 string indent_str = sb.ToString ();
857 foreach (string line in message.Split (new string[] {Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries))
858 parent.writeHandler (indent_str + line);
860 parent.writeHandler (message);
864 void ExecutePendingEventHandlers ()
866 foreach (var be in events)
867 be.ExecuteStartedHandler ();
870 string EventsToString ()
872 StringBuilder sb = new StringBuilder ();
874 string last_imported_target_file = String.Empty;
875 for (int i = 0; i < events.Count; i ++) {
876 var args = events [i].EventArgs;
877 ProjectStartedEventArgs pargs = args as ProjectStartedEventArgs;
879 sb.AppendFormat ("{0} ({1}) ->\n", pargs.ProjectFile,
880 String.IsNullOrEmpty (pargs.TargetNames) ?
883 last_imported_target_file = String.Empty;
887 TargetStartedEventArgs targs = args as TargetStartedEventArgs;
889 if (targs.TargetFile != targs.ProjectFile && targs.TargetFile != last_imported_target_file)
890 // target from an imported file,
891 // and it hasn't been mentioned as yet
892 sb.AppendFormat ("{0} ", targs.TargetFile);
894 last_imported_target_file = targs.TargetFile;
895 sb.AppendFormat ("({0} target) ->\n", targs.TargetName);
899 return sb.ToString ();
902 void DumpPerformanceSummary ()
904 SetColor (eventColor);
905 WriteLine ("Target perfomance summary:");
908 foreach (var pi in targetPerfTable.OrderBy (pair => pair.Value.Time))
909 WriteLine (String.Format ("{0,10:0.000} ms {1,-50} {2,5} calls", pi.Value.Time.TotalMilliseconds, pi.Key, pi.Value.NumberOfCalls));
911 WriteLine (String.Empty);
913 SetColor (eventColor);
914 WriteLine ("Tasks perfomance summary:");
917 foreach (var pi in tasksPerfTable.OrderBy (pair => pair.Value.Time))
918 WriteLine (String.Format ("{0,10:0.000} ms {1,-50} {2,5} calls", pi.Value.Time.TotalMilliseconds, pi.Key, pi.Value.NumberOfCalls));
920 WriteLine (String.Empty);
923 private string FormatErrorEvent (BuildErrorEventArgs args)
925 // For some reason we get an 1-char empty string as Subcategory somtimes.
926 string subprefix = args.Subcategory == null || args.Subcategory == "" || args.Subcategory == " " ? "" : " ";
927 string subcat = subprefix == "" ? "" : args.Subcategory;
929 if (args.LineNumber != 0){
930 if (args.ColumnNumber != 0 && !InEmacs)
931 return String.Format ("{0}({1},{2}): {3}{4}error {5}: {6}",
932 args.File, args.LineNumber, args.ColumnNumber,
933 subprefix, subcat, args.Code, args.Message);
935 return String.Format ("{0}({1}): {2}{3}error {4}: {5}",
936 args.File, args.LineNumber,
937 subprefix, subcat, args.Code, args.Message);
939 return String.Format ("{0}: {1}{2}error {3}: {4}", args.File, subprefix, subcat, args.Code,
944 static bool InEmacs = Environment.GetEnvironmentVariable ("EMACS") == "t";
946 private string FormatWarningEvent (BuildWarningEventArgs args)
948 // For some reason we get an 1-char empty string as Subcategory somtimes.
949 string subprefix = args.Subcategory == null || args.Subcategory == "" || args.Subcategory == " " ? "" : " ";
950 string subcat = subprefix == "" ? "" : args.Subcategory;
952 // FIXME: show more complicated args
953 if (args.LineNumber != 0){
955 if (args.ColumnNumber != 0 && !InEmacs) {
956 return String.Format ("{0}({1},{2}): {3}{4}warning {5}: {6}",
957 args.File, args.LineNumber, args.ColumnNumber,
958 subprefix, subcat, args.Code, args.Message);
960 return String.Format ("{0}({1}): {2}{3}warning {4}: {5}",
961 args.File, args.LineNumber,
962 subprefix, subcat, args.Code, args.Message);
964 return String.Format ("{0}: {1} warning {2}: {3}", args.File, args.Subcategory, args.Code,
969 void SetColor (ConsoleColor color)
971 if (parent.use_colors)
972 parent.colorSet (color);
977 if (parent.use_colors)
978 parent.colorReset ();
981 private void WriteLineWithoutIndent (string message)
983 parent.writeHandler (message);
989 public object Sender;
990 public BuildStatusEventArgs EventArgs;
991 public bool StartHandlerHasExecuted;
992 public ConsoleLogger ConsoleLogger;
994 public void ExecuteStartedHandler ()
996 if (StartHandlerHasExecuted)
999 if (EventArgs is ProjectStartedEventArgs)
1000 ConsoleLogger.ProjectStartedHandler (Sender, (ProjectStartedEventArgs)EventArgs);
1001 else if (EventArgs is TargetStartedEventArgs)
1002 ConsoleLogger.TargetStartedHandler (Sender, (TargetStartedEventArgs)EventArgs);
1003 else if (EventArgs is TaskStartedEventArgs)
1004 ConsoleLogger.TaskStartedHandler (Sender, (TaskStartedEventArgs)EventArgs);
1005 else if (!(EventArgs is BuildStartedEventArgs))
1006 throw new InvalidOperationException ("Unexpected event on the stack, type: " + EventArgs.GetType ());
1008 StartHandlerHasExecuted = true;
1011 public void ExecuteFinishedHandler (BuildStatusEventArgs finished_args)
1013 if (!StartHandlerHasExecuted)
1016 if (EventArgs is ProjectStartedEventArgs)
1017 ConsoleLogger.ProjectFinishedHandler (Sender, finished_args as ProjectFinishedEventArgs);
1018 else if (EventArgs is TargetStartedEventArgs)
1019 ConsoleLogger.TargetFinishedHandler (Sender, finished_args as TargetFinishedEventArgs);
1020 else if (EventArgs is TaskStartedEventArgs)
1021 ConsoleLogger.TaskFinishedHandler (Sender, finished_args as TaskFinishedEventArgs);
1022 else if (!(EventArgs is BuildStartedEventArgs))
1023 throw new InvalidOperationException ("Unexpected event on the stack, type: " + EventArgs.GetType ());
1028 public TimeSpan Time;
1029 public int NumberOfCalls;