[mdoc] Add "internal" 'mdoc x-msitomsx' command.
[mono.git] / mcs / tools / mdoc / Mono.Documentation / msitomsx.cs
1 //
2 // msitomsx.cs: Microsoft Internal XML to Microsoft XML Documentation
3 //
4 // Arguably this doesn't belong in mdoc, but I'd rather not do some
5 // stand-alone tool either, especially since the primary reason it exists is
6 // to facilitate generating ECMA documentation via mdoc-update and
7 // mdoc-update-ecma-xml...
8 //
9 // Author:
10 //   Jonathan Pryor  <jpryor@novell.com>
11 //
12 // Copyright (c) 2010 Novell, Inc. (http://www.novell.com)
13 //
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 //
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 //
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 //
33
34 using System;
35 using System.Collections.Generic;
36 using System.IO;
37 using System.Reflection;
38 using System.Text;
39 using System.Xml;
40 using System.Xml.Linq;
41 using System.Xml.Xsl;
42
43 using Mono.Options;
44
45 namespace Mono.Documentation {
46
47         class MsidocToMsxdocConverter : MDocCommand {
48
49                 XslCompiledTransform msiToMsxTransform = new XslCompiledTransform ();
50
51                 public MsidocToMsxdocConverter ()
52                 {
53                         using (var r = XmlReader.Create (
54                                                 Assembly.GetExecutingAssembly ().GetManifestResourceStream ("msitomsx.xsl")))
55                                 msiToMsxTransform.Load (r);
56                 }
57
58                 public override void Run (IEnumerable<string> args)
59                 {
60                         string current_library = "";
61
62                         var types = new List<string> ();
63                         string outdir = null;
64
65                         var options = new OptionSet () {
66                                 { "o|out=", 
67                                         "{DIRECTORY} to create Microsoft XML assembly.xml documentation files.",
68                                         v => outdir = v },
69                                 { "library=",
70                                         "Ignored for compatibility with update-ecma-xml.",
71                                         v => {} },
72                                 { "type=",
73                                         "The full {TYPE} name of a type to copy into the output file.",
74                                         v => types.Add (v) },
75                         };
76                         var sources = Parse (options, args, "export-ecma-xml", 
77                                         "[OPTIONS]+ DIRECTORIES",
78                                         "Convert Microsoft internal XML documentation within DIRECTORIES " +
79                                         "into Microsoft XML documentation.\n\n");
80                         if (sources == null)
81                                 return;
82                         if (sources.Count == 0)
83                                 Error ("No directories specified.");
84                         if (outdir == null)
85                                 Error ("No output directory specified.  Please use --out=DIRECTORY.");
86
87                         types.Sort ();
88
89                         Dictionary<string, XDocument> docs = Convert (sources, types);
90                         foreach (KeyValuePair<string, XDocument> e in docs) {
91                                 using (var o = CreateWriter (Path.Combine (outdir, e.Key + ".xml")))
92                                         e.Value.WriteTo (o);
93                         }
94                 }
95
96                 private Dictionary<string, XDocument> Convert (List<string> sources, List<string> types)
97                 {
98                         var docs = new Dictionary<string, XDocument> ();
99
100                         foreach (var source in sources) {
101                                 foreach (var dir in Directory.GetDirectories (source)) {
102                                         foreach (var file in Directory.GetFiles (dir, "*.xml")) {
103                                                 ConvertDocs (docs, types, file);
104                                         }
105                                 }
106                         }
107
108                         return docs;
109                 }
110
111                 private void ConvertDocs (Dictionary<string, XDocument> docs, List<string> types, string file)
112                 {
113                         var doc = LoadFile (file);
114                         var type = doc.Root.Element ("members").Element ("member").Attribute ("name").Value;
115
116                         if (type.StartsWith ("N:"))
117                                 return;
118
119                         if (!type.StartsWith ("T:"))
120                                 throw new InvalidOperationException ("File '" + file + "' doesn't contain type documentation, it contains docs for: " + type);
121
122                         type = type.Substring (2);
123                         if (types.Count > 0 && types.BinarySearch (type) < 0)
124                                 return;
125
126                         var assembly = doc.Root.Element ("assembly").Element ("name").Value;
127                         XDocument asmdocs;
128                         if (!docs.TryGetValue (assembly, out asmdocs)) {
129                                 docs.Add (assembly, 
130                                                 asmdocs = new XDocument (
131                                                         new XElement ("doc", 
132                                                                 new XElement ("members"))));
133                         }
134
135                         var import = new XDocument ();
136                         msiToMsxTransform.Transform (doc.CreateReader (), import.CreateWriter ());
137
138                         asmdocs.Root.Element ("members").Add (import.Root.Element ("members").Elements ("member"));
139                 }
140
141                 static XDocument LoadFile (string file)
142                 {
143                         using (XmlReader r = XmlReader.Create (file))
144                                 return XDocument.Load (r);
145                 }
146
147                 static XmlWriter CreateWriter (string file)
148                 {
149                         var settings = new XmlWriterSettings {
150                                 Encoding            = new UTF8Encoding (false),
151                                 Indent              = true,
152                                 IndentChars         = "    ",
153                                 NewLineChars        = "\r\n",
154                                 OmitXmlDeclaration  = true,
155                         };
156
157                         return XmlWriter.Create (file, settings);
158                 }
159         }
160 }
161