// SharpDevelop samples // Copyright (c) 2007, AlphaSierraPapa // All rights reserved. // // Redistribution and use in source and binary forms, with or without modification, are // permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, this list // of conditions and the following disclaimer. // // - Redistributions in binary form must reproduce the above copyright notice, this list // of conditions and the following disclaimer in the documentation and/or other materials // provided with the distribution. // // - Neither the name of the SharpDevelop team nor the names of its contributors may be used to // endorse or promote products derived from this software without specific prior written // permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &AS IS& AND ANY EXPRESS // OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER // IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using System; using System.IO; using System.Text.RegularExpressions; using ICSharpCode.Core; using ICSharpCode.SharpDevelop; namespace ICSharpCode.NAnt { /// /// Utility class that parses the console output from NAnt. /// public class NAntOutputParser { NAntOutputParser() { } /// /// Parses the NAnt console output and extracts a set of /// Tasks. /// /// The NAnt console output to parse. /// A . public static TaskCollection Parse(string output) { TaskCollection tasks = new TaskCollection(); output = output.Replace("\r\n", "\n"); // Look for errors on a per line basis. Task task = null; StringReader reader = new StringReader(output); while (reader.Peek() != -1) { string currentLine = reader.ReadLine(); if (currentLine.StartsWith("BUILD FAILED")) { break; } task = ParseLine(currentLine); if (task != null) { tasks.Add(task); } } reader.Close(); // Look for multiline build errors. task = ParseMultilineBuildError(output); if (task != null) { tasks.Add(task); } // Look for NAnt build failed. task = ParseNAntBuildFailedError(output); if (task != null) { tasks.Add(task); } return tasks; } /// /// Parses a single line of text looking for errors. /// /// A NAnt output line. /// A if the line contains an error or /// a warning; otherwise . static Task ParseLine(string textLine) { Task task = null; task = ParseCSharpError(textLine); if (task == null) { task = ParseVBError(textLine); } if (task == null) { task = ParseFatalError(textLine); } if (task == null) { task = ParseVBFatalError(textLine); } if (task == null) { task = ParseNAntWarning(textLine); } if (task == null) { task = ParseNAntError(textLine); } return task; } /// /// Looks for errors of the form /// "C:/MyProject/MyProject.build(40,3): error CS1000: An error occurred." /// /// The line of text to parse. /// A if an error was found; otherwise /// . static Task ParseCSharpError(string textLine) { Task task = null; Match match = Regex.Match(textLine, @"^.*?(\w+:[/\\].*?)\(([\d]*),([\d]*)\): (.*?) (.*?): (.*?)$"); if (match.Success) { try { int line = Convert.ToInt32(match.Groups[2].Value); int col = Convert.ToInt32(match.Groups[3].Value); string description = String.Concat(match.Groups[6].Value, " (", match.Groups[5], ")"); TaskType taskType = TaskType.Error; if (String.Compare(match.Groups[4].Value, "warning", true) == 0) { taskType = TaskType.Warning; } task = new Task(FileName.Create(match.Groups[1].Value), description, col, line, taskType); } catch (Exception) { // Ignore. } } return task; } /// /// Looks for errors of the form /// "C:/MyProject/MyProject.build(40,3): ifnot is deprecated." /// /// The line of text to parse. /// A if an error was found; otherwise /// . static Task ParseNAntError(string textLine) { Task task = null; Match match = Regex.Match(textLine, @"^.*?(\w+:[/\\].*?)\(([\d]*),([\d]*)\): (.*?)$"); if (match.Success) { try { int line = Convert.ToInt32(match.Groups[2].Value); int col = Convert.ToInt32(match.Groups[3].Value); task = new Task(FileName.Create(match.Groups[1].Value), match.Groups[4].Value, col, line, TaskType.Warning); } catch (Exception) { // Ignore. } } return task; } /// /// Looks for errors of the form /// "C:/MyProject/MyProject.build(40): error CS1000: An error occurred." /// /// /// This should handle C++ errors too. /// The line of text to parse. /// A if an error was found; otherwise /// . static Task ParseVBError(string textLine) { Task task = null; Match match = Regex.Match(textLine, @"^.*?(\w+:[/\\].*?)\(([\d]*)\) : (.*?) (.*?): (.*?)$"); if (match.Success) { try { int line = Convert.ToInt32(match.Groups[2].Value); string description = String.Concat(match.Groups[5].Value, " (", match.Groups[4], ")"); TaskType taskType = TaskType.Error; if (String.Compare(match.Groups[3].Value, "warning", true) == 0) { taskType = TaskType.Warning; } task = new Task(FileName.Create(match.Groups[1].Value), description, 0, line, taskType); } catch (Exception) { // Ignore. } } return task; } /// /// Looks for errors of the form /// "fatal error CS00042: An error occurred." /// /// The line of text to parse. /// A if an error was found; otherwise /// . static Task ParseFatalError(string textLine) { Task task = null; Match match = Regex.Match(textLine, @"^.*?(fatal error .*?: .*?)$"); if (match.Success) { try { task = new Task(null, match.Groups[1].Value, 0, 0, TaskType.Error); } catch (Exception) { // Ignore. } } return task; } /// /// Looks for errors of the form /// "vbc : error BC31019: Unable to write to output file." /// /// The line of text to parse. /// A if an error was found; otherwise /// . static Task ParseVBFatalError(string textLine) { Task task = null; Match match = Regex.Match(textLine, @"^.*?vbc : error (.*?): (.*?)$"); if (match.Success) { try { string description = String.Concat(match.Groups[2].Value, " (", match.Groups[1].Value, ")"); task = new Task(null, description, 0, 0, TaskType.Error); } catch (Exception) { // Ignore. } } return task; } /// /// Looks for errors of the form /// "fatal error CS00042: An error occurred." /// /// The line of text to parse. /// A if a warning was found; otherwise /// . static Task ParseNAntWarning(string textLine) { Task task = null; Match match = Regex.Match(textLine, @"^.*?(Read-only property .*? cannot be overwritten.)$"); if (match.Success) { try { task = new Task(null, match.Groups[1].Value, 0, 0, TaskType.Warning); } catch (Exception) { // Ignore. } } return task; } /// /// Looks for errors of the form /// "BUILD FAILED" /// "[csc] C:/foo/foo.cs(5,5):" /// "Something bad happened." /// /// The line of text to parse. /// A if an error was found; otherwise /// . static Task ParseNAntBuildFailedError(string output) { Task task = null; Match match = Regex.Match(output, @"^BUILD FAILED.*?$\n^$\n^(\w+:[/\\].*?)\(([\d]*),([\d]*)\):$\n^(.*?)$\n^(.*?)$", RegexOptions.Multiline); if (match.Success) { try { int line = Convert.ToInt32(match.Groups[2].Value); int col = Convert.ToInt32(match.Groups[3].Value); string description = String.Concat(match.Groups[4], Environment.NewLine, match.Groups[5]); task = new Task(FileName.Create(match.Groups[1].Value), description, col, line, TaskType.Error); } catch(Exception) { }; } else { match = Regex.Match(output, @"^BUILD FAILED$\n^$\n^(.*?)$", RegexOptions.Multiline); if (match.Success) { task = new Task(null, match.Groups[1].Value, 0, 0, TaskType.Error); } } return task; } /// /// Parses errors of the form. /// "[delete] C:\foo\foo.build(94,5):" /// "[delete] Cannot delete directory 'C:\foo\bin'. The directory does not exist." /// /// The line of text to parse. /// A if an error was found; otherwise /// . static Task ParseMultilineBuildError(string output) { Task task = null; Match match = Regex.Match(output, @"^.*?\[delete\] (\w+:[/\\].*?)\(([\d]*),([\d]*)\):$\n^.*?\[delete\] (.*?)$", RegexOptions.Multiline); if (match.Success) { try { int line = Convert.ToInt32(match.Groups[2].Value); int col = Convert.ToInt32(match.Groups[3].Value); string description = String.Concat(match.Groups[4]); task = new Task(FileName.Create(match.Groups[1].Value), description, col, line, TaskType.Error); } catch(Exception) { }; } return task; } } }