//
// 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
using System;
using System.Diagnostics;
+using System.Collections;
using System.Collections.Specialized;
using System.IO;
using System.Resources;
int exitCode;
int timeout;
string toolPath;
- Process process;
+ Encoding responseFileEncoding;
MessageImportance standardErrorLoggingImportance;
MessageImportance standardOutputLoggingImportance;
-
+ StringBuilder toolOutput;
+ bool typeLoadException;
+
static Regex regex;
protected ToolTask ()
this.TaskResources = taskResources;
this.HelpKeywordPrefix = helpKeywordPrefix;
this.toolPath = MonoLocationHelper.GetBinDir ();
+ this.responseFileEncoding = Encoding.UTF8;
+ this.timeout = Int32.MaxValue;
+ this.environmentOverride = new StringDictionary ();
}
static ToolTask ()
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;
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);
}
}
}
}
+ [MonoTODO]
protected virtual string GenerateCommandLineCommands ()
{
return null;
protected abstract string GenerateFullPathToTool ();
+ [MonoTODO]
protected virtual string GenerateResponseFileCommands ()
{
return null;
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 ()
[MonoTODO]
protected virtual void LogToolCommand (string message)
{
+ Log.LogMessage (MessageImportance.Normal, message);
}
[MonoTODO]
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; }
protected virtual Encoding ResponseFileEncoding
{
- get { return Encoding.UTF8; }
+ get { return responseFileEncoding; }
}
protected virtual Encoding StandardErrorEncoding
get { return standardOutputLoggingImportance; }
}
+ protected virtual bool HasLoggedErrors {
+ get { return Log.HasLoggedErrors; }
+ }
+
public virtual int Timeout
{
get { return timeout; }