audit: Add gen-apidiff-html tool to generate apidiff reports

The gen-apidiff-html tool takes all apidiff files in a directory, merges
them and then applies mono-api.xsl to produce a nice HTML page that
shows the information about the API changes.

The various resources needed by the HTML page (images, CSS, javascript)
are added in the html/ directory.

This is all adapted from an older version of the tools in Mono git
master, under mcs/tools/corcompare.
This commit is contained in:
Bertrand Lorentz 2013-03-29 17:50:07 +01:00
parent 1eb786c735
commit 2a7d26a8b0
26 changed files with 1415 additions and 1 deletions

73
audit/gen-apidiff-html.cs Normal file
View file

@ -0,0 +1,73 @@
//
// gen-apidiff-html.cs - Converts a set of apidiff files to HTML by
// merging them and applying an XSL file.
//
// Author:
// Bertrand Lorentz (bertrand.lorentz@gmail.com)
//
// Copyright (C) 2013 Bertrand Lorentz
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.IO;
using System.Xml;
using System.Xml.Xsl;
namespace Mono.AssemblyCompare
{
public class Driver
{
static int Main (string [] args)
{
if (args.Length != 2) {
Console.WriteLine ("Usage: mono gen-apidiff-html.exe <diff_dir> <html_file>");
return 1;
}
string diff_dir = args[0];
string out_file = args[1];
var all = new XmlDocument ();
all.AppendChild(all.CreateElement ("assemblies"));
foreach (string file in Directory.EnumerateFiles(diff_dir, "*.apidiff")) {
Console.WriteLine ("Merging " + file);
var doc = new XmlDocument ();
doc.Load (file);
foreach (XmlNode child in doc.GetElementsByTagName ("assembly")) {
XmlNode imported = all.ImportNode (child, true);
all.DocumentElement.AppendChild (imported);
}
}
var transform = new XslCompiledTransform ();
transform.Load ("mono-api.xsl");
var writer = new StreamWriter (out_file);
Console.WriteLine (String.Format ("Transforming to {0}...", out_file));
transform.Transform (all.CreateNavigator (), null, writer);
writer.Close ();
return 0;
}
}
}

BIN
audit/html/c.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 B

213
audit/html/cormissing.css Normal file
View file

@ -0,0 +1,213 @@
.y IMG
{
border: 0px;
padding: 0px;
margin: 0px;
margin-right: 4px;
vertical-align: middle;
}
.a, .a_,
.y, .y_,
.n, .n_,
.c, .c_,
.c, .c_,
.d, .d_,
.en, .en_,
.i, .i_,
.s, .s_,
.e, .e_,
.f, .f_,
.m, .m_,
.o, .o_,
.p, .p_,
.r, .r_,
.x, .x_,
.w, .w_
{
FONT: 12px 'Verdana';
margin-left: 20px;
}
.y_ .n,
.y_ .n_,
.n_ .c,
.n_ .c_,
.n_ .s,
.n_ .s_,
.n_ .d,
.n_ .d_,
.n_ .en,
.n_ .en_,
.n_ .i,
.n_ .i_,
.c_ .c,
.c_ .c_,
.c_ .d,
.c_ .d_,
.c_ .e,
.c_ .e_,
.c_ .f,
.c_ .f_,
.c_ .m,
.c_ .m_,
.c_ .o,
.c_ .o_,
.c_ .en,
.c_ .en_,
.c_ .p,
.c_ .p_,
.c_ .r,
.c_ .r_,
.c_ .x,
.c_ .x_,
.c_ .i,
.c_ .i_,
.c_ .w,
.c_ .w_,
.d_ .c,
.d_ .c_,
.d_ .e,
.d_ .e_,
.d_ .f,
.d_ .f_,
.d_ .i,
.d_ .i_,
.d_ .m,
.d_ .m_,
.d_ .o,
.d_ .o_,
.d_ .p,
.d_ .p_,
.d_ .r,
.d_ .r_,
.d_ .x,
.d_ .x_,
.d_ .w,
.d_ .w_,
.e_ .m,
.e_ .m_,
.en_ .c,
.en_ .c_,
.en_ .e,
.en_ .e_,
.en_ .f,
.en_ .f_,
.en_ .i,
.en_ .i_,
.en_ .m,
.en_ .m_,
.en_ .o,
.en_ .o_,
.en_ .p,
.en_ .p_,
.en_ .r,
.en_ .r_,
.en_ .x,
.en_ .x_,
.en_ .w,
.en_ .w_,
.i_ .c,
.i_ .c_,
.i_ .e,
.i_ .e_,
.i_ .f,
.i_ .f_,
.i_ .m,
.i_ .m_,
.i_ .o,
.i_ .o_,
.i_ .p,
.i_ .p_,
.i_ .r,
.i_ .r_,
.i_ .x,
.i_ .x_,
.i_ .w,
.i_ .w_,
.i_ .i,
.i_ .i_,
.s_ .c,
.s_ .c_,
.s_ .e,
.s_ .e_,
.s_ .f,
.s_ .f_,
.s_ .m,
.s_ .m_,
.s_ .o,
.s_ .o_,
.s_ .p,
.s_ .p_,
.s_ .r,
.s_ .r_,
.s_ .s,
.s_ .s_,
.s_ .x,
.s_ .x_,
.s_ .i,
.s_ .i_,
.s_ .w,
.s_ .w_,
.x_ .a,
.x_ .a_,
.m_ .a,
.m_ .a_,
.e_ .r,
.e_ .r_,
.e_ .o,
.e_ .o_,
.f_ .r,
.f_ .r_,
.f_ .o,
.f_ .o_,
.m_ .r,
.m_ .r_,
.m_ .o,
.m_ .o_,
.o_ .r,
.o_ .r_,
.o_ .o,
.o_ .o_,
.o_ .a_,
.p_ .r,
.p_ .r_,
.p_ .o,
.p_ .o_,
.r_ .r,
.r_ .r_,
.r_ .o,
.r_ .o_,
.x_ .r,
.x_ .r_,
.x_ .o,
.x_ .o_
.w_ .r,
.w_ .r_,
.w_ .o,
.w_ .o_
{
display: none;
}
.t
{
cursor: pointer;
margin-right: 8px;
}
.filter
{
cursor: pointer;
vertical-align: middle;
}
.st
{
margin-left: 20px;
}
.l
{
cursor: pointer;
}

584
audit/html/cormissing.js Normal file
View file

@ -0,0 +1,584 @@
// FIXME:
// It still does not update icons previous to a type/member name when
// certain icon kinds are unchecked (when an item has "todo" and "missing",
// the default display is "missing" and when "missing" is unchecked it
// should turn into "todo").
function toggle (elt)
{
if (elt == null)
return;
var eltLink = firstElement (elt);
if (eltLink != null && eltLink.className == 't') // toggle
{
var ich = elt.className.indexOf ('_');
if (ich < 0)
{
eltLink.src = 'tp.gif';
elt.className += '_';
}
else
{
eltLink.src = 'tm.gif';
elt.className = elt.className.slice (0, ich);
}
}
}
function setView (elt, fView)
{
var eltLink = firstElement (elt);
if (eltLink != null && eltLink.className == 't') // toggle
{
var ich = elt.className.indexOf ('_');
if (ich < 0 && !fView)
{
eltLink.src = 'tp.gif';
elt.className += '_';
}
else if (ich >= 0 && fView)
{
eltLink.src = 'tm.gif';
elt.className = elt.className.slice (0, ich);
}
}
}
function firstElement (elt)
{
var c = elt.firstChild;
while (c != null) {
if (c.nodeType == 1) // Node.ELEMENT_NODE (IE6 does not recognize it)
return c;
c = c.nextSibling;
}
return null;
}
function trimSrc (strSrc)
{
return strSrc.slice (strSrc.lastIndexOf ('/') + 1, strSrc.lastIndexOf ('.'));
}
function getChildrenByTagName (elt, strTag)
{
strTag = strTag.toLowerCase ();
var rgChildren = new Array ();
var eltChild = firstElement (elt);
while (eltChild)
{
if (eltChild.tagName && eltChild.tagName.toLowerCase () == strTag)
rgChildren.push (eltChild);
eltChild = eltChild.nextSibling;
}
return rgChildren;
}
function viewAll (elt, dictTypes)
{
var fView = isShown (elt, dictTypes);
var aCounts = new Array (4);
for (i = 0; i < 4; i++)
aCounts [i] = 0;
var rgElts = getChildrenByTagName (elt, 'DIV');
for (iElt in rgElts) {
var aChildRet = viewAll (rgElts [iElt], dictTypes);
if (aChildRet != null) {
fView = true;
for (i = 0; i < 4; i++)
aCounts [i] += aChildRet [i];
}
}
elt.style.display = fView ? '' : 'none';
if (!fView)
return null;
rgShownDivs = getChildrenByTagName (elt, 'DIV');
for (i = 0; i < rgShownDivs.length; i++) {
var cDiv = rgShownDivs [i];
if (cDiv.style.display == 'none')
continue;
incrementCount (cDiv, aCounts, dictTypes);
}
// update the numbers
rgSpans = getChildrenByTagName (elt, 'SPAN');
for (iSpan in rgSpans) {
var cSpan = rgSpans [iSpan];
var cImage = firstElement (cSpan);
if (cImage == null)
continue;
switch (trimSrc (cImage.src)) {
case 'st': cSpan.lastChild.nodeValue = ": " + aCounts [0]; break;
case 'sm': cSpan.lastChild.nodeValue = ": " + aCounts [1]; break;
case 'sx': cSpan.lastChild.nodeValue = ": " + aCounts [2]; break;
case 'se': cSpan.lastChild.nodeValue = ": " + aCounts [3]; break;
}
}
return aCounts;
}
function isShown (elt, dictTypes)
{
if (!isShownMarkType (elt, dictTypes))
return false;
return true;
}
function isShownMarkType (elt, dictTypes)
{
var rgImages = getChildrenByTagName (elt, 'IMG');
var cImages = rgImages.length;
for (var iImage = 0; iImage < cImages; iImage++)
{
var strImage = trimSrc (rgImages [iImage].src);
if (dictTypes [strImage])
return true;
}
return false;
}
function incrementCount (cDiv, aCounts, dictTypes)
{
switch (cDiv.className) {
case 'y': case 'y_': // assembly
case 'n': case 'n_': // namespace
// types
case 'c': case 'c_': case 'i': case 'i_':
case 'en': case 'en_': case 'd': case 'd_':
// members
case 'r': case 'r_': case 'x': case 'x_': case 'm': case 'm_':
case 'f': case 'f_': case 'e': case 'e_': case 'p': case 'p_':
case 'o': case 'o_': case 'a': case 'a_':
var rgImgs = getChildrenByTagName (cDiv, 'IMG');
for (iImg = 0; iImg < rgImgs.length; iImg++) {
var cImg = rgImgs [iImg];
if (cImg.className != 't')
continue;
var stype = trimSrc (cImg.src);
if (!dictTypes [stype])
continue;
switch (stype) {
case "st": aCounts [0]++; break;
case "sm": aCounts [1]++; break;
case "sx": aCounts [2]++; break;
case "se": aCounts [3]++; break;
default:
continue;
}
break;
}
break;
}
}
/* just for debugging use now.
function firstInnerText (elt)
{
var s = elt.innerText;
if (s != null)
return s;
var n = elt.firstChild;
while (n != null) {
s = n.nodeValue;
if (s != null && s.replace (/^\s+/g, '') != '')
return s;
s = firstInnerText (n);
if (s != null)
return s;
n = n.nextSibling;
}
return s;
}
*/
function getView (elt)
{
var eltLink = firstElement (elt);
if (eltLink != null && eltLink.className == 't') // toggle
{
var ich = elt.className.indexOf ('_');
if (ich < 0)
return true;
}
return false;
}
function getParentDiv (elt)
{
if (elt)
{
do
{
elt = elt.parentNode;
}
while (elt && elt.tagName != 'DIV');
}
return elt;
}
function getName (elt)
{
var rgSpans = getChildrenByTagName (elt, 'SPAN');
for (var iSpan = 0; iSpan < rgSpans.length; iSpan ++)
{
var span = rgSpans [iSpan];
if (span.className == 'l') // label
{
if (span.innerText)
return span.innerText;
else
return span.firstChild.nodeValue;
}
}
return null;
}
function clickHandler (evt)
{
var elt;
if (document.layers)
elt = evt.taget;
else if (window.event && window.event.srcElement)
{
elt = window.event.srcElement;
evt = window.event;
}
else if (evt && evt.stopPropagation)
elt = evt.target;
if (!elt.className && elt.parentNode)
elt = elt.parentNode;
if (elt.className == 'l') // label
{
var strClass;
var strField;
var strNamespace;
var strAssembly;
var strFieldType;
elt = getParentDiv (elt);
var strEltClass = elt.className;
if (strEltClass.charAt (strEltClass.length - 1) == '_')
strEltClass = strEltClass.slice (0, strEltClass.length - 1);
if (strEltClass == 'x') // constructor
{
strField = 'ctor';
elt = getParentDiv (elt);
}
else
if (strEltClass == 'm' || // method
strEltClass == 'p' || // property
strEltClass == 'e' || // event
strEltClass == 'f') // field
{
strFieldType = strEltClass;
strField = getName (elt);
var match = strField.match ( /[\.A-Z0-9_]*/i );
if (match)
strField = match [0];
elt = getParentDiv (elt);
}
var strEltClass = elt.className;
if (strEltClass.charAt (strEltClass.length - 1) == '_')
strEltClass = strEltClass.slice (0, strEltClass.length - 1);
if (strEltClass == 'c' || // class
strEltClass == 's' || // struct
strEltClass == 'i' || // struct
strEltClass == 'd' || // delegate
strEltClass == 'en') // enum
{
strClass = getName (elt);
if (strEltClass == 'en')
strField = null;
elt = getParentDiv (elt);
}
var strEltClass = elt.className;
if (strEltClass.charAt (strEltClass.length - 1) == '_')
strEltClass = strEltClass.slice (0, strEltClass.length - 1);
if (strEltClass == 'n')
{
strNamespace = getName (elt);
elt = getParentDiv (elt);
}
var strEltClass = elt.className;
if (strEltClass.charAt (strEltClass.length - 1) == '_')
strEltClass = strEltClass.slice (0, strEltClass.length - 1);
if (strEltClass == 'y')
{
strAssembly = getName (elt);
}
if (evt.ctrlKey)
{
var strRoot = 'http://anonsvn.mono-project.com/viewcvs/trunk/mcs/class/';
var strExtra = '';
if (strAssembly)
{
if (strAssembly == 'mscorlib')
strAssembly = 'corlib';
else if (strAssembly == 'System.Xml')
strAssembly = 'System.XML';
strRoot = strRoot + strAssembly + '/';
if (strNamespace)
{
strRoot = strRoot + strNamespace + '/';
if (strClass)
{
strRoot += strClass + '.cs';
strExtra += '?view=markup';
}
}
window.open (strRoot + strExtra, 'CVS');
}
}
else if (strNamespace)
{
if (document.getElementById ('TargetMsdn1').checked)
{
var re = /\./g ;
strNamespace = strNamespace.toLowerCase ().replace (re, '');
if (strClass)
strNamespace += strClass.toLowerCase () + 'class';
if (strField)
strNamespace += strField;
if (strClass || strField)
strNamespace += 'topic';
window.open ('http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrf' + strNamespace + '.asp', 'MSDN');
}
else
{
if (strClass)
strNamespace += '.' + strClass;
if (strField)
strNamespace += '.' + strField;
if (document.getElementById ('TargetMonodoc').checked)
{
var category = null;
if (strClass == null)
category = "N:";
else if (strField == null)
category = "T:";
else {
switch (strFieldType) {
case 'f': category = "F:"; break;
case 'p': category = "P:"; break;
case 'm': category = "M:"; break;
case 'e': category = "E:"; break;
}
}
if (category != null)
window.open ('http://www.go-mono.com/docs/monodoc.ashx?link=' + category + strNamespace);
}
else
{
window.open ('http://msdn2.microsoft.com/library/' + strNamespace + '.aspx', 'MSDN');
}
}
}
}
else
{
if (elt.parentNode && elt.parentNode.className == 't') // toggle
elt = elt.parentNode;
else if (elt.className != 't') // toggle
return;
while (elt != null && elt.tagName != 'DIV')
elt = elt.parentNode;
if (evt.shiftKey)
{
var rgElts = getChildrenByTagName (elt, 'DIV');
var cElts = rgElts.length;
if (cElts != 0)
{
var fView = false;
var iElt;
for (iElt = 0; iElt < cElts; iElt ++)
{
if (getView (rgElts [iElt]))
{
fView = true;
break;
}
}
for (iElt = 0; iElt < cElts; iElt ++)
{
setView (rgElts [iElt], !fView);
}
}
}
else if (evt.ctrlKey)
{
setView (elt, true);
var eltParent = getParentDiv (elt);
while (eltParent)
{
var rgSiblings = getChildrenByTagName (eltParent, 'DIV');
var cSiblings = rgSiblings.length;
for (var iSibling = 0; iSibling < cSiblings; iSibling++)
{
var eltSibling = rgSiblings [iSibling];
if (eltSibling != elt)
{
setView (eltSibling, false);
}
}
elt = eltParent;
eltParent = getParentDiv (elt);
}
}
else
toggle (elt);
}
return false;
}
function filterTree ()
{
var eltMissing = document.getElementById ('missing');
var eltTodo = document.getElementById ('todo');
var eltExtra = document.getElementById ('extra');
var eltErrors = document.getElementById ('errors');
var eltStable = document.getElementById ('stable');
var dictTypes = new Object ();
if (eltMissing.checked)
dictTypes ['sm'] = true;
if (eltTodo.checked)
dictTypes ['st'] = true;
if (eltErrors.checked)
dictTypes ['se'] = true;
if (eltExtra.checked)
dictTypes ['sx'] = true;
if (eltStable.checked)
dictTypes ['sc'] = true;
viewAll (document.getElementById ('ROOT'), dictTypes);
}
function addAndFilter ()
{
var newInput = document.getElementById ('NewFilterTarget');
var newAttr = newInput.value;
if (newAttr.length > 0) {
var selection = document.getElementById ('FilteredAttributes');
var newElem = document.createElement ('option');
newElem.appendChild (document.createTextNode (newAttr));
selection.appendChild (newElem);
newInput.value = '';
filterTree ();
}
}
function removeAndFilter ()
{
var selection = document.getElementById ('FilteredAttributes');
if (selection.selectedIndex >= 0) {
var newInput = document.getElementById ('NewFilterTarget');
if (newInput.value.length == 0)
newInput.value = selection.options [selection.selectedIndex].firstChild.nodeValue;
selection.removeChild (selection.options [selection.selectedIndex]);
filterTree ();
}
}
function selectMissing ()
{
toggleFilter ('missing');
}
function selectTodo ()
{
toggleFilter ('todo');
}
function selectExtra ()
{
toggleFilter ('extra');
}
function selectErrors ()
{
toggleFilter ('errors');
}
function selectStable ()
{
toggleFilter ('stable');
}
function toggleAttributeFilter (attrName)
{
toggleFilter (attrName);
}
function toggleFilter (strFilter)
{
var eltTodo = document.getElementById ('todo');
var eltMissing = document.getElementById ('missing');
var eltExtra = document.getElementById ('extra');
var eltErrors = document.getElementById ('errors');
var eltToggle = document.getElementById (strFilter);
if (window && window.event && window.event.shiftKey)
{
eltMissing.checked = eltTodo.checked = eltExtra.checked = eltErrors.checked = false;
eltToggle.checked = true;
}
else
if (!eltTodo.checked && !eltMissing.checked && !eltExtra.checked && !eltErrors.checked)
{
eltMissing.checked = eltTodo.checked = eltExtra.checked = eltErrors.checked = true;
eltToggle.checked = false;
}
filterTree ();
}
function onLoad ()
{
var eltMissing = document.getElementById ('missing');
var eltTodo = document.getElementById ('todo');
var eltExtra = document.getElementById ('extra');
var eltErrors = document.getElementById ('errors');
eltMissing.checked = eltTodo.checked = eltExtra.checked = eltErrors.checked = true;
filterTree ();
}
if (document.layers)
{
document.captureEvents (Event.MOUSEUP);
document.onmouseup = clickHandler;
}
else if (document.attachEvent)
{
document.attachEvent('onclick', clickHandler);
}
else if (document.addEventListener)
{
document.addEventListener('click', clickHandler, false);
}
else
document.onclick = clickHandler;

BIN
audit/html/d.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 B

BIN
audit/html/e.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 861 B

BIN
audit/html/en.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 B

BIN
audit/html/f.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 B

BIN
audit/html/i.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 B

BIN
audit/html/m.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 B

BIN
audit/html/n.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 B

BIN
audit/html/p.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 B

BIN
audit/html/r.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 B

BIN
audit/html/s.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 B

BIN
audit/html/sc.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 B

BIN
audit/html/se.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 B

BIN
audit/html/sm.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 B

BIN
audit/html/st.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 B

BIN
audit/html/sx.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 B

BIN
audit/html/tb.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 B

BIN
audit/html/tm.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 B

BIN
audit/html/tp.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 B

BIN
audit/html/w.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 B

BIN
audit/html/y.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 B

View file

@ -7,7 +7,7 @@ COMMON_SOURCES = \
APIINFO_SOURCES = mono-api-info.cs $(COMMON_SOURCES) APIINFO_SOURCES = mono-api-info.cs $(COMMON_SOURCES)
all: extract-missing.exe mono-api-info.exe mono-api-diff.exe all: extract-missing.exe mono-api-info.exe mono-api-diff.exe gen-apidiff-html.exe
check: all check: all
rm -rf curr diff rm -rf curr diff
@ -24,6 +24,9 @@ mono-api-info.exe: $(APIINFO_SOURCES)
extract-missing.exe: extract-missing.cs extract-missing.exe: extract-missing.cs
$(MCS) extract-missing.cs $(MCS) extract-missing.cs
gen-apidiff-html.exe: gen-apidiff-html.cs
$(MCS) -out:$@ $^
clean: clean:
rm -f *.exe rm -f *.exe
rm -rf curr rm -rf curr

541
audit/mono-api.xsl Normal file
View file

@ -0,0 +1,541 @@
<?xml version="1.0" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" indent="yes"/>
<!-- <xsl:output method="xml"/>-->
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<HTML>
<HEAD>
<TITLE>
Gtk# API Status
</TITLE>
<SCRIPT src="cormissing.js"></SCRIPT>
<LINK rel="stylesheet" type="text/css" href="cormissing.css"></LINK>
</HEAD>
<BODY onLoad="onLoad();">
<P>
<H1>Gtk# API Status</H1>
</P>
<table>
<tr>
<td> <input type="checkbox" ID="todo" onClick="selectTodo()" checked="checked"/> </td>
<td> <img src="st.gif"/> </td>
<td> TODO </td>
<td width="20"/>
<td> <input type="checkbox" ID="missing" onClick="selectMissing()" checked="checked"/> </td>
<td> <img src="sm.gif"/> </td>
<td> Removed </td>
</tr>
<tr>
<td> <input type="checkbox" ID="extra" onClick="selectExtra()" checked="checked"/> </td>
<td> <img src="sx.gif"/> </td>
<td> Added </td>
<td width="20"/>
<td> <input type="checkbox" ID="errors" onClick="selectErrors()" checked="checked"/> </td>
<td> <img src="se.gif"/> </td>
<td> Changed </td>
</tr>
<tr>
<td> <input type="checkbox" ID="stable" onClick="selectStable()"/> </td>
<td> <img src="sc.gif"/> </td>
<td> Stable </td>
</tr>
</table>
<p></p>
<div ID="ROOT">
<xsl:apply-templates/>
</div>
<p>
Legend :<br/>
<table>
<tr>
<td> <img src="y.gif"/> </td>
<td> Assembly </td>
<td width="20"/>
<td> <img src="n.gif"/> </td>
<td> Namespace </td>
<td width="20"/>
<td> <img src="c.gif"/> </td>
<td> Class </td>
<td width="20"/>
<td> <img src="s.gif"/> </td>
<td> Struct </td>
<tr>
</tr>
<td> <img src="i.gif"/> </td>
<td> Interface </td>
<td width="20"/>
<td> <img src="d.gif"/> </td>
<td> Delegate </td>
<td width="20"/>
<td> <img src="en.gif"/> </td>
<td> Enum </td>
<td width="20"/>
<td> <img src="m.gif"/> </td>
<td> Method </td>
</tr>
<tr>
<td> <img src="f.gif"/> </td>
<td> Field </td>
<td width="20"/>
<td> <img src="p.gif"/> </td>
<td> Property </td>
<td width="20"/>
<td> <img src="e.gif"/> </td>
<td> Event </td>
<td width="20"/>
<td> <img src="r.gif"/> </td>
<td> Attribute </td>
</tr>
</table>
</p>
</BODY>
</HTML>
</xsl:template>
<!-- assembly -->
<xsl:template match="/assemblies">
<xsl:apply-templates select="assembly">
<xsl:sort select="@name"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="assembly">
<div>
<xsl:call-template name="ELEMENT">
<xsl:with-param name="class">y</xsl:with-param>
</xsl:call-template>
<xsl:if test="not(@presence)">
<xsl:apply-templates/>
</xsl:if>
</div>
</xsl:template>
<!-- namespace -->
<xsl:template match="namespaces">
<xsl:apply-templates select="namespace">
<xsl:sort select="@name"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="namespace">
<div>
<xsl:call-template name="ELEMENT">
<xsl:with-param name="class">n</xsl:with-param>
</xsl:call-template>
<xsl:if test="not(@presence)">
<xsl:apply-templates/>
</xsl:if>
</div>
</xsl:template>
<xsl:template match="namespace/classes">
<xsl:apply-templates />
</xsl:template>
<!-- class -->
<xsl:template match="class[@type='class']">
<div>
<xsl:call-template name="ELEMENT">
<xsl:with-param name="class">c</xsl:with-param>
</xsl:call-template>
<xsl:if test="(@missing_total or @todo_total or @extra_total or @warning_total or @error) and not(@presence)">
<xsl:apply-templates select="attributes"/>
<xsl:apply-templates select="interfaces"/>
<xsl:apply-templates select="constructors"/>
<xsl:apply-templates select="./*[local-name() != 'attributes' and local-name() != 'constructors' and local-name() != 'interfaces']"/>
</xsl:if>
</div>
</xsl:template>
<!-- struct -->
<xsl:template match="class[@type='struct'][@missing_total or @todo_total or @extra_total or @warning_total or @error or @presence]">
<div>
<xsl:call-template name="ELEMENT">
<xsl:with-param name="class">s</xsl:with-param>
</xsl:call-template>
<xsl:if test="not(@presence)">
<xsl:apply-templates/>
</xsl:if>
</div>
</xsl:template>
<!-- interface types -->
<xsl:template match="class[@type='interface']">
<xsl:apply-templates select="class[@type='interface']">
<xsl:sort select="@name"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="class[@type='interface'][@missing_total or @todo_total or @extra_total or @warning_total or @error or @presence]">
<div>
<xsl:call-template name="ELEMENT">
<xsl:with-param name="class">i</xsl:with-param>
</xsl:call-template>
<xsl:if test="not(@presence)">
<xsl:apply-templates/>
</xsl:if>
</div>
</xsl:template>
<!-- interfaces implemented by Types -->
<xsl:template match="interface">
<xsl:apply-templates select="interface">
<xsl:sort select="@name"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="interface[@missing_total or @todo_total or @extra_total or @warning_total or @error or @presence]">
<div>
<xsl:call-template name="ELEMENT">
<xsl:with-param name="class">i</xsl:with-param>
</xsl:call-template>
<xsl:if test="not(@presence)">
<xsl:apply-templates/>
</xsl:if>
</div>
</xsl:template>
<!-- generic constraints -->
<xsl:template match="generic-type-constraints">
<xsl:apply-templates select="generic-type-constraint">
<xsl:sort select="@name"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="generic-type-constraint[@missing_total or @todo_total or @extra_total or @warning_total or @error or @presence]">
<div>
<xsl:call-template name="ELEMENT">
<xsl:with-param name="class">w</xsl:with-param>
</xsl:call-template>
<xsl:if test="not(@presence)">
<xsl:apply-templates/>
</xsl:if>
</div>
</xsl:template>
<!-- delegate -->
<xsl:template match="class[@type='delegate'][@missing_total or @todo_total or @extra_total or @warning_total or @error or @presence]">
<div>
<xsl:call-template name="ELEMENT">
<xsl:with-param name="class">d</xsl:with-param>
</xsl:call-template>
<xsl:if test="not(@presence)">
<xsl:apply-templates/>
</xsl:if>
</div>
</xsl:template>
<!-- enumeration -->
<xsl:template match="class[@type='enum'][@missing_total or @todo_total or @extra_total or @warning_total or @error or @presence]">
<div>
<xsl:call-template name="ELEMENT">
<xsl:with-param name="class">en</xsl:with-param>
</xsl:call-template>
<xsl:if test="not(@presence)">
<xsl:apply-templates/>
</xsl:if>
</div>
</xsl:template>
<!-- method -->
<xsl:template match="methods">
<xsl:apply-templates select="method">
<xsl:sort select="@name"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="method[@missing_total or @todo_total or @extra_total or @warning_total or @error or @presence]">
<div>
<xsl:call-template name="ELEMENT">
<xsl:with-param name="class">m</xsl:with-param>
</xsl:call-template>
<xsl:if test="not(@presence)">
<xsl:apply-templates/>
</xsl:if>
</div>
</xsl:template>
<!-- property -->
<xsl:template match="properties">
<xsl:apply-templates select="property">
<xsl:sort select="@name"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="property[@missing_total or @todo_total or @extra_total or @warning_total or @error or @presence]">
<div>
<xsl:call-template name="ELEMENT">
<xsl:with-param name="class">p</xsl:with-param>
</xsl:call-template>
<xsl:if test="not(@presence)">
<xsl:apply-templates/>
</xsl:if>
</div>
</xsl:template>
<!-- event -->
<xsl:template match="events">
<xsl:apply-templates select="event">
<xsl:sort select="@name"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="event[@missing_total or @todo_total or @extra_total or @warning_total or @error or @presence]">
<div>
<xsl:call-template name="ELEMENT">
<xsl:with-param name="class">e</xsl:with-param>
</xsl:call-template>
<xsl:if test="not(@presence)">
<xsl:apply-templates/>
</xsl:if>
</div>
</xsl:template>
<!-- constructor -->
<xsl:template match="constructors">
<xsl:apply-templates select="constructor">
<xsl:sort select="@name"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="constructor[@missing_total or @todo_total or @extra_total or @warning_total or @error or @presence]">
<div>
<xsl:call-template name="ELEMENT">
<xsl:with-param name="class">x</xsl:with-param>
<xsl:with-param name="image">m</xsl:with-param>
</xsl:call-template>
<xsl:if test="not(@presence)">
<xsl:apply-templates/>
</xsl:if>
</div>
</xsl:template>
<!-- field -->
<xsl:template match="fields">
<xsl:apply-templates select="field">
<xsl:sort select="@name"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="field[@missing_total or @todo_total or @extra_total or @warning_total or @error or @presence]">
<div>
<xsl:call-template name="ELEMENT">
<xsl:with-param name="class">f</xsl:with-param>
</xsl:call-template>
<xsl:if test="not(@presence)">
<xsl:apply-templates/>
</xsl:if>
</div>
</xsl:template>
<!-- accessor -->
<xsl:template match="property/methods">
<xsl:apply-templates select="method">
<xsl:sort select="@name"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="property[@missing_total or @todo_total or @extra_total or @warning_total or @error or @presence]/methods/method[@missing_total or @todo_total or @extra_total or @warning_total or @error or @presence]">
<div>
<xsl:call-template name="ELEMENT">
<xsl:with-param name="class">o</xsl:with-param>
<xsl:with-param name="image">m</xsl:with-param>
</xsl:call-template>
<xsl:if test="not(@presence)">
<xsl:apply-templates/>
</xsl:if>
</div>
</xsl:template>
<!-- attribute -->
<xsl:template match="attributes">
<xsl:apply-templates select="attribute">
<xsl:sort select="@name"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="attribute[@missing_total or @todo_total or @extra_total or @warning_total or @error or @presence]">
<div>
<xsl:call-template name="ELEMENT">
<xsl:with-param name="class">r</xsl:with-param>
</xsl:call-template>
<xsl:if test="not(@presence)">
<xsl:apply-templates/>
</xsl:if>
</div>
</xsl:template>
<!-- nested classes -->
<xsl:template match="classes">
<xsl:apply-templates select="class[@type='interface']">
<xsl:sort select="@name"/>
</xsl:apply-templates>
<xsl:apply-templates select="class[@type='class']">
<xsl:sort select="@name"/>
</xsl:apply-templates>
<xsl:apply-templates select="class[@type='struct']">
<xsl:sort select="@name"/>
</xsl:apply-templates>
<xsl:apply-templates select="class[@type='delegate']">
<xsl:sort select="@name"/>
</xsl:apply-templates>
<xsl:apply-templates select="class[@type='enum']">
<xsl:sort select="@name"/>
</xsl:apply-templates>
</xsl:template>
<!-- support templates -->
<xsl:template name="ELEMENT">
<xsl:param name="class"/>
<xsl:param name="image"/>
<xsl:attribute name="class">
<xsl:value-of select="$class"/>
<xsl:if test="./node() and local-name() != 'assembly'">_</xsl:if>
</xsl:attribute>
<xsl:call-template name="toggle"/>
<xsl:choose>
<xsl:when test="@error and @error != 'todo'">
<xsl:element name="img">
<xsl:attribute name="src">se.gif</xsl:attribute>
<xsl:attribute name="class">t</xsl:attribute>
<xsl:attribute name="title"><xsl:call-template name="warning-hover" /></xsl:attribute>
</xsl:element>
</xsl:when>
<xsl:when test="@error = 'todo'">
<xsl:element name="img">
<xsl:attribute name="src">st.gif</xsl:attribute>
<xsl:attribute name="class">t</xsl:attribute>
<xsl:if test="@comment">
<xsl:attribute name="title"><xsl:value-of select="@comment"/></xsl:attribute>
</xsl:if>
<xsl:if test="not(@comment)">
<xsl:attribute name="title">No TODO description</xsl:attribute>
</xsl:if>
</xsl:element>
</xsl:when>
<xsl:when test="@presence = 'missing'">
<img src="sm.gif" class="t"/>
</xsl:when>
<xsl:when test="@presence = 'extra'">
<img src="sx.gif" class="t"/>
</xsl:when>
<xsl:otherwise>
<img src="sc.gif" class="t"/>
</xsl:otherwise>
</xsl:choose>
<xsl:choose>
<xsl:when test="$image">
<img src="{$image}.gif" class="t"/>
</xsl:when>
<xsl:otherwise>
<img src="{$class}.gif" class="t"/>
</xsl:otherwise>
</xsl:choose>
<xsl:call-template name="name"/>
<xsl:if test="not(@presence)">
<xsl:call-template name="status"/>
</xsl:if>
<xsl:call-template name="warning-text" />
<xsl:for-each select="parameters/parameter[warnings/warning]">
<div>
<xsl:call-template name="ELEMENT">
<xsl:with-param name="class">a</xsl:with-param>
<xsl:with-param name="image">tb</xsl:with-param>
</xsl:call-template>
</div>
</xsl:for-each>
</xsl:template>
<xsl:template name="status">
<xsl:if test="@complete_total and @complete_total != 0">
<span class="st">
<img src="sc.gif"/>
<xsl:text>: </xsl:text>
<xsl:value-of select="@complete_total"/>
<xsl:text>%</xsl:text>
</span>
</xsl:if>
<xsl:if test="@todo_total">
<span class="st">
<img src="st.gif"/>: <xsl:value-of select="@todo_total"/>
</span>
</xsl:if>
<xsl:if test="@missing_total">
<span class="st">
<img src="sm.gif"/>: <xsl:value-of select="@missing_total"/>
</span>
</xsl:if>
<xsl:if test="@extra_total">
<span class="st">
<img src="sx.gif"/>: <xsl:value-of select="@extra_total"/>
</span>
</xsl:if>
<xsl:if test="@warning_total">
<span class="st">
<img src="se.gif"/>: <xsl:value-of select="@warning_total"/>
</span>
</xsl:if>
</xsl:template>
<xsl:template name="toggle">
<xsl:choose>
<xsl:when test="not(@presence) and .//*[@missing_total or @todo_total or @extra_total or @warning_total or @error or @presence]">
<xsl:choose>
<xsl:when test="local-name() != 'assembly'">
<img src="tp.gif" class="t"/>
</xsl:when>
<xsl:otherwise>
<img src="tm.gif" class="t"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<img src="tb.gif"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="name">
<xsl:if test="@name">
<span class="l"><xsl:value-of select="@name"/></span>
</xsl:if>
</xsl:template>
<xsl:template name="warning-hover">
<xsl:for-each select="warnings/warning">
<xsl:text>WARNING: </xsl:text>
<xsl:value-of select="@text"/>
</xsl:for-each>
</xsl:template>
<xsl:template name="warning-text">
<xsl:for-each select="warnings/warning">
<img src="tb.gif"/>
<xsl:value-of select="@text"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>