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