Normalize line endings.
[mono.git] / mcs / class / Microsoft.Build.Engine / Microsoft.Build.BuildEngine / ConsoleLogger.cs
1 //
2 // ConsoleLogger.cs: Outputs to the console
3 //
4 // Author:
5 //   Marek Sieradzki (marek.sieradzki@gmail.com)
6 // 
7 // (C) 2005 Marek Sieradzki
8 //
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:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
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.
27
28 #if NET_2_0
29
30 using System;
31 using System.Runtime.InteropServices;
32 using System.Collections;
33 using System.Collections.Generic;
34 using System.IO;
35 using System.Linq;
36 using System.Security;
37 using System.Text;
38 using Microsoft.Build.Framework;
39
40 namespace Microsoft.Build.BuildEngine {
41         public class ConsoleLogger : ILogger {
42         
43                 string          parameters;
44                 int             indent;
45                 LoggerVerbosity verbosity;
46                 WriteHandler    writeHandler;
47                 int             errorCount;
48                 int             warningCount;
49                 DateTime                buildStart;
50                 bool            performanceSummary;
51                 bool            showSummary;
52                 bool            skipProjectStartedText;
53                 List<string> errors, warnings;
54                 bool            projectFailed;
55                 ConsoleColor errorColor, warningColor, eventColor, messageColor, highMessageColor;
56                 ColorSetter colorSet;
57                 ColorResetter colorReset;
58                 bool no_message_color, use_colors;
59                 bool noItemAndPropertyList;
60
61                 List<BuildStatusEventArgs> events;
62                 Dictionary<string, List<string>> errorsTable;
63                 Dictionary<string, List<string>> warningsTable;
64                 SortedDictionary<string, PerfInfo> targetPerfTable, tasksPerfTable;
65                 string current_events_string;
66                 
67                 public ConsoleLogger ()
68                         : this (LoggerVerbosity.Normal, null, null, null)
69                 {
70                 }
71
72                 public ConsoleLogger (LoggerVerbosity verbosity)
73                         : this (LoggerVerbosity.Normal, null, null, null)
74                 {
75                 }
76                 
77                 public ConsoleLogger (LoggerVerbosity verbosity,
78                                       WriteHandler write,
79                                       ColorSetter colorSet,
80                                       ColorResetter colorReset)
81                 {
82                         this.verbosity = verbosity;
83                         this.indent = 0;
84                         this.errorCount = 0;
85                         this.warningCount = 0;
86                         if (write == null)
87                                 this.writeHandler += new WriteHandler (WriteHandlerFunction);
88                         else
89                                 this.writeHandler += write;
90                         this.performanceSummary = false;
91                         this.showSummary = true;
92                         this.skipProjectStartedText = false;
93                         errors = new List<string> ();
94                         warnings = new List<string> ();
95                         this.colorSet = colorSet;
96                         this.colorReset = colorReset;
97
98                         events = new List<BuildStatusEventArgs> ();
99                         errorsTable = new Dictionary<string, List<string>> ();
100                         warningsTable = new Dictionary<string, List<string>> ();
101                         targetPerfTable = new SortedDictionary<string, PerfInfo> ();
102                         tasksPerfTable = new SortedDictionary<string, PerfInfo> ();
103
104                         //defaults
105                         errorColor = ConsoleColor.DarkRed;
106                         warningColor = ConsoleColor.DarkYellow;
107                         eventColor = ConsoleColor.DarkCyan;
108                         messageColor = ConsoleColor.DarkGray;
109                         highMessageColor = ConsoleColor.White;
110
111                         // if message color is not set via the env var,
112                         // then don't use any color for it.
113                         no_message_color = true;
114
115                         use_colors = false;
116                         if (colorSet == null || colorReset == null)
117                                 return;
118
119                         // color support
120                         string config = Environment.GetEnvironmentVariable ("XBUILD_COLORS");
121                         if (config == null) {
122                                 use_colors = true;
123                                 return;
124                         }
125
126                         if (config == "disable")
127                                 return;
128
129                         use_colors = true;
130                         string [] pairs = config.Split (new char[] {','}, StringSplitOptions.RemoveEmptyEntries);
131                         foreach (string pair in pairs) {
132                                 string [] parts = pair.Split (new char[] {'='}, StringSplitOptions.RemoveEmptyEntries);
133                                 if (parts.Length != 2)
134                                         continue;
135
136                                 if (parts [0] == "errors")
137                                         TryParseConsoleColor (parts [1], ref errorColor);
138                                 else if (parts [0] == "warnings")
139                                         TryParseConsoleColor (parts [1], ref warningColor);
140                                 else if (parts [0] == "events")
141                                         TryParseConsoleColor (parts [1], ref eventColor);
142                                 else if (parts [0] == "messages") {
143                                         if (TryParseConsoleColor (parts [1], ref messageColor)) {
144                                                 highMessageColor = GetBrightColorFor (messageColor);
145                                                 no_message_color = false;
146                                         }
147                                 }
148                         }
149                 }
150
151                 bool TryParseConsoleColor (string color_str, ref ConsoleColor color)
152                 {
153                         switch (color_str.ToLower ()) {
154                         case "black": color = ConsoleColor.Black; break;
155
156                         case "blue": color = ConsoleColor.DarkBlue; break;
157                         case "green": color = ConsoleColor.DarkGreen; break;
158                         case "cyan": color = ConsoleColor.DarkCyan; break;
159                         case "red": color = ConsoleColor.DarkRed; break;
160                         case "magenta": color = ConsoleColor.DarkMagenta; break;
161                         case "yellow": color = ConsoleColor.DarkYellow; break;
162                         case "grey": color = ConsoleColor.DarkGray; break;
163
164                         case "brightgrey": color = ConsoleColor.Gray; break;
165                         case "brightblue": color = ConsoleColor.Blue; break;
166                         case "brightgreen": color = ConsoleColor.Green; break;
167                         case "brightcyan": color = ConsoleColor.Cyan; break;
168                         case "brightred": color = ConsoleColor.Red; break;
169                         case "brightmagenta": color = ConsoleColor.Magenta; break;
170                         case "brightyellow": color = ConsoleColor.Yellow; break;
171
172                         case "white":
173                         case "brightwhite": color = ConsoleColor.White; break;
174                         default: return false;
175                         }
176
177                         return true;
178                 }
179
180                 ConsoleColor GetBrightColorFor (ConsoleColor color)
181                 {
182                         switch (color) {
183                         case ConsoleColor.DarkBlue: return ConsoleColor.Blue;
184                         case ConsoleColor.DarkGreen: return ConsoleColor.Green;
185                         case ConsoleColor.DarkCyan: return ConsoleColor.Cyan;
186                         case ConsoleColor.DarkRed: return ConsoleColor.Red;
187                         case ConsoleColor.DarkMagenta: return ConsoleColor.Magenta;
188                         case ConsoleColor.DarkYellow: return ConsoleColor.Yellow;
189                         case ConsoleColor.DarkGray: return ConsoleColor.Gray;
190                         case ConsoleColor.Gray: return ConsoleColor.White;
191
192                         default: return color;
193                         }
194                 }
195                 
196                 public void ApplyParameter (string parameterName,
197                                             string parameterValue)
198                 {
199                         // FIXME: what we should do here? in msbuild it isn't
200                         // changing "parameters" property
201                 }
202
203                 public virtual void Initialize (IEventSource eventSource)
204                 {
205                         eventSource.BuildStarted +=  new BuildStartedEventHandler (BuildStartedHandler);
206                         eventSource.BuildFinished += new BuildFinishedEventHandler (BuildFinishedHandler);
207                         eventSource.ProjectStarted += new ProjectStartedEventHandler (ProjectStartedHandler);
208                         eventSource.ProjectFinished += new ProjectFinishedEventHandler (ProjectFinishedHandler);
209                         eventSource.TargetStarted += new TargetStartedEventHandler (TargetStartedHandler);
210                         eventSource.TargetFinished += new TargetFinishedEventHandler (TargetFinishedHandler);
211                         eventSource.TaskStarted += new TaskStartedEventHandler (TaskStartedHandler);
212                         eventSource.TaskFinished += new TaskFinishedEventHandler (TaskFinishedHandler);
213                         eventSource.MessageRaised += new BuildMessageEventHandler (MessageHandler);
214                         eventSource.WarningRaised += new BuildWarningEventHandler (WarningHandler);
215                         eventSource.ErrorRaised += new BuildErrorEventHandler (ErrorHandler);
216                 }
217                 
218                 public void BuildStartedHandler (object sender, BuildStartedEventArgs args)
219                 {
220                         if (IsVerbosityGreaterOrEqual (LoggerVerbosity.Normal)) {
221                                 WriteLine (String.Empty);
222                                 WriteLine (String.Format ("Build started {0}.", args.Timestamp));
223                                 WriteLine ("__________________________________________________");
224                         }
225                         buildStart = args.Timestamp;
226
227                         PushEvent (args);
228                 }
229                 
230                 public void BuildFinishedHandler (object sender, BuildFinishedEventArgs args)
231                 {
232                         if (!IsVerbosityGreaterOrEqual (LoggerVerbosity.Normal)) {
233                                 PopEvent ();
234                                 return;
235                         }
236
237                         TimeSpan timeElapsed = args.Timestamp - buildStart;
238                         if (performanceSummary || verbosity == LoggerVerbosity.Diagnostic)
239                                 DumpPerformanceSummary ();
240
241                         if (args.Succeeded == true && !projectFailed) {
242                                 WriteLine ("Build succeeded.");
243                         } else {
244                                 WriteLine ("Build FAILED.");
245                         }
246                         if (warnings.Count > 0) {
247                                 WriteLine (Environment.NewLine + "Warnings:");
248                                 SetColor (warningColor);
249
250                                 WriteLine (String.Empty);
251                                 foreach (KeyValuePair<string, List<string>> pair in warningsTable) {
252                                         if (!String.IsNullOrEmpty (pair.Key))
253                                                 WriteLine (pair.Key);
254
255                                         string indent_str = String.IsNullOrEmpty (pair.Key) ? String.Empty : "\t";
256                                         foreach (string msg in pair.Value)
257                                                 WriteLine (String.Format ("{0}{1}", indent_str, msg));
258
259                                         WriteLine (String.Empty);
260                                 }
261
262                                 ResetColor ();
263                         }
264
265                         if (errors.Count > 0) {
266                                 WriteLine ("Errors:");
267                                 SetColor (errorColor);
268
269                                 WriteLine (String.Empty);
270                                 foreach (KeyValuePair<string, List<string>> pair in errorsTable) {
271                                         if (!String.IsNullOrEmpty (pair.Key))
272                                                 WriteLine (pair.Key);
273
274                                         string indent_str = String.IsNullOrEmpty (pair.Key) ? String.Empty : "\t";
275                                         foreach (string msg in pair.Value)
276                                                 WriteLine (String.Format ("{0}{1}", indent_str, msg));
277
278                                         WriteLine (String.Empty);
279                                 }
280                                 ResetColor ();
281                         }
282
283                         if (showSummary == true){
284                                 WriteLine (String.Format ("\t {0} Warning(s)", warningCount));
285                                 WriteLine (String.Format ("\t {0} Error(s)", errorCount));
286                                 WriteLine (String.Empty);
287                                 WriteLine (String.Format ("Time Elapsed {0}", timeElapsed));
288                         } 
289                         PopEvent ();
290                 }
291
292                 public void ProjectStartedHandler (object sender, ProjectStartedEventArgs args)
293                 {
294                         if (IsVerbosityGreaterOrEqual (LoggerVerbosity.Normal)) {
295                                 SetColor (eventColor);
296                                 WriteLine (String.Format ("Project \"{0}\" ({1} target(s)):", args.ProjectFile,
297                                                         String.IsNullOrEmpty (args.TargetNames) ? "default" : args.TargetNames));
298                                 ResetColor ();
299                                 WriteLine (String.Empty);
300                                 DumpProperties (args.Properties);
301                                 DumpItems (args.Items);
302                         }
303                         PushEvent (args);
304                 }
305                 
306                 public void ProjectFinishedHandler (object sender, ProjectFinishedEventArgs args)
307                 {
308                         if (IsVerbosityGreaterOrEqual (LoggerVerbosity.Normal)) {
309                                 if (indent == 1)
310                                         indent --;
311                                 SetColor (eventColor);
312                                 WriteLine (String.Format ("Done building project \"{0}\".{1}", args.ProjectFile,
313                                                         args.Succeeded ? String.Empty : "-- FAILED"));
314                                 ResetColor ();
315                                 WriteLine (String.Empty);
316                         }
317                         if (!projectFailed)
318                                 // no project has failed yet, so update the flag
319                                 projectFailed = !args.Succeeded;
320
321                         PopEvent ();
322                 }
323                 
324                 public void TargetStartedHandler (object sender, TargetStartedEventArgs args)
325                 {
326                         if (IsVerbosityGreaterOrEqual (LoggerVerbosity.Normal)) {
327                                 indent++;
328                                 SetColor (eventColor);
329                                 WriteLine (String.Format ("Target {0}:",args.TargetName));
330                                 ResetColor ();
331                         }
332                         PushEvent (args);
333                 }
334                 
335                 public void TargetFinishedHandler (object sender, TargetFinishedEventArgs args)
336                 {
337                         if (IsVerbosityGreaterOrEqual (LoggerVerbosity.Detailed) ||
338                                         (!args.Succeeded && IsVerbosityGreaterOrEqual (LoggerVerbosity.Normal))) {
339                                 SetColor (eventColor);
340                                 WriteLine (String.Format ("Done building target \"{0}\" in project \"{1}\".{2}",
341                                         args.TargetName, args.ProjectFile,
342                                         args.Succeeded ? String.Empty : "-- FAILED"));
343                                 ResetColor ();
344                                 WriteLine (String.Empty);
345                         }
346                         indent--;
347
348                         PopEvent ();
349                 }
350                 
351                 public void TaskStartedHandler (object sender, TaskStartedEventArgs args)
352                 {
353                         if (this.verbosity == LoggerVerbosity.Detailed) {
354                                 SetColor (eventColor);
355                                 WriteLine (String.Format ("Task \"{0}\"",args.TaskName));
356                                 ResetColor ();
357                         }
358                         indent++;
359                         PushEvent (args);
360                 }
361                 
362                 public void TaskFinishedHandler (object sender, TaskFinishedEventArgs args)
363                 {
364                         indent--;
365                         if (IsVerbosityGreaterOrEqual (LoggerVerbosity.Detailed) ||
366                                         (!args.Succeeded && IsVerbosityGreaterOrEqual (LoggerVerbosity.Normal))) {
367                                 SetColor (eventColor);
368                                 if (args.Succeeded)
369                                         WriteLine (String.Format ("Done executing task \"{0}\"", args.TaskName));
370                                 else
371                                         WriteLine (String.Format ("Task \"{0}\" execution -- FAILED", args.TaskName));
372                                 ResetColor ();
373                         }
374                         PopEvent ();
375                 }
376                 
377                 public void MessageHandler (object sender, BuildMessageEventArgs args)
378                 {
379                         if (IsMessageOk (args)) {
380                                 if (no_message_color) {
381                                         WriteLine (args.Message);
382                                 } else {
383                                         SetColor (args.Importance == MessageImportance.High ? highMessageColor : messageColor);
384                                         WriteLine (args.Message);
385                                         ResetColor ();
386                                 }
387                         }
388                 }
389                 
390                 public void WarningHandler (object sender, BuildWarningEventArgs args)
391                 {
392                         string msg = FormatWarningEvent (args);
393                         if (IsVerbosityGreaterOrEqual (LoggerVerbosity.Quiet)) {
394                                 SetColor (warningColor);
395                                 WriteLineWithoutIndent (msg);
396                                 ResetColor ();
397                         }
398                         warnings.Add (msg);
399
400                         List<string> list = null;
401                         if (!warningsTable.TryGetValue (EventsAsString, out list))
402                                 warningsTable [EventsAsString] = list = new List<string> ();
403                         list.Add (msg);
404
405                         warningCount++;
406                 }
407                 
408                 public void ErrorHandler (object sender, BuildErrorEventArgs args)
409                 {
410                         string msg = FormatErrorEvent (args);
411                         if (IsVerbosityGreaterOrEqual (LoggerVerbosity.Quiet)) {
412                                 SetColor (errorColor);
413                                 WriteLineWithoutIndent (msg);
414                                 ResetColor ();
415                         }
416                         errors.Add (msg);
417
418                         List<string> list = null;
419                         if (!errorsTable.TryGetValue (EventsAsString, out list))
420                                 errorsTable [EventsAsString] = list = new List<string> ();
421                         list.Add (msg);
422                         errorCount++;
423                 }
424                 
425                 [MonoTODO]
426                 public void CustomEventHandler (object sender, CustomBuildEventArgs args)
427                 {
428                 }
429
430                 private void WriteLine (string message)
431                 {
432                         if (indent > 0) {
433                                 StringBuilder sb = new StringBuilder ();
434                                 for (int i = 0; i < indent; i++)
435                                         sb.Append ('\t');
436                                 sb.Append (message);
437
438                                 writeHandler (sb.ToString ());
439                         } else {
440                                 writeHandler (message);
441                         }
442                 }
443
444                 void PushEvent (BuildStatusEventArgs args)
445                 {
446                         events.Add (args);
447                         current_events_string = null;
448                 }
449
450                 void PopEvent ()
451                 {
452                         if (performanceSummary || verbosity == LoggerVerbosity.Diagnostic) {
453                                 var args = events [events.Count - 1];
454                                 TargetStartedEventArgs tgt_args = args as TargetStartedEventArgs;
455                                 if (tgt_args != null) {
456                                         AddPerfInfo (tgt_args.TargetName, args.Timestamp, targetPerfTable);
457                                 } else {
458                                         TaskStartedEventArgs tsk_args = args as TaskStartedEventArgs;
459                                         if (tsk_args != null)
460                                                 AddPerfInfo (tsk_args.TaskName, args.Timestamp, tasksPerfTable);
461                                 }
462                         }
463
464                         events.RemoveAt (events.Count - 1);
465                         current_events_string = null;
466                 }
467
468                 string EventsToString ()
469                 {
470                         StringBuilder sb = new StringBuilder ();
471
472                         string last_imported_target_file = String.Empty;
473                         for (int i = 0; i < events.Count; i ++) {
474                                 var args = events [i];
475                                 ProjectStartedEventArgs pargs = args as ProjectStartedEventArgs;
476                                 if (pargs != null) {
477                                         sb.AppendFormat ("{0} ({1}) ->\n", pargs.ProjectFile,
478                                                         String.IsNullOrEmpty (pargs.TargetNames) ?
479                                                                 "default targets" :
480                                                                 pargs.TargetNames);
481                                         last_imported_target_file = String.Empty;
482                                         continue;
483                                 }
484
485                                 TargetStartedEventArgs targs = args as TargetStartedEventArgs;
486                                 if (targs != null) {
487                                         if (targs.TargetFile != targs.ProjectFile && targs.TargetFile != last_imported_target_file)
488                                                 // target from an imported file,
489                                                 // and it hasn't been mentioned as yet
490                                                 sb.AppendFormat ("{0} ", targs.TargetFile);
491
492                                         last_imported_target_file = targs.TargetFile;
493                                         sb.AppendFormat ("({0} target) ->\n", targs.TargetName);
494                                 }
495                         }
496
497                         return sb.ToString ();
498                 }
499
500                 void AddPerfInfo (string name, DateTime start, IDictionary<string, PerfInfo> perf_table)
501                 {
502                         PerfInfo pi;
503                         if (!perf_table.TryGetValue (name, out pi)) {
504                                 pi = new PerfInfo ();
505                                 perf_table [name] = pi;
506                         }
507
508                         pi.Time += DateTime.Now - start;
509                         pi.NumberOfCalls ++;
510                 }
511
512                 void DumpPerformanceSummary ()
513                 {
514                         SetColor (eventColor);
515                         WriteLine ("Target perfomance summary:");
516                         ResetColor ();
517
518                         foreach (var pi in targetPerfTable.OrderBy (pair => pair.Value.Time))
519                                 WriteLine (String.Format ("{0,10:0.000} ms  {1,-50}  {2,5} calls", pi.Value.Time.TotalMilliseconds, pi.Key, pi.Value.NumberOfCalls));
520
521                         WriteLine (String.Empty);
522
523                         SetColor (eventColor);
524                         WriteLine ("Tasks perfomance summary:");
525                         ResetColor ();
526
527                         foreach (var pi in tasksPerfTable.OrderBy (pair => pair.Value.Time))
528                                 WriteLine (String.Format ("{0,10:0.000} ms  {1,-50}  {2,5} calls", pi.Value.Time.TotalMilliseconds, pi.Key, pi.Value.NumberOfCalls));
529
530                         WriteLine (String.Empty);
531                 }
532                 
533                 private void WriteLineWithoutIndent (string message)
534                 {
535                         writeHandler (message);
536                 }
537                 
538                 private void WriteHandlerFunction (string message)
539                 {
540                         Console.WriteLine (message);
541                 }
542
543                 void SetColor (ConsoleColor color)
544                 {
545                         if (use_colors)
546                                 colorSet (color);
547                 }
548
549                 void ResetColor ()
550                 {
551                         if (use_colors)
552                                 colorReset ();
553                 }
554                 
555                 private void ParseParameters ()
556                 {
557                         string[] splittedParameters = parameters.Split (';');
558                         foreach (string s in splittedParameters ) {
559                                 switch (s) {
560                                 case "PerformanceSummary":
561                                         this.performanceSummary = true;
562                                         break;
563                                 case "NoSummary":
564                                         this.showSummary = false;
565                                         break;
566                                 case "NoItemAndPropertyList":
567                                         this.noItemAndPropertyList = true;
568                                         break;
569                                 default:
570                                         throw new ArgumentException ("Invalid parameter : " + s);
571                                 }
572                         }
573                 }
574                 
575                 public virtual void Shutdown ()
576                 {
577                 }
578
579                 static bool InEmacs = Environment.GetEnvironmentVariable ("EMACS") == "t";
580                 
581                 private string FormatErrorEvent (BuildErrorEventArgs args)
582                 {
583                         // For some reason we get an 1-char empty string as Subcategory somtimes.
584                         string subprefix = args.Subcategory == null || args.Subcategory == "" || args.Subcategory == " " ? "" : " ";
585                         string subcat = subprefix == "" ? "" : args.Subcategory;
586                                 
587                         if (args.LineNumber != 0){
588                                 if (args.ColumnNumber != 0 && !InEmacs) 
589                                         return String.Format ("{0}({1},{2}): {3}{4}error {5}: {6}",
590                                                               args.File, args.LineNumber, args.ColumnNumber,
591                                                               subprefix, subcat, args.Code, args.Message);
592
593                                 return String.Format ("{0}({1}): {2}{3}error {4}: {5}",
594                                                       args.File, args.LineNumber,
595                                                       subprefix, subcat, args.Code, args.Message);
596                         } else {
597                                 return String.Format ("{0}: {1}{2}error {3}: {4}", args.File, subprefix, subcat, args.Code,
598                                         args.Message);
599                         }
600                 }
601
602                 private string FormatWarningEvent (BuildWarningEventArgs args)
603                 {
604                         // For some reason we get an 1-char empty string as Subcategory somtimes.
605                         string subprefix = args.Subcategory == null || args.Subcategory == "" || args.Subcategory == " " ? "" : " ";
606                         string subcat = subprefix == "" ? "" : args.Subcategory;
607
608                         // FIXME: show more complicated args
609                         if (args.LineNumber != 0){
610
611                                 if (args.ColumnNumber != 0 && !InEmacs) {
612                                         return String.Format ("{0}({1},{2}): {3}{4}warning {5}: {6}",
613                                                               args.File, args.LineNumber, args.ColumnNumber,
614                                                               subprefix, subcat, args.Code, args.Message);
615                                 }
616                                 return String.Format ("{0}({1}): {2}{3}warning {4}: {5}",
617                                                       args.File, args.LineNumber,
618                                                       subprefix, subcat, args.Code, args.Message);
619                         } else {
620                                 return String.Format ("{0}: {1} warning {2}: {3}", args.File, args.Subcategory, args.Code,
621                                         args.Message);
622                         }
623                 }
624                 
625                 private bool IsMessageOk (BuildMessageEventArgs bsea)
626                 {
627                         if (bsea.Importance == MessageImportance.High && IsVerbosityGreaterOrEqual (LoggerVerbosity.Minimal)) {
628                                 return true;
629                         } else if (bsea.Importance == MessageImportance.Normal && IsVerbosityGreaterOrEqual (LoggerVerbosity.Normal)) {
630                                 return true;
631                         } else if (bsea.Importance == MessageImportance.Low && IsVerbosityGreaterOrEqual (LoggerVerbosity.Detailed)) {
632                                 return true;
633                         } else
634                                 return false;
635                 }
636                 
637                 private bool IsVerbosityGreaterOrEqual (LoggerVerbosity v)
638                 {
639                                 if (v == LoggerVerbosity.Diagnostic) {
640                                         return LoggerVerbosity.Diagnostic <= verbosity;
641                                 } else if (v == LoggerVerbosity.Detailed) {
642                                         return LoggerVerbosity.Detailed <= verbosity;
643                                 } else if (v == LoggerVerbosity.Normal) {
644                                         return LoggerVerbosity.Normal <= verbosity;
645                                 } else if (v == LoggerVerbosity.Minimal) {
646                                         return LoggerVerbosity.Minimal <= verbosity;
647                                 } else if (v == LoggerVerbosity.Quiet) {
648                                         return true;
649                                 } else
650                                         return false;
651                 }
652
653                 void DumpProperties (IEnumerable properties)
654                 {
655                         if (noItemAndPropertyList || !IsVerbosityGreaterOrEqual (LoggerVerbosity.Diagnostic))
656                                 return;
657
658                         SetColor (eventColor);
659                         WriteLine ("\n");
660                         WriteLine ("Initial Properties:");
661                         ResetColor ();
662
663                         if (properties == null)
664                                 return;
665
666                         var dict = new SortedDictionary<string, string> ();
667                         foreach (DictionaryEntry de in properties)
668                                 dict [(string)de.Key] = (string)de.Value;
669
670                         foreach (KeyValuePair<string, string> pair in dict)
671                                 WriteLine (String.Format ("{0} = {1}", pair.Key, pair.Value));
672                         WriteLine ("\n");
673                 }
674
675                 void DumpItems (IEnumerable items)
676                 {
677                         if (noItemAndPropertyList || !IsVerbosityGreaterOrEqual (LoggerVerbosity.Diagnostic) || items == null)
678                                 return;
679
680                         SetColor (eventColor);
681                         WriteLine ("\n");
682                         WriteLine ("Initial Items:");
683                         ResetColor ();
684                         if (items == null)
685                                 return;
686
687                         var items_table = new SortedDictionary<string, List<ITaskItem>> ();
688                         foreach (DictionaryEntry de in items) {
689                                 string key = (string)de.Key;
690                                 if (!items_table.ContainsKey (key))
691                                         items_table [key] = new List<ITaskItem> ();
692
693                                 items_table [key].Add ((ITaskItem) de.Value);
694                         }
695
696                         foreach (string name in items_table.Keys) {
697                                 WriteLine (name);
698                                 indent ++;
699                                 foreach (ITaskItem item in items_table [name])
700                                         WriteLine (item.ItemSpec);
701                                 indent--;
702                         }
703                         WriteLine ("\n");
704                 }
705
706                 public string Parameters {
707                         get {
708                                 return parameters;
709                         }
710                         set {
711                                 if (value == null)
712                                         throw new ArgumentNullException ();
713                                 parameters = value;
714                                 if (parameters != String.Empty)
715                                         ParseParameters ();
716                         }
717                 }
718
719                 string EventsAsString {
720                         get {
721                                 if (current_events_string == null)
722                                         current_events_string = EventsToString ();
723                                 return current_events_string;
724                         }
725                 }
726                 
727                 public bool ShowSummary {
728                         get { return showSummary; }
729                         set { showSummary = value; }
730                 }
731                 
732                 public bool SkipProjectStartedText {
733                         get { return skipProjectStartedText; }
734                         set { skipProjectStartedText = value; }
735                 }
736
737                 public LoggerVerbosity Verbosity {
738                         get { return verbosity; }
739                         set { verbosity = value; }
740                 }
741
742                 protected WriteHandler WriteHandler {
743                         get { return writeHandler; }
744                         set { writeHandler = value; }
745                 }
746         }
747
748         class PerfInfo {
749                 public TimeSpan Time;
750                 public int NumberOfCalls;
751         }
752 }
753
754 #endif