using System.IO; using System.Text; using System.Text.RegularExpressions; using System.Xml; using NAnt.Core; using NAnt.Core.Attributes; using NAnt.Core.Types; namespace Com.GuyMahieu.NAnt.Build.Tasks { /// /// Custom NAnt task to do regular expression searches in a set of files. /// /// Author: Guy Mahieu (http://blog.guymahieu.com) /// Feel free to use and improve this, but if you do make improvements, please /// drop me a line (guy.mahieu@gmail.com). /// [TaskName("regexfinder")] public class RegexFinderTask : Task { private string regexPattern; private bool ignoreCase; private FileSet files; private FileInfo outputFile; [TaskAttribute("pattern")] [StringValidator(AllowEmpty = false)] public string RegexPattern { get { return regexPattern; } set { regexPattern = value; } } [TaskAttribute("outputfile")] [StringValidator(AllowEmpty = false)] public FileInfo OutputFile { get { return outputFile; } set { outputFile = value; } } [TaskAttribute("ignorecase")] [BooleanValidator] public bool IgnoreCase { get { return ignoreCase; } set { ignoreCase = value; } } [BuildElement("fileset")] public FileSet Files { get { return files; } set { files = value; } } protected override void ExecuteTask() { Regex regex = CreateRegularExpression(); XmlElement rootElement = GetRootXmlElement(); LogInfoMessage(); foreach (string fileName in files.FileNames) { ProcessInputFile(fileName, regex, rootElement); } SaveResultFile(rootElement); } private void LogInfoMessage() { StringBuilder result = new StringBuilder(); result.AppendFormat("Processing {0} file(s) for matches to pattern: {1}", files.FileNames.Count, regexPattern); if (ignoreCase) { result.Append(" (case insensitive)"); } else { result.Append(" (case sensitive)"); } Log(Level.Info, result.ToString()); } private void ProcessInputFile(string fileName, Regex regex, XmlElement rootElement) { using (StreamReader reader = new StreamReader(File.Open(fileName, FileMode.Open, FileAccess.Read))) { string line; int lineNumber = 0; while ((line = reader.ReadLine()) != null) { lineNumber++; if (regex.IsMatch(line)) { RegisterResult(rootElement, fileName, lineNumber, line); } } } } private Regex CreateRegularExpression() { RegexOptions options = RegexOptions.Singleline; if (ignoreCase) { options |= RegexOptions.IgnoreCase; } return new Regex(regexPattern, options); } private void RegisterResult(XmlElement rootElement, string fileName, int lineNumber, string lineData) { XmlDocument doc = rootElement.OwnerDocument; XmlElement matchElement = doc.CreateElement("match"); XmlElement fileNameElement = doc.CreateElement("fileName"); fileNameElement.InnerText = fileName.Substring(files.BaseDirectory.FullName.Length); matchElement.AppendChild(fileNameElement); XmlElement lineNrElement = doc.CreateElement("lineNumber"); lineNrElement.InnerText = lineNumber.ToString(); matchElement.AppendChild(lineNrElement); XmlElement lineDataElement = doc.CreateElement("lineData"); lineDataElement.InnerText = lineData; matchElement.AppendChild(lineDataElement); rootElement.AppendChild(matchElement); } private void SaveResultFile(XmlElement rootElement) { using (StreamWriter writer = new StreamWriter(outputFile.Open(FileMode.Create, FileAccess.ReadWrite))) { rootElement.OwnerDocument.Save(writer); } } private XmlElement GetRootXmlElement() { XmlDocument xmlDoc = new XmlDocument(); xmlDoc.AppendChild(xmlDoc.CreateNode(XmlNodeType.XmlDeclaration, "", "")); XmlElement element = xmlDoc.CreateElement("regexFinder"); XmlAttribute baseDirAttribute = xmlDoc.CreateAttribute("basedir"); baseDirAttribute.Value = files.BaseDirectory.FullName; element.Attributes.Append(baseDirAttribute); xmlDoc.AppendChild(element); return element; } } }