1 using System;
2 using System.Collections.Generic;
3 using System.Diagnostics;
4 using System.IO;
5 using System.Reflection;
6 using System.Xml;
7 using System.Xml.Schema;
8 
9 using Mono.Options;
10 
11 namespace Mono.Documentation
12 {
13 	public class MDocValidator : MDocCommand
14 	{
15 		XmlReaderSettings settings;
16 		long errors = 0;
17 
Run(IEnumerable<string> args)18 		public override void Run (IEnumerable<string> args)
19 		{
20 			string[] validFormats = {
21 				"ecma",
22 			};
23 			string format = "ecma";
24 			var p = new OptionSet () {
25 				{ "f|format=",
26 					"The documentation {0:FORMAT} used within PATHS.  " +
27 						"Valid formats include:\n  " +
28 						string.Join ("\n  ", validFormats) + "\n" +
29 						"If no format provided, `ecma' is used.",
30 					v => format = v },
31 			};
32 			List<string> files = Parse (p, args, "validate",
33 					"[OPTIONS]+ PATHS",
34 					"Validate PATHS against the specified format schema.");
35 			if (files == null)
36 				return;
37 			if (Array.IndexOf (validFormats, format) < 0)
38 				Error ("Invalid documentation format: {0}.", format);
39 			Run (format, files);
40 		}
41 
Run(string format, IEnumerable<string> files)42 		public void Run (string format, IEnumerable<string> files)
43 		{
44 			Stream s = null;
45 
46 			switch (format) {
47 				case "ecma":
48 					s = Assembly.GetExecutingAssembly ().GetManifestResourceStream ("monodoc-ecma.xsd");
49 					break;
50 
51 				default:
52 					throw new NotSupportedException (string.Format ("The format `{0}' is not suppoted.", format));
53 			}
54 
55 			if (s == null)
56 				throw new NotSupportedException (string.Format ("The schema for `{0}' was not found.", format));
57 
58 			settings = new XmlReaderSettings ();
59 			settings.Schemas.Add (XmlSchema.Read (s, null));
60 			settings.Schemas.Compile ();
61 			settings.ValidationType = ValidationType.Schema;
62 			settings.ValidationEventHandler += OnValidationEvent;
63 
64 			// skip args[0] because it is the provider name
65 			foreach (string arg in files) {
66 				if (IsMonodocFile (arg))
67 					ValidateFile (arg);
68 
69 				if (Directory.Exists (arg))
70 				{
71 					RecurseDirectory (arg);
72 				}
73 			}
74 
75 			Message (errors == 0 ? TraceLevel.Info : TraceLevel.Error,
76 					"Total validation errors: {0}", errors);
77 		}
78 
ValidateFile(string file)79 		void ValidateFile (string file)
80 		{
81 			try {
82 				using (var reader = XmlReader.Create (new XmlTextReader (file), settings)) {
83 					while (reader.Read ()) {
84 						// do nothing
85 					}
86 				}
87 			}
88 			catch (Exception e) {
89 				Message (TraceLevel.Error, "mdoc: {0}", e.ToString ());
90 			}
91 		}
92 
RecurseDirectory(string dir)93 		void RecurseDirectory (string dir)
94 		{
95 			string[] files = Directory.GetFiles (dir, "*.xml");
96 			foreach (string f in files)
97 			{
98 				if (IsMonodocFile (f))
99 					ValidateFile (f);
100 			}
101 
102 			string[] dirs = Directory.GetDirectories (dir);
103 			foreach (string d in dirs)
104 				RecurseDirectory (d);
105 		}
106 
OnValidationEvent(object sender, ValidationEventArgs a)107 		void OnValidationEvent (object sender, ValidationEventArgs a)
108 		{
109 			errors ++;
110 			Message (TraceLevel.Error, "mdoc: {0}", a.Message);
111 		}
112 
IsMonodocFile(string file)113 		static bool IsMonodocFile (string file)
114 		{
115 				if (File.Exists (file) && Path.GetExtension (file).ToLower () == ".xml")
116 					return true;
117 				else
118 					return false;
119 
120 		}
121 	}
122 }
123 
124