diff options
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | doc/templates/devhelp.devhelp2 | 18 | ||||
-rw-r--r-- | doc/templates/errors.html | 60 | ||||
-rw-r--r-- | doc/templates/fullindex.html | 60 | ||||
-rw-r--r-- | doc/templates/generic-types.html | 59 | ||||
-rw-r--r-- | doc/templates/index.html | 66 | ||||
-rw-r--r-- | doc/templates/interface.html | 424 | ||||
-rw-r--r-- | doc/templates/interfaces.html | 50 | ||||
-rw-r--r-- | doc/templates/style.css | 224 | ||||
-rw-r--r-- | extensions/Logger.xml (renamed from extensions/Telepathy_Logger.xml) | 39 | ||||
-rw-r--r-- | extensions/Makefile.am | 42 | ||||
-rw-r--r-- | extensions/all.xml | 129 | ||||
-rw-r--r-- | extensions/extensions.c | 5 | ||||
-rw-r--r-- | extensions/extensions.h | 15 | ||||
-rwxr-xr-x | tools/doc-generator.py | 104 | ||||
-rw-r--r-- | tools/identity.xsl | 7 | ||||
-rw-r--r-- | tools/specparser.py | 885 |
19 files changed, 2024 insertions, 168 deletions
@@ -50,7 +50,7 @@ telepathy-logger/libtelepathy-logger.pc telepathy-logger/libtelepathy-logger-uninstalled.pc extensions/_gen/ -extensions/extensions.html +extensions/doc/ tests/test-*[^ch] tests/twisted/telepathy-logger-debug tests/twisted/tools/org.freedesktop.Telepathy.Client.TelepathyLogger.service diff --git a/Makefile.am b/Makefile.am index 15a8471..fa54155 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = tools telepathy-logger data src tests doc +SUBDIRS = tools extensions telepathy-logger data src tests doc ACLOCAL_AMFLAGS = -I m4 diff --git a/configure.ac b/configure.ac index 352362b..e6f99ea 100644 --- a/configure.ac +++ b/configure.ac @@ -221,6 +221,7 @@ AC_OUTPUT([ doc/Makefile doc/reference/Makefile doc/reference/libtelepathy-logger/Makefile + extensions/Makefile src/Makefile telepathy-logger/Makefile telepathy-logger/libtelepathy-logger.pc diff --git a/doc/templates/devhelp.devhelp2 b/doc/templates/devhelp.devhelp2 new file mode 100644 index 0000000..af327fa --- /dev/null +++ b/doc/templates/devhelp.devhelp2 @@ -0,0 +1,18 @@ +<?xml version="1.0"?> +<book xmlns="http://www.devhelp.net/book" title="$spec.title" name="$name" link="index.html"> + <chapters> +#for $interface in $spec.interfaces + <sub name="$interface.name" link="$interface.get_url()"/> +#end for + <sub name="Generic Types" link="generic-types.html"/> + <sub name="Errors" link="errors.html"/> + <sub name="Full Index" link="fullindex.html"/> + </chapters> + <functions> +#for $obj in $spec.everything.values() + $spec.types.values() + $spec.errors.values() + <keyword type="$obj.devhelp_name" name="$obj.get_title()" link="$obj.get_url()" #slurp +#if $obj.deprecated: deprecated="true" #slurp +/> +#end for + </functions> +</book> diff --git a/doc/templates/errors.html b/doc/templates/errors.html new file mode 100644 index 0000000..907d660 --- /dev/null +++ b/doc/templates/errors.html @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE html PUBLIC "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd" ""> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> + <head> + <title>Errors</title> + <link rel="stylesheet" href="style.css" type="text/css"/> + </head> + <body> + <div class="header"> + <h1>Errors</h1> + <a href="index.html">Interface Index</a> + (<a href="interfaces.html">Compact</a>) + | <a href="#summary">Summary</a> + | <a href="#errors">Errors</a> + </div> + <div class="main"> + <div class="summary"> + <a name="summary"></a> + <h3>Errors</h3> + <table class="summary"> + #for $error in $spec.errors.values() + #if $error.deprecated + <tr class="deprecated"> + #else + <tr> + #end if + <td><a href="$error.get_url()">$error.short_name</a></td> + <td> + #if $error.deprecated: (deprecated) + </td> + </tr> + #end for + </table> + </div> + + <div class="outset errors error"> + <a name="errors"></a> + <h1>Errors</h1> + #for $error in $spec.errors.values() + <div class="inset error"> + <a name="$error.name"></a> + <span class="permalink">(<a href="$error.get_url()">Permalink</a>)</span> + <h2> + $error.short_name + </h2> + + <div class="indent"> + <code>$error.name</code> + </div> + + $error.get_added() + $error.get_deprecated() + $error.get_docstring() + </div> + #end for + </div> + </div> + + </body> +</html> diff --git a/doc/templates/fullindex.html b/doc/templates/fullindex.html new file mode 100644 index 0000000..2c465e1 --- /dev/null +++ b/doc/templates/fullindex.html @@ -0,0 +1,60 @@ +#from itertools import groupby +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE html PUBLIC "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd" ""> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> + <head> + <title>Full Index</title> + <link rel="stylesheet" href="style.css" type="text/css"/> + </head> + +#set $star = [] +#for $item in $spec.everything.values() + $spec.errors.values() + $spec.generic_types + #echo $star.append(($item.short_name, $item)) + #slurp +#end for +#echo $star.sort(key = lambda t: t[0].title()) +#slurp +## one use iterators... +#set $groups = [ (l, list(g)) for l, g in (groupby($star, key = lambda t: t[0][0].upper())) ] +#set $letters = set(map(lambda t: t[0], groups)) + + <body> + <div class="header"> + <h1>Full Index</h1> + <a href="index.html">Interface Index</a> + (<a href="interfaces.html">Compact</a>) + #for $a in map(chr, xrange(ord('A'), ord('Z')+1)) + #if $a in $letters + | <a href="#$a">$a</a> + #else + | $a + #end if + #end for + </div> + + <div class="main"> + <table class="summary"> + #for l, g in $groups + <tr><th colspan="3"><a name="$l"></a>$l</th></tr> + #for $n in $g + #if $n[1].deprecated + <tr class="deprecated"> + #else + <tr> + #end if + <td> + <a href="$n[1].get_url()" title="$n[1].get_title()">$n[0]</a> + #if $n[1].deprecated: (deprecated) + </td> + <td>$n[1].get_type_name()</td> + <td> + #if $n[1].parent.__class__.__name__ == 'Interface': $n[1].parent.name + </td> + </tr> + #end for + #end for + <table> + </div> + + </body> +</html> diff --git a/doc/templates/generic-types.html b/doc/templates/generic-types.html new file mode 100644 index 0000000..0bb209e --- /dev/null +++ b/doc/templates/generic-types.html @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE html PUBLIC "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd" ""> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> + <head> + <title>Generic Types</title> + <link rel="stylesheet" href="style.css" type="text/css"/> + </head> + <body> + <div class="header"> + <h1>Generic Types</h1> + <a href="index.html">Interface Index</a> + (<a href="interfaces.html">Compact</a>) + | <a href="#summary">Summary</a> + | <a href="#types">Types</a> + </div> + <div class="main"> + <div class="summary"> + <a name="summary"></a> + <h3>Generic Types</h3> + <table class="summary"> + #for $type in $spec.generic_types + #if $type.deprecated + <tr class="deprecated"> + #else + <tr> + #end if + <td><a href="$type.get_url()">$type.short_name</a></td> + <td>$type.get_type_name()</td> + <td>$type.dbus_type</td> + <td> + #if $type.deprecated: (deprecated) + </td> + </tr> + #end for + </table> + </div> + + <div class="outset types type"> + <a name="types"></a> + <h1>Generic Types</h1> + #for $type in $spec.generic_types + <div class="inset type"> + <a name="$type.name"></a> + <span class="permalink">$type.get_type_name() (<a href="$type.get_url()">Permalink</a>)</span> + <h2> + $type.short_name — $type.dbus_type + </h2> + + $type.get_added() + $type.get_deprecated() + $type.get_docstring() + $type.get_breakdown() + </div> + #end for + </div> + </div> + + </body> +</html> diff --git a/doc/templates/index.html b/doc/templates/index.html new file mode 100644 index 0000000..efc38d4 --- /dev/null +++ b/doc/templates/index.html @@ -0,0 +1,66 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE html PUBLIC "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd" ""> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> + <head> + <title>$spec.title &mdash v$spec.version</title> + <link rel="stylesheet" href="style.css" type="text/css"/> + </head> + <body> + <div class="header"> + <h1>$spec.title</h1> + <a href="#interfaces">Interfaces</a> + (<a href="interfaces.html">Compact</a>) + | <a href="generic-types.html">Generic Types</a> + | <a href="errors.html">Errors</a> + | <a href="fullindex.html">Full Index</a> + </div> + + <div class="main"> + <h3 class="version">Version $spec.version</h3> + <p class="copyrights"> + #echo '<br/>'.join($spec.copyrights) + </p> + $spec.license + + <a name="interfaces"></a> + <h3>Interfaces</h3> + <ul> + #def output($items) + #for $item in $items + #if $item.__class__.__name__ == 'Section' + <li class="chapter">$item.short_name</li> + $item.get_docstring() + <ul> + $output($item.items) + </ul> + #else + #if $item.causes_havoc + <li class="causes-havoc"> + #elif $item.deprecated + <li class="deprecated"> + #else + <li> + #end if + <a href="$item.get_url()">$item.name</a> + #if $item.causes_havoc + (unstable) + #elif $item.deprecated + (deprecated) + #end if + </li> + #end if + #end for + #end def + $output($spec.items) + </ul> + + <a name="other"></a> + <h3>Other</h3> + <ul> + <li><a href="generic-types.html">Generic Types</a></li> + <li><a href="errors.html">Errors</a></li> + </ul> + + </div> + </body> +</html> diff --git a/doc/templates/interface.html b/doc/templates/interface.html new file mode 100644 index 0000000..79c35b2 --- /dev/null +++ b/doc/templates/interface.html @@ -0,0 +1,424 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE html PUBLIC "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd" ""> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> + <head> + <title>$interface.name</title> + <link rel="stylesheet" href="style.css" type="text/css"/> + </head> + <body> + <div class="header"> + <h1>Interface $interface.name</h1> + <a href="index.html">Interface Index</a> + (<a href="interfaces.html">Compact</a>) + | <a href="#summary">Summary</a> + #if $interface.docstring: | <a href="#description">Description</a> + #if $interface.methods: | <a href="#methods">Methods</a> + #if $interface.signals: | <a href="#signals">Signals</a> + #if $interface.properties: | <a href="#properties">Properties</a> + #if $interface.tpproperties: | <a href="#tpproperties">Telepathy Properties</a> + #if $interface.contact_attributes: | <a href="#contact-attributes">Contact Attributes</a> + #if $interface.handler_capability_tokens: | <a href="#handler-capability-tokens">Handler Capability Tokens</a> + #if $interface.types: | <a href="#types">Types</a> + </div> + <div class="main"> + + #if $interface.methods or $interface.signals or $interface.properties or $interface.types or $interface.tpproperties + <div class="summary"> + <a name="summary"></a> + #if $interface.methods + <h3>Methods</h3> + <table class="summary"> + #for $method in $interface.methods + #if $method.deprecated + <tr class="deprecated"> + #else + <tr> + #end if + <td><a href="$method.get_url()">$method.short_name</a></td> + <td>($method.get_in_args())</td> + <td>→</td> + <td>$method.get_out_args()</td> + <td> + #if $method.deprecated: (deprecated) + </td> + </tr> + #end for + </table> + #end if + + #if $interface.signals + <h3>Signals</h3> + <table class="summary"> + #for $signal in $interface.signals + #if $signal.deprecated + <tr class="deprecated"> + #else + <tr> + #end if + <td><a href="$signal.get_url()">$signal.short_name</a></td> + <td>($signal.get_args())</td> + <td> + #if $signal.deprecated: (deprecated) + </td> + </tr> + #end for + </table> + #end if + + #if $interface.properties + <h3>Properties</h3> + <table class="summary"> + #for $property in $interface.properties + #if $property.deprecated + <tr class="deprecated"> + #else + <tr> + #end if + <td><a href="$property.get_url()">$property.short_name</a></td> + <td> + $property.dbus_type + #if $property.type: (<a href="$property.get_type_url()" title="$property.get_type_title()">$property.get_type().short_name</a>) + </td> + <td>$property.get_access()</td> + <td> + #if $property.deprecated: (deprecated) + </td> + </tr> + #end for + </table> + #end if + + #if $interface.tpproperties + <h3>Telepathy Properties</h3> + <table class="summary"> + #for $property in $interface.tpproperties + <tr class="deprecated"> + <td><a href="$property.get_url()">$property.short_name</a></td> + <td> + $property.dbus_type + #if $property.type: (<a href="$property.get_type_url()" title="$property.get_type_title()">$property.get_type().short_name</a>) + </td> + </tr> + #end for + </table> + #end if + + #if $interface.contact_attributes + <h3>Contact Attributes</h3> + <table class="summary"> + #for $token in $interface.contact_attributes + <tr class="contact-attribute"> + <td><a href="$token.get_url()">$token.name</a></td> + <td> + $token.dbus_type + #if $token.type: (<a href="$token.get_type_url()" title="$token.get_type_title()">$token.get_type().short_name</a>) + </td> + </tr> + #end for + </table> + #end if + + #if $interface.handler_capability_tokens + <h3>Handler Capability Tokens</h3> + <table class="summary"> + #for $token in $interface.handler_capability_tokens + <tr class="handler-capability-token"> + <td><a href="$token.get_url()">$token.name</a> + #if $token.is_family + (etc.) + #end if + </td> + <td> + </td> + </tr> + #end for + </table> + #end if + + #if $interface.types + <h3>Types</h3> + <table class="summary"> + #for $type in $interface.types + #if type.deprecated + <tr class="deprecated"> + #else + <tr> + #end if + <td><a href="$type.get_url()">$type.short_name</a></td> + <td>$type.get_type_name()</td> + <td>$type.dbus_type</td> + <td> + #if $type.deprecated: (deprecated) + </td> + </tr> + #end for + </table> + #end if + </div> + #end if + + #if $interface.causes_havoc + <div class="havoc"><span class="warning">WARNING:</span> + This interface is $interface.causes_havoc and is likely to cause havoc + to your API/ABI if bindings are generated. Do not include this interface + in libraries that care about compatibility. + </div> + #end if + $interface.get_added() + $interface.get_changed() + $interface.get_deprecated() + + #if $interface.requires + <div class="requires"> + Objects implementing this interface must also implement: + <ul> + #for $req in $interface.get_requires() + <li><a href="$req.get_url()" title="$req.get_title()">$req.name</a></li> + #end for + </ul> + </div> + #end if + + #if $interface.docstring + <a name="description"></a> + <h3>Description</h3> + $interface.get_docstring() + #end if + + #if $interface.methods + <div class="outset methods method"> + <a name="methods"></a> + <h1>Methods</h1> + #for $method in $interface.methods + <div class="inset method"> + <a name="$method.name"></a> + <span class="permalink">(<a href="$method.get_url()">Permalink</a>)</span> + <h2>$method.short_name ($method.get_in_args()) → $method.get_out_args()</h2> + + $method.get_added() + $method.get_changed() + $method.get_deprecated() + + #if $method.in_args + <div class="indent"> + <h3>Parameters</h3> + <ul> + #for $arg in $method.in_args + <li> + $arg.short_name — $arg.dbus_type + #if $arg.get_type(): (<a href="$arg.get_type_url()" title="$arg.get_type_title()">$arg.get_type().short_name</a>) + </li> + $arg.get_added() + $arg.get_changed() + $arg.get_deprecated() + $arg.get_docstring() + #end for + </ul> + </div> + #end if + + #if $method.out_args + <div class="indent"> + <h3>Returns</h3> + <ul> + #for $arg in $method.out_args + <li> + $arg.short_name — $arg.dbus_type + #if $arg.get_type(): (<a href="$arg.get_type_url()" title="$arg.get_type_title()">$arg.get_type().short_name</a>) + </li> + $arg.get_added() + $arg.get_changed() + $arg.get_deprecated() + $arg.get_docstring() + #end for + </ul> + </div> + #end if + + $method.get_docstring() + + #if $method.possible_errors + <hr/> + <div class="indent"> + <h3>Possible Errors</h3> + <ul> + #for $error in $method.possible_errors + <li><a href="$error.get_url()" title="$error.get_title()">$error.get_error().short_name</a></li> + $error.get_added() + $error.get_changed() + $error.get_deprecated() + $error.get_docstring() + #end for + </ul> + </div> + #end if + </div> + #end for + </div> + #end if + + #if $interface.signals + <div class="outset signals signal"> + <a name="signals"></a> + <h1>Signals</h1> + #for $signal in $interface.signals + <div class="inset signal"> + <a name="$signal.name"></a> + <span class="permalink">(<a href="$signal.get_url()">Permalink</a>)</span> + <h2>$signal.short_name ($signal.get_args())</h2> + + $signal.get_added() + $signal.get_changed() + $signal.get_deprecated() + + #if $signal.args + <div class="indent"> + <h3>Parameters</h3> + <ul> + #for $arg in $signal.args + <li> + $arg.short_name — $arg.dbus_type + #if $arg.get_type(): (<a href="$arg.get_type_url()" title="$arg.get_type_title()">$arg.get_type().short_name</a>) + </li> + $arg.get_added() + $arg.get_changed() + $arg.get_deprecated() + $arg.get_docstring() + #end for + </ul> + </div> + #end if + + $signal.get_docstring() + </div> + #end for + </div> + #end if + + #if $interface.properties + <div class="outset properties property"> + <a name="properties"></a> + <h1>Properties</h1> + <div> + Accessed using the org.freedesktop.DBus.Properties interface. + </div> + #for $property in $interface.properties + <div class="inset property"> + <a name="$property.name"></a> + <span class="permalink">(<a href="$property.get_url()">Permalink</a>)</span> + <h2> + $property.short_name — $property.dbus_type + #if $property.type: (<a href="$property.get_type_url()" title="$property.get_type_title()">$property.get_type().short_name</a>) + </h2> + <div class="access">$property.get_access()</div> + + $property.get_added() + $property.get_changed() + $property.get_deprecated() + $property.get_docstring() + </div> + #end for + </div> + #end if + + #if $interface.tpproperties + <div class="outset tpproperties tpproperty"> + <a name="tpproperties"></a> + <h1>Telepathy Properties</h1> + <div> + Accessed using the org.freedesktop.Telepathy.Properties interface. + </div> + #for $property in $interface.tpproperties + <div class="inset tpproperty"> + <a name="$property.name"></a> + <span class="permalink">(<a href="$property.get_url()">Permalink</a>)</span> + <h2> + $property.short_name — $property.dbus_type + #if $property.type: (<a href="$property.get_type_url()" title="$property.get_type_title()">$property.get_type().short_name</a>) + </h2> + $property.get_added() + $property.get_changed() + $property.get_deprecated() + $property.get_docstring() + </div> + #end for + </div> + #end if + + #if $interface.contact_attributes + <div class="outset contact-attributes"> + <a name="contact-attributes"></a> + <h1>Contact Attributes</h1> + <div> + Attributes that a contact can have, accessed with the + org.freedesktop.Telepathy.Connection.Interface.Contacts interface. + </div> + #for $token in $interface.contact_attributes + <div class="inset contact-attribute"> + <a name="$token.name"></a> + <span class="permalink">(<a href="$token.get_url()">Permalink</a>)</span> + <h2> + $token.name — $token.dbus_type + #if $token.type: (<a href="$token.get_type_url()" title="$token.get_type_title()">$token.get_type().short_name</a>) + </h2> + $token.get_added() + $token.get_changed() + $token.get_deprecated() + $token.get_docstring() + </div> + #end for + </div> + #end if + + #if $interface.handler_capability_tokens + <div class="outset handler-capability-tokens"> + <a name="handler-capability-tokens"></a> + <h1>Handler Capability Tokens</h1> + <div> + Tokens representing capabilities that a Client.Handler can have. + </div> + #for $token in $interface.handler_capability_tokens + <div class="inset handler-capability-token"> + <a name="$token.name"></a> + <span class="permalink">(<a href="$token.get_url()">Permalink</a>)</span> + <h2> + $token.name + #if $token.is_family + (etc.) + #end if + </h2> + $token.get_added() + $token.get_changed() + $token.get_deprecated() + $token.get_docstring() + </div> + #end for + </div> + #end if + + #if $interface.types + <div class="outset types type"> + <a name="types"></a> + <h1>Types</h1> + #for $type in $interface.types + <div class="inset type"> + <a name="$type.name"></a> + <span class="permalink">$type.get_type_name() (<a href="$type.get_url()">Permalink</a>)</span> + <h2> + $type.short_name — $type.dbus_type + </h2> + + $type.get_added() + $type.get_changed() + $type.get_deprecated() + $type.get_docstring() + $type.get_breakdown() + </div> + #end for + </div> + #end if + + </div> + + </body> +</html> diff --git a/doc/templates/interfaces.html b/doc/templates/interfaces.html new file mode 100644 index 0000000..a93334c --- /dev/null +++ b/doc/templates/interfaces.html @@ -0,0 +1,50 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE html PUBLIC "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd" ""> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> + <head> + <title>$spec.title &mdash v$spec.version</title> + <link rel="stylesheet" href="style.css" type="text/css"/> + </head> + <body> + <div class="header"> + <h1>$spec.title</h1> + <a href="index.html">Full</a> + | <a href="generic-types.html">Generic Types</a> + | <a href="errors.html">Errors</a> + | <a href="fullindex.html">Full Index</a> + </div> + + <div class="main"> + <b>Version $spec.version</b> + + <a name="interfaces"></a> + <h3>Interfaces</h3> + <ul> + #for $interface in $spec.interfaces + #if $interface.causes_havoc + <li class="causes-havoc"> + #elif $interface.deprecated + <li class="deprecated"> + #else + <li> + #end if + <a href="$interface.get_url()">$interface.name</a> + #if $interface.causes_havoc + (unstable) + #elif $interface.deprecated + (deprecated) + #end if + </li> + #end for + </ul> + + <a name="other"></a> + <h3>Other</h3> + <ul> + <li><a href="generic-types.html">Generic Types</a></li> + <li><a href="errors.html">Errors</a></li> + </ul> + + </div> + </body> +</html> diff --git a/doc/templates/style.css b/doc/templates/style.css new file mode 100644 index 0000000..964d88b --- /dev/null +++ b/doc/templates/style.css @@ -0,0 +1,224 @@ +html, body, +h1, h2 { + margin: 0; + padding: 0; +} + +h3 { + margin-top: 2pt; + margin-bottom: 2pt; +} + +ul { + margin: 1ex; + margin-left: 1.5em; + padding: 0; +} + +hr { + border-style: none; + color: #cccccc; + background-color: #cccccc; + height: 1px; +} + +div.header { + position: fixed; + height: 4em; + background-color: white; + width: 100%; + margin: 0; + padding: 0.5ex; + border-bottom: 1px solid black; + top: 0; + left: 0; + z-index: 1; +} + +div.header h1 { + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; +} + +div.main { + margin-top: 5em; + margin-left: 1ex; + margin-right: 1ex; + margin-bottom: 1ex; +} + +div.main a[name] { + position: relative; + top: -4.5em; +} + +div.outset { + padding: 1ex; + margin-top: 1ex; + margin-bottom: 1ex; +} + +div.inset { + background-color: white; + margin-top: 1ex; + margin-bottom: 1ex; + padding: 0.5ex; +} + +div.indent { + margin-left: 1em; +} + +div.methods { + background-color: #fcaf3e; +} + +div.method { + border: 1px solid #f57900; +} + +div.signals { + background-color: #729fcf; +} + +div.signal { + border: 1px solid #3465a4; +} + +div.properties { + background-color: #ad7fa8; +} + +div.property { + border: 1px solid #75507b; +} + +div.tpproperties { + background-color: #999999; +} + +div.tpproperty { + border: 1px solid #333333; +} + +div.contact-attributes { + background-color: #ccccff; + border: 1px solid #9999cc; +} + +div.contact-attribute { + border: 1px solid #9999cc; +} + +div.handler-capability-tokens { + background-color: #339933; + border: 1px solid #228822; +} + +div.handler-capability-token { + border: 1px solid #228822; +} + +div.types { + background-color: #e9b96e; +} + +div.type { + border: 1px solid #c17d11; +} + +div.errors { + background-color: #ef2929; +} + +div.error { + border: 1px solid #cc0000; +} + +div.access { + font-weight: bold; + margin-left: 1ex; +} + +div.summary { + padding: 0.5ex; + background-color: #eeeeec; + border: 1px solid #d3d7cf; +} + +table.summary { + margin: 1ex; + font-size: small; +} + +table.summary td { + padding-right: 1ex; +} + +li.chapter { + margin-top: 1ex; + font-weight: bold; +} + +li.causes-havoc { + font-style: italic; +} + +li.deprecated, +li.deprecated a, +table.summary tr.deprecated td, +table.summary tr.deprecated td a { + color: gray; +} + +div.requires, +div.docstring { + margin: 1ex; +} + +div.added { + border-left: 2px solid #4e9a06; + margin: 1ex; + padding-left: 1ex; +} + +div.added span.version { + color: #4e9a06; + font-weight: bold; +} + +div.changed { + border-left: 2px solid #8f5902; + margin: 1ex; + padding-left: 1ex; +} + +div.changed span.version { + color: #8f5902; + font-weight: bold; +} + +div.deprecated, +div.havoc { + border-left: 2px solid #a40000; + margin: 1ex; + padding-left: 1ex; +} + +div.deprecated span.version, +span.warning { + color: #a40000; + font-weight: bold; +} + +div.rationale { + border-left: 2px solid gray; + margin: 1ex; + padding-left: 1ex; +} + +span.permalink { + float: right; + font-size: x-small; +} diff --git a/extensions/Telepathy_Logger.xml b/extensions/Logger.xml index 648f698..b63198b 100644 --- a/extensions/Telepathy_Logger.xml +++ b/extensions/Logger.xml @@ -1,5 +1,5 @@ <?xml version="1.0" ?> -<node name="/Telepathy_Logger" +<node name="/Logger" xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"> <tp:copyright>Copyright © 2009 Collabora Ltd.</tp:copyright> <tp:license xmlns="http://www.w3.org/1999/xhtml"> @@ -17,11 +17,17 @@ Lesser General Public License for more details.</p> License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.</p> </tp:license> - <interface name="org.freedesktop.Telepathy.TelepathyLoggerService.DRAFT" + <interface name="org.freedesktop.Telepathy.Logger.DRAFT" tp:causes-havoc="experimental"> <tp:added version="0.1">(as a draft)</tp:added> - <tp:struct name="Chat_Message_Field" array-name="Chat_Message_Field_List"> + <tp:docstring> + <!-- FIXME --> + An interface for requesting information from the Telepathy Logger + service. + </tp:docstring> + + <tp:struct name="Chat_Message" array-name="Chat_Message_List"> <tp:member type="s" name="Sender"> <tp:docstring> The identifier of the contact who originated this message. @@ -41,33 +47,32 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.</ <p>It represents a single message, received or sent.</p> <p>The receiver is implicit in the request: if the sender is the user, the receiver is the identifier in chat_id paramenter, if the sender is - not the user, the user is consequently the receiver of the message<p> + not the user, the user is consequently the receiver of the message</p> </tp:docstring> </tp:struct> - <method name="LastChats" - tp:name-for-bindings="LastChats"> - <arg direction="in" name="Account" type="o" tp:type="Contact_Handle[]"> + <method name="GetRecentMessages" + tp:name-for-bindings="Get_Recent_Messages"> + <arg direction="in" name="Account" type="o" tp:type="Account"> <tp:docstring> - An array of handles representing contacts. + <!-- FIXME --> </tp:docstring> </arg> - <arg direction="in" name="Identifier" type="s" - tp:type="Contact_Info_Map"> + <arg direction="in" name="Identifier" type="s"> <tp:docstring> - A dictionary mapping contact handles to information, whose keys are - the subset of the requested list of handles for which information was - cached. + <!-- FIXME --> </tp:docstring> </arg> + <arg direction="in" name="Is_Chatroom" type="b" /> + <arg direction="in" name="Lines" type="u" /> + <arg direction="out" name="Messages" type="a(ssu)" + tp:type="Chat_Message[]" /> <tp:docstring> - Request the last Lines entries of logs for the specified couple Account+Identifier. + Request the last Lines entries of logs for the specified couple + Account+Identifier. </tp:docstring> </method> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - An interface for requesting informatiosn about the Telepathy Logger entries. - </tp:docstring> </interface> </node> <!-- vim:set sw=2 sts=2 et ft=xml: --> diff --git a/extensions/Makefile.am b/extensions/Makefile.am index 61ba12d..bac6ce9 100644 --- a/extensions/Makefile.am +++ b/extensions/Makefile.am @@ -2,15 +2,16 @@ tools_dir = $(top_srcdir)/tools EXTRA_DIST = \ all.xml \ - Telepathy_Logger.xml + Logger.xml \ + $(NULL) -noinst_LTLIBRARIES = libtelepathy-logger-extensions.la +noinst_LTLIBRARIES = libtpl-extensions.la -libtelepathy_logger_extensions_la_SOURCES = \ +libtpl_extensions_la_SOURCES = \ extensions.c \ extensions.h -nodist_libtelepathy_logger_extensions_la_SOURCES = \ +nodist_libtpl_extensions_la_SOURCES = \ _gen/signals-marshal.c \ _gen/signals-marshal.h \ _gen/signals-marshal.list \ @@ -24,13 +25,12 @@ nodist_libtelepathy_logger_extensions_la_SOURCES = \ BUILT_SOURCES = \ _gen/all.xml \ - $(nodist_libtelepathy_logger_extensions_la_SOURCES) \ - extensions.html + $(nodist_libtpl_extensions_la_SOURCES) CLEANFILES = $(BUILT_SOURCES) -AM_CFLAGS = $(ERROR_CFLAGS) @DBUS_CFLAGS@ @GLIB_CFLAGS@ @TP_GLIB_CFLAGS@ @HANDLE_LEAK_DEBUG_CFLAGS@ -AM_LDFLAGS = @DBUS_LIBS@ @GLIB_LIBS@ @TP_GLIB_LIBS@ +AM_CFLAGS = $(ERROR_CFLAGS) @LIBTPL_CFLAGS@ @HANDLE_LEAK_DEBUG_CFLAGS@ +AM_LDFLAGS = @LIBTPL_LIBS@ # Generated stuff @@ -39,24 +39,22 @@ XSLTPROCFLAGS = --nonet --novalid _gen/all.xml: all.xml $(wildcard *.xml) Makefile.am @$(mkdir_p) _gen - $(AM_V_GEN)$(PYTHON) $(tools_dir)/xincludator.py \ - $< > $@.tmp && mv $@.tmp $@ - -extensions.html: _gen/all.xml $(tools_dir)/doc-generator.xsl Makefile.am - $(AM_V_GEN)$(XSLTPROC) $(XSLTPROCFLAGS) \ - --param "allow-undefined-interfaces" "true()" \ - $(tools_dir)/doc-generator.xsl \ + $(AM_V_GEN)$(XSLTPROC) $(XSLTPROCFLAGS) --xinclude $(tools_dir)/identity.xsl \ $< > $@ +doc/index.html: _gen/all.xml $(tools_dir)/specparser.py $(tools_dir)/doc-generator.py Makefile.am + $(AM_V_GEN)$(PYTHON) $(tools_dir)/doc-generator.py all.xml doc/ \ + telepathy-spec org.freedesktop.Telepathy + _gen/svc.c _gen/svc.h: _gen/all.xml $(tools_dir)/glib-ginterface-gen.py \ Makefile.am $(AM_V_GEN)$(PYTHON) $(tools_dir)/glib-ginterface-gen.py \ - --filename=_gen/svc --signal-marshal-prefix=_gabble_ext \ + --filename=_gen/svc --signal-marshal-prefix=_tpl_ext \ --include='<telepathy-glib/dbus.h>' \ --include='"_gen/signals-marshal.h"' \ --allow-unstable \ --not-implemented-func='tp_dbus_g_method_return_not_implemented' \ - $< Gabble_Svc_ + $< Tpl_Svc_ _gen/signals-marshal.list: _gen/all.xml \ $(tools_dir)/glib-signals-marshal-gen.py \ @@ -64,23 +62,23 @@ _gen/signals-marshal.list: _gen/all.xml \ $(AM_V_GEN)$(PYTHON) $(tools_dir)/glib-signals-marshal-gen.py $< > $@ _gen/signals-marshal.h: _gen/signals-marshal.list Makefile.am - $(AM_V_GEN)$(GLIB_GENMARSHAL) --header --prefix=_gabble_ext_marshal $< > $@ + $(AM_V_GEN)$(GLIB_GENMARSHAL) --header --prefix=_tpl_ext_marshal $< > $@ _gen/signals-marshal.c: _gen/signals-marshal.list Makefile.am $(AM_V_GEN){ echo '#include "_gen/signals-marshal.h"' && \ - $(GLIB_GENMARSHAL) --body --prefix=_gabble_ext_marshal $< ; } > $@ + $(GLIB_GENMARSHAL) --body --prefix=_tpl_ext_marshal $< ; } > $@ _gen/enums.h: _gen/all.xml $(tools_dir)/c-constants-gen.py \ Makefile.am - $(AM_V_GEN)$(PYTHON) $(tools_dir)/c-constants-gen.py Gabble $< > $@ + $(AM_V_GEN)$(PYTHON) $(tools_dir)/c-constants-gen.py Tpl $< > $@ _gen/interfaces.h _gen/interfaces-body.h: _gen/all.xml \ $(tools_dir)/glib-interfaces-gen.py \ Makefile.am $(AM_V_GEN)$(PYTHON) $(tools_dir)/glib-interfaces-gen.py \ - Gabble _gen/interfaces-body.h _gen/interfaces.h $< + Tpl _gen/interfaces-body.h _gen/interfaces.h $< _gen/gtypes.h _gen/gtypes-body.h: _gen/all.xml \ $(tools_dir)/glib-gtypes-generator.py Makefile.am $(AM_V_GEN)$(PYTHON) $(tools_dir)/glib-gtypes-generator.py \ - $< _gen/gtypes Gabble + $< _gen/gtypes Tpl diff --git a/extensions/all.xml b/extensions/all.xml index a750472..6c7af8e 100644 --- a/extensions/all.xml +++ b/extensions/all.xml @@ -23,135 +23,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA</p> </tp:license> <tp:generic-types> - <tp:external-type name="Room_Handle" type="u" + <tp:external-type name="Account" type="o" from="Telepathy specification"/> - <tp:external-type name="Handle_Type" type="u" - from="Telepathy specification"/> - <tp:external-type name="Contact_Handle" type="u" - from="Telepathy specification"/> - <tp:external-type name="DBus_Unique_Name" type="s" - from="Telepathy specification"/> -</tp:generic-types> - -<xi:include href="Telepathy_Logger.xml"/> - -<tp:generic-types> - <tp:external-type name="Contact_Handle" type="u" - from="Telepathy specification"/> - <tp:external-type name="DBus_Interface" type="s" - from="Telepathy specification"/> - <tp:external-type name="DBus_Qualified_Member" type="s" - from="Telepathy specification"/> - <tp:external-type name="Qualified_Property_Value_Map" type="a{sv}" - from="Telepathy specification"/> - <tp:external-type name="DBus_Error_Name" type="s" - from="Telepathy specification"/> - <tp:external-type name="DBus_Well_Known_Name" type="s" - from="Telepathy specification"/> - <tp:external-type name="Handler_Capability_Token" type="s" - from="Telepathy specification"/> - - <!-- for localisation --> - <tp:external-type name="Rich_Presence_Access_Control_Type" type="u" - from="Telepathy specification"/> - <tp:external-type name="Rich_Presence_Access_Control" type="(uv)" - from="Telepathy specification"/> - <tp:external-type name="Unix_Timestamp64" type="t" - from="Telepathy specification"/> - <tp:external-type name="Unix_Timestamp" type="u" - from="Telepathy specification"/> - <tp:external-type name="String_String_Map" type="a{ss}" - from="Telepathy specification"/> - - <tp:external-type name="String_Variant_Map" type="a{sv}" - from="Telepathy specification"/> - - <!-- use types from Connection_Interface_Requests --> - <tp:external-type name="Channel_Class" type="a{sv}" - from="Telepathy specification"/> - - <!-- use types from Channel_Type_Tubes --> - <tp:external-type name="Socket_Address_Type" type="u" - from="Telepathy specification"/> - <tp:external-type name="Socket_Access_Control" type="u" - from="Telepathy specification"/> - <tp:external-type name="Supported_Socket_Map" type="a{uau}" - from="Telepathy specification"/> - <tp:external-type name="DBus_Tube_Member" type="(us)" - from="Telepathy specification"/> - - <!-- use types from Connection_Interface_Contact_Capabilities --> - <tp:external-type name="Requestable_Channel_Class" type="(a{sv}as)" - from="Telepathy specification"/> - - <tp:external-type name="Connection_Status" type="u" - from="Telepathy specification"/> - - <!-- use types from Channel_Type_Streamed_Media.xml --> - <tp:enum name="Media_Stream_Type" type="u" - array-name="Media_Stream_Type_List"> - <tp:enumvalue suffix="Audio" value="0"> - <tp:docstring>An audio stream</tp:docstring> - </tp:enumvalue> - <tp:enumvalue suffix="Video" value="1"> - <tp:docstring>A video stream</tp:docstring> - </tp:enumvalue> - </tp:enum> - - <!-- use types from generic-types.xml --> - <tp:struct name="Socket_Address_IP" array-name="Socket_Address_IP_List"> - <tp:docstring>An IP address and port.</tp:docstring> - <tp:member type="s" name="Address"> - <tp:docstring>Either a dotted-quad IPv4 address literal as for - <tp:type>Socket_Address_IPv4</tp:type>, or an RFC2373 IPv6 address - as for <tp:type>Socket_Address_IPv6</tp:type>. - </tp:docstring> - </tp:member> - <tp:member type="q" name="Port"> - <tp:docstring>The TCP or UDP port number.</tp:docstring> - </tp:member> - </tp:struct> - - <tp:struct name="Socket_Address_IPv4"> - <tp:docstring>An IPv4 address and port.</tp:docstring> - <tp:member type="s" name="Address"> - <tp:docstring>A dotted-quad IPv4 address literal: four ASCII decimal - numbers, each between 0 and 255 inclusive, e.g. - "192.168.0.1".</tp:docstring> - </tp:member> - <tp:member type="q" name="Port"> - <tp:docstring>The TCP or UDP port number.</tp:docstring> - </tp:member> - </tp:struct> - - <tp:struct name="Socket_Address_IPv6"> - <tp:docstring>An IPv6 address and port.</tp:docstring> - <tp:member type="s" name="Address"> - <tp:docstring>An IPv6 address literal as specified by RFC2373 - section 2.2, e.g. "2001:DB8::8:800:200C:4171".</tp:docstring> - </tp:member> - <tp:member type="q" name="Port"> - <tp:docstring>The TCP or UDP port number.</tp:docstring> - </tp:member> - </tp:struct> - - <tp:enum name="Media_Stream_State" type="u"> - <tp:enumvalue suffix="Disconnected" value="0"> - <tp:docstring>The stream is disconnected.</tp:docstring> - </tp:enumvalue> - <tp:enumvalue suffix="Connecting" value="1"> - <tp:docstring>The stream is trying to connect.</tp:docstring> - </tp:enumvalue> - <tp:enumvalue suffix="Connected" value="2"> - <tp:docstring>The stream is connected.</tp:docstring> - </tp:enumvalue> - </tp:enum> - - <tp:simple-type name="Handle" type="u" array-name="Handle_List"> - <tp:docstring>An unsigned 32-bit integer representing a - handle</tp:docstring> - </tp:simple-type> </tp:generic-types> +<xi:include href="Logger.xml"/> </tp:spec> diff --git a/extensions/extensions.c b/extensions/extensions.c new file mode 100644 index 0000000..c81d126 --- /dev/null +++ b/extensions/extensions.c @@ -0,0 +1,5 @@ +#include "extensions.h" + +/* auto-generated stubs */ +#include "_gen/gtypes-body.h" +#include "_gen/interfaces-body.h" diff --git a/extensions/extensions.h b/extensions/extensions.h new file mode 100644 index 0000000..bf8f36d --- /dev/null +++ b/extensions/extensions.h @@ -0,0 +1,15 @@ +#ifndef _TPL_EXTENSIONS_H +#define _TPL_EXTENSIONS_H + +#include "extensions/_gen/enums.h" +#include "extensions/_gen/svc.h" + +G_BEGIN_DECLS + +#include "extensions/_gen/gtypes.h" +#include "extensions/_gen/interfaces.h" + +G_END_DECLS + +#endif /* _GABBLE_EXTENSIONS_H */ + diff --git a/tools/doc-generator.py b/tools/doc-generator.py new file mode 100755 index 0000000..5fc19ce --- /dev/null +++ b/tools/doc-generator.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python +# +# doc-generator.py +# +# Generates HTML documentation from the parsed spec using Cheetah templates. +# +# Copyright (C) 2009 Collabora Ltd. +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or (at +# your option) any later version. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# Authors: Davyd Madeley <davyd.madeley@collabora.co.uk> +# + +import sys +import os +import os.path +import shutil + +try: + from Cheetah.Template import Template +except ImportError, e: + print >> sys.stderr, e + print >> sys.stderr, "Install `python-cheetah'?" + sys.exit(-1) + +import specparser + +program, spec_file, output_path, project, namespace = sys.argv + +template_path = os.path.join(os.path.dirname(program), '../doc/templates') + +# make the output path +try: + os.mkdir(output_path) +except OSError: + pass +# copy in the CSS +shutil.copy(os.path.join(template_path, 'style.css'), output_path) + +def load_template(filename): + try: + file = open(os.path.join(template_path, filename)) + template_def = file.read() + file.close() + except IOError, e: + print >> sys.stderr, "Could not load template file `%s'" % filename + print >> sys.stderr, e + sys.exit(-1) + + return template_def + +spec = specparser.parse(spec_file, namespace) + +# write out HTML files for each of the interfaces + +# Not using render_template here to avoid recompiling it n times. +namespace = {} +template_def = load_template('interface.html') +t = Template(template_def, namespaces = [namespace]) +for interface in spec.interfaces: + namespace['interface'] = interface + + # open the output file + out = open(os.path.join(output_path, '%s.html' % interface.name), 'w') + print >> out, unicode(t).encode('utf-8') + out.close() + +def render_template(name, namespaces, target=None): + if target is None: + target = name + + namespace = { 'spec': spec } + template_def = load_template(name) + t = Template(template_def, namespaces=namespaces) + out = open(os.path.join(output_path, target), 'w') + print >> out, unicode(t).encode('utf-8') + out.close() + +namespaces = { 'spec': spec } + +render_template('generic-types.html', namespaces) +render_template('errors.html', namespaces) +render_template('interfaces.html', namespaces) +render_template('fullindex.html', namespaces) + +dh_namespaces = { 'spec': spec, 'name': project } +render_template('devhelp.devhelp2', dh_namespaces, + target=('%s.devhelp2' % project)) + +# write out the TOC last, because this is the file used as the target in the +# Makefile. +render_template('index.html', namespaces) diff --git a/tools/identity.xsl b/tools/identity.xsl new file mode 100644 index 0000000..6630f84 --- /dev/null +++ b/tools/identity.xsl @@ -0,0 +1,7 @@ +<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> + <xsl:template match="@*|node()"> + <xsl:copy> + <xsl:apply-templates select="@*|node()"/> + </xsl:copy> + </xsl:template> +</xsl:stylesheet> diff --git a/tools/specparser.py b/tools/specparser.py new file mode 100644 index 0000000..16b770e --- /dev/null +++ b/tools/specparser.py @@ -0,0 +1,885 @@ +# +# specparser.py +# +# Reads in a spec document and generates pretty data structures from it. +# +# Copyright (C) 2009 Collabora Ltd. +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or (at +# your option) any later version. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# Authors: Davyd Madeley <davyd.madeley@collabora.co.uk> +# + +import sys +import xml.dom.minidom + +import xincludator + +XMLNS_TP = 'http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0' + +class UnknownAccess(Exception): pass +class UnknownDirection(Exception): pass +class UnknownType(Exception): pass +class UnnamedItem(Exception): pass +class UntypedItem(Exception): pass +class UnsupportedArray(Exception): pass +class BadNameForBindings(Exception): pass + +def getText(dom): + try: + if dom.childNodes[0].nodeType == dom.TEXT_NODE: + return dom.childNodes[0].data + else: + return '' + except IndexError: + return '' + +def getChildrenByName(dom, namespace, name): + return filter(lambda n: n.nodeType == n.ELEMENT_NODE and \ + n.namespaceURI == namespace and \ + n.localName == name, + dom.childNodes) + +def build_name(namespace, name): + """Returns a name by appending `name' to the namespace of this object. + """ + return '.'.join( + filter(lambda n: n is not None and n != '', + [namespace, name.replace(' ', '')]) + ) + +class Base(object): + """The base class for any type of XML node in the spec that implements the + 'name' attribute. + + Don't instantiate this class directly. + """ + devhelp_name = "" + + def __init__(self, parent, namespace, dom): + self.short_name = name = dom.getAttribute('name') + self.namespace = namespace + self.name = build_name(namespace, name) + self.parent = parent + + try: + self.docstring = getChildrenByName(dom, XMLNS_TP, 'docstring')[0] + except IndexError: + self.docstring = None + + try: + self.added = getChildrenByName(dom, XMLNS_TP, 'added')[0] + except IndexError: + self.added = None + + try: + self.deprecated = getChildrenByName(dom, XMLNS_TP, 'deprecated')[0] + except IndexError: + self.deprecated = None + + self.changed = getChildrenByName(dom, XMLNS_TP, 'changed') + + self.validate() + + def validate(self): + if self.short_name == '': + raise UnnamedItem("Node %s of %s has no name" % ( + self.__class__.__name__, self.parent)) + + def get_type_name(self): + return self.__class__.__name__ + + def get_spec(self): + return self.parent.get_spec() + + def get_root_namespace(self): + return self.get_interface().name + + def get_interface(self): + return self.parent.get_interface() + + def get_url(self): + return "%s#%s" % (self.get_interface().get_url(), self.name) + + def _get_generic_with_ver(self, nnode, htmlclass, txt): + if nnode is None: + return '' + else: + # make a copy of this node, turn it into a HTML <div> tag + node = nnode.cloneNode(True) + node.tagName = 'div' + node.baseURI = None + node.setAttribute('class', htmlclass) + + try: + node.removeAttribute('version') + + span = xml.dom.minidom.parseString( + ('<span class="version">%s\n</span>' % txt) % + nnode.getAttribute('version')).firstChild + node.insertBefore(span, node.firstChild) + except xml.dom.NotFoundErr: + print >> sys.stderr, \ + 'WARNING: %s was %s, but gives no version' % (self, htmlclass) + + self._convert_to_html(node) + + return node.toxml().encode('ascii', 'xmlcharrefreplace') + + def get_added(self): + return self._get_generic_with_ver(self.added, 'added', + "Added in %s.") + + def get_deprecated(self): + return self._get_generic_with_ver(self.deprecated, 'deprecated', + "Deprecated since %s.") + + def get_changed(self): + return '\n'.join(map(lambda n: + self._get_generic_with_ver(n, 'changed', "Changed in %s."), + self.changed)) + + def get_docstring(self): + """Get the docstring for this node, but do node substitution to + rewrite types, interfaces, etc. as links. + """ + if self.docstring is None: + return '' + else: + # make a copy of this node, turn it into a HTML <div> tag + node = self.docstring.cloneNode(True) + node.tagName = 'div' + node.baseURI = None + node.setAttribute('class', 'docstring') + + self._convert_to_html(node) + + return node.toxml().encode('ascii', 'xmlcharrefreplace') + + def _convert_to_html(self, node): + spec = self.get_spec() + namespace = self.get_root_namespace() + + # rewrite <tp:rationale> + for n in node.getElementsByTagNameNS(XMLNS_TP, 'rationale'): + n.tagName = 'div' + n.namespaceURI = None + n.setAttribute('class', 'rationale') + + # rewrite <tp:type> + for n in node.getElementsByTagNameNS(XMLNS_TP, 'type'): + t = spec.lookup_type(getText(n)) + n.tagName = 'a' + n.namespaceURI = None + n.setAttribute('href', t.get_url()) + + # rewrite <tp:member-ref> + for n in node.getElementsByTagNameNS(XMLNS_TP, 'member-ref'): + key = getText(n) + try: + o = spec.lookup(key, namespace=namespace) + except KeyError: + print >> sys.stderr, \ + "WARNING: Key '%s' not known in namespace '%s'" % ( + key, namespace) + continue + + n.tagName = 'a' + n.namespaceURI = None + n.setAttribute('href', o.get_url()) + n.setAttribute('title', o.get_title()) + + # rewrite <tp:dbus-ref> + for n in node.getElementsByTagNameNS(XMLNS_TP, 'dbus-ref'): + namespace = n.getAttribute('namespace') + key = getText(n) + try: + o = spec.lookup(key, namespace=namespace) + except KeyError: + print >> sys.stderr, \ + "WARNING: Key '%s' not known in namespace '%s'" % ( + key, namespace) + continue + + n.tagName = 'a' + n.namespaceURI = None + n.setAttribute('href', o.get_url()) + n.setAttribute('title', o.get_title()) + + def get_title(self): + return '%s %s' % (self.get_type_name(), self.name) + + def __repr__(self): + return '%s(%s)' % (self.__class__.__name__, self.name) + +class DBusConstruct(Base): + """Base class for signals, methods and properties.""" + + def __init__(self, parent, namespace, dom): + super(DBusConstruct, self).__init__(parent, namespace, dom) + + self.name_for_bindings = dom.getAttributeNS(XMLNS_TP, + 'name-for-bindings') + + if not self.name_for_bindings: + raise BadNameForBindings('%s has no name-for-bindings' + % self) + + if self.name_for_bindings.replace('_', '') != self.short_name: + raise BadNameForBindings('%s name-for-bindings = %s does not ' + 'match short_name = %s' % (self, self.name_for_bindings, + self.short_name)) + +class PossibleError(Base): + def __init__(self, parent, namespace, dom): + super(PossibleError, self).__init__(parent, namespace, dom) + + def get_error(self): + spec = self.get_spec() + try: + return spec.errors[self.name] + except KeyError: + return External(self.name) + + def get_url(self): + return self.get_error().get_url() + + def get_title(self): + return self.get_error().get_title() + + def get_docstring(self): + d = super(PossibleError, self).get_docstring() + if d == '': + return self.get_error().get_docstring() + else: + return d + +class Method(DBusConstruct): + devhelp_name = "function" + + def __init__(self, parent, namespace, dom): + super(Method, self).__init__(parent, namespace, dom) + + args = build_list(self, Arg, self.name, + dom.getElementsByTagName('arg')) + + # separate arguments as input and output arguments + self.in_args = filter(lambda a: a.direction == Arg.DIRECTION_IN, args) + self.out_args = filter(lambda a: a.direction == Arg.DIRECTION_OUT, args) + + for arg in args: + if arg.direction == Arg.DIRECTION_IN or \ + arg.direction == Arg.DIRECTION_OUT: + continue + + print >> sys.stderr, "WARNING: '%s' of method '%s' does not specify a suitable direction" % (arg, self) + + self.possible_errors = build_list(self, PossibleError, None, + dom.getElementsByTagNameNS(XMLNS_TP, 'error')) + + def get_in_args(self): + return ', '.join(map(lambda a: a.spec_name(), self.in_args)) + + def get_out_args(self): + if len(self.out_args) > 0: + return ', '.join(map(lambda a: a.spec_name(), self.out_args)) + else: + return 'nothing' + +class Typed(Base): + """The base class for all typed nodes (i.e. Arg and Property). + + Don't instantiate this class directly. + """ + + def __init__(self, parent, namespace, dom): + super(Typed, self).__init__(parent, namespace, dom) + + self.type = dom.getAttributeNS(XMLNS_TP, 'type') + self.dbus_type = dom.getAttribute('type') + + # check we have a dbus type + if self.dbus_type == '': + raise UntypedItem("Node referred to by '%s' has no type" % dom.toxml()) + def get_type(self): + return self.get_spec().lookup_type(self.type) + + def get_type_url(self): + t = self.get_type() + if t is None: return '' + else: return t.get_url() + + def get_type_title(self): + t = self.get_type() + if t is None: return '' + else: return t.get_title() + + def spec_name(self): + return '%s: %s' % (self.dbus_type, self.short_name) + + def __repr__(self): + return '%s(%s:%s)' % (self.__class__.__name__, self.name, self.dbus_type) + +class Property(DBusConstruct, Typed): + ACCESS_READ = 1 + ACCESS_WRITE = 2 + + ACCESS_READWRITE = ACCESS_READ | ACCESS_WRITE + + def __init__(self, parent, namespace, dom): + super(Property, self).__init__(parent, namespace, dom) + + access = dom.getAttribute('access') + if access == 'read': + self.access = self.ACCESS_READ + elif access == 'write': + self.access = self.ACCESS_WRITE + elif access == 'readwrite': + self.access = self.ACCESS_READWRITE + else: + raise UnknownAccess("Unknown access '%s' on %s" % (access, self)) + + def get_access(self): + if self.access & self.ACCESS_READ and self.access & self.ACCESS_WRITE: + return 'Read/Write' + elif self.access & self.ACCESS_READ: + return 'Read only' + elif self.access & self.ACCESS_WRITE: + return 'Write only' + +class AwkwardTelepathyProperty(Typed): + def get_type_name(self): + return 'Telepathy Property' + +class Arg(Typed): + DIRECTION_IN, DIRECTION_OUT, DIRECTION_UNSPECIFIED = range(3) + + def __init__(self, parent, namespace, dom): + super(Arg, self).__init__(parent, namespace, dom) + + direction = dom.getAttribute('direction') + if direction == 'in': + self.direction = self.DIRECTION_IN + elif direction == 'out': + self.direction = self.DIRECTION_OUT + elif direction == '': + self.direction = self.DIRECTION_UNSPECIFIED + else: + raise UnknownDirection("Unknown direction '%s' on %s" % ( + direction, self.parent)) + +class Signal(DBusConstruct): + def __init__(self, parent, namespace, dom): + super(Signal, self).__init__(parent, namespace, dom) + + self.args = build_list(self, Arg, self.name, + dom.getElementsByTagName('arg')) + + for arg in self.args: + if arg.direction == Arg.DIRECTION_UNSPECIFIED: + continue + + print >> sys.stderr, "WARNING: '%s' of signal '%s' does not specify a suitable direction" % (arg, self) + + def get_args(self): + return ', '.join(map(lambda a: a.spec_name(), self.args)) + +class External(object): + """External objects are objects that are referred to in another spec. + + We have to attempt to look them up if at all possible. + """ + + def __init__(self, name): + self.name = self.short_name = name + + def get_url(self): + return None + + def get_title(self): + return 'External %s' % self.name + + def get_docstring(self): + return None + + def __repr__(self): + return '%s(%s)' % (self.__class__.__name__, self.name) + +class Interface(Base): + def __init__(self, parent, namespace, dom, spec_namespace): + super(Interface, self).__init__(parent, namespace, dom) + + # If you're writing a spec with more than one top-level namespace, you + # probably want to replace spec_namespace with a list. + if self.name.startswith(spec_namespace + "."): + self.short_name = self.name[len(spec_namespace) + 1:] + else: + self.short_name = self.name + + # build lists of methods, etc., in this interface + self.methods = build_list(self, Method, self.name, + dom.getElementsByTagName('method')) + self.properties = build_list(self, Property, self.name, + dom.getElementsByTagName('property')) + self.signals = build_list(self, Signal, self.name, + dom.getElementsByTagName('signal')) + self.tpproperties = build_list(self, AwkwardTelepathyProperty, + self.name, dom.getElementsByTagNameNS(XMLNS_TP, 'property')) + self.handler_capability_tokens = build_list(self, + HandlerCapabilityToken, self.name, + dom.getElementsByTagNameNS(XMLNS_TP, + 'handler-capability-token')) + self.contact_attributes = build_list(self, ContactAttribute, self.name, + dom.getElementsByTagNameNS(XMLNS_TP, 'contact-attribute')) + + # build a list of types in this interface + self.types = parse_types(self, dom, self.name) + + # find out if this interface causes havoc + self.causes_havoc = dom.getAttributeNS(XMLNS_TP, 'causes-havoc') + if self.causes_havoc == '': self.causes_havoc = None + + # find out what we're required to also implement + self.requires = map(lambda n: n.getAttribute('interface'), + getChildrenByName(dom, XMLNS_TP, 'requires')) + + def get_interface(self): + return self + + def get_requires(self): + spec = self.get_spec() + + def lookup(r): + try: + return spec.lookup(r) + except KeyError: + return External(r) + + return map(lookup, self.requires) + + def get_url(self): + return '%s.html' % self.name + +class Error(Base): + def get_url(self): + return 'errors.html#%s' % self.name + + def get_root_namespace(self): + return self.namespace + +class DBusList(object): + """Stores a list of a given DBusType. Provides some basic validation to + determine whether or not the type is sane. + """ + def __init__(self, child): + self.child = child + + if isinstance(child, DBusType): + self.ultimate = child + self.depth = 1 + + if self.child.array_name == '': + raise UnsupportedArray("Type '%s' does not support being " + "used in an array" % self.child.name) + else: + self.name = build_name(self.child.namespace, + self.child.array_name) + self.short_name = self.child.array_name + + elif isinstance(child, DBusList): + self.ultimate = child.ultimate + self.depth = child.depth + 1 + self.name = self.child.name + '_List' + self.short_name = self.child.short_name + '_List' + + # check that our child can operate at this depth + maxdepth = int(self.ultimate.array_depth) + if self.depth > maxdepth: + raise TypeError("Type '%s' has exceeded its maximum depth (%i)" % (self, maxdepth)) + + else: + raise TypeError("DBusList can contain only a DBusType or DBusList not '%s'" % child) + + self.dbus_type = 'a' + self.child.dbus_type + + def get_url(self): + return self.ultimate.get_url() + + def get_title(self): + return "Array of %s" % self.child.get_title() + + def __repr__(self): + return 'Array(%s)' % self.child + +class DBusType(Base): + """The base class for all D-Bus types referred to in the spec. + + Don't instantiate this class directly. + """ + + devhelp_name = "typedef" + + def __init__(self, parent, namespace, dom): + super(DBusType, self).__init__(parent, namespace, dom) + + self.dbus_type = dom.getAttribute('type') + self.array_name = dom.getAttribute('array-name') + self.array_depth = dom.getAttribute('array-depth') + + def get_root_namespace(self): + return self.namespace + + def get_breakdown(self): + return '' + + def get_url(self): + if isinstance(self.parent, Interface): + html = self.parent.get_url() + else: + html = 'generic-types.html' + + return '%s#%s' % (html, self.name) + +class SimpleType(DBusType): + def get_type_name(self): + return 'Simple Type' + +class ExternalType(DBusType): + def __init__(self, parent, namespace, dom): + super(ExternalType, self).__init__(parent, namespace, dom) + + # FIXME: until we are able to cross reference external types to learn + # about their array names, we're just going to assume they work like + # this + self.array_name = self.short_name + '_List' + + def get_type_name(self): + return 'External Type' + +class StructLike(DBusType): + """Base class for all D-Bus types that look kind of like Structs + + Don't instantiate this class directly. + """ + + class StructMember(Typed): + def get_root_namespace(self): + return self.parent.get_root_namespace() + + def __init__(self, parent, namespace, dom): + super(StructLike, self).__init__(parent, namespace, dom) + + self.members = build_list(self, StructLike.StructMember, None, + dom.getElementsByTagNameNS(XMLNS_TP, 'member')) + + def get_breakdown(self): + str = '' + str += '<ul>\n' + for member in self.members: + # attempt to lookup the member up in the type system + t = member.get_type() + + str += '<li>%s — %s' % (member.name, member.dbus_type) + if t: str += ' (<a href="%s" title="%s">%s</a>)' % ( + t.get_url(), t.get_title(), t.short_name) + str += '</li>\n' + str += member.get_docstring() + str += '</ul>\n' + + return str + +class Mapping(StructLike): + def __init__(self, parent, namespace, dom): + super(Mapping, self).__init__(parent, namespace, dom) + + # rewrite the D-Bus type + self.dbus_type = 'a{%s}' % ''.join(map(lambda m: m.dbus_type, self.members)) + +class Struct(StructLike): + + devhelp_name = "struct" + + def __init__(self, parent, namespace, dom): + super(Struct, self).__init__(parent, namespace, dom) + + # rewrite the D-Bus type + self.dbus_type = '(%s)' % ''.join(map(lambda m: m.dbus_type, self.members)) + +class EnumLike(DBusType): + """Base class for all D-Bus types that look kind of like Enums + + Don't instantiate this class directly. + """ + class EnumValue(Base): + def __init__(self, parent, namespace, dom): + super(EnumLike.EnumValue, self).__init__(parent, namespace, dom) + + # rewrite self.name + self.short_name = dom.getAttribute('suffix') + self.name = build_name(namespace, self.short_name) + + self.value = dom.getAttribute('value') + + super(EnumLike.EnumValue, self).validate() + + def validate(self): + pass + + def get_root_namespace(self): + return self.parent.get_root_namespace() + + def get_breakdown(self): + str = '' + str += '<ul>\n' + for value in self.values: + # attempt to lookup the member.name as a type in the type system + str += '<li>%s (%s)</li>\n' % (value.short_name, value.value) + str += value.get_added() + str += value.get_changed() + str += value.get_deprecated() + str += value.get_docstring() + str += '</ul>\n' + + return str + +class Enum(EnumLike): + + devhelp_name = "enum" + + def __init__(self, parent, namespace, dom): + super(Enum, self).__init__(parent, namespace, dom) + + self.values = build_list(self, EnumLike.EnumValue, self.name, + dom.getElementsByTagNameNS(XMLNS_TP, 'enumvalue')) + +class Flags(EnumLike): + def __init__(self, parent, namespace, dom): + super(Flags, self).__init__(parent, namespace, dom) + + self.values = build_list(self, EnumLike.EnumValue, self.name, + dom.getElementsByTagNameNS(XMLNS_TP, 'flag')) + self.flags = self.values # in case you're looking for it + +class TokenBase(Base): + + devhelp_name = "macro" # it's a constant, which is near enough... + separator = '/' + + def __init__(self, parent, namespace, dom): + super(TokenBase, self).__init__(parent, namespace, dom) + self.name = namespace + '/' + self.short_name + +class ContactAttribute(TokenBase, Typed): + + def get_type_name(self): + return 'Contact Attribute' + +class HandlerCapabilityToken(TokenBase): + + def get_type_name(self): + return 'Handler Capability Token' + + def __init__(self, parent, namespace, dom): + super(HandlerCapabilityToken, self).__init__(parent, namespace, dom) + + is_family = dom.getAttribute('is-family') + assert is_family in ('yes', 'no', '') + self.is_family = (is_family == 'yes') + +class SectionBase(object): + """A SectionBase is an abstract base class for any type of node that can + contain a <tp:section>, which means the top-level Spec object, or any + Section object. + + It should not be instantiated directly. + """ + + def __init__(self, dom, spec_namespace): + + self.items = [] + + def recurse(nodes): + # iterate through the list of child nodes + for node in nodes: + if node.nodeType != node.ELEMENT_NODE: continue + + if node.tagName == 'node': + # recurse into this level for interesting items + recurse(node.childNodes) + elif node.namespaceURI == XMLNS_TP and \ + node.localName == 'section': + self.items.append(Section(self, None, node, + spec_namespace)) + elif node.tagName == 'interface': + self.items.append(Interface(self, None, node, + spec_namespace)) + + recurse(dom.childNodes) + +class Section(Base, SectionBase): + def __init__(self, parent, namespace, dom, spec_namespace): + Base.__init__(self, parent, namespace, dom) + SectionBase.__init__(self, dom, spec_namespace) + + def get_root_namespace(self): + return None + +class Spec(SectionBase): + def __init__(self, dom, spec_namespace): + # build a dictionary of errors in this spec + try: + errorsnode = dom.getElementsByTagNameNS(XMLNS_TP, 'errors')[0] + self.errors = build_dict(self, Error, + errorsnode.getAttribute('namespace'), + errorsnode.getElementsByTagNameNS(XMLNS_TP, 'error')) + except IndexError: + self.errors = {} + + # build a list of generic types + self.generic_types = reduce (lambda a, b: a + b, + map(lambda l: parse_types(self, l), + dom.getElementsByTagNameNS(XMLNS_TP, 'generic-types')), + []) + + # create a top-level section for this Spec + SectionBase.__init__(self, dom.documentElement, spec_namespace) + + # build a list of interfaces in this spec + self.interfaces = [] + def recurse(items): + for item in items: + if isinstance(item, Section): recurse(item.items) + elif isinstance(item, Interface): self.interfaces.append(item) + recurse(self.items) + + # build a giant dictionary of everything (interfaces, methods, signals + # and properties); also build a dictionary of types + self.everything = {} + self.types = {} + + for type in self.generic_types: self.types[type.short_name] = type + + for interface in self.interfaces: + self.everything[interface.name] = interface + + for method in interface.methods: + self.everything[method.name] = method + for signal in interface.signals: + self.everything[signal.name] = signal + for property in interface.properties: + self.everything[property.name] = property + for property in interface.tpproperties: + self.everything[property.name] = property + for token in interface.contact_attributes: + self.everything[token.name] = token + for token in interface.handler_capability_tokens: + self.everything[token.name] = token + + for type in interface.types: + self.types[type.short_name] = type + + # get some extra bits for the HTML + node = dom.getElementsByTagNameNS(XMLNS_TP, 'spec')[0] + self.title = getText(getChildrenByName(node, XMLNS_TP, 'title')[0]) + + try: + self.version = getText(getChildrenByName(node, XMLNS_TP, 'version')[0]) + except IndexError: + self.version = None + + self.copyrights = map(getText, + getChildrenByName(node, XMLNS_TP, 'copyright')) + + try: + license = getChildrenByName(node, XMLNS_TP, 'license')[0] + license.tagName = 'div' + license.namespaceURI = None + license.setAttribute('class', 'license') + self.license = license.toxml() + except IndexError: + self.license = '' + + # FIXME: we need to check all args for type correctness + + def get_spec(self): + return self + + def lookup(self, name, namespace=None): + key = build_name(namespace, name) + return self.everything[key] + + def lookup_type(self, type_): + if type_.endswith('[]'): + return DBusList(self.lookup_type(type_[:-2])) + + if type_ == '': return None + elif type_ in self.types: + return self.types[type_] + + raise UnknownType("Type '%s' is unknown" % type_) + + def __repr__(self): + return '%s(%s)' % (self.__class__.__name__, self.title) + +def build_dict(parent, type_, namespace, nodes): + """Build a dictionary of D-Bus names to Python objects representing that + name using the XML node for that item in the spec. + + e.g. 'org.freedesktop.Telepathy.Channel' : Interface(Channel) + + Works for any Python object inheriting from 'Base' whose XML node + implements the 'name' attribute. + """ + + def build_tuple(node): + o = type_(parent, namespace, node) + return(o.name, o) + + return dict(build_tuple(n) for n in nodes) + +def build_list(parent, type_, namespace, nodes): + return map(lambda node: type_(parent, namespace, node), nodes) + +def parse_types(parent, dom, namespace = None): + """Parse all of the types of type nodes mentioned in 't' from the node + 'dom' and insert them into the dictionary 'd'. + """ + t = [ + (SimpleType, 'simple-type'), + (Enum, 'enum'), + (Flags, 'flags'), + (Mapping, 'mapping'), + (Struct, 'struct'), + (ExternalType, 'external-type'), + ] + + types = [] + + for (type_, tagname) in t: + types += build_list(parent, type_, namespace, + dom.getElementsByTagNameNS(XMLNS_TP, tagname)) + + return types + +def parse(filename, spec_namespace): + dom = xml.dom.minidom.parse(filename) + xincludator.xincludate(dom, filename) + + spec = Spec(dom, spec_namespace) + + return spec + +if __name__ == '__main__': + parse(sys.argv[1]) |