[xbuild] TaskLoggingHelper: Implement support for correctly using task resources
[mono.git] / mcs / class / Microsoft.Build.Utilities / Microsoft.Build.Utilities / TaskLoggingHelper.cs
1 //
2 // TaskLoggingHelper.cs: Wrapper aroudn IBuildEngine.
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
29 using System;
30 using System.IO;
31 using System.Resources;
32 using System.Text;
33 using Microsoft.Build.Framework;
34
35 namespace Microsoft.Build.Utilities
36 {
37         public class TaskLoggingHelper : MarshalByRefObject
38         {
39                 IBuildEngine    buildEngine;
40                 bool            hasLoggedErrors;
41                 string          helpKeywordPrefix;
42                 string          taskName;
43                 ResourceManager taskResources;
44                 ITask           taskInstance;
45         
46                 public TaskLoggingHelper (ITask taskInstance)
47                 {
48                         if (taskInstance == null)
49                                 throw new ArgumentNullException ("taskInstance");
50
51                         this.taskInstance = taskInstance;
52                         taskName = null;
53                 }
54
55                 [MonoTODO]
56                 public string ExtractMessageCode (string message,
57                                                   out string messageWithoutCodePrefix)
58                 {
59                         if (message == null)
60                                 throw new ArgumentNullException ("message");
61                                 
62                         messageWithoutCodePrefix = String.Empty;
63                         return String.Empty;
64                 }
65
66                 [MonoTODO]
67                 public virtual string FormatResourceString (string resourceName,
68                                                             params object[] args)
69                 {
70                         if (resourceName == null)
71                                 throw new ArgumentNullException ("resourceName");
72
73                         if (taskResources == null)
74                                 throw new InvalidOperationException ("Task did not register any task resources");
75
76                         string resourceString = taskResources.GetString (resourceName);
77                         if (resourceString == null)
78                                 throw new ArgumentException ($"No resource string found for resource named {resourceName}");
79
80                         return FormatString (resourceString, args);
81                 }
82
83                 [MonoTODO]
84                 public virtual string FormatString (string unformatted,
85                                                    params object[] args)
86                 {
87                         if (unformatted == null)
88                                 throw new ArgumentNullException ("unformatted");
89                 
90                         if (args == null || args.Length == 0)
91                                 return unformatted;
92                         else
93                                 return String.Format (unformatted, args);
94                 }
95                 
96                 [MonoTODO]
97                 public void LogCommandLine (string commandLine)
98                 {
99                 }
100                 
101                 [MonoTODO]
102                 public void LogCommandLine (MessageImportance importance,
103                                             string commandLine)
104                 {
105                 }
106
107                 public void LogError (string message,
108                                      params object[] messageArgs)
109                 {
110                         if (message == null)
111                                 throw new ArgumentNullException ("message");
112
113                         ThrowInvalidOperationIf (BuildEngine == null, "Task is attempting to log before it was initialized");
114                                 
115                         BuildErrorEventArgs beea = new BuildErrorEventArgs (
116                                 null, null, BuildEngine.ProjectFileOfTaskNode, 0, 0, 0, 0, FormatString (message, messageArgs),
117                                 helpKeywordPrefix, null);
118                         BuildEngine.LogErrorEvent (beea);
119                         hasLoggedErrors = true;
120                 }
121
122                 public void LogError (string subcategory, string errorCode,
123                                       string helpKeyword, string file,
124                                       int lineNumber, int columnNumber,
125                                       int endLineNumber, int endColumnNumber,
126                                       string message,
127                                       params object[] messageArgs)
128                 {
129                         if (message == null)
130                                 throw new ArgumentNullException ("message");
131                         
132                         ThrowInvalidOperationIf (BuildEngine == null, "Task is attempting to log before it was initialized");
133
134                         BuildErrorEventArgs beea = new BuildErrorEventArgs (
135                                 subcategory, errorCode, file, lineNumber,
136                                 columnNumber, endLineNumber, endColumnNumber,
137                                 FormatString (message, messageArgs), helpKeyword /*it's helpKeyword*/,
138                                 null /*it's senderName*/);
139                         BuildEngine.LogErrorEvent (beea);
140                         hasLoggedErrors = true;
141                 }
142
143                 public void LogErrorFromException (Exception exception)
144                 {
145                         LogErrorFromException (exception, true);
146                 }
147
148                 public void LogErrorFromException (Exception exception,
149                                                    bool showStackTrace)
150                 {
151                         LogErrorFromException (exception, showStackTrace, true, String.Empty);
152                 }
153
154                 [MonoTODO ("Arguments @showDetail and @file are not honored")]
155                 public void LogErrorFromException (Exception exception,
156                                                    bool showStackTrace, bool showDetail, string file)
157                 {
158                         if (exception == null)
159                                 throw new ArgumentNullException ("exception");
160                 
161                         ThrowInvalidOperationIf (BuildEngine == null, "Task is attempting to log before it was initialized");
162
163                         StringBuilder sb = new StringBuilder ();
164                         sb.Append (exception.Message);
165                         if (showStackTrace == true)
166                                 sb.Append (exception.StackTrace);
167                         BuildErrorEventArgs beea = new BuildErrorEventArgs (
168                                 null, null, BuildEngine.ProjectFileOfTaskNode, 0, 0, 0, 0, sb.ToString (),
169                                 exception.HelpLink, exception.Source);
170                         BuildEngine.LogErrorEvent (beea);
171                         hasLoggedErrors = true;
172                 }
173
174                 public void LogErrorFromResources (string messageResourceName,
175                                                    params object[] messageArgs)
176                 {
177                         LogErrorFromResources (null, null, null, null, 0, 0, 0,
178                                 0, messageResourceName, messageArgs);
179                 }
180
181                 public void LogErrorFromResources (string subcategoryResourceName,
182                                                    string errorCode,
183                                                    string helpKeyword,
184                                                    string file, int lineNumber,
185                                                    int columnNumber,
186                                                    int endLineNumber,
187                                                    int endColumnNumber,
188                                                    string messageResourceName,
189                                                    params object[] messageArgs)
190                 {
191                         if (messageResourceName == null)
192                                 throw new ArgumentNullException ("messageResourceName");
193
194                         ThrowInvalidOperationIf (BuildEngine == null, "Task is attempting to log before it was initialized");
195
196                         string subcategory = null;
197                         if (!String.IsNullOrEmpty (subcategoryResourceName))
198                                 subcategory = taskResources.GetString (subcategoryResourceName);
199
200                         BuildErrorEventArgs beea = new BuildErrorEventArgs (
201                                 subcategory,
202                                 errorCode, file, lineNumber, columnNumber,
203                                 endLineNumber, endColumnNumber,
204                                 FormatResourceString (messageResourceName, messageArgs),
205                                 helpKeyword, null );
206                         BuildEngine.LogErrorEvent (beea);
207                         hasLoggedErrors = true;
208                 }
209
210                 public void LogErrorWithCodeFromResources (string messageResourceName,
211                                                           params object[] messageArgs)
212                 {
213                         // FIXME: there should be something different than normal
214                         // LogErrorFromResources
215                         LogErrorFromResources (messageResourceName, messageArgs);
216                 }
217
218                 public void LogErrorWithCodeFromResources (string subcategoryResourceName,
219                                                           string file,
220                                                           int lineNumber,
221                                                           int columnNumber,
222                                                           int endLineNumber,
223                                                           int endColumnNumber,
224                                                           string messageResourceName,
225                                                           params object[] messageArgs)
226                 {
227                         // FIXME: there should be something different than normal
228                         // LogErrorFromResources
229                         LogErrorFromResources (subcategoryResourceName, file,
230                                 lineNumber, columnNumber, endLineNumber,
231                                 endColumnNumber, messageResourceName,
232                                 messageArgs);
233                 }
234
235                 public void LogMessage (string message,
236                                        params object[] messageArgs)
237                 {
238                         LogMessage (MessageImportance.Normal, message, messageArgs); 
239                 }
240
241                 public void LogMessage (MessageImportance importance,
242                                         string message,
243                                         params object[] messageArgs)
244                 {
245                         if (message == null)
246                                 throw new ArgumentNullException ("message");
247                 
248                         LogMessageFromText (FormatString (message, messageArgs), importance);
249                 }
250
251                 public void LogMessageFromResources (string messageResourceName,
252                                                      params object[] messageArgs)
253                 {
254                         LogMessageFromResources (MessageImportance.Normal, messageResourceName, messageArgs);
255                 }
256
257                 public void LogMessageFromResources (MessageImportance importance,
258                                                      string messageResourceName,
259                                                      params object[] messageArgs)
260                 {
261                         if (messageResourceName == null)
262                                 throw new ArgumentNullException ("messageResourceName");
263
264                         LogMessage (importance, FormatResourceString (messageResourceName, messageArgs));
265                 }
266
267                 public bool LogMessagesFromFile (string fileName)
268                 {
269                         return LogMessagesFromFile (fileName, MessageImportance.Normal);
270                 }
271
272                 public bool LogMessagesFromFile (string fileName,
273                                                  MessageImportance messageImportance)
274                 {
275                         try {
276                                 StreamReader sr = new StreamReader (fileName);
277                                 LogMessage (messageImportance, sr.ReadToEnd (),
278                                         null);
279                                 sr.Close ();
280                                 return true;
281                         }
282                         catch (Exception) {
283                                 return false;
284                         }
285                 }
286
287                 public bool LogMessagesFromStream (TextReader stream,
288                                                    MessageImportance messageImportance)
289                 {
290                         try {
291                                 LogMessage (messageImportance, stream.ReadToEnd (), null);
292                                 return true;
293                         }
294                         catch (Exception) {
295                                 return false;
296                         }
297                         finally {
298                                 // FIXME: should it be done here?
299                                 stream.Close ();
300                         }
301                 }
302
303                 public bool LogMessageFromText (string lineOfText,
304                                                 MessageImportance messageImportance)
305                 {
306                         if (lineOfText == null)
307                                 throw new ArgumentNullException ("lineOfText");
308
309                         ThrowInvalidOperationIf (BuildEngine == null, "Task is attempting to log before it was initialized");
310
311                         BuildMessageEventArgs bmea = new BuildMessageEventArgs (
312                                 lineOfText, helpKeywordPrefix,
313                                 null, messageImportance);
314                         BuildEngine.LogMessageEvent (bmea);
315
316                         return true;
317                 }
318
319                 public void LogWarning (string message,
320                                        params object[] messageArgs)
321                 {
322                         ThrowInvalidOperationIf (BuildEngine == null, "Task is attempting to log before it was initialized");
323
324                         // FIXME: what about all the parameters?
325                         BuildWarningEventArgs bwea = new BuildWarningEventArgs (
326                                 null, null, BuildEngine.ProjectFileOfTaskNode, 0, 0, 0, 0, FormatString (message, messageArgs),
327                                 helpKeywordPrefix, null);
328                         BuildEngine.LogWarningEvent (bwea);
329                 }
330
331                 public void LogWarning (string subcategory, string warningCode,
332                                         string helpKeyword, string file,
333                                         int lineNumber, int columnNumber,
334                                         int endLineNumber, int endColumnNumber,
335                                         string message,
336                                         params object[] messageArgs)
337                 {
338                         ThrowInvalidOperationIf (BuildEngine == null, "Task is attempting to log before it was initialized");
339
340                         BuildWarningEventArgs bwea = new BuildWarningEventArgs (
341                                 subcategory, warningCode, file, lineNumber,
342                                 columnNumber, endLineNumber, endColumnNumber,
343                                 FormatString (message, messageArgs), helpKeyword, null);
344                         BuildEngine.LogWarningEvent (bwea);
345                 }
346
347                 public void LogWarningFromException (Exception exception)
348                 {
349                         LogWarningFromException (exception, false);
350                 }
351
352                 public void LogWarningFromException (Exception exception,
353                                                      bool showStackTrace)
354                 {
355                         StringBuilder sb = new StringBuilder ();
356                         sb.Append (exception.Message);
357                         if (showStackTrace)
358                                 sb.Append (exception.StackTrace);
359                         LogWarning (null, null, null, null, 0, 0, 0, 0,
360                                 sb.ToString (), null);
361                 }
362
363                 public void LogWarningFromResources (string messageResourceName,
364                                                      params object[] messageArgs)
365                 {
366                         if (messageResourceName == null)
367                                 throw new ArgumentNullException ("messageResourceName");
368
369                         LogWarningFromResources (null, null, null, null, 0, 0, 0, 0, messageResourceName, messageArgs);
370                 }
371
372                 public void LogWarningFromResources (string subcategoryResourceName,
373                                                      string warningCode,
374                                                      string helpKeyword,
375                                                      string file,
376                                                      int lineNumber,
377                                                      int columnNumber,
378                                                      int endLineNumber,
379                                                      int endColumnNumber,
380                                                      string messageResourceName,
381                                                      params object[] messageArgs)
382                 {
383                         if (messageResourceName == null)
384                                 throw new ArgumentNullException ("messageResourceName");
385
386                         string subcategory = null;
387                         if (!String.IsNullOrEmpty (subcategoryResourceName))
388                                 subcategory = taskResources.GetString (subcategoryResourceName);
389
390                         LogWarning (subcategory,
391                                 warningCode, helpKeyword, file, lineNumber,
392                                 columnNumber, endLineNumber, endColumnNumber,
393                                 FormatResourceString (messageResourceName, messageArgs));
394                 }
395
396                 public void LogWarningWithCodeFromResources (string messageResourceName,
397                                                              params object[] messageArgs)
398                 {
399                         // FIXME: what's different from normal logwarning?
400                         LogWarningFromResources (messageResourceName, messageArgs);
401                 }
402
403                 public void LogWarningWithCodeFromResources (string subcategoryResourceName,
404                                                              string file,
405                                                              int lineNumber,
406                                                              int columnNumber,
407                                                              int endLineNumber,
408                                                              int endColumnNumber,
409                                                              string messageResourceName,
410                                                              params object[] messageArgs)
411                 {
412                         LogWarningFromResources (subcategoryResourceName, file,
413                                 lineNumber, columnNumber, endLineNumber,
414                                 endColumnNumber, messageResourceName,
415                                 messageArgs);
416                 }
417                 
418                 [MonoTODO]
419                 public void LogExternalProjectFinished (string message,
420                                                         string helpKeyword,
421                                                         string projectFile,
422                                                         bool succeeded)
423                 {
424                 }
425                 
426                 [MonoTODO]
427                 public void LogExternalProjectStarted (string message,
428                                                        string helpKeyword,
429                                                        string projectFile,
430                                                        string targetNames)
431                 {
432                 }
433
434                 void ThrowInvalidOperationIf (bool condition, string message)
435                 {
436                         if (condition)
437                                 throw new InvalidOperationException (message);
438                 }
439
440                 protected IBuildEngine BuildEngine {
441                         get {
442                                 return taskInstance?.BuildEngine;
443                         }
444                 }
445
446                 public bool HasLoggedErrors {
447                         get {
448                                 return hasLoggedErrors;
449                         }
450                 }
451
452                 public string HelpKeywordPrefix {
453                         get {
454                                 return helpKeywordPrefix;
455                         }
456                         set {
457                                 helpKeywordPrefix = value;
458                         }
459                 }
460
461                 protected string TaskName {
462                         get {
463                                 return taskName;
464                         }
465                 }
466
467                 public ResourceManager TaskResources {
468                         get {
469                                 return taskResources;
470                         }
471                         set {
472                                 taskResources = value;
473                         }
474                 }
475         }
476 }
477