3
# Author: Guillermo Gonzalez <guillermo.gonzalez@canonical.com>
5
# Copyright 2009 Canonical Ltd.
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.
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.
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/>.
19
from twisted.internet import glib2reactor
20
glib2reactor.install()
29
from xml.etree import ElementTree
31
sys.path.insert(0, os.path.abspath("."))
33
from contrib.dbus_util import DBusRunner
34
from contrib.testing.testcase import (
41
from ubuntuone.syncdaemon.dbus_interface import (
43
DBUS_IFACE_STATUS_NAME,
44
DBUS_IFACE_EVENTS_NAME,
46
DBUS_IFACE_SHARES_NAME,
47
DBUS_IFACE_CONFIG_NAME,
49
from ubuntuone.syncdaemon.tools import DBusClient
50
from twisted.internet import reactor, defer
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'))
60
def parse_introspect_data(xml):
61
"""Parse the xml returned by Introspect and returns a 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'):
68
iface_name = c.attrib['name']
69
info[iface_name] = dict()
72
for method in c.findall('method'):
73
meth_name = method.attrib['name']
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))
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
89
for signal in c.findall('signal'):
90
sig_name = signal.attrib['name']
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
104
"""Get all the introspectable info from 'path'"""
106
client = DBusClient(bus, path, 'org.freedesktop.DBus.Introspectable')
107
client.call_method('Introspect', reply_handler=d.callback,
108
error_handler=d.errback)
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']
124
if out_args and in_args:
125
print >>stream, " %s(%s) -> %s" % (meth_name, in_args,
128
print >>stream, " %s(%s)" % (meth_name, in_args)
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']])
137
print >>stream, " %s(%s)" % (signal_name, in_args)
139
print >>stream, " %s(%s)" % signal_name
140
print >>stream, " %s\n" % val['docstring']
143
@defer.inlineCallbacks
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)
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
173
if __name__ == '__main__':
174
dbus_runner = DBusRunner()
175
dbus_runner.startDBus()
176
tmp_dir = os.path.join(os.getcwd(), 'tmp')
179
m, bus = start_syncdaemon(tmp_dir)
181
reactor.callWhenRunning(main, bus)
186
dbus_runner.stopDBus()
188
os.chmod(tmp_dir, 0777)
189
for dirpath, dirs, _ in os.walk(tmp_dir):
191
os.chmod(os.path.join(dirpath, dir), 0777)
192
shutil.rmtree(tmp_dir)