Fix warnings.
[mono.git] / mcs / class / Microsoft.Build.Utilities / Microsoft.Build.Utilities / ToolTask.cs
index ed0cefbde19f4fc3ab433cccc2c7a60daab80750..b6b298feca10a17b1833146cf7e5edbb81866eaa 100644 (file)
@@ -3,8 +3,10 @@
 //
 // Author:
 //   Marek Sieradzki (marek.sieradzki@gmail.com)
+//   Ankit Jain (jankit@novell.com)
 //
 // (C) 2005 Marek Sieradzki
+// Copyright 2009 Novell, Inc (http://www.novell.com)
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
@@ -29,6 +31,7 @@
 
 using System;
 using System.Diagnostics;
+using System.Collections;
 using System.Collections.Specialized;
 using System.IO;
 using System.Resources;
@@ -45,10 +48,12 @@ namespace Microsoft.Build.Utilities
                int                     exitCode;
                int                     timeout;
                string                  toolPath;
-               Process                 process;
+               Encoding                responseFileEncoding;
                MessageImportance       standardErrorLoggingImportance;
                MessageImportance       standardOutputLoggingImportance;
-               
+               StringBuilder toolOutput;
+               bool typeLoadException;
+
                static Regex            regex;
                
                protected ToolTask ()
@@ -69,6 +74,9 @@ namespace Microsoft.Build.Utilities
                        this.TaskResources = taskResources;
                        this.HelpKeywordPrefix = helpKeywordPrefix;
                        this.toolPath = MonoLocationHelper.GetBinDir ();
+                       this.responseFileEncoding = Encoding.UTF8;
+                       this.timeout = Int32.MaxValue;
+                       this.environmentOverride = new StringDictionary ();
                }
 
                static ToolTask ()
@@ -84,84 +92,145 @@ namespace Microsoft.Build.Utilities
                                RegexOptions.IgnoreCase);
                }
 
+               [MonoTODO]
                protected virtual bool CallHostObjectToExecute ()
                {
                        return true;
                }
 
-               protected virtual int ExecuteTool (string pathToTool,
-                                                  string responseFileCommands,
-                                                  string commandLineCommands)
-               {
-                       string arguments;
-                       bool success;
-                       
-                       arguments = String.Concat (commandLineCommands, " ", responseFileCommands);
-                       
-                       success  = RealExecute (pathToTool, arguments);
-                       
-                       if (success)
-                               return 0;
-                       else
-                               return -1;
-               }
-               
                public override bool Execute ()
                {
-                       int result;
-                       
-                       result = ExecuteTool (GenerateFullPathToTool (), GenerateResponseFileCommands (),
-                               GenerateCommandLineCommands ());
-                       
-                       if (result == 0)
+                       if (SkipTaskExecution ())
                                return true;
-                       else
-                               return false;
+
+                       exitCode = ExecuteTool (GenerateFullPathToTool (), GenerateResponseFileCommands (),
+                               GenerateCommandLineCommands ());
+
+                       // HandleTaskExecutionErrors is called only if exitCode != 0
+                       return exitCode == 0 || HandleTaskExecutionErrors ();
                }
                
+               [MonoTODO]
                protected virtual string GetWorkingDirectory ()
                {
                        return null;
                }
                
-               private bool RealExecute (string filename, string arguments)
+               protected virtual int ExecuteTool (string pathToTool,
+                                                  string responseFileCommands,
+                                                  string commandLineCommands)
+
                {
-                       string line;
-               
-                       if (filename == null)
-                               throw new ArgumentNullException ("filename");
-                       if (arguments == null)
-                               throw new ArgumentNullException ("arguments");
-                       
-                       process = new Process ();
-                       process.StartInfo.Arguments = arguments;
-                       process.StartInfo.CreateNoWindow = true;
-                       process.StartInfo.FileName = filename;
-                       process.StartInfo.RedirectStandardError = true;
-                       process.StartInfo.RedirectStandardOutput = true;
-                       process.StartInfo.UseShellExecute = false;
-                       
-                       Log.LogMessage (MessageImportance.Low, String.Format ("Tool {0} execution started with arguments: {1}",
-                               filename, arguments));
-                       
-                       process.Start ();
-                       process.WaitForExit ();
-                       
-                       while ((line = process.StandardError.ReadLine ()) != null) {
-                               LogEventsFromTextOutput (line, MessageImportance.Normal);
+                       if (pathToTool == null)
+                               throw new ArgumentNullException ("pathToTool");
+
+                       string output, error, responseFileName;
+                       StreamWriter outwr, errwr;
+
+                       outwr = errwr = null;
+                       responseFileName = output = error = null;
+                       toolOutput = new StringBuilder ();
+
+                       try {
+                               string arguments = commandLineCommands;
+                               if (!String.IsNullOrEmpty (responseFileCommands)) {
+                                       responseFileName = Path.GetTempFileName ();
+                                       File.WriteAllText (responseFileName, responseFileCommands);
+                                       arguments = arguments + " " + GetResponseFileSwitch (responseFileName);
+                               }
+
+                               LogToolCommand (String.Format ("Tool {0} execution started with arguments: {1} {2}",
+                                               pathToTool, commandLineCommands, responseFileCommands));
+
+                               output = Path.GetTempFileName ();
+                               error = Path.GetTempFileName ();
+                               outwr = new StreamWriter (output);
+                               errwr = new StreamWriter (error);
+
+                               ProcessStartInfo pinfo = new ProcessStartInfo (pathToTool, arguments);
+                               pinfo.WorkingDirectory = GetWorkingDirectory () ?? Environment.CurrentDirectory;
+
+                               pinfo.UseShellExecute = false;
+                               pinfo.RedirectStandardOutput = true;
+                               pinfo.RedirectStandardError = true;
+
+                               try {
+                                       ProcessWrapper pw = ProcessService.StartProcess (pinfo, outwr, errwr, null, environmentOverride);
+                                       pw.WaitForOutput (timeout == Int32.MaxValue ? -1 : timeout);
+                                       exitCode = pw.ExitCode;
+                                       outwr.Close();
+                                       errwr.Close();
+                                       pw.Dispose ();
+                               } catch (System.ComponentModel.Win32Exception e) {
+                                       Log.LogError ("Error executing tool '{0}': {1}", pathToTool, e.Message);
+                                       return -1;
+                               }
+
+                               ProcessOutputFile (output, standardOutputLoggingImportance);
+                               ProcessOutputFile (error, standardErrorLoggingImportance);
+
+                               Log.LogMessage (MessageImportance.Low, "Tool {0} execution finished.", pathToTool);
+                               return exitCode;
+                       } finally {
+                               DeleteTempFile (responseFileName);
+                               if (outwr != null)
+                                       outwr.Dispose ();
+                               if (errwr != null)
+                                       errwr.Dispose ();
+
+                               DeleteTempFile (output);
+                               DeleteTempFile (error);
                        }
-                       
-                       Log.LogMessage (MessageImportance.Low, String.Format ("Tool {0} execution finished.", filename));
-                       
-                       return !Log.HasLoggedErrors;
                }
-               
-               
-               // FIXME: use importance
-               [MonoTODO]
-               protected virtual void LogEventsFromTextOutput (string singleLine,
-                                                               MessageImportance importance)
+
+               void ProcessOutputFile (string filename, MessageImportance importance)
                {
+                       using (StreamReader sr = File.OpenText (filename)) {
+                               string line;
+                               while ((line = sr.ReadLine ()) != null) {
+                                       if (typeLoadException) {
+                                               toolOutput.Append (sr.ReadToEnd ());
+                                               string output_str = toolOutput.ToString ();
+                                               Regex reg  = new Regex (@".*WARNING.*used in (mscorlib|System),.*",
+                                                               RegexOptions.Multiline);
+
+                                               if (reg.Match (output_str).Success)
+                                                       Log.LogError (
+                                                               "Error: A referenced assembly may be built with an incompatible " + 
+                                                               "CLR version. See the compilation output for more details.");
+                                               else
+                                                       Log.LogError (
+                                                               "Error: A dependency of a referenced assembly may be missing, or " +
+                                                               "you may be referencing an assembly created with a newer CLR " +
+                                                               "version. See the compilation output for more details.");
+
+                                               Log.LogError (output_str);
+                                       }
+
+                                       toolOutput.AppendLine (line);
+                                       LogEventsFromTextOutput (line, importance);
+                               }
+                       }
+               }
+
+               protected virtual void LogEventsFromTextOutput (string singleLine, MessageImportance importance)
+               {
+                       singleLine = singleLine.Trim ();
+                       if (singleLine.Length == 0)
+                               return;
+
+                       if (singleLine.StartsWith ("Unhandled Exception: System.TypeLoadException") ||
+                           singleLine.StartsWith ("Unhandled Exception: System.IO.FileNotFoundException")) {
+                               typeLoadException = true;
+                       }
+
+                       // When IncludeDebugInformation is true, prevents the debug symbols stats from braeking this.
+                       if (singleLine.StartsWith ("WROTE SYMFILE") ||
+                               singleLine.StartsWith ("OffsetTable") ||
+                               singleLine.StartsWith ("Compilation succeeded") ||
+                               singleLine.StartsWith ("Compilation failed"))
+                               return;
+
                        string filename, origin, category, code, subcategory, text;
                        int lineNumber, columnNumber, endLineNumber, endColumnNumber;
                
@@ -173,13 +242,15 @@ namespace Microsoft.Build.Utilities
                        text = m.Groups [regex.GroupNumberFromName ("TEXT")].Value;
                        
                        ParseOrigin (origin, out filename, out lineNumber, out columnNumber, out endLineNumber, out endColumnNumber);
-                       
+
                        if (category == "warning") {
                                Log.LogWarning (subcategory, code, null, filename, lineNumber, columnNumber, endLineNumber,
                                        endColumnNumber, text, null);
                        } else if (category == "error") {
                                Log.LogError (subcategory, code, null, filename, lineNumber, columnNumber, endLineNumber,
                                        endColumnNumber, text, null);
+                       } else {
+                               Log.LogMessage (singleLine);
                        }
                }
                
@@ -237,6 +308,7 @@ namespace Microsoft.Build.Utilities
                        }
                }
 
+               [MonoTODO]
                protected virtual string GenerateCommandLineCommands ()
                {
                        return null;
@@ -244,6 +316,7 @@ namespace Microsoft.Build.Utilities
 
                protected abstract string GenerateFullPathToTool ();
 
+               [MonoTODO]
                protected virtual string GenerateResponseFileCommands ()
                {
                        return null;
@@ -254,10 +327,14 @@ namespace Microsoft.Build.Utilities
                        return String.Format ("@{0}", responseFilePath);
                }
 
-               [MonoTODO]
                protected virtual bool HandleTaskExecutionErrors ()
                {
-                       return true;
+                       if (!Log.HasLoggedErrors && exitCode != 0)
+                               Log.LogError ("Tool exited with code: {0}. Output: {1}", exitCode,
+                                               toolOutput != null ? toolOutput.ToString () : String.Empty);
+                       toolOutput = null;
+
+                       return ExitCode == 0 && !Log.HasLoggedErrors;
                }
 
                protected virtual HostObjectInitializationStatus InitializeHostObject ()
@@ -268,6 +345,7 @@ namespace Microsoft.Build.Utilities
                [MonoTODO]
                protected virtual void LogToolCommand (string message)
                {
+                       Log.LogMessage (MessageImportance.Normal, message);
                }
                
                [MonoTODO]
@@ -286,12 +364,25 @@ namespace Microsoft.Build.Utilities
                        return true;
                }
 
+               protected void DeleteTempFile (string fileName)
+               {
+                       if (String.IsNullOrEmpty (fileName))
+                               return;
+
+                       try {
+                               File.Delete (fileName);
+                       } catch (IOException ioe) {
+                               Log.LogWarning ("Unable to delete temporary file '{0}' : {1}", ioe.Message);
+                       } catch (UnauthorizedAccessException uae) {
+                               Log.LogWarning ("Unable to delete temporary file '{0}' : {1}", uae.Message);
+                       }
+               }
+
                protected virtual StringDictionary EnvironmentOverride
                {
                        get { return environmentOverride; }
                }
                
-               [MonoTODO]
                [Output]
                public int ExitCode {
                        get { return exitCode; }
@@ -299,7 +390,7 @@ namespace Microsoft.Build.Utilities
 
                protected virtual Encoding ResponseFileEncoding
                {
-                       get { return Encoding.UTF8; }
+                       get { return responseFileEncoding; }
                }
 
                protected virtual Encoding StandardErrorEncoding
@@ -320,6 +411,10 @@ namespace Microsoft.Build.Utilities
                        get { return standardOutputLoggingImportance; }
                }
 
+               protected virtual bool HasLoggedErrors {
+                       get { return Log.HasLoggedErrors; }
+               }
+
                public virtual int Timeout
                {
                        get { return timeout; }