[Mono-dev] gendarme patch (feature): console runner gets xml output

Christian Birkl christian.birkl at gmail.com
Mon Aug 28 16:43:47 EDT 2006


Hi all (again) ;-),

attached a patch which enables different outputs for the console runner
(currently only text and xml) is supported. Also attached is a small test
output when running on framework.dll. For showing the advantages this patch
imho brings i've also attached a simple xslt which transform the ouput into
a mono styled html report page.

Note: This patch also contains my first gendarme - 001.patch bugfix.

Christian
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.ximian.com/pipermail/mono-devel-list/attachments/20060828/c21d1cd4/attachment.html 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: gendarme output transformation.zip
Type: application/zip
Size: 6140 bytes
Desc: not available
Url : http://lists.ximian.com/pipermail/mono-devel-list/attachments/20060828/c21d1cd4/attachment.zip 
-------------- next part --------------
Index: console/ConsoleRunner.cs
===================================================================
--- console/ConsoleRunner.cs	(revision 64483)
+++ console/ConsoleRunner.cs	(working copy)
@@ -36,14 +36,18 @@
 using Mono.Cecil;
 using Gendarme.Framework;
 
+
 class ConsoleRunner : Runner {
 
 	private const string defaultConfiguration = "rules.xml";
 	private const string defaultRuleSet = "default";
+	private const string defaultOutput = "text";
 
 	private string config;
 	private string set;
+	private string output;
 	private ArrayList assemblies;
+	private static ConsoleWriter Output = null;
 
 	private static Assembly assembly;
 
@@ -91,6 +95,10 @@
 				break;
 			case "--help":
 				return false;
+			case "--output":
+				output = GetNext(args, ++i, defaultOutput);
+				break;
+
 			default:
 				string filename = args[i];
 				if (filename.IndexOfAny (new char[] { '*', '?' }) >= 0) {
@@ -124,10 +132,10 @@
 			return false;
 
 		bool result = false;
-		foreach (XmlElement ruleset in doc.DocumentElement) {
+		foreach (XmlElement ruleset in doc.DocumentElement.SelectNodes("ruleset")) {
 			if (ruleset.Attributes["name"].Value != set)
 				continue;
-			foreach (XmlElement assembly in ruleset) {
+			foreach (XmlElement assembly in ruleset.SelectNodes("rules")) {
 				string include = GetAttribute (assembly, "include", "*");
 				string exclude = GetAttribute (assembly, "exclude", String.Empty);
 				string from = GetFullPath (GetAttribute (assembly, "from", String.Empty));
@@ -149,92 +157,92 @@
 		Assembly a = Assembly.GetExecutingAssembly();
 		Version v = a.GetName ().Version;
 		if (v.ToString () != "0.0.0.0") {
-			Console.WriteLine ("Gendarme v{0}", v);
+			Output.Info ("Gendarme v{0}", v);
 			object[] attr = a.GetCustomAttributes (typeof (AssemblyCopyrightAttribute), false);
 			if (attr.Length > 0)
-				Console.WriteLine (((AssemblyCopyrightAttribute) attr [0]).Copyright);
+				Output.Info (((AssemblyCopyrightAttribute) attr [0]).Copyright);
 		} else {
-			Console.WriteLine ("Gendarme - Development Snapshot");
-		}
-		Console.WriteLine ();
+			Output.Info ("Gendarme - Development Snapshot");
+		}		
 	}
 
 	static void Help ()
 	{
-		Console.WriteLine ("Usage: gendarme [--config configfile] [--set ruleset] assembly");
-		Console.WriteLine ("Where");
-		Console.WriteLine ("  --config configfile\tSpecify the configuration file. Default is 'rules.xml'.");
-		Console.WriteLine ("  --set ruleset\t\tSpecify the set of rules to verify. Default is '*'.");
-		Console.WriteLine ("  --debug\t\tEnable debugging output.");
-		Console.WriteLine ("  assembly\t\tSpecify the assembly to verify.");
-		Console.WriteLine ();
+		Output.Info (@"
+Usage: gendarme [--config configfile] [--set ruleset] [--output format] <assembly [assembly [assembly ...]]>
+Where
+  --config configfile	Specify the configuration file. Default is 'rules.xml'.
+  --set ruleset		Specify the set of rules to verify. Default is '*'.
+  --output format	Specify the output format, 'text' or 'xml'. Default is 'text'.
+  --debug		Enable debugging output.  
+  assembly		Specify the assemblies to verify.
+");
 	}
 
-	static int Main (string[] args)
-	{
-		Header ();
+	static int Main (string[] args) {
 		ConsoleRunner runner = new ConsoleRunner ();
 
-		try {
-			if (!runner.ParseOptions (args)) {
-				Help ();
-				return 1;
-			}
-			if (!runner.LoadConfiguration ()) {
-				return 1;
-			}
-		}
-		catch (Exception e) {
-			Console.WriteLine (e);
-			return 1;
-		}
+		bool parseOptionsResult = runner.ParseOptions (args);
 
-		foreach (string assembly in runner.assemblies) {
-			IAssemblyDefinition ad = null;
+		if (runner.output == "xml")
+			Output = new XmlConsoleWriter();
+		else
+			Output = new TextConsoleWriter();
+
+		try {			
+			Header ();			
+
 			try {
-				ad = AssemblyFactory.GetAssembly (assembly);
+				if (!parseOptionsResult) {
+					Help ();
+					return 1;
+				}
+				if (!runner.LoadConfiguration ()) {
+					return 1;
+				}
 			}
 			catch (Exception e) {
-				Console.WriteLine ("Error processing assembly '{0}'{1}Details: {2}",
-					assembly, Environment.NewLine, e);
+				Console.WriteLine (e);
+				return 1;
 			}
-			try {
-				runner.Process (ad);
-			}
-			catch (Exception e) {
-				Console.WriteLine ("Error executing rules on assembly '{0}'{1}Details: {2}",
-					assembly, Environment.NewLine, e);
-			}
-		}
 
-		int i = 0;
-		foreach (Violation v in runner.Violations.List) {
-			RuleInformation ri = RuleInformationManager.GetRuleInformation (v.Rule);
-			Console.WriteLine ("{0}. {1}", ++i, ri.Name);
-			Console.WriteLine ();
-			Console.WriteLine ("Problem: {0}", String.Format (ri.Problem, v.Violator));
-			Console.WriteLine ();
-			if(v.Messages != null && v.Messages.Count > 0) {
-				Console.WriteLine ("Details:");
-				foreach(object message in v.Messages) {
-					Console.WriteLine("  {0}", message);
+			Output.Rules (runner.Rules);			
+
+			foreach (string assembly in runner.assemblies) {
+				IAssemblyDefinition ad = null;
+				try {
+					ad = AssemblyFactory.GetAssembly (assembly);
 				}
-				Console.WriteLine ();
+				catch (Exception e) {
+					Output.Error ("Error processing assembly '{0}'", assembly);
+					Output.Error ("Details: {0}", e);
+				}
+				if (ad != null) {
+					try {
+						Output.Input (assembly);
+
+						runner.Process (ad);
+
+						if (runner.Violations.Count == 0) {
+							Output.Info ("No rule's violation were found in assembly '{0}'.", assembly);							
+						} else {
+							foreach (Violation v in runner.Violations) {				
+								Output.Write (assembly, v);
+							}
+						}
+						
+					}
+					catch (Exception e) {
+						Output.Error ("Error executing rules on assembly '{0}'", assembly);
+						Output.Error ("Details: {0}", e);
+					}
+				}
 			}
-			Console.WriteLine ("Solution: {0}", String.Format (ri.Solution, v.Violator));
-			Console.WriteLine ();
-			string url = ri.Uri;
-			if (url.Length > 0) {
-				Console.WriteLine ("More info available at: {0}", url);
-				Console.WriteLine ();
-			}
-			Console.WriteLine ();
-		}
 
-		if (i == 0) {
-			Console.WriteLine ("No rule's violation were found.");
-			return 0;
-		}
-		return 1;
+			return 1;			
+		} finally {				
+			Output.Dispose();		
+		}		
 	}
+
 }
Index: console/ConsoleWriter.cs
===================================================================
--- console/ConsoleWriter.cs	(revision 0)
+++ console/ConsoleWriter.cs	(revision 0)
@@ -0,0 +1,143 @@
+using System;
+using System.Xml;
+using System.Xml.Serialization;
+
+using Gendarme.Framework;
+
+public interface ConsoleWriter : IDisposable {
+	void Info(string text, params object[] args);
+	void Error(string text, params object[] args);
+
+	void Rules(Rules rules);
+	void Input(string assembly);
+	void Write(string assembly, Violation v);
+}
+
+public class XmlConsoleWriter : ConsoleWriter {
+
+	private XmlTextWriter writer = null;
+
+	public XmlConsoleWriter() {
+		writer = new XmlTextWriter(Console.Out);
+		writer.WriteProcessingInstruction("xml", "version='1.0'");
+		writer.WriteStartElement("gendarme-output");
+	}
+
+	public void Dispose() {
+		if (writer == null)
+			throw new ObjectDisposedException("writer");
+		writer.WriteEndElement();
+		writer.Flush();
+		writer = null;
+	}
+
+	public void Rules(Rules rules) {
+		writer.WriteStartElement("rules");
+		Rules("Assembly", rules.Assembly);
+		Rules("Module", rules.Module);
+		Rules("Type", rules.Type);
+		Rules("Method", rules.Method);
+		writer.WriteEndElement();
+	}
+
+	private void Rules(string type, RuleCollection rules) {				
+		foreach (IRule rule in rules) {
+			writer.WriteStartElement("rule");			
+			writer.WriteAttributeString("Type", type);
+			writer.WriteString(rule.GetType().FullName);
+			writer.WriteEndElement();
+		}
+		
+	}
+
+	public void Input(string assembly) {
+		writer.WriteElementString("input", assembly);
+	}
+
+	public void Info(string text, params object[] args) {
+		if (args != null)
+			text = string.Format(text, args);
+		writer.WriteElementString("info", text);
+	}
+
+	public void Error(string text, params object[] args) {
+		if (args != null)
+			text = string.Format(text, args);
+		writer.WriteElementString("error", text);
+	}
+
+	public void Write(string assembly, Violation v) {
+		RuleInformation ri = RuleInformationManager.GetRuleInformation (v.Rule);
+
+		writer.WriteStartElement("violation");		
+		writer.WriteAttributeString("Assembly", assembly);
+		writer.WriteAttributeString("Name", ri.Name);
+		writer.WriteAttributeString("Uri", ri.Uri);
+		writer.WriteElementString("problem", string.Format(ri.Problem, v.Violator));
+		writer.WriteElementString("solution", String.Format (ri.Solution, v.Violator));
+		
+		if(v.Messages != null && v.Messages.Count > 0) {
+			writer.WriteStartElement("messages");
+			foreach(Message message in v.Messages) {
+				writer.WriteStartElement("message");	
+				if (message.Location != null)
+					writer.WriteAttributeString("Location", message.Location.ToString());
+				writer.WriteAttributeString("Type", message.Type.ToString());
+				writer.WriteString(message.Text);
+				writer.WriteEndElement();
+			}
+			writer.WriteEndElement();
+		}
+
+		writer.WriteEndElement();
+	}
+}
+
+public class TextConsoleWriter : ConsoleWriter {
+
+	public void Info(string text, params object[] args) {
+		Console.Out.WriteLine(text, args);
+	}
+
+	public void Error(string text, params object[] args) {
+		Console.Error.WriteLine(text, args);
+	}
+
+	public void Rules(Rules rules) {
+		;
+	}
+
+	public void Dispose() {
+		;
+	}
+
+	private static int index = 0;
+
+	public void Input(string assembly) {
+		Console.WriteLine ("Assembly: {0}", assembly);
+	}
+
+	public void Write(string assembly, Violation v) {
+		RuleInformation ri = RuleInformationManager.GetRuleInformation (v.Rule);
+		Console.WriteLine ("{0}. {1}", ++index, ri.Name);
+		Console.WriteLine ();
+		Console.WriteLine ("Problem: {0}", String.Format (ri.Problem, v.Violator));
+		Console.WriteLine ();
+		if(v.Messages != null && v.Messages.Count > 0) {
+			Console.WriteLine ("Details:");
+			foreach(Message message in v.Messages) {
+				Console.WriteLine("  {0}", message);
+			}
+			Console.WriteLine ();
+		}
+		Console.WriteLine ("Solution: {0}", String.Format (ri.Solution, v.Violator));
+		Console.WriteLine ();
+		string url = ri.Uri;
+		if (url.Length > 0) {
+			Console.WriteLine ("More info available at: {0}", url);
+			Console.WriteLine ();
+		}
+		Console.WriteLine ();
+	}
+}
+
Index: framework/Runner.cs
===================================================================
--- framework/Runner.cs	(revision 64483)
+++ framework/Runner.cs	(working copy)
@@ -116,6 +116,8 @@
 
 		public void Process (IAssemblyDefinition assembly)
 		{
+			Violations.Reset();
+			
 			IList messages;
 			foreach (IAssemblyRule rule in Rules.Assembly) {
 				messages = rule.CheckAssembly(assembly, this);
Index: framework/Violations.cs
===================================================================
--- framework/Violations.cs	(revision 64483)
+++ framework/Violations.cs	(working copy)
@@ -32,7 +32,7 @@
 
 namespace Gendarme.Framework {
 
-	public class Violations {
+	public class Violations : IEnumerable {
 
 		private ArrayList list;
 
@@ -40,7 +40,7 @@
 		{
 		}
 
-		public IList List {
+		private IList List {
 			get {
 				if (list == null)
 					list = new ArrayList ();
@@ -48,6 +48,16 @@
 			}
 		}
 
+		public int Count {
+			get {
+				return List.Count; 
+			}
+		}
+		
+		public void Reset() {
+			list = null;
+		}
+		
 		public void Add (IRule rule, object obj, IList messages)
 		{
 			if (rule == null)
@@ -62,5 +72,11 @@
 		{
 			List.Add (v);
 		}
+		
+		public IEnumerator GetEnumerator ()
+		{
+				return List.GetEnumerator();
+		}
+		
 	}
 }


More information about the Mono-devel-list mailing list