[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