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