Skip to content

Commit

Permalink
[mono-api-html] Expand "ignore" functionality
Browse files Browse the repository at this point in the history
Context: dotnet/android#1078

xamarin-android uses `mono-api-html` and `mono-api-info` in order to
perform API comparisons; see e.g. 4e45904.

A recent problem has arisen regarding "inter-API-level diffs": there
are many API changes which we consider to be acceptable, and thus
would like to ignore. Unfortunately, `mono-api-html` doesn't support
ignoring many of these constructs, e.g. base class changes:

	<h3>Type Changed: Android.Preferences.CheckBoxPreference</h3>
	Modified base type: <span class='removed removed-inline removed-breaking-inline'>Android.Preferences.Preference</span> <span class='added '>Android.Preferences.TwoStatePreference</span>

and property type changes:

	<h3>Type Changed: Android.Views.InputEvent</h3>
	<p>Modified properties:</p>
	<pre>
	<div data-is-breaking>	public <span class='added added-breaking-inline'>abstract</span> int DeviceId { get; }
	</div><div data-is-breaking>	public <span class='added added-breaking-inline'>abstract</span> InputSourceType Source { get; }

Overhaul the `mono-api-html` "ignore" infrastructure:

  * Introduce ignore "scoping". Previously, the ignore options would
    only match the *member* text against any provided regular
    expression. Thus, `mono-api-html -r ToString` would ignore *all*
    members containing `ToString`. Furthermore, there was no way to
    restrict the ignore to a particular type. Expand the regex
    semantics so that the declaring type is used as a "prefix" for the
    to-be-matched text. For example, if a class `Example` is removed,
    `mono-api-html` will now match the following value against any
    `-r` regular expressions:

	Example: Removed type

  * Add a `mono-api-html -v` option, to control output verbosity.
    When specified, `mono-api-html` will print out available `-r`/etc.
    option values:

	$ mono-api-html expected.xml new.xml -v
	Possible -a value: Android.Resource: Added fields: public static const int AccessibilityEventTypes;
	Possible -r value: Android.Preferences.CheckBoxPreference: Modified base type: 'Android.Preferences.Preference' to 'Android.Preferences.TwoStatePreference'
	Possible -r value: Android.Views.InputEvent: Modified properties: public int DeviceId { get; }
	Possible -n value: Android.Views.UnavailableException: Added type
	...

Additionally, allow `mono-api-html` to take a
`Mono.Options.ResponseFileSource`, which allows `@response-files` to
be used as command-line options.
  • Loading branch information
jonpryor committed Feb 20, 2018
1 parent 0d51a80 commit a75d15b
Show file tree
Hide file tree
Showing 9 changed files with 53 additions and 13 deletions.
12 changes: 12 additions & 0 deletions mcs/tools/mono-api-html/ApiChange.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;

Expand All @@ -12,6 +13,12 @@ public class ApiChange
public bool Breaking;
public bool AnyChange;
public bool HasIgnoredChanges;
public string SourceDescription;

public ApiChange (string sourceDescription)
{
SourceDescription = sourceDescription;
}

public ApiChange Append (string text)
{
Expand Down Expand Up @@ -69,6 +76,11 @@ public void Add (XElement source, XElement target, ApiChange change)
return;
}

var changeDescription = $"{State.Namespace}.{State.Type}: {change.Header}: {change.SourceDescription}";
State.LogDebugMessage ($"Possible -r value: {changeDescription}");
if (State.IgnoreRemoved.Any (re => re.IsMatch (changeDescription)))
return;

List<ApiChange> list;
if (!TryGetValue (change.Header, out list)) {
list = new List<ApiChange> ();
Expand Down
14 changes: 13 additions & 1 deletion mcs/tools/mono-api-html/ApiDiff.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,15 @@ public static List<Regex> IgnoreRemoved {

public static bool Lax;
public static bool Colorize = true;

public static int Verbosity;

public static void LogDebugMessage (string value)
{
if (Verbosity == 0)
return;
Console.WriteLine (value);
}
}
class Program {

Expand Down Expand Up @@ -122,7 +131,10 @@ public static int Main (string[] args)
},
{ "c|colorize:", "Colorize HTML output", v => State.Colorize = string.IsNullOrEmpty (v) ? true : bool.Parse (v) },
{ "x|lax", "Ignore duplicate XML entries", v => State.Lax = true },
{ "ignore-nonbreaking", "Ignore all nonbreaking changes", v => State.IgnoreNonbreaking = true }
{ "ignore-nonbreaking", "Ignore all nonbreaking changes", v => State.IgnoreNonbreaking = true },
{ "v|verbose:", "Verbosity level; when set, will print debug messages",
(int? v) => State.Verbosity = v ?? (State.Verbosity + 1)},
new ResponseFileSource (),
};

try {
Expand Down
14 changes: 11 additions & 3 deletions mcs/tools/mono-api-html/ClassComparer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,9 @@ public void Compare (XElement source, XElement target)
public override void Added (XElement target, bool wasParentAdded)
{
string name = target.Attribute ("name").Value;
if (State.IgnoreNew.Any (re => re.IsMatch (name)))
var addedDescription = $"{State.Namespace}.{name}: Added type";
State.LogDebugMessage ($"Possible -n value: {addedDescription}");
if (State.IgnoreNew.Any (re => re.IsMatch (addedDescription)))
return;
Output.WriteLine ("<div> <!-- start type {0} -->", name);
Output.WriteLine ("<h3>New Type {0}.{1}</h3>", State.Namespace, name);
Expand Down Expand Up @@ -220,9 +222,13 @@ public override void Modified (XElement source, XElement target, ApiChanges diff

var sb = source.GetAttribute ("base");
var tb = target.GetAttribute ("base");
if (sb != tb && !(State.IgnoreNonbreaking && IsBaseChangeCompatible (sb, tb))) {
var rm = $"{State.Namespace}.{State.Type}: Modified base type: '{sb}' to '{tb}'";
State.LogDebugMessage ($"Possible -r value: {rm}");
if (sb != tb &&
!State.IgnoreRemoved.Any (re => re.IsMatch (rm)) &&
!(State.IgnoreNonbreaking && IsBaseChangeCompatible (sb, tb))) {
Output.Write ("Modified base type: ");
Output.WriteLine (new ApiChange ().AppendModified (sb, tb, true).Member.ToString ());
Output.WriteLine (new ApiChange ($"{State.Namespace}.{State.Type}").AppendModified (sb, tb, true).Member.ToString ());
}

ccomparer.Compare (source, target);
Expand Down Expand Up @@ -254,6 +260,8 @@ public override void Removed (XElement source)
{
string name = State.Namespace + "." + GetTypeName (source);

var memberDescription = $"{name}: Removed type";
State.LogDebugMessage ($"Possible -r value: {memberDescription}");
if (State.IgnoreRemoved.Any (re => re.IsMatch (name)))
return;

Expand Down
2 changes: 1 addition & 1 deletion mcs/tools/mono-api-html/ConstructorComparer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public override bool Equals (XElement source, XElement target, ApiChanges change
if (base.Equals (source, target, changes))
return true;

var change = new ApiChange ();
var change = new ApiChange (GetDescription (source));
change.Header = "Modified " + GroupName;
RenderMethodAttributes (source, target, change);
RenderReturnType (source, target, change);
Expand Down
2 changes: 1 addition & 1 deletion mcs/tools/mono-api-html/EventComparer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public override bool Equals (XElement source, XElement target, ApiChanges change
if (base.Equals (source, target, changes))
return true;

var change = new ApiChange ();
var change = new ApiChange (GetDescription (source));
change.Header = "Modified " + GroupName;
change.Append ("public event ");

Expand Down
2 changes: 1 addition & 1 deletion mcs/tools/mono-api-html/FieldComparer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ public override bool Equals (XElement source, XElement target, ApiChanges change
var name = source.GetAttribute ("name");
var srcValue = source.GetAttribute ("value");
var tgtValue = target.GetAttribute ("value");
var change = new ApiChange ();
var change = new ApiChange (GetDescription (source));
change.Header = "Modified " + GroupName;

if (State.BaseType == "System.Enum") {
Expand Down
10 changes: 7 additions & 3 deletions mcs/tools/mono-api-html/MemberComparer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,10 @@ void Add (IEnumerable<XElement> elements)
{
bool a = false;
foreach (var item in elements) {
var memberDescription = $"{State.Namespace}.{State.Type}: Added {GroupName}: {GetDescription (item)}";
State.LogDebugMessage ($"Possible -a value: {memberDescription}");
SetContext (item);
if (State.IgnoreAdded.Any (re => re.IsMatch (GetDescription (item))))
if (State.IgnoreAdded.Any (re => re.IsMatch (memberDescription)))
continue;
if (!a) {
BeforeAdding (elements);
Expand Down Expand Up @@ -159,7 +161,9 @@ void Remove (IEnumerable<XElement> elements)
{
bool r = false;
foreach (var item in elements) {
if (State.IgnoreRemoved.Any (re => re.IsMatch (GetDescription (item))))
var memberDescription = $"{State.Namespace}.{State.Type}: Removed {GroupName}: {GetDescription (item)}";
State.LogDebugMessage ($"Possible -r value: {memberDescription}");
if (State.IgnoreRemoved.Any (re => re.IsMatch (memberDescription)))
continue;
SetContext (item);
if (State.IgnoreNonbreaking && !IsBreakingRemoval (item))
Expand Down Expand Up @@ -597,7 +601,7 @@ protected void RenderAttributes (XElement source, XElement target, ApiChanges ch
if (srcObsolete == null) {
if (tgtObsolete == null)
return; // neither is obsolete
var change = new ApiChange ();
var change = new ApiChange (GetDescription (source));
change.Header = "Obsoleted " + GroupName;
change.Append (string.Format ("<span class='obsolete obsolete-{0}' data-is-non-breaking>", ElementName));
change.Append ("[Obsolete (");
Expand Down
8 changes: 6 additions & 2 deletions mcs/tools/mono-api-html/NamespaceComparer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@ public override void SetContext (XElement current)
public override void Added (XElement target, bool wasParentAdded)
{
string name = target.Attribute ("name").Value;
if (State.IgnoreNew.Any (re => re.IsMatch (name)))
var namespaceDescription = $"{name}: Added namespace";
State.LogDebugMessage ($"Possible -n value: {namespaceDescription}");
if (State.IgnoreNew.Any (re => re.IsMatch (namespaceDescription)))
return;

Output.WriteLine ("<!-- start namespace {0} --> <div> ", name);
Expand Down Expand Up @@ -92,7 +94,9 @@ public override void Removed (XElement source)
{
var name = source.Attribute ("name").Value;

if (State.IgnoreRemoved.Any (re => re.IsMatch (name)))
var namespaceDescription = $"{name}: Removed namespace";
State.LogDebugMessage ($"Possible -r value: {namespaceDescription}");
if (State.IgnoreRemoved.Any (re => re.IsMatch (namespaceDescription)))
return;

Output.WriteLine ("<!-- start namespace {0} --> <div>", name);
Expand Down
2 changes: 1 addition & 1 deletion mcs/tools/mono-api-html/PropertyComparer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ public override bool Equals (XElement source, XElement target, ApiChanges change
isIndexer = srcIndexers != null && srcIndexers.Count > 0;
}

var change = new ApiChange ();
var change = new ApiChange (GetDescription (source));
change.Header = "Modified " + GroupName;
RenderMethodAttributes (GetMethodAttributes (srcGetter, srcSetter), GetMethodAttributes (tgtGetter, tgtSetter), change);
RenderPropertyType (source, target, change);
Expand Down

0 comments on commit a75d15b

Please sign in to comment.