[xbuild] ToolTask - make error column check a little non-specific.
[mono.git] / mcs / class / Microsoft.Build.Utilities / Microsoft.Build.Utilities / ToolTask.cs
index 91f95adfcc358da8e57d4c53352ffc663205feda..4094c122e3b9e9afc86574ece4e1ea98afbd9cb9 100644 (file)
@@ -46,7 +46,6 @@ namespace Microsoft.Build.Utilities
 {
        public abstract class ToolTask : Task
        {
-               SCS.ProcessStringDictionary     environmentOverride;
                int                     exitCode;
                int                     timeout;
                string                  toolPath, toolExe;
@@ -54,7 +53,6 @@ namespace Microsoft.Build.Utilities
                MessageImportance       standardErrorLoggingImportance;
                MessageImportance       standardOutputLoggingImportance;
                StringBuilder toolOutput;
-               StringBuilder pendingLineFragmentError, pendingLineFragmentOutput;
                bool typeLoadException;
 
                protected ToolTask ()
@@ -77,7 +75,6 @@ namespace Microsoft.Build.Utilities
                        this.toolPath = MonoLocationHelper.GetBinDir ();
                        this.responseFileEncoding = Encoding.UTF8;
                        this.timeout = Int32.MaxValue;
-                       this.environmentOverride = new SCS.ProcessStringDictionary ();
                }
 
                [MonoTODO]
@@ -112,53 +109,43 @@ namespace Microsoft.Build.Utilities
                        if (pathToTool == null)
                                throw new ArgumentNullException ("pathToTool");
 
-                       string output, error, responseFileName;
-                       StreamWriter outwr, errwr;
-
-                       outwr = errwr = null;
-                       responseFileName = output = error = null;
+                       string responseFileName;
+                       responseFileName = null;
                        toolOutput = new StringBuilder ();
 
                        try {
-                               string arguments = commandLineCommands;
+                               string responseFileSwitch = String.Empty;
                                if (!String.IsNullOrEmpty (responseFileCommands)) {
                                        responseFileName = Path.GetTempFileName ();
                                        File.WriteAllText (responseFileName, responseFileCommands);
-                                       arguments = arguments + " " + GetResponseFileSwitch (responseFileName);
+                                       responseFileSwitch = GetResponseFileSwitch (responseFileName);
                                }
 
+                               var pinfo = GetProcessStartInfo (pathToTool, commandLineCommands, responseFileSwitch);
                                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;
-
-                               pendingLineFragmentOutput = new StringBuilder ();
-                               pendingLineFragmentError = new StringBuilder ();
+                                               pinfo.FileName, commandLineCommands, responseFileCommands));
 
+                               var pendingLineFragmentOutput = new StringBuilder ();
+                               var pendingLineFragmentError = new StringBuilder ();
+                               var environmentOverride = GetAndLogEnvironmentVariables ();
                                try {
-                                       ProcessWrapper pw = ProcessService.StartProcess (pinfo, outwr, errwr, null, environmentOverride);
-                                       pw.OutputStreamChanged += (_, msg) => ProcessLine (pendingLineFragmentOutput, msg, StandardOutputLoggingImportance);
-                                       pw.ErrorStreamChanged += (_, msg) => ProcessLine (pendingLineFragmentError, msg, StandardErrorLoggingImportance);
-
-                                       pw.WaitForOutput (timeout == Int32.MaxValue ? -1 : timeout);
+                                       // When StartProcess returns, the process has already .Start()'ed
+                                       // If we subscribe to the events after that, then for processes that
+                                       // finish executing before we can subscribe, we won't get the output/err
+                                       // events at all!
+                                       ProcessWrapper pw = ProcessService.StartProcess (pinfo,
+                                                       (_, msg) => ProcessLine (pendingLineFragmentOutput, msg, StandardOutputLoggingImportance),
+                                                       (_, msg) => ProcessLine (pendingLineFragmentError, msg, StandardErrorLoggingImportance),
+                                                       null,
+                                                       environmentOverride);
+
+                                       pw.WaitForOutput (timeout == Int32.MaxValue ? Int32.MaxValue : timeout);
 
                                        // Process any remaining line
                                        ProcessLine (pendingLineFragmentOutput, StandardOutputLoggingImportance, true);
                                        ProcessLine (pendingLineFragmentError, StandardErrorLoggingImportance, true);
 
                                        exitCode = pw.ExitCode;
-                                       outwr.Close();
-                                       errwr.Close();
                                        pw.Dispose ();
                                } catch (System.ComponentModel.Win32Exception e) {
                                        Log.LogError ("Error executing tool '{0}': {1}", pathToTool, e.Message);
@@ -175,13 +162,6 @@ namespace Microsoft.Build.Utilities
                                return exitCode;
                        } finally {
                                DeleteTempFile (responseFileName);
-                               if (outwr != null)
-                                       outwr.Dispose ();
-                               if (errwr != null)
-                                       errwr.Dispose ();
-
-                               DeleteTempFile (output);
-                               DeleteTempFile (error);
                        }
                }
 
@@ -278,7 +258,7 @@ namespace Microsoft.Build.Utilities
                        string col = match.Result ("${column}");
                        int columnNumber = 0;
                        if (!string.IsNullOrEmpty (col))
-                               columnNumber = col == "255+" ? -1 : Int32.Parse (col);
+                               columnNumber = col.IndexOf ("+") >= 0 ? -1 : Int32.Parse (col);
 
                        string category = match.Result ("${level}");
                        string code = match.Result ("${number}");
@@ -312,6 +292,18 @@ namespace Microsoft.Build.Utilities
                        return String.Format ("@{0}", responseFilePath);
                }
 
+               protected virtual ProcessStartInfo GetProcessStartInfo (string pathToTool, string commandLineCommands, string responseFileSwitch)
+               {
+                       var pinfo = new ProcessStartInfo (pathToTool, String.Format ("{0} {1}", commandLineCommands, responseFileSwitch));
+
+                       pinfo.WorkingDirectory = GetWorkingDirectory () ?? Environment.CurrentDirectory;
+                       pinfo.UseShellExecute = false;
+                       pinfo.RedirectStandardOutput = true;
+                       pinfo.RedirectStandardError = true;
+
+                       return pinfo;
+               }
+
                protected virtual bool HandleTaskExecutionErrors ()
                {
                        if (!Log.HasLoggedErrors && exitCode != 0)
@@ -362,11 +354,50 @@ namespace Microsoft.Build.Utilities
                        }
                }
 
+               // If EnvironmentVariables is defined, then merge EnvironmentOverride
+               // EnvironmentOverride is Obsolete'd in 4.0
+               //
+               // Returns the final set of environment variables and logs them
+               SCS.StringDictionary GetAndLogEnvironmentVariables ()
+               {
+                       var env_vars = GetEnvironmentVariables ();
+                       if (env_vars == null)
+                               return env_vars;
+
+                       Log.LogMessage (MessageImportance.Low, "Environment variables being passed to the tool:");
+                       foreach (DictionaryEntry entry in env_vars)
+                               Log.LogMessage (MessageImportance.Low, "\t{0}={1}", (string)entry.Key, (string)entry.Value);
+
+                       return env_vars;
+               }
+
+               SCS.StringDictionary GetEnvironmentVariables ()
+               {
+                       if (EnvironmentVariables == null || EnvironmentVariables.Length == 0)
+                               return EnvironmentOverride;
+
+                       var env_vars = new SCS.ProcessStringDictionary ();
+                       foreach (string pair in EnvironmentVariables) {
+                               string [] key_value = pair.Split ('=');
+                               if (!String.IsNullOrEmpty (key_value [0]))
+                                       env_vars [key_value [0]] = key_value.Length > 1 ? key_value [1] : String.Empty;
+                       }
+
+                       if (EnvironmentOverride != null)
+                               foreach (DictionaryEntry entry in EnvironmentOverride)
+                                       env_vars [(string)entry.Key] = (string)entry.Value;
+
+                       return env_vars;
+               }
+
                protected virtual StringDictionary EnvironmentOverride
                {
-                       get { return environmentOverride; }
+                       get { return null; }
                }
-               
+
+               // Ignore EnvironmentOverride if this is set
+               public string[] EnvironmentVariables { get; set; }
+
                [Output]
                public int ExitCode {
                        get { return exitCode; }