~verterok/ubuntuone-client/volumemanager_udfs-2

« back to all changes in this revision

Viewing changes to contrib/dbus-docs

  • Committer: Tarmac
  • Author(s): guillermo.gonzalez at canonical
  • Date: 2009-12-17 13:10:22 UTC
  • mfrom: (289.1.3 dbus-iface-docs)
  • Revision ID: john.lenton@canonical.com-20091217131022-1h4mlsys313hr0sl
export method and signal docstrings via DBus Introspect, add script to generate a simple text file with SyncDaemon DBus API

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
#
 
3
# Author: Guillermo Gonzalez <guillermo.gonzalez@canonical.com>
 
4
#
 
5
# Copyright 2009 Canonical Ltd.
 
6
#
 
7
# This program is free software: you can redistribute it and/or modify it
 
8
# under the terms of the GNU General Public License version 3, as published
 
9
# by the Free Software Foundation.
 
10
#
 
11
# This program is distributed in the hope that it will be useful, but
 
12
# WITHOUT ANY WARRANTY; without even the implied warranties of
 
13
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
 
14
# PURPOSE.  See the GNU General Public License for more details.
 
15
#
 
16
# You should have received a copy of the GNU General Public License along
 
17
# with this program.  If not, see <http://www.gnu.org/licenses/>.
 
18
 
 
19
from twisted.internet import glib2reactor
 
20
glib2reactor.install()
 
21
 
 
22
import sys
 
23
import os
 
24
import signal
 
25
import dbus
 
26
import subprocess
 
27
import shutil
 
28
 
 
29
from xml.etree import ElementTree
 
30
 
 
31
sys.path.insert(0, os.path.abspath("."))
 
32
 
 
33
from contrib.dbus_util import DBusRunner
 
34
from contrib.testing.testcase import (
 
35
    FakeMain, 
 
36
    DBusGMainLoop, 
 
37
    DBusInterface, 
 
38
    FakeNetworkManager,
 
39
)
 
40
 
 
41
from ubuntuone.syncdaemon.dbus_interface import (
 
42
    DBUS_IFACE_SYNC_NAME,
 
43
    DBUS_IFACE_STATUS_NAME,
 
44
    DBUS_IFACE_EVENTS_NAME,
 
45
    DBUS_IFACE_FS_NAME,
 
46
    DBUS_IFACE_SHARES_NAME,
 
47
    DBUS_IFACE_CONFIG_NAME,
 
48
)
 
49
from ubuntuone.syncdaemon.tools import DBusClient
 
50
from twisted.internet import reactor, defer
 
51
 
 
52
 
 
53
iface_path = ((DBUS_IFACE_SYNC_NAME, '/'), (DBUS_IFACE_CONFIG_NAME, '/config'),
 
54
              (DBUS_IFACE_EVENTS_NAME, '/events'), 
 
55
              (DBUS_IFACE_FS_NAME, '/filesystem'), 
 
56
              (DBUS_IFACE_SHARES_NAME, '/shares'), 
 
57
              (DBUS_IFACE_STATUS_NAME, '/status'))
 
58
 
 
59
 
 
60
def parse_introspect_data(xml):
 
61
    """Parse the xml returned by Introspect and returns a dict"""
 
62
    info = dict()
 
63
    e = ElementTree.fromstring(xml)
 
64
    for c in e.findall('interface'):
 
65
        # ignore other interfaces 
 
66
        if not c.attrib['name'].startswith('com.ubuntuone'):
 
67
            continue
 
68
        iface_name = c.attrib['name']
 
69
        info[iface_name] = dict()
 
70
        # methods
 
71
        methods = dict()
 
72
        for method in c.findall('method'):
 
73
            meth_name = method.attrib['name']
 
74
            args = []
 
75
            for arg in method.findall('arg'):
 
76
                dir = arg.attrib['direction']
 
77
                type = arg.attrib['type']
 
78
                if 'name' in arg.attrib:
 
79
                    name = arg.attrib['name']
 
80
                    args.append((type, dir, name))
 
81
                else:
 
82
                    args.append((type, dir))
 
83
            docstrings = method.findall('docstring')
 
84
            docstring = docstrings[0].text if docstrings else 'No docstring'
 
85
            methods[meth_name] = dict(args=args, docstring=docstring)
 
86
        info[iface_name]['methods'] = methods
 
87
        # signals
 
88
        signals = dict()
 
89
        for signal in c.findall('signal'):
 
90
            sig_name = signal.attrib['name']
 
91
            args = []
 
92
            for arg in signal.findall('arg'):
 
93
                type = arg.attrib['type']
 
94
                name = arg.attrib['name']
 
95
                args.append((type, name))
 
96
            docstrings = signal.findall('docstring')
 
97
            docstring = docstrings[0].text if docstrings else 'No docstring'
 
98
            signals[sig_name] = dict(args=args, docstring=docstring)
 
99
        info[iface_name]['signals'] = signals
 
100
    return info
 
101
 
 
102
 
 
103
def get_info(path):
 
104
    """Get all the introspectable info from 'path'"""
 
105
    d = defer.Deferred()
 
106
    client = DBusClient(bus, path, 'org.freedesktop.DBus.Introspectable')
 
107
    client.call_method('Introspect', reply_handler=d.callback, 
 
108
                       error_handler=d.errback)
 
109
    return d
 
110
 
 
111
 
 
112
def dump_to_stream(info_by_path, stream):
 
113
    print >>stream, "SyncDaemon DBus API\n"
 
114
    for path, interfaces in info_by_path.items():
 
115
        print >>stream, "Object path: %s" % path
 
116
        for iface_name, kinds in interfaces.items():
 
117
            print >>stream, "  Interface: %s" % iface_name
 
118
            print >>stream, "    Methods:"
 
119
            for meth_name, val in kinds['methods'].items():
 
120
                in_args = ','.join([arg[2] + '=' + arg[0] for arg in 
 
121
                                    val['args'] if arg[1] == 'in'])
 
122
                out_args = ','.join([arg[0] for arg in val['args'] 
 
123
                                     if arg[1] == 'out'])
 
124
                if out_args and in_args:
 
125
                    print >>stream, "      %s(%s) -> %s" % (meth_name, in_args,
 
126
                                                            out_args)
 
127
                elif in_args:
 
128
                    print >>stream, "      %s(%s)" % (meth_name, in_args)
 
129
                else:
 
130
                    print >>stream, "      %s()" % meth_name
 
131
                print >>stream, "        %s\n" % val['docstring']
 
132
            print >>stream, "    Signals:"
 
133
            for signal_name, val in kinds['signals'].items():
 
134
                in_args = ','.join([arg[1] + '=' + arg[0] \
 
135
                                    for arg in val['args']])
 
136
                if in_args:
 
137
                    print >>stream, "      %s(%s)" % (signal_name, in_args)
 
138
                else:
 
139
                    print >>stream, "      %s(%s)" % signal_name
 
140
                print >>stream, "        %s\n" % val['docstring']
 
141
 
 
142
 
 
143
@defer.inlineCallbacks
 
144
def main(bus):
 
145
    """Entry point"""
 
146
    info_by_path = dict()
 
147
    for iface, path in iface_path:
 
148
        xml = yield get_info(path)
 
149
        obj_info = parse_introspect_data(xml)
 
150
        info_by_path[path] = obj_info
 
151
    dest_file = os.path.join(os.getcwd(), 'docs', 'syncdaemon_dbus_api.txt')
 
152
    with open(dest_file, 'w') as f:
 
153
        dump_to_stream(info_by_path, f)
 
154
    reactor.stop() 
 
155
 
 
156
 
 
157
def start_syncdaemon(tmp_dir):
 
158
    """Starts a syncdaemon instance just like the one used in the test suite"""
 
159
    xdg_cache = os.path.join(tmp_dir, 'xdg_cache')
 
160
    data_dir = os.path.join(xdg_cache, 'data')
 
161
    partials_dir = os.path.join(xdg_cache, 'partials')
 
162
    root_dir = os.path.join(tmp_dir, 'root')
 
163
    shares_dir = os.path.join(tmp_dir, 'shares')
 
164
    main = FakeMain(root_dir, shares_dir, data_dir, partials_dir)
 
165
    loop = DBusGMainLoop(set_as_default=True)
 
166
    bus = dbus.bus.BusConnection(mainloop=loop)
 
167
    nm = FakeNetworkManager(bus)
 
168
    dbus_iface = DBusInterface(bus, main, system_bus=bus)
 
169
    main.dbus_iface = dbus_iface
 
170
    return main, bus
 
171
 
 
172
 
 
173
if __name__ == '__main__':
 
174
    dbus_runner = DBusRunner()
 
175
    dbus_runner.startDBus()
 
176
    tmp_dir = os.path.join(os.getcwd(), 'tmp')
 
177
    try:
 
178
 
 
179
        m, bus = start_syncdaemon(tmp_dir)
 
180
        try:
 
181
            reactor.callWhenRunning(main, bus)
 
182
            reactor.run()
 
183
        finally:
 
184
            m.quit()
 
185
    finally:
 
186
        dbus_runner.stopDBus()
 
187
        # remove the tmp dir
 
188
        os.chmod(tmp_dir, 0777)
 
189
        for dirpath, dirs, _ in os.walk(tmp_dir):
 
190
            for dir in dirs:
 
191
                os.chmod(os.path.join(dirpath, dir), 0777)
 
192
        shutil.rmtree(tmp_dir)
 
193