Merge lp:~cmiller/ubuntu/oneiric/desktopcouch/1.0.8-0u1 into lp:ubuntu/oneiric/desktopcouch
- Oneiric (11.10)
- 1.0.8-0u1
- Merge into oneiric
Status: | Merged |
---|---|
Merged at revision: | 47 |
Proposed branch: | lp:~cmiller/ubuntu/oneiric/desktopcouch/1.0.8-0u1 |
Merge into: | lp:ubuntu/oneiric/desktopcouch |
Diff against target: |
1660 lines (+521/-554) 29 files modified
MANIFEST (+126/-0) PKG-INFO (+21/-2) config/desktop-couch/default.ini (+3/-0) data/epydoc.conf (+25/-0) debian/changelog (+21/-0) debian/control (+2/-2) debian/patches/5-defer-dbus-service-for-plugins.patch (+0/-249) debian/python-desktopcouch-application.install (+6/-2) debian/python-desktopcouch-recordtypes.install (+4/-1) debian/rules (+0/-1) desktopcouch.egg-info/PKG-INFO (+0/-10) desktopcouch.egg-info/SOURCES.txt (+0/-126) desktopcouch.egg-info/dependency_links.txt (+0/-1) desktopcouch.egg-info/top_level.txt (+0/-1) desktopcouch/application/local_files.py (+5/-2) desktopcouch/application/platform/linux/tests/test_keyring.py (+1/-1) desktopcouch/application/platform/windows/tests/test_base_dirs.py (+2/-2) desktopcouch/application/plugins/__init__.py (+13/-3) desktopcouch/application/plugins/tests/test_plugins.py (+3/-1) desktopcouch/application/plugins/tests/test_ubuntuone_pairing.py (+36/-8) desktopcouch/application/plugins/ubuntuone_pairing.py (+75/-44) desktopcouch/application/replication.py (+1/-1) desktopcouch/application/service.py (+51/-11) desktopcouch/application/start_local_couchdb.py (+1/-1) desktopcouch/application/tests/test_service.py (+96/-62) desktopcouch/records/tests/test_mocked_server.py (+4/-3) desktopcouch/recordtypes/contacts/tests/test_view.py (+8/-8) setup.cfg (+4/-4) setup.py (+13/-8) |
To merge this branch: | bzr merge lp:~cmiller/ubuntu/oneiric/desktopcouch/1.0.8-0u1 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu branches | Pending | ||
Review via email: mp+75028@code.launchpad.net |
Commit message
Description of the change
New version:
Behavior change: Preserves Ubuntu One service through longer replication period, 10 minutes changed to 60 minutes.
Feature: Allow COUCH_INI environment variable to override /etc/ default config.
Feature: Install apport hook.
Bug fix: When ubuntuone credentials don't exist, don't wait forever and consume CPU.
Bug fix: Accept "linux3" kernel also.
Bug fix: Clean up all children when service exits.
- 48. By Chad Miller
-
- Behavior change: Preserves Ubuntu One service through longer replication
period, 10 minutes changed to 60 minutes.
- Feature: Allow COUCH_INI environment variable to override /etc/ default
config.
- Feature: Install apport hook.
- Bug fix: When ubuntuone credentials don't exist, don't wait forever and
consume CPU.
- Bug fix: Accept "linux3" kernel also.
- Bug fix: Clean up all children when service exits. - 49. By Chad Miller
-
consume CPU. (LP: #760236, #787583)
- Bug fix: Accept "linux3" kernel also. (LP: #803062)
- Bug fix: Clean up all children when service exits. (LP: #597197)
Preview Diff
1 | === added file 'MANIFEST' |
2 | --- MANIFEST 1970-01-01 00:00:00 +0000 |
3 | +++ MANIFEST 2011-09-13 15:01:24 +0000 |
4 | @@ -0,0 +1,126 @@ |
5 | +# file GENERATED by distutils, do NOT edit |
6 | +COPYING |
7 | +COPYING.LESSER |
8 | +MANIFEST |
9 | +MANIFEST.in |
10 | +README |
11 | +desktopcouch-pair.desktop.in |
12 | +org.desktopcouch.CouchDB.service |
13 | +setup.cfg |
14 | +setup.py |
15 | +start-desktop-couchdb.sh |
16 | +stop-desktop-couchdb.sh |
17 | +bin/desktopcouch-get-port |
18 | +bin/desktopcouch-pair |
19 | +bin/desktopcouch-service |
20 | +bin/desktopcouch-stop |
21 | +config/desktop-couch/compulsory-auth.ini |
22 | +config/desktop-couch/default.ini |
23 | +data/couchdb.tmpl |
24 | +data/epydoc.conf |
25 | +data/source_desktopcouch.py |
26 | +desktopcouch/__init__.py |
27 | +desktopcouch/local_files.py |
28 | +desktopcouch/replication.py |
29 | +desktopcouch/service.py |
30 | +desktopcouch/start_local_couchdb.py |
31 | +desktopcouch/stop_local_couchdb.py |
32 | +desktopcouch/util.py |
33 | +desktopcouch/application/__init__.py |
34 | +desktopcouch/application/local_files.py |
35 | +desktopcouch/application/replication.py |
36 | +desktopcouch/application/server.py |
37 | +desktopcouch/application/service.py |
38 | +desktopcouch/application/start_local_couchdb.py |
39 | +desktopcouch/application/stop_local_couchdb.py |
40 | +desktopcouch/application/util.py |
41 | +desktopcouch/application/migration/__init__.py |
42 | +desktopcouch/application/migration/tests/__init__.py |
43 | +desktopcouch/application/migration/tests/test_migration.py |
44 | +desktopcouch/application/pair/__init__.py |
45 | +desktopcouch/application/pair/couchdb_pairing/__init__.py |
46 | +desktopcouch/application/pair/couchdb_pairing/couchdb_io.py |
47 | +desktopcouch/application/pair/couchdb_pairing/dbus_io.py |
48 | +desktopcouch/application/pair/couchdb_pairing/network_io.py |
49 | +desktopcouch/application/pair/tests/__init__.py |
50 | +desktopcouch/application/pair/tests/test_couchdb_io.py |
51 | +desktopcouch/application/pair/tests/test_network_io.py |
52 | +desktopcouch/application/platform/__init__.py |
53 | +desktopcouch/application/platform/linux/__init__.py |
54 | +desktopcouch/application/platform/linux/base_dirs.py |
55 | +desktopcouch/application/platform/linux/ipc.py |
56 | +desktopcouch/application/platform/linux/keyring.py |
57 | +desktopcouch/application/platform/linux/tests/__init__.py |
58 | +desktopcouch/application/platform/linux/tests/test_keyring.py |
59 | +desktopcouch/application/platform/windows/__init__.py |
60 | +desktopcouch/application/platform/windows/base_dirs.py |
61 | +desktopcouch/application/platform/windows/keyring.py |
62 | +desktopcouch/application/platform/windows/tests/__init__.py |
63 | +desktopcouch/application/platform/windows/tests/test_base_dirs.py |
64 | +desktopcouch/application/platform/windows/tests/test_keyring.py |
65 | +desktopcouch/application/plugins/__init__.py |
66 | +desktopcouch/application/plugins/ubuntuone_pairing.py |
67 | +desktopcouch/application/plugins/tests/__init__.py |
68 | +desktopcouch/application/plugins/tests/test_plugins.py |
69 | +desktopcouch/application/plugins/tests/test_ubuntuone_pairing.py |
70 | +desktopcouch/application/replication_services/__init__.py |
71 | +desktopcouch/application/replication_services/example.py |
72 | +desktopcouch/application/replication_services/ubuntuone.py |
73 | +desktopcouch/application/tests/__init__.py |
74 | +desktopcouch/application/tests/test_local_files.py |
75 | +desktopcouch/application/tests/test_replication.py |
76 | +desktopcouch/application/tests/test_service.py |
77 | +desktopcouch/application/tests/test_start_local_couchdb.py |
78 | +desktopcouch/bookmarks/__init__.py |
79 | +desktopcouch/bookmarks/record.py |
80 | +desktopcouch/contacts/__init__.py |
81 | +desktopcouch/contacts/record.py |
82 | +desktopcouch/contacts/view.py |
83 | +desktopcouch/notes/__init__.py |
84 | +desktopcouch/notes/record.py |
85 | +desktopcouch/pair/__init__.py |
86 | +desktopcouch/pair/couchdb_pairing/__init__.py |
87 | +desktopcouch/pair/couchdb_pairing/couchdb_io.py |
88 | +desktopcouch/pair/couchdb_pairing/dbus_io.py |
89 | +desktopcouch/pair/couchdb_pairing/network_io.py |
90 | +desktopcouch/pair/couchdb_pairing/ubuntuone_pairing.py |
91 | +desktopcouch/records/__init__.py |
92 | +desktopcouch/records/database.py |
93 | +desktopcouch/records/field_registry.py |
94 | +desktopcouch/records/http.py |
95 | +desktopcouch/records/record.py |
96 | +desktopcouch/records/server.py |
97 | +desktopcouch/records/server_base.py |
98 | +desktopcouch/records/doc/an_example_application.txt |
99 | +desktopcouch/records/doc/field_registry.txt |
100 | +desktopcouch/records/doc/records.txt |
101 | +desktopcouch/records/tests/__init__.py |
102 | +desktopcouch/records/tests/test_field_registry.py |
103 | +desktopcouch/records/tests/test_mocked_server.py |
104 | +desktopcouch/records/tests/test_record.py |
105 | +desktopcouch/records/tests/test_server.py |
106 | +desktopcouch/recordtypes/__init__.py |
107 | +desktopcouch/recordtypes/bookmarks.py |
108 | +desktopcouch/recordtypes/notes.py |
109 | +desktopcouch/recordtypes/tasks.py |
110 | +desktopcouch/recordtypes/contacts/__init__.py |
111 | +desktopcouch/recordtypes/contacts/schema.txt |
112 | +desktopcouch/recordtypes/contacts/view.py |
113 | +desktopcouch/recordtypes/contacts/testing/__init__.py |
114 | +desktopcouch/recordtypes/contacts/testing/create.py |
115 | +desktopcouch/recordtypes/contacts/tests/__init__.py |
116 | +desktopcouch/recordtypes/contacts/tests/test_create.py |
117 | +desktopcouch/recordtypes/contacts/tests/test_record.py |
118 | +desktopcouch/recordtypes/contacts/tests/test_view.py |
119 | +desktopcouch/recordtypes/tests/__init__.py |
120 | +desktopcouch/recordtypes/tests/test_bookmarks.py |
121 | +desktopcouch/recordtypes/tests/test_notes.py |
122 | +desktopcouch/recordtypes/tests/test_tasks.py |
123 | +desktopcouch/replication_services/__init__.py |
124 | +desktopcouch/replication_services/example.py |
125 | +desktopcouch/replication_services/ubuntuone.py |
126 | +desktopcouch/tasks/__init__.py |
127 | +desktopcouch/tasks/record.py |
128 | +desktopcouch/tests/__init__.py |
129 | +docs/man/desktopcouch-pair.1 |
130 | +po/POTFILES.in |
131 | |
132 | === modified file 'PKG-INFO' |
133 | --- PKG-INFO 2011-04-08 20:42:51 +0000 |
134 | +++ PKG-INFO 2011-09-13 15:01:24 +0000 |
135 | @@ -1,6 +1,6 @@ |
136 | -Metadata-Version: 1.0 |
137 | +Metadata-Version: 1.1 |
138 | Name: desktopcouch |
139 | -Version: 1.0.7 |
140 | +Version: 1.0.8 |
141 | Summary: A Desktop CouchDB instance. |
142 | Home-page: https://launchpad.net/desktopcouch |
143 | Author: Stuart Langridge |
144 | @@ -8,3 +8,22 @@ |
145 | License: LGPL-3 |
146 | Description: UNKNOWN |
147 | Platform: UNKNOWN |
148 | +Requires: avahi |
149 | +Requires: couchdb |
150 | +Requires: dbus |
151 | +Requires: gnomekeyring |
152 | +Requires: gobject |
153 | +Requires: gtk |
154 | +Requires: mocker |
155 | +Requires: oauth |
156 | +Requires: pango |
157 | +Requires: pygtk |
158 | +Requires: simplejson |
159 | +Requires: twisted.internet |
160 | +Requires: twisted.protocols |
161 | +Requires: twisted.python.threadable |
162 | +Requires: ubuntu_sso |
163 | +Requires: ubuntuone.clientdefs |
164 | +Requires: ubuntuone.devtools.testcase |
165 | +Requires: xdg.BaseDirectory |
166 | +Provides: desktopcouch |
167 | |
168 | === added file 'config/desktop-couch/default.ini' |
169 | --- config/desktop-couch/default.ini 1970-01-01 00:00:00 +0000 |
170 | +++ config/desktop-couch/default.ini 2011-09-13 15:01:24 +0000 |
171 | @@ -0,0 +1,3 @@ |
172 | +[replicator] |
173 | +max_http_sessions = 1 |
174 | + |
175 | |
176 | === added file 'data/epydoc.conf' |
177 | --- data/epydoc.conf 1970-01-01 00:00:00 +0000 |
178 | +++ data/epydoc.conf 2011-09-13 15:01:24 +0000 |
179 | @@ -0,0 +1,25 @@ |
180 | +[epydoc] # Epydoc section marker (required by ConfigParser) |
181 | + |
182 | +# Information about the project. |
183 | +name: desktopcouch |
184 | +url: http://www.freedesktop.org/wiki/Specifications/desktopcouch |
185 | + |
186 | +# The list of modules to document. Modules can be named using |
187 | +# dotted names, module filenames, or package directory names. |
188 | +# This option may be repeated. |
189 | +modules: desktopcouch, desktopcouch.records |
190 | +exclude: test |
191 | + |
192 | +# Write html output to the directory "apidocs" |
193 | +output: html |
194 | +target: docs/html/api/ |
195 | + |
196 | + |
197 | +parse: yes |
198 | +introspect: no |
199 | + |
200 | +# Include all automatically generated graphs. These graphs are |
201 | +# generated using Graphviz dot. |
202 | +graph: all |
203 | +dotpath: /usr/bin/dot |
204 | + |
205 | |
206 | === modified file 'debian/changelog' |
207 | --- debian/changelog 2011-08-25 09:29:15 +0000 |
208 | +++ debian/changelog 2011-09-13 15:01:24 +0000 |
209 | @@ -1,3 +1,24 @@ |
210 | +desktopcouch (1.0.8-0ubuntu1) UNRELEASED; urgency=low |
211 | + |
212 | + * New upstream release. |
213 | + - Behavior change: Preserves Ubuntu One service through longer replication |
214 | + period, 10 minutes changed to 60 minutes. |
215 | + - Feature: Allow COUCH_INI environment variable to override /etc/ default |
216 | + config. |
217 | + - Feature: Install apport hook. |
218 | + - Bug fix: When ubuntuone credentials don't exist, don't wait forever and |
219 | + consume CPU. (LP: #760236, #787583) |
220 | + - Bug fix: Accept "linux3" kernel also. (LP: #803062) |
221 | + - Bug fix: Clean up all children when service exits. (LP: #597197) |
222 | + * Update standards-version 3.9.1 to 3.9.2. |
223 | + * Remove brace-expansion from python-desktopcouch-application.install . |
224 | + * Remove brace-expansion from python-desktopcouch-recordtypes.install . |
225 | + * Remove patch |
226 | + - patches/5-defer-dbus-service-for-plugins.patch |
227 | + * Remove deprecated CDBS simple-patch system from rules. |
228 | + |
229 | + -- Chad MILLER <chad.miller@canonical.com> Mon, 12 Sep 2011 13:08:25 -0400 |
230 | + |
231 | desktopcouch (1.0.7-0ubuntu3) oneiric; urgency=low |
232 | |
233 | * debian/rules: langpack.mk does not exist any more, call dh_translations |
234 | |
235 | === modified file 'debian/control' |
236 | --- debian/control 2011-01-12 15:08:25 +0000 |
237 | +++ debian/control 2011-09-13 15:01:24 +0000 |
238 | @@ -8,7 +8,7 @@ |
239 | python-distutils-extra (>= 2.8), |
240 | python-setuptools |
241 | Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com> |
242 | -Standards-Version: 3.9.1 |
243 | +Standards-Version: 3.9.2 |
244 | XS-Python-Version: current |
245 | Homepage: http://launchpad.net/desktopcouch |
246 | |
247 | @@ -20,7 +20,7 @@ |
248 | couchdb-bin (>= 0.10.0-0ubuntu3), |
249 | python-desktopcouch-application (= ${source:Version}) |
250 | Breaks: gwibber-service (<< 2.31.0), gwibber (<< 2.31.0) |
251 | -Description: A Desktop CouchDB instance |
252 | +Description: Desktop CouchDB instance |
253 | Runs an instance of CouchDB with the user's session. Includes python library |
254 | for interacting with database. |
255 | |
256 | |
257 | === removed file 'debian/patches/5-defer-dbus-service-for-plugins.patch' |
258 | --- debian/patches/5-defer-dbus-service-for-plugins.patch 2011-04-15 23:48:39 +0000 |
259 | +++ debian/patches/5-defer-dbus-service-for-plugins.patch 1970-01-01 00:00:00 +0000 |
260 | @@ -1,249 +0,0 @@ |
261 | -Description: Make plugins be able to stall dbus service from signaling that |
262 | - couchdb is ready to use. |
263 | -Bug-Ubuntu: https://bugs.edge.launchpad.net/ubuntu/+source/desktopcouch/+bug/760236 |
264 | -Applied-upstream: bzr id chad.miller@canonical.com-20110412173802-flmya9dma0et83qr |
265 | -Author: Chad Miller <chad.miller@canonical.com> |
266 | - |
267 | - |
268 | -=== modified file 'desktopcouch/application/plugins/__init__.py' |
269 | ---- desktopcouch/application/plugins/__init__.py 2011-02-02 18:15:53 +0000 |
270 | -+++ desktopcouch/application/plugins/__init__.py 2011-04-15 23:40:28 +0000 |
271 | -@@ -19,8 +19,18 @@ |
272 | - DESKTOPCOUCH_PLUGIN_PATHS = [os.path.join(os.path.dirname(__file__))] |
273 | - |
274 | - |
275 | --def load_plugins(couchdb_port): |
276 | -- """Load the desktopcouch application plug-ins.""" |
277 | -+def load_plugins(couchdb_port, blocking_semaphores, gobject): |
278 | -+ """Load the desktopcouch application plug-ins. |
279 | -+ |
280 | -+ The blocking_semaphores set is OPTIONALLY mutated by any plugin to signal |
281 | -+ that the service is not ready until a plugin has finished its asynchronous |
282 | -+ operations. Plugins may add a distinguishing object to the set, and it |
283 | -+ must remove what it adds when it is finished. |
284 | -+ |
285 | -+ couchdb -- the integer of the port number of the running couchdb |
286 | -+ blocking_semaphores -- the set() of semaphores, which we will mutate |
287 | -+ gobject -- the mainloop module. always 'gobject' except when testing. |
288 | -+ """ |
289 | - plugin_names = set() |
290 | - for path in DESKTOPCOUCH_PLUGIN_PATHS: |
291 | - try: |
292 | -@@ -37,6 +47,6 @@ |
293 | - modpath = name.replace(os.path.sep, '.')[:-3] |
294 | - try: |
295 | - plugin = __import__(modpath, None, None, ['']) |
296 | -- plugin.plugin_init(couchdb_port) |
297 | -+ plugin.plugin_init(couchdb_port, blocking_semaphores, gobject) |
298 | - except (ImportError, AttributeError): |
299 | - logging.warning('Failed to load plug-in: %s', modpath) |
300 | - |
301 | -=== modified file 'desktopcouch/application/plugins/ubuntuone_pairing.py' |
302 | ---- desktopcouch/application/plugins/ubuntuone_pairing.py 2011-02-02 18:15:53 +0000 |
303 | -+++ desktopcouch/application/plugins/ubuntuone_pairing.py 2011-04-15 23:41:29 +0000 |
304 | -@@ -24,6 +24,7 @@ |
305 | - from desktopcouch.application.server import DesktopDatabase |
306 | - from ubuntuone.clientdefs import APP_NAME |
307 | - |
308 | -+PLUGIN_NAME = __name__ |
309 | - U1_PAIR_RECORD = "ubuntu_one_pair_record" |
310 | - MAP_JS = """function(doc) { |
311 | - if (doc.service_name == "ubuntuone") { |
312 | -@@ -33,48 +34,57 @@ |
313 | - """ |
314 | - |
315 | - |
316 | --def pair_with_ubuntuone(couchdb_port, management_db=None, |
317 | -+def pair_with_ubuntuone(couchdb_port, blocking_semaphores, |
318 | -+ management_db=None, |
319 | - db_class=DesktopDatabase, |
320 | - put_service_fn=put_static_paired_service): |
321 | - """Adds a pairing record with ubuntu one when needed.""" |
322 | -- # Use explicit uri so that we do not access dbus service. |
323 | -- uri = "http://localhost:%s" % (couchdb_port,) |
324 | -- if not management_db: |
325 | -- management_db = db_class("management", uri=uri, create=True, ctx=None) |
326 | -- # we indeed have credentials to add to the pairing records |
327 | -- # but first we ensure that the required view is present |
328 | -- if not management_db.view_exists(U1_PAIR_RECORD, U1_PAIR_RECORD): |
329 | -- management_db.add_view( |
330 | -- U1_PAIR_RECORD, MAP_JS, design_doc=U1_PAIR_RECORD) |
331 | -- view_results = management_db.execute_view(U1_PAIR_RECORD, U1_PAIR_RECORD) |
332 | -- pairing_found = False |
333 | -- # Results should contain either one row or no rows |
334 | -- # If there is one row, its value will be 0, meaning that there is |
335 | -- # already an Ubuntu One pairing record, or 1, meaning that there |
336 | -- # was an Ubuntu One pairing record but it has since been unpaired |
337 | -- # Only create a new record if there is not one already. Specifically, |
338 | -- # do not add the record if there is a deleted one, as this means |
339 | -- # that the user explicitly unpaired it! |
340 | -- for row in view_results: |
341 | -- pairing_found = True |
342 | -- if row.value == 1: |
343 | -- logging.debug("Not adding desktopcouch pairing since the user " |
344 | -- "has explicitly unpaired with Ubuntu One") |
345 | -- else: |
346 | -- logging.debug("Not adding desktopcouch pairing since we are " |
347 | -- "already paired") |
348 | -- if not pairing_found: |
349 | -- put_service_fn(None, "ubuntuone", uri=uri, ctx=None) |
350 | -- logging.debug("Pairing desktopcouch with Ubuntu One") |
351 | -- |
352 | -- |
353 | --def got_new_credentials(couchdb_port, app_name, credentials): |
354 | -+ try: |
355 | -+ # Use explicit uri so that we do not access dbus service. |
356 | -+ uri = "http://localhost:%s" % (couchdb_port,) |
357 | -+ if not management_db: |
358 | -+ management_db = db_class("management", uri=uri, create=True, |
359 | -+ ctx=None) |
360 | -+ # we indeed have credentials to add to the pairing records |
361 | -+ # but first we ensure that the required view is present |
362 | -+ if not management_db.view_exists(U1_PAIR_RECORD, U1_PAIR_RECORD): |
363 | -+ management_db.add_view( |
364 | -+ U1_PAIR_RECORD, MAP_JS, design_doc=U1_PAIR_RECORD) |
365 | -+ view_results = management_db.execute_view(U1_PAIR_RECORD, |
366 | -+ U1_PAIR_RECORD) |
367 | -+ pairing_found = False |
368 | -+ # Results should contain either one row or no rows |
369 | -+ # If there is one row, its value will be 0, meaning that there is |
370 | -+ # already an Ubuntu One pairing record, or 1, meaning that there |
371 | -+ # was an Ubuntu One pairing record but it has since been unpaired |
372 | -+ # Only create a new record if there is not one already. Specifically, |
373 | -+ # do not add the record if there is a deleted one, as this means |
374 | -+ # that the user explicitly unpaired it! |
375 | -+ for row in view_results: |
376 | -+ pairing_found = True |
377 | -+ if row.value == 1: |
378 | -+ logging.debug("Not adding desktopcouch pairing since the user " |
379 | -+ "has explicitly unpaired with Ubuntu One") |
380 | -+ else: |
381 | -+ logging.debug("Not adding desktopcouch pairing since we are " |
382 | -+ "already paired") |
383 | -+ if not pairing_found: |
384 | -+ put_service_fn(None, "ubuntuone", uri=uri, ctx=None) |
385 | -+ logging.debug("Pairing desktopcouch with Ubuntu One") |
386 | -+ |
387 | -+ finally: |
388 | -+ logging.info("removing semaphore for %s", PLUGIN_NAME) |
389 | -+ blocking_semaphores.discard(PLUGIN_NAME) |
390 | -+ |
391 | -+ |
392 | -+def got_new_credentials(couchdb_port, blocking_semaphores, |
393 | -+ app_name, credentials): |
394 | - """Pair with Ubuntu One when we get the new credentials.""" |
395 | - if app_name == APP_NAME: |
396 | -- pair_with_ubuntuone(couchdb_port) |
397 | -- |
398 | -- |
399 | --def listen_to_dbus(couchdb_port): |
400 | -+ pair_with_ubuntuone(couchdb_port, blocking_semaphores) |
401 | -+ |
402 | -+ |
403 | -+def listen_to_dbus(couchdb_port, blocking_semaphores): |
404 | - """Set up the signal handler on D-Bus for Ubuntu One pairing.""" |
405 | - import dbus |
406 | - bus = dbus.SessionBus() |
407 | -@@ -82,7 +92,9 @@ |
408 | - try: |
409 | - import ubuntu_sso |
410 | - |
411 | -- receiver = lambda *args: got_new_credentials(couchdb_port, *args) |
412 | -+ receiver = lambda *args: \ |
413 | -+ got_new_credentials(couchdb_port, blocking_semaphores, |
414 | -+ *args) |
415 | - |
416 | - iface = ubuntu_sso.DBUS_CREDENTIALS_IFACE |
417 | - bus.add_signal_receiver(handler_function=receiver, |
418 | -@@ -96,13 +108,20 @@ |
419 | - sso_backend.find_credentials(APP_NAME, {}) |
420 | - except ImportError: |
421 | - logging.info('Ubuntu SSO is not available.') |
422 | -- |
423 | -- |
424 | --def plugin_init(couchdb_port): |
425 | -+ blocking_semaphores.discard(PLUGIN_NAME) |
426 | -+ |
427 | -+ |
428 | -+def plugin_init(couchdb_port, blocking_semaphores, gobject): |
429 | - """Set up the signal handler for pairing with Ubuntu One.""" |
430 | - logging.info('Loaded Ubuntu One extension for desktopcouch.') |
431 | - if sys.platform == 'win32': |
432 | - logging.warning('Windows support for Ubuntu One is not yet ready.') |
433 | - else: |
434 | -- import gobject |
435 | -- gobject.idle_add(listen_to_dbus, couchdb_port) |
436 | -+ |
437 | -+ # Signal that we are critical for desktopcouch usage, and the server |
438 | -+ # must not begin until we are finished. We are responsible for |
439 | -+ # removing this item from the list. |
440 | -+ logging.info("adding %s to to blocking semaphore list", PLUGIN_NAME) |
441 | -+ blocking_semaphores.add(PLUGIN_NAME) |
442 | -+ |
443 | -+ gobject.idle_add(listen_to_dbus, couchdb_port, blocking_semaphores) |
444 | - |
445 | -=== modified file 'desktopcouch/application/service.py' |
446 | ---- desktopcouch/application/service.py 2011-02-02 18:15:53 +0000 |
447 | -+++ desktopcouch/application/service.py 2011-04-15 23:42:17 +0000 |
448 | -@@ -39,6 +39,7 @@ |
449 | - import logging |
450 | - import logging.handlers |
451 | - import signal |
452 | -+import gobject |
453 | - |
454 | - from desktopcouch.application import local_files |
455 | - from desktopcouch.application import replication |
456 | -@@ -84,7 +85,8 @@ |
457 | - replication_actions=replication, |
458 | - advertiser_factory=PortAdvertiser, set_logging=set_up_logging, |
459 | - fork=os.fork, nice=os.nice, |
460 | -- kill=os.kill, sleep=time.sleep): |
461 | -+ kill=os.kill, sleep=time.sleep, set_type=set, |
462 | -+ gobject_module=gobject): |
463 | - self._mainloop = main_loop |
464 | - self._pid_finder = pid_finder |
465 | - self._port_finder = port_finder |
466 | -@@ -97,6 +99,8 @@ |
467 | - self._nice = nice |
468 | - self._kill = kill |
469 | - self._sleep = sleep |
470 | -+ self._set = set_type |
471 | -+ self._gobject = gobject_module |
472 | - # pylint: enable=C0301 |
473 | - |
474 | - def _start_replicator_main(self, couchdb_port): |
475 | -@@ -112,11 +116,30 @@ |
476 | - replication.tear_down(*replication_runtime) |
477 | - |
478 | - def _start_server_main(self, couchdb_port): |
479 | -- """Start server.""" |
480 | -- self._advertiser_factory(self._mainloop.stop, self._ctx) |
481 | -+ """Start server answering DBus calls, and run plugins first.""" |
482 | -+ |
483 | -+ def if_all_semaphores_cleared(blocking_semaphores, |
484 | -+ func, *args, **kwargs): |
485 | -+ """Run a function if no semaphores exist, else try later.""" |
486 | -+ if blocking_semaphores: |
487 | -+ return True # Make idle call try us again. |
488 | -+ else: |
489 | -+ func(*args, **kwargs) |
490 | -+ return False # Handled! |
491 | -+ |
492 | -+ blocking_semaphores = self._set() |
493 | -+ load_plugins(couchdb_port, blocking_semaphores, self._gobject) |
494 | -+ |
495 | -+ # Answering queries on DBus signals that we are ready for users |
496 | -+ # to connect. We mustn't begin that until every plugin has a chance |
497 | -+ # to run to completion if it needs it. |
498 | -+ self._gobject.idle_add(if_all_semaphores_cleared, blocking_semaphores, |
499 | -+ self._advertiser_factory, |
500 | -+ self._mainloop.stop, |
501 | -+ self._ctx) |
502 | -+ |
503 | - logging.debug("starting dbus main loop") |
504 | - try: |
505 | -- load_plugins(couchdb_port) |
506 | - self._mainloop.run() |
507 | - finally: |
508 | - logging.debug("ending dbus main loop") |
509 | - |
510 | |
511 | === modified file 'debian/python-desktopcouch-application.install' |
512 | --- debian/python-desktopcouch-application.install 2011-01-12 15:08:25 +0000 |
513 | +++ debian/python-desktopcouch-application.install 2011-09-13 15:01:24 +0000 |
514 | @@ -1,5 +1,8 @@ |
515 | debian/tmp/usr/lib/*/*/desktopcouch/application/*.py |
516 | -debian/tmp/usr/lib/*/*/desktopcouch/application/{migration,pair,platform,replication_services} |
517 | +debian/tmp/usr/lib/*/*/desktopcouch/application/migration |
518 | +debian/tmp/usr/lib/*/*/desktopcouch/application/pair |
519 | +debian/tmp/usr/lib/*/*/desktopcouch/application/platform |
520 | +debian/tmp/usr/lib/*/*/desktopcouch/application/replication_services |
521 | debian/tmp/usr/lib/*/*/desktopcouch/application/plugins/__init__.py |
522 | debian/tmp/usr/lib/*/*/desktopcouch/local_files.py |
523 | debian/tmp/usr/lib/*/*/desktopcouch/replication.py |
524 | @@ -7,4 +10,5 @@ |
525 | debian/tmp/usr/lib/*/*/desktopcouch/start_local_couchdb.py |
526 | debian/tmp/usr/lib/*/*/desktopcouch/stop_local_couchdb.py |
527 | debian/tmp/usr/lib/*/*/desktopcouch/util.py |
528 | -debian/tmp/usr/lib/*/*/desktopcouch/{pair,replication_services} |
529 | +debian/tmp/usr/lib/*/*/desktopcouch/pair |
530 | +debian/tmp/usr/lib/*/*/desktopcouch/replication_services |
531 | |
532 | === modified file 'debian/python-desktopcouch-recordtypes.install' |
533 | --- debian/python-desktopcouch-recordtypes.install 2011-01-12 15:08:25 +0000 |
534 | +++ debian/python-desktopcouch-recordtypes.install 2011-09-13 15:01:24 +0000 |
535 | @@ -1,2 +1,5 @@ |
536 | debian/tmp/usr/lib/*/*/desktopcouch/recordtypes |
537 | -debian/tmp/usr/lib/*/*/desktopcouch/{bookmarks,contacts,notes,tasks} |
538 | +debian/tmp/usr/lib/*/*/desktopcouch/bookmarks |
539 | +debian/tmp/usr/lib/*/*/desktopcouch/contacts |
540 | +debian/tmp/usr/lib/*/*/desktopcouch/notes |
541 | +debian/tmp/usr/lib/*/*/desktopcouch/tasks |
542 | |
543 | === modified file 'debian/rules' |
544 | --- debian/rules 2011-08-25 09:28:07 +0000 |
545 | +++ debian/rules 2011-09-13 15:01:24 +0000 |
546 | @@ -5,7 +5,6 @@ |
547 | |
548 | include /usr/share/cdbs/1/rules/debhelper.mk |
549 | include /usr/share/cdbs/1/class/python-distutils.mk |
550 | -include /usr/share/cdbs/1/rules/simple-patchsys.mk |
551 | |
552 | common-binary-post-install-indep:: |
553 | dh_translations |
554 | |
555 | === removed directory 'desktopcouch.egg-info' |
556 | === removed file 'desktopcouch.egg-info/PKG-INFO' |
557 | --- desktopcouch.egg-info/PKG-INFO 2011-04-08 20:42:51 +0000 |
558 | +++ desktopcouch.egg-info/PKG-INFO 1970-01-01 00:00:00 +0000 |
559 | @@ -1,10 +0,0 @@ |
560 | -Metadata-Version: 1.0 |
561 | -Name: desktopcouch |
562 | -Version: 1.0.7 |
563 | -Summary: A Desktop CouchDB instance. |
564 | -Home-page: https://launchpad.net/desktopcouch |
565 | -Author: Stuart Langridge |
566 | -Author-email: stuart.langridge@canonical.com |
567 | -License: LGPL-3 |
568 | -Description: UNKNOWN |
569 | -Platform: UNKNOWN |
570 | |
571 | === removed file 'desktopcouch.egg-info/SOURCES.txt' |
572 | --- desktopcouch.egg-info/SOURCES.txt 2011-01-12 15:08:25 +0000 |
573 | +++ desktopcouch.egg-info/SOURCES.txt 1970-01-01 00:00:00 +0000 |
574 | @@ -1,126 +0,0 @@ |
575 | -COPYING |
576 | -COPYING.LESSER |
577 | -MANIFEST.in |
578 | -README |
579 | -desktopcouch-pair.desktop.in |
580 | -org.desktopcouch.CouchDB.service |
581 | -setup.cfg |
582 | -setup.py |
583 | -start-desktop-couchdb.sh |
584 | -stop-desktop-couchdb.sh |
585 | -bin/desktopcouch-get-port |
586 | -bin/desktopcouch-pair |
587 | -bin/desktopcouch-service |
588 | -bin/desktopcouch-stop |
589 | -config/desktop-couch/compulsory-auth.ini |
590 | -data/couchdb.tmpl |
591 | -data/source_desktopcouch.py |
592 | -desktopcouch/__init__.py |
593 | -desktopcouch/local_files.py |
594 | -desktopcouch/replication.py |
595 | -desktopcouch/service.py |
596 | -desktopcouch/start_local_couchdb.py |
597 | -desktopcouch/stop_local_couchdb.py |
598 | -desktopcouch/util.py |
599 | -desktopcouch.egg-info/PKG-INFO |
600 | -desktopcouch.egg-info/SOURCES.txt |
601 | -desktopcouch.egg-info/dependency_links.txt |
602 | -desktopcouch.egg-info/top_level.txt |
603 | -desktopcouch/application/__init__.py |
604 | -desktopcouch/application/local_files.py |
605 | -desktopcouch/application/replication.py |
606 | -desktopcouch/application/server.py |
607 | -desktopcouch/application/service.py |
608 | -desktopcouch/application/start_local_couchdb.py |
609 | -desktopcouch/application/stop_local_couchdb.py |
610 | -desktopcouch/application/util.py |
611 | -desktopcouch/application/migration/__init__.py |
612 | -desktopcouch/application/migration/tests/__init__.py |
613 | -desktopcouch/application/migration/tests/test_migration.py |
614 | -desktopcouch/application/pair/__init__.py |
615 | -desktopcouch/application/pair/couchdb_pairing/__init__.py |
616 | -desktopcouch/application/pair/couchdb_pairing/couchdb_io.py |
617 | -desktopcouch/application/pair/couchdb_pairing/dbus_io.py |
618 | -desktopcouch/application/pair/couchdb_pairing/network_io.py |
619 | -desktopcouch/application/pair/tests/__init__.py |
620 | -desktopcouch/application/pair/tests/test_couchdb_io.py |
621 | -desktopcouch/application/pair/tests/test_network_io.py |
622 | -desktopcouch/application/platform/__init__.py |
623 | -desktopcouch/application/platform/linux/__init__.py |
624 | -desktopcouch/application/platform/linux/base_dirs.py |
625 | -desktopcouch/application/platform/linux/ipc.py |
626 | -desktopcouch/application/platform/linux/keyring.py |
627 | -desktopcouch/application/platform/linux/tests/__init__.py |
628 | -desktopcouch/application/platform/linux/tests/test_keyring.py |
629 | -desktopcouch/application/platform/windows/__init__.py |
630 | -desktopcouch/application/platform/windows/base_dirs.py |
631 | -desktopcouch/application/platform/windows/keyring.py |
632 | -desktopcouch/application/platform/windows/tests/__init__.py |
633 | -desktopcouch/application/platform/windows/tests/test_base_dirs.py |
634 | -desktopcouch/application/platform/windows/tests/test_keyring.py |
635 | -desktopcouch/application/plugins/__init__.py |
636 | -desktopcouch/application/plugins/ubuntuone_pairing.py |
637 | -desktopcouch/application/plugins/tests/__init__.py |
638 | -desktopcouch/application/plugins/tests/test_plugins.py |
639 | -desktopcouch/application/plugins/tests/test_ubuntuone_pairing.py |
640 | -desktopcouch/application/replication_services/__init__.py |
641 | -desktopcouch/application/replication_services/example.py |
642 | -desktopcouch/application/replication_services/ubuntuone.py |
643 | -desktopcouch/application/tests/__init__.py |
644 | -desktopcouch/application/tests/test_local_files.py |
645 | -desktopcouch/application/tests/test_replication.py |
646 | -desktopcouch/application/tests/test_service.py |
647 | -desktopcouch/application/tests/test_start_local_couchdb.py |
648 | -desktopcouch/bookmarks/__init__.py |
649 | -desktopcouch/bookmarks/record.py |
650 | -desktopcouch/contacts/__init__.py |
651 | -desktopcouch/contacts/record.py |
652 | -desktopcouch/contacts/view.py |
653 | -desktopcouch/notes/__init__.py |
654 | -desktopcouch/notes/record.py |
655 | -desktopcouch/pair/__init__.py |
656 | -desktopcouch/pair/couchdb_pairing/__init__.py |
657 | -desktopcouch/pair/couchdb_pairing/couchdb_io.py |
658 | -desktopcouch/pair/couchdb_pairing/dbus_io.py |
659 | -desktopcouch/pair/couchdb_pairing/network_io.py |
660 | -desktopcouch/pair/couchdb_pairing/ubuntuone_pairing.py |
661 | -desktopcouch/records/__init__.py |
662 | -desktopcouch/records/database.py |
663 | -desktopcouch/records/field_registry.py |
664 | -desktopcouch/records/http.py |
665 | -desktopcouch/records/record.py |
666 | -desktopcouch/records/server.py |
667 | -desktopcouch/records/server_base.py |
668 | -desktopcouch/records/doc/an_example_application.txt |
669 | -desktopcouch/records/doc/field_registry.txt |
670 | -desktopcouch/records/doc/records.txt |
671 | -desktopcouch/records/tests/__init__.py |
672 | -desktopcouch/records/tests/test_field_registry.py |
673 | -desktopcouch/records/tests/test_mocked_server.py |
674 | -desktopcouch/records/tests/test_record.py |
675 | -desktopcouch/records/tests/test_server.py |
676 | -desktopcouch/recordtypes/__init__.py |
677 | -desktopcouch/recordtypes/bookmarks.py |
678 | -desktopcouch/recordtypes/notes.py |
679 | -desktopcouch/recordtypes/tasks.py |
680 | -desktopcouch/recordtypes/contacts/__init__.py |
681 | -desktopcouch/recordtypes/contacts/schema.txt |
682 | -desktopcouch/recordtypes/contacts/view.py |
683 | -desktopcouch/recordtypes/contacts/testing/__init__.py |
684 | -desktopcouch/recordtypes/contacts/testing/create.py |
685 | -desktopcouch/recordtypes/contacts/tests/__init__.py |
686 | -desktopcouch/recordtypes/contacts/tests/test_create.py |
687 | -desktopcouch/recordtypes/contacts/tests/test_record.py |
688 | -desktopcouch/recordtypes/contacts/tests/test_view.py |
689 | -desktopcouch/recordtypes/tests/__init__.py |
690 | -desktopcouch/recordtypes/tests/test_bookmarks.py |
691 | -desktopcouch/recordtypes/tests/test_notes.py |
692 | -desktopcouch/recordtypes/tests/test_tasks.py |
693 | -desktopcouch/replication_services/__init__.py |
694 | -desktopcouch/replication_services/example.py |
695 | -desktopcouch/replication_services/ubuntuone.py |
696 | -desktopcouch/tasks/__init__.py |
697 | -desktopcouch/tasks/record.py |
698 | -desktopcouch/tests/__init__.py |
699 | -docs/man/desktopcouch-pair.1 |
700 | -po/POTFILES.in |
701 | \ No newline at end of file |
702 | |
703 | === removed file 'desktopcouch.egg-info/dependency_links.txt' |
704 | --- desktopcouch.egg-info/dependency_links.txt 2009-10-22 17:15:57 +0000 |
705 | +++ desktopcouch.egg-info/dependency_links.txt 1970-01-01 00:00:00 +0000 |
706 | @@ -1,1 +0,0 @@ |
707 | - |
708 | |
709 | === removed file 'desktopcouch.egg-info/top_level.txt' |
710 | --- desktopcouch.egg-info/top_level.txt 2009-10-22 17:15:57 +0000 |
711 | +++ desktopcouch.egg-info/top_level.txt 1970-01-01 00:00:00 +0000 |
712 | @@ -1,1 +0,0 @@ |
713 | -desktopcouch |
714 | |
715 | === modified file 'desktopcouch/application/local_files.py' |
716 | --- desktopcouch/application/local_files.py 2011-04-08 20:40:53 +0000 |
717 | +++ desktopcouch/application/local_files.py 2011-09-13 15:01:24 +0000 |
718 | @@ -83,9 +83,11 @@ |
719 | if "-hashed-" in bookmark_file_contents: |
720 | raise ValueError("Basic-auth cred lost.") |
721 | # trial run, check sanity. |
722 | + # pylint: disable=W0106 |
723 | re.findall( |
724 | "<!-- !!([^!]+)!!([^!]+)!! -->", |
725 | bookmark_file_contents)[-1] |
726 | + # pylint: enable=W0106 |
727 | self._fill_from_file(self.file_name_used) |
728 | return |
729 | except (IOError, ValueError, IndexError): |
730 | @@ -196,7 +198,7 @@ |
731 | for d in (run_dir, db_dir, config_dir): |
732 | try: |
733 | os.makedirs(d, 0700) |
734 | - except OSError, ex: |
735 | + except OSError: |
736 | pass # Probably that it already exists. |
737 | try: |
738 | os.chmod(d, 0700) |
739 | @@ -257,7 +259,8 @@ |
740 | def couch_chain_ini_files(self): |
741 | """Chain couchdb ini files.""" |
742 | # Explicitly add default ini file |
743 | - ini_files = ["/etc/couchdb/default.ini"] |
744 | + ini_files = [os.environ.get("COUCHDB_INI") or |
745 | + "/etc/couchdb/default.ini"] |
746 | |
747 | # find all ini files in the desktopcouch XDG_CONFIG_DIRS and |
748 | # add them to the chain |
749 | |
750 | === modified file 'desktopcouch/application/platform/linux/tests/test_keyring.py' |
751 | --- desktopcouch/application/platform/linux/tests/test_keyring.py 2011-01-12 15:08:25 +0000 |
752 | +++ desktopcouch/application/platform/linux/tests/test_keyring.py 2011-09-13 15:01:24 +0000 |
753 | @@ -30,7 +30,7 @@ |
754 | try: |
755 | import gnomekeyring |
756 | except ImportError, e: |
757 | - if sys.platform != 'linux2': |
758 | + if not sys.platform.startswith('linux'): |
759 | gnomekeyring = None |
760 | else: |
761 | raise e |
762 | |
763 | === modified file 'desktopcouch/application/platform/windows/tests/test_base_dirs.py' |
764 | --- desktopcouch/application/platform/windows/tests/test_base_dirs.py 2011-02-02 18:15:53 +0000 |
765 | +++ desktopcouch/application/platform/windows/tests/test_base_dirs.py 2011-09-13 15:01:24 +0000 |
766 | @@ -63,7 +63,7 @@ |
767 | self.mocker.result('hive') |
768 | self._winreg.OpenKey('hive', SHELL_FOLDERS_KEY) |
769 | self.mocker.result('key') |
770 | - self._winreg.QueryInfoKey('key')[1] |
771 | + self._winreg.QueryInfoKey('key')[1] # pylint: disable=W0106 |
772 | self.mocker.throw(Exception('Cannot get info.')) |
773 | self._winreg.CloseKey('hive') |
774 | self._winreg.CloseKey('key') |
775 | @@ -78,7 +78,7 @@ |
776 | self.mocker.result('hive') |
777 | self._winreg.OpenKey('hive', SHELL_FOLDERS_KEY) |
778 | self.mocker.result('key') |
779 | - self._winreg.QueryInfoKey('key')[1] |
780 | + self._winreg.QueryInfoKey('key')[1] # pylint: disable=W0106 |
781 | self.mocker.result(1) |
782 | self._winreg.EnumValue('key', 0) |
783 | self.mocker.result(('AppData', 'path', 1)) |
784 | |
785 | === modified file 'desktopcouch/application/plugins/__init__.py' |
786 | --- desktopcouch/application/plugins/__init__.py 2011-02-02 18:15:53 +0000 |
787 | +++ desktopcouch/application/plugins/__init__.py 2011-09-13 15:01:24 +0000 |
788 | @@ -19,8 +19,18 @@ |
789 | DESKTOPCOUCH_PLUGIN_PATHS = [os.path.join(os.path.dirname(__file__))] |
790 | |
791 | |
792 | -def load_plugins(couchdb_port): |
793 | - """Load the desktopcouch application plug-ins.""" |
794 | +def load_plugins(couchdb_port, blocking_semaphores, gobject): |
795 | + """Load the desktopcouch application plug-ins. |
796 | + |
797 | + The blocking_semaphores set is OPTIONALLY mutated by any plugin to signal |
798 | + that the service is not ready until a plugin has finished its asynchronous |
799 | + operations. Plugins may add a distinguishing object to the set, and it |
800 | + must remove what it adds when it is finished. |
801 | + |
802 | + couchdb -- the integer of the port number of the running couchdb |
803 | + blocking_semaphores -- the set() of semaphores, which we will mutate |
804 | + gobject -- the mainloop module. always 'gobject' except when testing. |
805 | + """ |
806 | plugin_names = set() |
807 | for path in DESKTOPCOUCH_PLUGIN_PATHS: |
808 | try: |
809 | @@ -37,6 +47,6 @@ |
810 | modpath = name.replace(os.path.sep, '.')[:-3] |
811 | try: |
812 | plugin = __import__(modpath, None, None, ['']) |
813 | - plugin.plugin_init(couchdb_port) |
814 | + plugin.plugin_init(couchdb_port, blocking_semaphores, gobject) |
815 | except (ImportError, AttributeError): |
816 | logging.warning('Failed to load plug-in: %s', modpath) |
817 | |
818 | === modified file 'desktopcouch/application/plugins/tests/test_plugins.py' |
819 | --- desktopcouch/application/plugins/tests/test_plugins.py 2011-02-02 18:15:53 +0000 |
820 | +++ desktopcouch/application/plugins/tests/test_plugins.py 2011-09-13 15:01:24 +0000 |
821 | @@ -28,6 +28,8 @@ |
822 | |
823 | def setUp(self): |
824 | self.couchdb_port = platform.find_port(ctx=test_context) |
825 | + self.blockers = set() |
826 | + self.gobject = None |
827 | |
828 | def test_load_plugins(self): |
829 | """Test that plug-ins are loaded correctly.""" |
830 | @@ -44,7 +46,7 @@ |
831 | self._imported = modname |
832 | old_import = __import__ |
833 | __builtins__['__import__'] = _fake_import |
834 | - plugins.load_plugins(self.couchdb_port) |
835 | + plugins.load_plugins(self.couchdb_port, self.blockers, self.gobject) |
836 | __builtins__['__import__'] = old_import |
837 | plugins.DESKTOPCOUCH_PLUGIN_PATHS = old_paths |
838 | self.assertEqual(self._imported, __name__) |
839 | |
840 | === modified file 'desktopcouch/application/plugins/tests/test_ubuntuone_pairing.py' |
841 | --- desktopcouch/application/plugins/tests/test_ubuntuone_pairing.py 2011-02-02 18:15:53 +0000 |
842 | +++ desktopcouch/application/plugins/tests/test_ubuntuone_pairing.py 2011-09-13 15:01:24 +0000 |
843 | @@ -38,9 +38,11 @@ |
844 | self.couchdb_port = self.mocker.mock() |
845 | self.put_static_paired_service = self.mocker.mock() |
846 | self.database_class = self.mocker.mock() |
847 | + self.blocking_semaphores = self.mocker.mock() |
848 | |
849 | def test_pair_with_ubuntuone_no_view(self): |
850 | """Test that when the view is not present it is indeed created.""" |
851 | + # plugin_init adds name to blocking semaphores, but we remove it. |
852 | self.couchdb.view_exists(U1_PAIR_RECORD, U1_PAIR_RECORD) |
853 | self.mocker.result(False) |
854 | # we are interested in the fact that the view is created |
855 | @@ -50,8 +52,11 @@ |
856 | self.couchdb.execute_view(U1_PAIR_RECORD, U1_PAIR_RECORD) |
857 | self.mocker.result([]) |
858 | self.put_static_paired_service(None, 'ubuntuone', ctx=None, uri=ANY) |
859 | + self.blocking_semaphores.discard(ANY) |
860 | + |
861 | self.mocker.replay() |
862 | - pair_with_ubuntuone(self.couchdb_port, self.couchdb, |
863 | + pair_with_ubuntuone(self.couchdb_port, self.blocking_semaphores, |
864 | + management_db=self.couchdb, |
865 | db_class=self.database_class, |
866 | put_service_fn=self.put_static_paired_service) |
867 | self.mocker.verify() |
868 | @@ -59,21 +64,27 @@ |
869 | def test_pair_with_ubuntuone_no_record(self): |
870 | """Ensure pairing is not done when there are no records .""" |
871 | # execute the steps when no records are returned by the view |
872 | + # plugin_init adds name to blocking semaphores, but we remove it. |
873 | self.couchdb.view_exists(U1_PAIR_RECORD, U1_PAIR_RECORD) |
874 | self.mocker.result(True) |
875 | self.couchdb.execute_view(U1_PAIR_RECORD, U1_PAIR_RECORD) |
876 | self.mocker.result([]) |
877 | self.put_static_paired_service(None, 'ubuntuone', ctx=None, uri=ANY) |
878 | + self.blocking_semaphores.discard(ANY) |
879 | + |
880 | self.mocker.replay() |
881 | - pair_with_ubuntuone(self.couchdb_port, self.couchdb, |
882 | + pair_with_ubuntuone(self.couchdb_port, self.blocking_semaphores, |
883 | + management_db=self.couchdb, |
884 | db_class=self.database_class, |
885 | put_service_fn=self.put_static_paired_service) |
886 | + |
887 | self.mocker.verify() |
888 | |
889 | def test_pair_with_ubuntuone_user_deleted_record(self): |
890 | """Ensure pairing is not done when the user explicitly removed it.""" |
891 | # create a mock object that will be the result from the view |
892 | row = self.mocker.mock() |
893 | + # plugin_init adds name to blocking semaphores, but we remove it. |
894 | # execute the steps to show that the user deleted the record |
895 | self.couchdb.view_exists(U1_PAIR_RECORD, U1_PAIR_RECORD) |
896 | self.mocker.result(True) |
897 | @@ -82,14 +93,18 @@ |
898 | # FIXME does this do anything? |
899 | _ = row.value |
900 | self.mocker.result(1) |
901 | + self.blocking_semaphores.discard(ANY) |
902 | + |
903 | self.mocker.replay() |
904 | - pair_with_ubuntuone(self.couchdb_port, self.couchdb) |
905 | + pair_with_ubuntuone(self.couchdb_port, self.blocking_semaphores, |
906 | + management_db=self.couchdb) |
907 | self.mocker.verify() |
908 | |
909 | def test_pair_with_ubuntuone_record_present(self): |
910 | """Ensure pairing is not done when the record is already present.""" |
911 | # create a mock object that will be the result from the view |
912 | row = self.mocker.mock() |
913 | + # plugin_init adds name to blocking semaphores, but we remove it. |
914 | # execute the steps to show that the user deleted the record |
915 | self.couchdb.view_exists(U1_PAIR_RECORD, U1_PAIR_RECORD) |
916 | self.mocker.result(True) |
917 | @@ -98,8 +113,11 @@ |
918 | # FIXME does this do anything? |
919 | _ = row.value |
920 | self.mocker.result(0) |
921 | + self.blocking_semaphores.discard(ANY) |
922 | + |
923 | self.mocker.replay() |
924 | - pair_with_ubuntuone(self.couchdb_port, self.couchdb) |
925 | + pair_with_ubuntuone(self.couchdb_port, self.blocking_semaphores, |
926 | + management_db=self.couchdb) |
927 | self.mocker.verify() |
928 | |
929 | |
930 | @@ -109,6 +127,7 @@ |
931 | def setUp(self): |
932 | super(TestUbuntuOnePlugin, self).setUp() |
933 | self.couchdb_port = self.mocker.mock() |
934 | + self.blocking_semaphores = self.mocker.mock() |
935 | self.called = False |
936 | |
937 | def test_got_new_credentials_other(self): |
938 | @@ -117,21 +136,27 @@ |
939 | """Fail if we get called.""" |
940 | self.called = True |
941 | |
942 | + saved_pair = uone.pair_with_ubuntuone |
943 | uone.pair_with_ubuntuone = fail_if_called |
944 | - uone.got_new_credentials(self.couchdb_port, 'Unknown App', {}) |
945 | + uone.got_new_credentials(self.couchdb_port, self.blocking_semaphores, |
946 | + 'Unknown App', {}) |
947 | self.assertFalse(self.called, 'pair_with_ubuntuone was not expected.') |
948 | self.mocker.replay() |
949 | + uone.pair_with_ubuntuone = saved_pair |
950 | |
951 | def test_got_new_credentials(self): |
952 | """Check that pairing is called for Ubuntu One.""" |
953 | - def pass_if_called(db=None): |
954 | + def pass_if_called(db=None, semaphores=None): |
955 | """Check that pair_with_ubuntuone was called.""" |
956 | self.called = True |
957 | |
958 | + saved_pair = uone.pair_with_ubuntuone |
959 | uone.pair_with_ubuntuone = pass_if_called |
960 | - uone.got_new_credentials(self.couchdb_port, uone.APP_NAME, {}) |
961 | + uone.got_new_credentials(self.couchdb_port, self.blocking_semaphores, |
962 | + uone.APP_NAME, {}) |
963 | self.assertTrue(self.called, 'pair_with_ubuntuone was not called.') |
964 | self.mocker.replay() |
965 | + uone.pair_with_ubuntuone = saved_pair |
966 | |
967 | def test_listen_to_dbus(self): |
968 | """Test that listening to credentails works.""" |
969 | @@ -144,6 +169,9 @@ |
970 | |
971 | iface = ubuntu_sso.DBUS_CREDENTIALS_IFACE |
972 | bus.add_signal_receiver(handler_function=ANY, |
973 | + signal_name='CredentialsNotFound', |
974 | + dbus_interface=iface) |
975 | + bus.add_signal_receiver(handler_function=ANY, |
976 | signal_name='CredentialsFound', |
977 | dbus_interface=iface) |
978 | |
979 | @@ -161,4 +189,4 @@ |
980 | |
981 | self.mocker.replay() |
982 | |
983 | - uone.listen_to_dbus(self.couchdb_port) |
984 | + uone.listen_to_dbus(self.couchdb_port, self.blocking_semaphores) |
985 | |
986 | === modified file 'desktopcouch/application/plugins/ubuntuone_pairing.py' |
987 | --- desktopcouch/application/plugins/ubuntuone_pairing.py 2011-02-02 18:15:53 +0000 |
988 | +++ desktopcouch/application/plugins/ubuntuone_pairing.py 2011-09-13 15:01:24 +0000 |
989 | @@ -24,6 +24,8 @@ |
990 | from desktopcouch.application.server import DesktopDatabase |
991 | from ubuntuone.clientdefs import APP_NAME |
992 | |
993 | +TIMEOUT_SEC = 20 |
994 | +PLUGIN_NAME = __name__ |
995 | U1_PAIR_RECORD = "ubuntu_one_pair_record" |
996 | MAP_JS = """function(doc) { |
997 | if (doc.service_name == "ubuntuone") { |
998 | @@ -32,49 +34,57 @@ |
999 | } |
1000 | """ |
1001 | |
1002 | - |
1003 | -def pair_with_ubuntuone(couchdb_port, management_db=None, |
1004 | +def pair_with_ubuntuone(couchdb_port, blocking_semaphores, |
1005 | + management_db=None, |
1006 | db_class=DesktopDatabase, |
1007 | put_service_fn=put_static_paired_service): |
1008 | """Adds a pairing record with ubuntu one when needed.""" |
1009 | - # Use explicit uri so that we do not access dbus service. |
1010 | - uri = "http://localhost:%s" % (couchdb_port,) |
1011 | - if not management_db: |
1012 | - management_db = db_class("management", uri=uri, create=True, ctx=None) |
1013 | - # we indeed have credentials to add to the pairing records |
1014 | - # but first we ensure that the required view is present |
1015 | - if not management_db.view_exists(U1_PAIR_RECORD, U1_PAIR_RECORD): |
1016 | - management_db.add_view( |
1017 | - U1_PAIR_RECORD, MAP_JS, design_doc=U1_PAIR_RECORD) |
1018 | - view_results = management_db.execute_view(U1_PAIR_RECORD, U1_PAIR_RECORD) |
1019 | - pairing_found = False |
1020 | - # Results should contain either one row or no rows |
1021 | - # If there is one row, its value will be 0, meaning that there is |
1022 | - # already an Ubuntu One pairing record, or 1, meaning that there |
1023 | - # was an Ubuntu One pairing record but it has since been unpaired |
1024 | - # Only create a new record if there is not one already. Specifically, |
1025 | - # do not add the record if there is a deleted one, as this means |
1026 | - # that the user explicitly unpaired it! |
1027 | - for row in view_results: |
1028 | - pairing_found = True |
1029 | - if row.value == 1: |
1030 | - logging.debug("Not adding desktopcouch pairing since the user " |
1031 | - "has explicitly unpaired with Ubuntu One") |
1032 | - else: |
1033 | - logging.debug("Not adding desktopcouch pairing since we are " |
1034 | - "already paired") |
1035 | - if not pairing_found: |
1036 | - put_service_fn(None, "ubuntuone", uri=uri, ctx=None) |
1037 | - logging.debug("Pairing desktopcouch with Ubuntu One") |
1038 | - |
1039 | - |
1040 | -def got_new_credentials(couchdb_port, app_name, credentials): |
1041 | + try: |
1042 | + # Use explicit uri so that we do not access dbus service. |
1043 | + uri = "http://localhost:%s" % (couchdb_port,) |
1044 | + if not management_db: |
1045 | + management_db = db_class("management", uri=uri, create=True, |
1046 | + ctx=None) |
1047 | + # we indeed have credentials to add to the pairing records |
1048 | + # but first we ensure that the required view is present |
1049 | + if not management_db.view_exists(U1_PAIR_RECORD, U1_PAIR_RECORD): |
1050 | + management_db.add_view( |
1051 | + U1_PAIR_RECORD, MAP_JS, design_doc=U1_PAIR_RECORD) |
1052 | + view_results = management_db.execute_view(U1_PAIR_RECORD, |
1053 | + U1_PAIR_RECORD) |
1054 | + pairing_found = False |
1055 | + # Results should contain either one row or no rows |
1056 | + # If there is one row, its value will be 0, meaning that there is |
1057 | + # already an Ubuntu One pairing record, or 1, meaning that there |
1058 | + # was an Ubuntu One pairing record but it has since been unpaired |
1059 | + # Only create a new record if there is not one already. Specifically, |
1060 | + # do not add the record if there is a deleted one, as this means |
1061 | + # that the user explicitly unpaired it! |
1062 | + for row in view_results: |
1063 | + pairing_found = True |
1064 | + if row.value == 1: |
1065 | + logging.debug("Not adding desktopcouch pairing since the user " |
1066 | + "has explicitly unpaired with Ubuntu One") |
1067 | + else: |
1068 | + logging.debug("Not adding desktopcouch pairing since we are " |
1069 | + "already paired") |
1070 | + if not pairing_found: |
1071 | + put_service_fn(None, "ubuntuone", uri=uri, ctx=None) |
1072 | + logging.debug("Pairing desktopcouch with Ubuntu One") |
1073 | + |
1074 | + finally: |
1075 | + logging.info("removing semaphore for %s", PLUGIN_NAME) |
1076 | + blocking_semaphores.discard(PLUGIN_NAME) |
1077 | + |
1078 | + |
1079 | +def got_new_credentials(couchdb_port, blocking_semaphores, |
1080 | + app_name, credentials): |
1081 | """Pair with Ubuntu One when we get the new credentials.""" |
1082 | if app_name == APP_NAME: |
1083 | - pair_with_ubuntuone(couchdb_port) |
1084 | - |
1085 | - |
1086 | -def listen_to_dbus(couchdb_port): |
1087 | + pair_with_ubuntuone(couchdb_port, blocking_semaphores) |
1088 | + |
1089 | + |
1090 | +def listen_to_dbus(couchdb_port, blocking_semaphores): |
1091 | """Set up the signal handler on D-Bus for Ubuntu One pairing.""" |
1092 | import dbus |
1093 | bus = dbus.SessionBus() |
1094 | @@ -82,9 +92,20 @@ |
1095 | try: |
1096 | import ubuntu_sso |
1097 | |
1098 | - receiver = lambda *args: got_new_credentials(couchdb_port, *args) |
1099 | + receiver = lambda *args: \ |
1100 | + got_new_credentials(couchdb_port, blocking_semaphores, |
1101 | + *args) |
1102 | + def abort_getting_credentials(*args): |
1103 | + """Log and remove our semaphore.""" |
1104 | + logging.warn("Credentials not found for ubuntuone.") |
1105 | + blocking_semaphores.discard(PLUGIN_NAME) |
1106 | |
1107 | iface = ubuntu_sso.DBUS_CREDENTIALS_IFACE |
1108 | + |
1109 | + bus.add_signal_receiver(handler_function=abort_getting_credentials, |
1110 | + signal_name='CredentialsNotFound', |
1111 | + dbus_interface=iface) |
1112 | + |
1113 | bus.add_signal_receiver(handler_function=receiver, |
1114 | signal_name='CredentialsFound', |
1115 | dbus_interface=iface) |
1116 | @@ -96,13 +117,23 @@ |
1117 | sso_backend.find_credentials(APP_NAME, {}) |
1118 | except ImportError: |
1119 | logging.info('Ubuntu SSO is not available.') |
1120 | - |
1121 | - |
1122 | -def plugin_init(couchdb_port): |
1123 | + blocking_semaphores.discard(PLUGIN_NAME) |
1124 | + |
1125 | + |
1126 | +def plugin_init(couchdb_port, blocking_semaphores, gobject): |
1127 | """Set up the signal handler for pairing with Ubuntu One.""" |
1128 | logging.info('Loaded Ubuntu One extension for desktopcouch.') |
1129 | if sys.platform == 'win32': |
1130 | logging.warning('Windows support for Ubuntu One is not yet ready.') |
1131 | else: |
1132 | - import gobject |
1133 | - gobject.idle_add(listen_to_dbus, couchdb_port) |
1134 | + |
1135 | + # Signal that we are critical for desktopcouch usage, and the server |
1136 | + # must not begin until we are finished. We are responsible for |
1137 | + # removing this item from the list. |
1138 | + logging.info("adding %s to to blocking semaphore list", PLUGIN_NAME) |
1139 | + blocking_semaphores.add(PLUGIN_NAME) |
1140 | + |
1141 | + gobject.idle_add(listen_to_dbus, couchdb_port, blocking_semaphores) |
1142 | + |
1143 | + gobject.timeout_add_seconds(TIMEOUT_SEC, blocking_semaphores.discard, |
1144 | + PLUGIN_NAME) |
1145 | |
1146 | === modified file 'desktopcouch/application/replication.py' |
1147 | --- desktopcouch/application/replication.py 2011-01-12 15:08:25 +0000 |
1148 | +++ desktopcouch/application/replication.py 2011-09-13 15:01:24 +0000 |
1149 | @@ -246,7 +246,7 @@ |
1150 | dbus_io.maintain_discovered_servers() |
1151 | |
1152 | task_running = task.LoopingCall(do_all_replication, int(port)) |
1153 | - task_running.start(600) |
1154 | + task_running.start(3600) |
1155 | |
1156 | # TODO: port may change, so every so often, check it and |
1157 | # perhaps refresh the beacons. We return an array of beacons, so we could |
1158 | |
1159 | === modified file 'desktopcouch/application/service.py' |
1160 | --- desktopcouch/application/service.py 2011-02-02 18:15:53 +0000 |
1161 | +++ desktopcouch/application/service.py 2011-09-13 15:01:24 +0000 |
1162 | @@ -39,6 +39,7 @@ |
1163 | import logging |
1164 | import logging.handlers |
1165 | import signal |
1166 | +import gobject |
1167 | |
1168 | from desktopcouch.application import local_files |
1169 | from desktopcouch.application import replication |
1170 | @@ -84,7 +85,8 @@ |
1171 | replication_actions=replication, |
1172 | advertiser_factory=PortAdvertiser, set_logging=set_up_logging, |
1173 | fork=os.fork, nice=os.nice, |
1174 | - kill=os.kill, sleep=time.sleep): |
1175 | + kill=os.kill, sleep=time.sleep, set_type=set, |
1176 | + gobject_module=gobject): |
1177 | self._mainloop = main_loop |
1178 | self._pid_finder = pid_finder |
1179 | self._port_finder = port_finder |
1180 | @@ -97,6 +99,8 @@ |
1181 | self._nice = nice |
1182 | self._kill = kill |
1183 | self._sleep = sleep |
1184 | + self._set = set_type |
1185 | + self._gobject = gobject_module |
1186 | # pylint: enable=C0301 |
1187 | |
1188 | def _start_replicator_main(self, couchdb_port): |
1189 | @@ -112,25 +116,46 @@ |
1190 | replication.tear_down(*replication_runtime) |
1191 | |
1192 | def _start_server_main(self, couchdb_port): |
1193 | - """Start server.""" |
1194 | - self._advertiser_factory(self._mainloop.stop, self._ctx) |
1195 | + """Start server answering DBus calls, and run plugins first.""" |
1196 | + |
1197 | + def if_all_semaphores_cleared(blocking_semaphores, |
1198 | + func, *args, **kwargs): |
1199 | + """Run a function if no semaphores exist, else try later.""" |
1200 | + if blocking_semaphores: |
1201 | + self._sleep(0.2) # Never peg the CPU |
1202 | + return True # Make idle call try us again. |
1203 | + else: |
1204 | + func(*args, **kwargs) |
1205 | + return False # Handled! |
1206 | + |
1207 | + blocking_semaphores = self._set() |
1208 | + load_plugins(couchdb_port, blocking_semaphores, self._gobject) |
1209 | + |
1210 | + # Answering queries on DBus signals that we are ready for users |
1211 | + # to connect. We mustn't begin that until every plugin has a chance |
1212 | + # to run to completion if it needs it. |
1213 | + self._gobject.idle_add(if_all_semaphores_cleared, blocking_semaphores, |
1214 | + self._advertiser_factory, |
1215 | + self._mainloop.stop, |
1216 | + self._ctx) |
1217 | + |
1218 | logging.debug("starting dbus main loop") |
1219 | try: |
1220 | - load_plugins(couchdb_port) |
1221 | self._mainloop.run() |
1222 | finally: |
1223 | logging.debug("ending dbus main loop") |
1224 | |
1225 | def start(self): |
1226 | """Start the services used by desktopcouch.""" |
1227 | - should_shut_down_couchdb = False |
1228 | + maintained_child_pids = list() |
1229 | couchdb_pid = self._pid_finder(start_if_not_running=False, |
1230 | ctx=self._ctx) |
1231 | if couchdb_pid is None: |
1232 | logging.warn("Starting up personal couchdb.") |
1233 | couchdb_pid = self._pid_finder(start_if_not_running=True, |
1234 | ctx=self._ctx) |
1235 | - should_shut_down_couchdb = True |
1236 | + if couchdb_pid: |
1237 | + maintained_child_pids.append(couchdb_pid) |
1238 | else: |
1239 | logging.warn("Personal couchdb is already running at PID#%d.", |
1240 | couchdb_pid) |
1241 | @@ -145,6 +170,7 @@ |
1242 | return |
1243 | else: |
1244 | assert child_pid > 0 |
1245 | + maintained_child_pids.append(child_pid) |
1246 | child_pid = self._fork() # Split! |
1247 | if child_pid == 0: |
1248 | # Let's be the migration tool! |
1249 | @@ -161,8 +187,18 @@ |
1250 | return |
1251 | else: |
1252 | assert child_pid > 0 |
1253 | + maintained_child_pids.append(child_pid) |
1254 | # Let's be the dbus server! |
1255 | # This is the parent process. When we exit, we kill children. |
1256 | + |
1257 | + def receive_signal(signum, stackframe): |
1258 | + """On signal, quit main loop gracefully.""" |
1259 | + logging.warn("Received signal %d. Quitting.", signum) |
1260 | + self._mainloop.stop() |
1261 | + |
1262 | + signal.signal(signal.SIGHUP, receive_signal) |
1263 | + signal.signal(signal.SIGTERM, receive_signal) |
1264 | + |
1265 | try: |
1266 | set_up_logging("dbus") |
1267 | # offer the dbus service |
1268 | @@ -172,14 +208,18 @@ |
1269 | "uncaught exception makes us shut down.") |
1270 | finally: |
1271 | logging.info("exiting.") |
1272 | - if should_shut_down_couchdb: |
1273 | - logging.warn("shutting down personal couchdb.") |
1274 | - self._stop_couchdb(ctx=self._ctx) |
1275 | + self._stop_couchdb(ctx=self._ctx) |
1276 | |
1277 | + for child_pid in maintained_child_pids: |
1278 | try: |
1279 | self._kill(child_pid, signal.SIGTERM) |
1280 | - self._sleep(1) |
1281 | + logging.warn("Sent SIGTERM to %d", child_pid) |
1282 | + except OSError: |
1283 | + pass |
1284 | + self._sleep(1) |
1285 | + for child_pid in maintained_child_pids: |
1286 | + try: |
1287 | self._kill(child_pid, signal.SIGKILL) |
1288 | + logging.warn("Sent SIGKILL to %d", child_pid) |
1289 | except OSError: |
1290 | pass |
1291 | - return # pylint: disable=W0150 |
1292 | |
1293 | === modified file 'desktopcouch/application/start_local_couchdb.py' |
1294 | --- desktopcouch/application/start_local_couchdb.py 2011-04-08 20:40:53 +0000 |
1295 | +++ desktopcouch/application/start_local_couchdb.py 2011-09-13 15:01:24 +0000 |
1296 | @@ -166,7 +166,7 @@ |
1297 | break |
1298 | except RuntimeError, ex: |
1299 | saved_exception = ex |
1300 | - logging.exception("Starting couchdb failed on try %d", (retry,)) |
1301 | + logging.exception("Starting couchdb failed on try %d", retry) |
1302 | time.sleep(1) |
1303 | continue |
1304 | |
1305 | |
1306 | === modified file 'desktopcouch/application/tests/test_service.py' |
1307 | --- desktopcouch/application/tests/test_service.py 2011-02-02 18:15:53 +0000 |
1308 | +++ desktopcouch/application/tests/test_service.py 2011-09-13 15:01:24 +0000 |
1309 | @@ -37,6 +37,8 @@ |
1310 | self._replication = self.mocker.mock() |
1311 | self._advertiser = self.mocker.mock() |
1312 | self._resources = self.mocker.mock() |
1313 | + self._set = self.mocker.mock() |
1314 | + self._gobject = self.mocker.mock() |
1315 | self._service = DesktopcouchService(self._mainloop, |
1316 | pid_finder=self._pid_finder, |
1317 | port_finder=self._port_finder, |
1318 | @@ -48,65 +50,97 @@ |
1319 | fork=self._fork, |
1320 | nice=self._nice, |
1321 | kill=self._kill, |
1322 | - sleep=self._sleep) |
1323 | - |
1324 | - def test_start_new_desktopcouch_no_extensions(self): |
1325 | - """Test that desktopcouch is started. |
1326 | - |
1327 | - We test that when the pid cannot be found we ensure |
1328 | - that the desktopcouch instance is started and that the |
1329 | - start as the dbus service, |
1330 | - """ |
1331 | - self._pid_finder(start_if_not_running=False, ctx=self._ctx) |
1332 | - self.mocker.result(None) |
1333 | - self._pid_finder(start_if_not_running=True, ctx=self._ctx) |
1334 | - self.mocker.result(self._pid_result) |
1335 | - self._port_finder(pid=self._pid_result, ctx=self._ctx) |
1336 | - self.mocker.result(self._port_result) |
1337 | - self._fork() |
1338 | - self.mocker.result(234) |
1339 | - self._fork() |
1340 | - self.mocker.result(234) |
1341 | - # XXX: call this? |
1342 | - self._mainloop.stop # pylint: disable=W0104 |
1343 | - self.mocker.result(ANY) |
1344 | - self._advertiser(ANY, self._ctx) |
1345 | - self._mainloop.run() |
1346 | - self._stop_couchdb(ctx=self._ctx) |
1347 | - self._kill(234, signal.SIGTERM) |
1348 | - self._sleep(1) |
1349 | - self._kill(234, signal.SIGKILL) |
1350 | - self.mocker.replay() |
1351 | - self._service.start() |
1352 | - |
1353 | - def test_start_new_desktopcouch_extensions(self): |
1354 | - """Test that desktopcouch is started. |
1355 | - |
1356 | - We test that when the pid cannot be found we ensure |
1357 | - that the desktopcouch instance is started and that the |
1358 | - start as the dbus service, |
1359 | - """ |
1360 | - self._pid_finder(start_if_not_running=False, ctx=self._ctx) |
1361 | - self.mocker.result(None) |
1362 | - self._pid_finder(start_if_not_running=True, ctx=self._ctx) |
1363 | - self.mocker.result(self._pid_result) |
1364 | - self._port_finder(pid=self._pid_result, ctx=self._ctx) |
1365 | - self.mocker.result(self._port_result) |
1366 | - self._fork() |
1367 | - self.mocker.result(234) |
1368 | - self._fork() |
1369 | - self.mocker.result(234) |
1370 | - # XXX: call this? |
1371 | - self._mainloop.stop # pylint: disable=W0104 |
1372 | - self.mocker.result(ANY) |
1373 | - self._advertiser(ANY, self._ctx) |
1374 | - self._mainloop.run() |
1375 | - self._stop_couchdb(ctx=self._ctx) |
1376 | - self._kill(234, signal.SIGTERM) |
1377 | - self._sleep(1) |
1378 | - self._kill(234, signal.SIGKILL) |
1379 | - self.mocker.replay() |
1380 | - self._service.start() |
1381 | + sleep=self._sleep, |
1382 | + set_type=self._set, |
1383 | + gobject_module=self._gobject) |
1384 | + |
1385 | + self.gobject_idle_task_list = list() |
1386 | + |
1387 | + def test_start_new_desktopcouch_with_plugins(self): |
1388 | + """Test that desktopcouch is started. |
1389 | + |
1390 | + We test that when the pid cannot be found we ensure |
1391 | + that the desktopcouch instance is started and that the |
1392 | + start as the dbus service, |
1393 | + """ |
1394 | + self._pid_finder(start_if_not_running=False, ctx=self._ctx) |
1395 | + self.mocker.result(None) |
1396 | + self._pid_finder(start_if_not_running=True, ctx=self._ctx) |
1397 | + self.mocker.result(self._pid_result) |
1398 | + self._port_finder(pid=self._pid_result, ctx=self._ctx) |
1399 | + self.mocker.result(self._port_result) |
1400 | + self._fork() |
1401 | + self.mocker.result(234) # We are parent |
1402 | + self._fork() |
1403 | + self.mocker.result(345) # We are parent |
1404 | + |
1405 | + # plugins load |
1406 | + semaphores = self.mocker.mock() |
1407 | + self._set() |
1408 | + self.mocker.result(semaphores) |
1409 | + |
1410 | + self._mainloop.stop # pylint: disable=W0104 |
1411 | + self.mocker.result(ANY) |
1412 | + |
1413 | + semaphores.discard # pylint: disable=W0104 |
1414 | + self.mocker.result("disc") |
1415 | + self._gobject.timeout_add_seconds(ANY, "disc", ANY) |
1416 | + |
1417 | + self._gobject.idle_add(ANY, self._port_result, semaphores) |
1418 | + self._gobject.idle_add(ANY, semaphores, self._advertiser, ANY, |
1419 | + self._ctx) |
1420 | + |
1421 | + self._mainloop.run() |
1422 | + |
1423 | + # Tasks are added to the mainloop's idle queue. With that^ |
1424 | + # mainloop.run, they'd be called. Simulate their call. |
1425 | + |
1426 | + # Idle loop to add plugins calls a plugin. ubuntuone_pairing |
1427 | + semaphores.add(ANY) # A plugin asserts it must be completed. |
1428 | + |
1429 | + # Idle loop calls plugin for ubuntuone_pairing, which fires up DBus |
1430 | + # client to get credentials from ubuntu-login app. When that returns, |
1431 | + # it calls got_new_credentials, which calls pair_with_ubuntuone. |
1432 | + |
1433 | + # Mock call to pair_with_ubuntuone |
1434 | + management_db = self.mocker.mock() |
1435 | + put_service_fn = self.mocker.mock() |
1436 | + |
1437 | + bool(management_db) |
1438 | + self.mocker.result(True) |
1439 | + |
1440 | + management_db.view_exists(ANY, ANY) |
1441 | + self.mocker.result(False) |
1442 | + management_db.add_view(ANY, ANY, design_doc=ANY) |
1443 | + |
1444 | + row = self.mocker.mock() |
1445 | + management_db.execute_view(ANY, ANY) |
1446 | + self.mocker.result([row]) |
1447 | + |
1448 | + row.value # pylint: disable=W0104 |
1449 | + self.mocker.result(1) |
1450 | + |
1451 | + semaphores.discard(ANY) |
1452 | + |
1453 | + # and then dbus service is ready to answer queries. |
1454 | + |
1455 | + self._stop_couchdb(ctx=self._ctx) |
1456 | + self._kill(self._pid_result, signal.SIGTERM) |
1457 | + self._kill(234, signal.SIGTERM) |
1458 | + self._kill(345, signal.SIGTERM) |
1459 | + self._sleep(1) |
1460 | + self._kill(self._pid_result, signal.SIGKILL) |
1461 | + self._kill(234, signal.SIGKILL) |
1462 | + self._kill(345, signal.SIGKILL) |
1463 | + |
1464 | + self.mocker.replay() |
1465 | + |
1466 | + self._service.start() |
1467 | + # Manually do what dbus idle-loop would do. |
1468 | + import desktopcouch.application.plugins.ubuntuone_pairing as u_p |
1469 | + u_p.pair_with_ubuntuone(self._port_result, semaphores, |
1470 | + management_db=management_db, |
1471 | + put_service_fn=put_service_fn) |
1472 | |
1473 | def test_start_desktopcouch_replication(self): |
1474 | """ Test that the repliciation works. |
1475 | @@ -119,7 +153,7 @@ |
1476 | self._port_finder(pid=self._pid_result, ctx=self._ctx) |
1477 | self.mocker.result(self._port_result) |
1478 | self._fork() |
1479 | - self.mocker.result(0) |
1480 | + self.mocker.result(0) # We are child process |
1481 | self._nice(10) |
1482 | self._replication.set_up(ANY) |
1483 | self._mainloop.run() |
1484 | @@ -146,9 +180,9 @@ |
1485 | self._port_finder(pid=self._pid_result, ctx=self._ctx) |
1486 | self.mocker.result(self._port_result) |
1487 | self._fork() |
1488 | - self.mocker.result(567) |
1489 | + self.mocker.result(567) # We are parent process |
1490 | self._fork() |
1491 | - self.mocker.result(0) |
1492 | + self.mocker.result(0) # We are child process |
1493 | self._sleep(ANY) |
1494 | self._ctx.db_dir # searching for files # pylint: disable=W0104 |
1495 | self.mocker.result("/tmp/migration-data/does/not/exist") |
1496 | |
1497 | === modified file 'desktopcouch/records/tests/test_mocked_server.py' |
1498 | --- desktopcouch/records/tests/test_mocked_server.py 2011-04-08 20:40:53 +0000 |
1499 | +++ desktopcouch/records/tests/test_mocked_server.py 2011-09-13 15:01:24 +0000 |
1500 | @@ -61,6 +61,7 @@ |
1501 | |
1502 | |
1503 | class TestMockedCouchDatabaseCreateStates(MockerTestCase): |
1504 | + """Mocked Couch Database tests for create= flag states.""" |
1505 | def setUp(self): |
1506 | """Set up tests.""" |
1507 | super(TestMockedCouchDatabaseCreateStates, self).setUp() |
1508 | @@ -85,7 +86,7 @@ |
1509 | self.mocker.result({'update_seq': []}) |
1510 | |
1511 | self.mocker.replay() |
1512 | - database = DesktopDatabase(self.dbname, uri=self.uri, |
1513 | + DesktopDatabase(self.dbname, uri=self.uri, |
1514 | record_factory=self.record_factory, create=True, |
1515 | server_class=self.server_class, |
1516 | oauth_tokens=self.oauth_tokens, ctx=self.ctx) |
1517 | @@ -105,7 +106,7 @@ |
1518 | info["update_seq"] |
1519 | self.mocker.result({}) |
1520 | self.mocker.replay() |
1521 | - database = DesktopDatabase(self.dbname, uri=self.uri, |
1522 | + DesktopDatabase(self.dbname, uri=self.uri, |
1523 | record_factory=self.record_factory, create=True, |
1524 | server_class=self.server_class, |
1525 | oauth_tokens=self.oauth_tokens, ctx=self.ctx) |
1526 | @@ -140,7 +141,7 @@ |
1527 | self.mocker.result({}) |
1528 | |
1529 | self.mocker.replay() |
1530 | - database = DesktopDatabase(self.dbname, uri=self.uri, |
1531 | + DesktopDatabase(self.dbname, uri=self.uri, |
1532 | record_factory=self.record_factory, create=False, |
1533 | server_class=self.server_class, |
1534 | oauth_tokens=self.oauth_tokens, ctx=self.ctx) |
1535 | |
1536 | === modified file 'desktopcouch/recordtypes/contacts/tests/test_view.py' |
1537 | --- desktopcouch/recordtypes/contacts/tests/test_view.py 2011-01-12 15:08:25 +0000 |
1538 | +++ desktopcouch/recordtypes/contacts/tests/test_view.py 2011-09-13 15:01:24 +0000 |
1539 | @@ -280,29 +280,29 @@ |
1540 | |
1541 | contacts = list( |
1542 | view.find_contacts_starting(self.db, first_name="Frances")) |
1543 | - self.assertEqual(len(contacts), 1) |
1544 | + self.assertEqual(len(contacts), 1, "Length of 1. %s" % (contacts,)) |
1545 | |
1546 | contacts = list( |
1547 | view.find_contacts_starting(self.db, birth_date="1918")) |
1548 | - self.assertEqual(len(contacts), 1) |
1549 | + self.assertEqual(len(contacts), 1, "Length of 1. %s" % (contacts,)) |
1550 | |
1551 | contacts = list( |
1552 | view.find_contacts_starting(self.db, birth_date="1918-08")) |
1553 | - self.assertEqual(len(contacts), 1) |
1554 | + self.assertEqual(len(contacts), 1, "Length of 1. %s" % (contacts,)) |
1555 | |
1556 | contacts = list( |
1557 | view.find_contacts_starting(self.db, wedding_date="1970")) |
1558 | - self.assertEqual(len(contacts), 1) |
1559 | + self.assertEqual(len(contacts), 1, "Length of 1. %s" % (contacts,)) |
1560 | |
1561 | contacts = list( |
1562 | view.find_contacts_starting( |
1563 | self.db, email_addressesaddress="blah.example.com")) |
1564 | - self.assertEqual(len(contacts), 1) |
1565 | + self.assertEqual(len(contacts), 1, "Length of 1. %s" % (contacts,)) |
1566 | |
1567 | contacts = list( |
1568 | view.find_contacts_starting( |
1569 | self.db, email_addressesaddress="berkeley")) |
1570 | - self.assertEqual(len(contacts), 1) |
1571 | + self.assertEqual(len(contacts), 1, "Length of 1. %s" % (contacts,)) |
1572 | |
1573 | contacts = list( |
1574 | view.find_contacts_starting(self.db, first_name="random")) |
1575 | @@ -317,7 +317,7 @@ |
1576 | |
1577 | contacts = list( |
1578 | view.find_contacts_exact(self.db, first_name="Frances")) |
1579 | - self.assertEqual(len(contacts), 1) |
1580 | + self.assertEqual(len(contacts), 1, "Length of 1. %s" % (contacts,)) |
1581 | |
1582 | contacts = list(view.find_contacts_exact(self.db, birth_date="-08-23")) |
1583 | - self.assertEqual(len(contacts), 1) |
1584 | + self.assertEqual(len(contacts), 1, "Length of 1. %s" % (contacts,)) |
1585 | |
1586 | === modified file 'setup.cfg' |
1587 | --- setup.cfg 2011-01-12 15:08:25 +0000 |
1588 | +++ setup.cfg 2011-09-13 15:01:24 +0000 |
1589 | @@ -4,10 +4,10 @@ |
1590 | tag_svn_revision = 0 |
1591 | |
1592 | [build] |
1593 | -i18n = True |
1594 | -icons = True |
1595 | +i18n=True |
1596 | +icons=True |
1597 | |
1598 | [build_i18n] |
1599 | -domain = desktopcouch |
1600 | -desktop_files = [("share/applications", ("desktopcouch-pair.desktop.in",))] |
1601 | +domain=desktopcouch |
1602 | +desktop_files=[("share/applications", ("desktopcouch-pair.desktop.in",))] |
1603 | |
1604 | |
1605 | === modified file 'setup.py' |
1606 | --- setup.py 2011-04-08 20:42:51 +0000 |
1607 | +++ setup.py 2011-09-13 15:01:24 +0000 |
1608 | @@ -1,6 +1,6 @@ |
1609 | #!/usr/bin/env python |
1610 | # |
1611 | -# Copyright 2009-2010 Canonical Ltd. |
1612 | +# Copyright 2009-2011 Canonical Ltd. |
1613 | # |
1614 | # This file is part of desktopcouch. |
1615 | # |
1616 | @@ -17,12 +17,13 @@ |
1617 | # along with desktopcouch. If not, see <http://www.gnu.org/licenses/>. |
1618 | """setup.py""" |
1619 | |
1620 | -from setuptools import setup, find_packages |
1621 | +from setuptools import find_packages |
1622 | from DistUtilsExtra.command import build_extra, build_i18n |
1623 | +from DistUtilsExtra.auto import setup |
1624 | |
1625 | setup( |
1626 | name='desktopcouch', |
1627 | - version='1.0.7', |
1628 | + version='1.0.8', |
1629 | description='A Desktop CouchDB instance.', |
1630 | url='https://launchpad.net/desktopcouch', |
1631 | license='LGPL-3', |
1632 | @@ -30,19 +31,23 @@ |
1633 | author_email='stuart.langridge@canonical.com', |
1634 | packages=find_packages(), |
1635 | scripts=['bin/desktopcouch-pair'], |
1636 | - data_files=[('/usr/lib/desktopcouch/', ['bin/desktopcouch-service', |
1637 | + data_files=[('lib/desktopcouch/', ['bin/desktopcouch-service', |
1638 | 'bin/desktopcouch-pair', |
1639 | 'bin/desktopcouch-get-port', |
1640 | 'bin/desktopcouch-stop']), |
1641 | # Be sure all additions are reflected in MANIFEST.in ! |
1642 | - ('/usr/share/doc/python-desktopcouch-records/api/', |
1643 | + ('share/doc/python-desktopcouch-records/api/', |
1644 | ['desktopcouch/records/doc/records.txt', |
1645 | + 'desktopcouch/records/doc/an_example_application.txt', |
1646 | 'desktopcouch/records/doc/field_registry.txt', |
1647 | 'desktopcouch/recordtypes/contacts/schema.txt']), |
1648 | ('/etc/xdg/desktop-couch/', |
1649 | - ['config/desktop-couch/compulsory-auth.ini']), |
1650 | - ('/usr/share/desktopcouch/', ['data/couchdb.tmpl']), |
1651 | - ('/usr/share/dbus-1/services/', [ |
1652 | + ['config/desktop-couch/compulsory-auth.ini', |
1653 | + 'config/desktop-couch/default.ini']), |
1654 | + ('share/desktopcouch/', ['data/couchdb.tmpl']), |
1655 | + ('share/apport/package-hooks/', [ |
1656 | + 'data/source_desktopcouch.py']), |
1657 | + ('share/dbus-1/services/', [ |
1658 | 'org.desktopcouch.CouchDB.service']), |
1659 | ('share/man/man1/', ['docs/man/desktopcouch-pair.1'])], |
1660 | cmdclass={"build": build_extra.build_extra, |