mono-api-html: ignore members using regex, add detailed help
[mono.git] / mcs / tools / corcompare / mono-api-html / ApiDiff.cs
1 //
2 // The main differences with mono-api-diff are:
3 // * this tool directly produce HTML similar to gdiff.sh used for Xamarin.iOS
4 // * this tool reports changes in an "evolutionary" way, not in a breaking way,
5 //   i.e. it does not assume the source assembly is right (but simply older)
6 // * the diff .xml output was not easy to convert back into the HTML format
7 //   that gdiff.sh produced
8 // 
9 // Authors
10 //    Sebastien Pouliot  <sebastien@xamarin.com>
11 //
12 // Copyright 2013 Xamarin Inc. http://www.xamarin.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.IO;
36 using System.Collections.Generic;
37 using System.Text.RegularExpressions;
38
39 using Mono.Options;
40
41 namespace Xamarin.ApiDiff {
42
43         public static class State {
44                 static TextWriter output;
45
46                 public static TextWriter Output { 
47                         get {
48                                 if (output == null)
49                                         output = Console.Out;
50                                 return output;
51                         }
52                         set { output = value; } 
53                 }
54
55                 public static string Assembly { get; set; }
56                 public static string Namespace { get; set; }
57                 public static string Type { get; set; }
58                 public static string BaseType { get; set; }
59
60                 public static int Indent { get; set; }
61
62                 static List<Regex> ignoreAdded = new List<Regex> ();
63                 public static List<Regex> IgnoreAdded {
64                         get { return ignoreAdded; }
65                 }
66         }
67
68         class Program {
69
70                 public static int Main (string[] args)
71                 {
72                         var showHelp = false;
73                         string diff = null;
74                         List<string> extra = null;
75
76                         var options = new OptionSet {
77                                 { "h|help", "Show this help", v => showHelp = true },
78                                 { "d|diff=", "HTML diff file out output (omit for stdout)", v => diff = v },
79                                 { "i|ignore-added=", "Ignore added members whose description matches a given C# regular expression (see below).",
80                                         v => State.IgnoreAdded.Add (new Regex (v))
81                                 }
82                         };
83
84                         try {
85                                 extra = options.Parse (args);
86                         } catch (OptionException e) {
87                                 Console.WriteLine ("Option error: {0}", e.Message);
88                                 showHelp = true;
89                         }
90
91                         if (showHelp || extra == null || extra.Count < 2 || extra.Count > 3) {
92                                 Console.WriteLine (@"Usage: mono-api-html [options] <reference.xml> <assembly.xml> [diff.html]");
93                                 Console.WriteLine ();
94                                 Console.WriteLine ("Available options:");
95                                 options.WriteOptionDescriptions (Console.Out);
96                                 Console.WriteLine ();
97                                 Console.WriteLine ("Ignoring Members:");
98                                 Console.WriteLine ();
99                                 Console.WriteLine ("  Members that were added can be filtered out of the diff by using the");
100                                 Console.WriteLine ("  -i, --ignore-added option. The option takes a C# regular expression");
101                                 Console.WriteLine ("  to match against member descriptions. For example, to ignore the");
102                                 Console.WriteLine ("  introduction of the interfaces 'INSCopying' and 'INSCoding' on types");
103                                 Console.WriteLine ("  pass the following to mono-api-html:");
104                                 Console.WriteLine ();
105                                 Console.WriteLine ("    mono-api-html ... -i 'INSCopying$' -i 'INSCoding$'");
106                                 Console.WriteLine ();
107                                 Console.WriteLine ("  The regular expressions will match any member description ending with");
108                                 Console.WriteLine ("  'INSCopying' or 'INSCoding'.");
109                                 Console.WriteLine ();
110                                 return 1;
111                         }
112
113                         var input = extra [0];
114                         var output = extra [1];
115                         if (extra.Count == 3 && diff == null)
116                                 diff = extra [2];
117
118                         try {
119                                 var ac = new AssemblyComparer (input, output);
120                                 if (diff != null) {
121                                         string diffHtml = String.Empty;
122                                         using (var writer = new StringWriter ()) {
123                                                 State.Output = writer;
124                                                 ac.Compare ();
125                                                 diffHtml = State.Output.ToString ();
126                                         }
127                                         if (diffHtml.Length > 0) {
128                                                 using (var file = new StreamWriter (diff)) {
129                                                         if (ac.SourceAssembly == ac.TargetAssembly) {
130                                                                 file.WriteLine ("<h1>{0}.dll</h1>", ac.SourceAssembly);
131                                                         } else {
132                                                                 file.WriteLine ("<h1>{0}.dll vs {1}.dll</h1>", ac.SourceAssembly, ac.TargetAssembly);
133                                                         }
134                                                         file.Write (diffHtml);
135                                                 }
136                                         }
137                                 } else {
138                                         State.Output = Console.Out;
139                                         ac.Compare ();
140                                 }
141                         }
142                         catch (Exception e) {
143                                 Console.WriteLine (e);
144                                 return 1;
145                         }
146                         return 0;
147                 }
148         }
149 }