using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.Build.Utilities; using System.Diagnostics; using MessageImportance = Microsoft.Build.Framework.MessageImportance; using Microsoft.Build.Framework; namespace Cosmos.Build.MSBuild { public enum WriteType { Warning, Error, Message, // only issued on console Info } public class LogInfo { /// /// Specifies if warning, error, info or message. /// public WriteType logType; /// /// Description of the type (can be null). /// public string subcategory; /// /// Message, Warning or Error code (can be null) /// public string code; /// /// The help keyword for the host IDE (can be null). /// public string helpKeyword; /// /// The path to the file causing the message (can be null). /// public string file; /// /// The line in the file causing the message (set to zero if not available). /// public int lineNumber; /// /// The column in the file causing the message (set to zero if not available). /// public int columnNumber; /// /// The last line of a range of lines in the file causing the message (set to zero if not available). /// public int endLineNumber; /// /// The last column of a range of columns in the file causing the message (set to zero if not available). /// public int endColumnNumber; /// /// Importance of the message. (default is High) /// public MessageImportance importance; /// /// The message string. /// public string message; /// /// Optional arguments for formatting the message string. /// public object[] messageArgs;//TODO check if null is allowed, if yes document it here } public abstract class BaseToolTask : AppDomainIsolatedTask { protected bool ExecuteTool(string workingDir, string filename, string arguments, string name) { var xProcessStartInfo = new ProcessStartInfo(); xProcessStartInfo.WorkingDirectory = workingDir; xProcessStartInfo.FileName = filename; xProcessStartInfo.Arguments = arguments; xProcessStartInfo.UseShellExecute = false; xProcessStartInfo.RedirectStandardOutput = true; xProcessStartInfo.RedirectStandardError = true; xProcessStartInfo.CreateNoWindow = true; using (var xProcess = new Process()) { xProcess.ErrorDataReceived += delegate(object sender, DataReceivedEventArgs e) { if (e.Data != null) mErrors.Add(e.Data); }; xProcess.OutputDataReceived += delegate(object sender, DataReceivedEventArgs e) { if (e.Data != null) mOutput.Add(e.Data); }; xProcess.StartInfo = xProcessStartInfo; mErrors = new List(); mOutput = new List(); xProcess.Start(); xProcess.BeginErrorReadLine(); xProcess.BeginOutputReadLine(); xProcess.WaitForExit(15 * 60 * 1000); // wait 15 minutes if (xProcess.ExitCode != 0) { if (!xProcess.HasExited) { xProcess.Kill(); Log.LogError("{0} timed out.", name); } else { Log.LogError("Error occurred while invoking {0}.", name); } } LogInfo logContent; foreach (var xError in mErrors) { if(ExtendLineError(xProcess.ExitCode, xError, out logContent)) { Logs(logContent); } } foreach (var xOutput in mOutput) { if (ExtendLineError(xProcess.ExitCode, xOutput, out logContent)) { Logs(logContent); } } return xProcess.ExitCode == 0; } } private List mErrors; private List mOutput; public virtual bool ExtendLineError(int exitCode, string errorMessage, out LogInfo log) { log = new LogInfo(); log.logType = WriteType.Error; if (exitCode == 0) return false; return true; } public virtual bool ExtendLineOutput(int exitCode, ref string errorMessage, out LogInfo log) { log = new LogInfo(); log.logType = WriteType.Info; return true; } public void Logs(LogInfo logInfo)// string message, string category, string filename, string lineNumber = 0, string columnNumber = 0) { switch (logInfo.logType) { case WriteType.Warning: //Log.LogWarning(category, string.Empty, string.Empty, filename, lineNumber, columnNumber, lineNumber, columnNumber, message); Log.LogWarning(logInfo.subcategory, logInfo.code, logInfo.helpKeyword, logInfo.file, logInfo.lineNumber, logInfo.columnNumber, logInfo.endLineNumber, logInfo.endColumnNumber, logInfo.message, logInfo.messageArgs); break; case WriteType.Message: Log.LogMessage(logInfo.subcategory, logInfo.code, logInfo.helpKeyword, logInfo.file, logInfo.lineNumber, logInfo.columnNumber, logInfo.endLineNumber, logInfo.endColumnNumber, logInfo.message, logInfo.messageArgs); break; case WriteType.Info: // changed IDEBuildLogger.cs for this behavior of add to ErrorList Messages Log.LogMessage(logInfo.subcategory, logInfo.code, logInfo.helpKeyword, logInfo.file, logInfo.lineNumber, logInfo.columnNumber, logInfo.endLineNumber, logInfo.endColumnNumber, logInfo.importance, logInfo.message, logInfo.messageArgs); break; case WriteType.Error: default: Log.LogError(logInfo.subcategory, logInfo.code, logInfo.helpKeyword, logInfo.file, logInfo.lineNumber, logInfo.columnNumber, logInfo.endLineNumber, logInfo.endColumnNumber, logInfo.message, logInfo.messageArgs);; break; } } } }