Merge lp:~cmiller/desktopcouch/couchdb-polutes-its-ini into lp:desktopcouch

Proposed by Chad Miller
Status: Merged
Approved by: Chad Miller
Approved revision: not available
Merged at revision: not available
Proposed branch: lp:~cmiller/desktopcouch/couchdb-polutes-its-ini
Merge into: lp:desktopcouch
Diff against target: 279 lines (+69/-58)
8 files modified
bin/desktopcouch-service (+8/-3)
bin/desktopcouch-stop (+3/-15)
data/couchdb.tmpl (+2/-2)
desktopcouch/local_files.py (+22/-1)
desktopcouch/records/server_base.py (+7/-1)
desktopcouch/start_local_couchdb.py (+9/-6)
desktopcouch/stop_local_couchdb.py (+17/-28)
desktopcouch/tests/__init__.py (+1/-2)
To merge this branch: bzr merge lp:~cmiller/desktopcouch/couchdb-polutes-its-ini
Reviewer Review Type Date Requested Status
John O'Brien (community) Approve
Stuart Langridge (community) Approve
Review via email: mp+18645@code.launchpad.net

Commit message

The couchdb INI file may be updatec by couchdb to have a hashed password value, so we can not blindly take that to update the bookmark file any more. Now, store the username and password (yes in the INI also, but) in the bookmark file using a parsable format. Now, we can poke the value in initially, and later read the bookmark file to update the bookmark file.

To post a comment you must log in.
Revision history for this message
Stuart Langridge (sil) wrote :

Excellent.

review: Approve
Revision history for this message
John O'Brien (jdobrien) :
review: Approve
Revision history for this message
Chad Miller (cmiller) wrote :

The couchdb INI file may be updatec by couchdb to have a hashed password value, so we can not blindly take that to update the bookmark file any more. Now, store the username and password (yes in the INI also, but) in the bookmark file using a parsable format. Now, we can poke the value in initially, and later read the bookmark file to update the bookmark file.

Revision history for this message
Chad Miller (cmiller) wrote :
Download full text (10.9 KiB)

The attempt to merge lp:~cmiller/desktopcouch/couchdb-polutes-its-ini into lp:desktopcouch failed.Below is the output from the failed tests.

Apache CouchDB has started, time to relax.
Browse your desktop CouchDB at file:///tmp/tmpCA9l0y/data/couchdb.html
desktopcouch.contacts.tests.test_contactspicker
  TestContactsPicker
    test_can_contruct_contactspicker ... [OK]
desktopcouch.contacts.tests.test_create
  TestCreate
    test_create_many_contacts ... [OK]
    test_head_or_tails ... [OK]
    test_random_bools ... [OK]
desktopcouch.contacts.tests.test_record
  TestContactRecord
    test_contact_record ... [OK]
desktopcouch.pair.tests.test_couchdb_io
  TestCouchdbIo
    test_get_database_names_replicatable ... [OK]
    test_get_database_names_replicatable_bad_server ... [OK]
    test_get_my_host_unique_id ... [ERROR]
    test_mkuri ... [OK]
    test_obsfuscation ... [OK]
    test_put_dynamic_paired_host ... [OK]
    test_put_static_paired_service ... [OK]
desktopcouch.pair.tests.test_network_io
  TestNetworkIO
    test_successful_lifespan ... [OK]
desktopcouch.records.tests.test_couchgrid
  TestCouchGrid
    test_all_from_database ... [OK]
    test_constructor_guarded ... [OK]
    test_new_rows_with_headings ... [OK]
    test_no_headings_or_stored_records ... [OK]
    test_optional_args_no_stored_records ... [OK]
    test_optional_record_type_arg ... [OK]
    test_programatically_add_row ... [OK]
    test_selected_id_property ... [OK]
    test_single_col_from_database ... [OK]
desktopcouch.records.tests.test_field_registry
  TestFieldMapping
    test_mergeable_list_field_mapping ... [OK]
    test_mergeable_list_field_mapping_empty_field ... [OK]
    test_simple_field_mapping ... [OK]
  TestTransformer
    test_from_app ... [OK]
    test_run_doctests ... [OK]
    test_to_app ... [OK]
desktopcouch.records.tests.test_record
  TestRecordFactory
    test_build ... [OK]
  TestRecords
    test_application_annotations ... [OK]
    test_delitem ... ...

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bin/desktopcouch-service'
2--- bin/desktopcouch-service 2009-10-14 14:48:25 +0000
3+++ bin/desktopcouch-service 2010-02-05 00:09:13 +0000
4@@ -46,6 +46,7 @@
5 import desktopcouch
6 from desktopcouch import local_files
7 from desktopcouch import replication
8+from desktopcouch.stop_local_couchdb import stop_couchdb
9
10
11 class PortAdvertiser(dbus.service.Object):
12@@ -104,7 +105,11 @@
13 mainloop.run()
14
15 finally:
16- if replication_runtime:
17- print "Shutting down, but may be a moment to finish replication."
18- replication.tear_down(*replication_runtime)
19+ try:
20+ print "Shutting down...",
21+ if replication_runtime:
22+ replication.tear_down(*replication_runtime)
23+ finally:
24+ stop_couchdb()
25+ print "done."
26
27
28=== modified file 'bin/desktopcouch-stop'
29--- bin/desktopcouch-stop 2009-07-24 19:32:52 +0000
30+++ bin/desktopcouch-stop 2010-02-05 00:09:13 +0000
31@@ -19,18 +19,6 @@
32 """
33 Stop local CouchDB server.
34 """
35-import subprocess, sys
36-from desktopcouch import local_files
37-
38-local_exec = local_files.COUCH_EXEC_COMMAND + ["-k"]
39-try:
40- retcode = subprocess.call(local_exec, shell=False)
41- if retcode < 0:
42- print >> sys.stderr, "Child was terminated by signal", -retcode
43- elif retcode > 0:
44- print >> sys.stderr, "Child returned", retcode
45-except OSError, e:
46- print >> sys.stderr, "Execution failed: %s: %s" % (e, local_exec)
47- exit(1)
48-
49-
50+
51+from desktopcouch.stop_local_couchdb import stop_couchdb
52+stop_couchdb()
53
54=== modified file 'data/couchdb.tmpl'
55--- data/couchdb.tmpl 2009-08-20 12:55:54 +0000
56+++ data/couchdb.tmpl 2010-02-05 00:09:13 +0000
57@@ -26,7 +26,7 @@
58 <h1>Desktop CouchDB</h1>
59 <p>Your desktop CouchDB is the data store for many of your applications.
60 You can browse around it to see which data your applications are storing.</p>
61-<p>You should bookmark this page (by going to <strong>Bookmarks > Bookmark
62+<p>You should bookmark this page (by going to <strong>Bookmarks &gt; Bookmark
63 This Page</strong> or pressing <strong>Ctrl-D</strong>) so you can easily
64 come back to browse your CouchDB again.</p>
65 <p>Don't bookmark the CouchDB page itself, because its location may change!</p>
66@@ -35,4 +35,4 @@
67 there straight away from now on</a> (remember to bookmark this page first!)</p>
68 </body>
69 </html>
70-
71+<!-- !![[COUCHDB_USERNAME]]!![[COUCHDB_PASSWORD]]!! -->
72
73=== modified file 'desktopcouch/local_files.py'
74--- desktopcouch/local_files.py 2009-12-14 14:52:48 +0000
75+++ desktopcouch/local_files.py 2010-02-05 00:09:13 +0000
76@@ -29,6 +29,7 @@
77 import tempfile
78 import random
79 import string
80+import re
81 import gnomekeyring
82 try:
83 import ConfigParser as configparser
84@@ -53,10 +54,16 @@
85 # monkeypatch ConfigParser to stop it lower-casing option names
86 self._c.optionxform = lambda s: s
87
88+ bookmark_file = os.path.join(ctx.db_dir, "couchdb.html")
89 try:
90+ bookmark_file_contents = open(bookmark_file).read()
91+ if "-hashed-" in bookmark_file_contents:
92+ raise ValueError("Basic-auth cred lost.")
93+ u, p = re.findall("<!-- !!([^!]+)!!([^!]+)!! -->",
94+ bookmark_file_contents)[-1] # trial run, check sanity.
95 self._fill_from_file(self.file_name_used)
96 return
97- except (IOError,):
98+ except (IOError, ValueError, IndexError):
99 pass # Loading failed. Let's fill it with sensible defaults.
100
101 try:
102@@ -123,6 +130,20 @@
103 self._fill_from_structure(local)
104 self.save_to_file(self.file_name_used)
105
106+ fp = open(bookmark_file, "w")
107+ try:
108+ fp.write("Desktopcouch is not yet started.\n")
109+ fp.write("<!-- Couch clobbers useful creds in INI file. -->\n")
110+ fp.write("<!-- So, store creds in the place we need it. -->\n")
111+ fp.write("<!-- The '!' fmt is perpetual but port varies. -->\n")
112+ fp.write("<!-- !!%(admin_username)s!!%(admin_password)s!! -->\n" \
113+ % locals())
114+ fp.write("<!-- ^^ Seeded only creds into bookmark file. -->\n")
115+ fp.write("<!-- Will flesh out with port when we know it. -->\n")
116+ fp.write("<!-- Replacement text also uses creds format. -->\n")
117+ finally:
118+ fp.close()
119+
120 # randomly generate tokens and usernames
121 @staticmethod
122 def _make_random_string(count):
123
124=== modified file 'desktopcouch/records/server_base.py'
125--- desktopcouch/records/server_base.py 2010-01-29 22:14:25 +0000
126+++ desktopcouch/records/server_base.py 2010-02-05 00:09:13 +0000
127@@ -153,8 +153,12 @@
128 self.record_factory = record_factory or Record
129 self._changes_since = 0
130 self._changes_last_used = 0
131- self.report_changes(lambda **_: None) # Update _changes_since.
132+ try:
133+ self.report_changes(lambda **_: None) # Update _changes_since.
134+ except IOError:
135+ pass
136 self._changes_last_used = 0 # Immediate run works.
137+
138
139 def _temporary_query(self, map_fun, reduce_fun=None, language='javascript',
140 wrapper=None, **options):
141@@ -489,6 +493,8 @@
142 uri = couchdburi(self._server.resource.uri, self.db.name, "_changes",
143 since=self._changes_since)
144 resp, data = self._server.resource.http.request(uri, "GET", "", {})
145+ if resp["status"] != '200':
146+ raise IOError("HTTP response code %s.\n%s" % (resp["status"], data))
147 structure = json.loads(data)
148 for change in structure.get("results"):
149 # kw-args can't have unicode keys
150
151=== modified file 'desktopcouch/start_local_couchdb.py'
152--- desktopcouch/start_local_couchdb.py 2009-12-16 14:21:09 +0000
153+++ desktopcouch/start_local_couchdb.py 2010-02-05 00:09:13 +0000
154@@ -42,6 +42,7 @@
155 from desktopcouch.records.server import CouchDatabase
156 import logging
157 import itertools
158+import re
159
160
161 def process_is_couchdb__linux(pid):
162@@ -187,10 +188,15 @@
163 # than inefficiently just overwriting it regardless
164 db.add_view(view_name, mapjs, reducejs, dd_name)
165
166-def write_bookmark_file(username, password, port, ctx=local_files.DEFAULT_CONTEXT):
167+def update_bookmark_file(port, ctx=local_files.DEFAULT_CONTEXT):
168 """Write out an HTML document that the user can bookmark to find their DB"""
169 bookmark_file = os.path.join(ctx.db_dir, "couchdb.html")
170
171+ try:
172+ username, password = re.findall("<!-- !!([^!]+)!!([^!]+)!! -->", open(bookmark_file).read())[-1]
173+ except ValueError:
174+ raise IOError("Bookmark file is corrupt. Username/password are missing.")
175+
176 if os.path.exists(
177 os.path.join(os.path.split(__file__)[0], "../data/couchdb.tmpl")):
178 bookmark_template = os.path.join(
179@@ -208,9 +214,7 @@
180
181 fp = open(bookmark_file, "w")
182 try:
183- if port is None:
184- fp.write("<html><body><p>Sorry, desktop couchdb does is not running.</body></html>\n")
185- else:
186+ if port is not None:
187 out = html.replace("[[COUCHDB_PORT]]", str(port))
188 out = out.replace("[[COUCHDB_USERNAME]]", username)
189 out = out.replace("[[COUCHDB_PASSWORD]]", password)
190@@ -222,14 +226,13 @@
191
192 def start_couchdb(ctx=local_files.DEFAULT_CONTEXT):
193 """Execute each step to start a desktop CouchDB."""
194- username, password = local_files.get_admin_credentials(ctx=ctx)
195 pid, port = run_couchdb(ctx=ctx)
196 # Note that we do not call update_design_documents here. This is because
197 # Couch won't actually have started yet, so when update_design_documents
198 # calls the Records API, that will call back into get_port and we end up
199 # starting Couch again. Instead, get_port calls update_design_documents
200 # *after* Couch startup has occurred.
201- write_bookmark_file(username, password, port, ctx=ctx)
202+ update_bookmark_file(port, ctx=ctx)
203 return pid
204
205
206
207=== modified file 'desktopcouch/stop_local_couchdb.py'
208--- desktopcouch/stop_local_couchdb.py 2009-11-24 14:55:27 +0000
209+++ desktopcouch/stop_local_couchdb.py 2010-02-05 00:09:13 +0000
210@@ -15,38 +15,27 @@
211 # along with desktopcouch. If not, see <http://www.gnu.org/licenses/>.
212 #
213 # Author: Chad Miller <chad.miller@canonical.com>
214+# Stuart Langridge <stuart.langridge@canonical.com>
215+
216 """
217 Stop local CouchDB server.
218 """
219
220-import os
221-import desktopcouch
222-import time
223-import signal
224-import errno
225-
226-def stop_couchdb(pid=None):
227- by_pid = pid
228- if pid is None:
229- pid = desktopcouch.find_pid(start_if_not_running=False)
230- while pid is not None:
231- try:
232- os.kill(pid, signal.SIGTERM)
233- except OSError, e:
234- if e.errno == errno.ESRCH:
235- break
236- raise
237-
238- for retry in xrange(300):
239- try:
240- os.kill(pid, 0) # test existence. sig-zero is special.
241- except OSError:
242- break
243- time.sleep(0.01)
244- if by_pid:
245- pid = None
246- else:
247- pid = desktopcouch.find_pid(start_if_not_running=False)
248+import subprocess, sys
249+from desktopcouch import local_files
250+
251+def stop_couchdb(ctx=local_files.DEFAULT_CONTEXT):
252+ local_exec = ctx.couch_exec_command + ["-k"]
253+ try:
254+ retcode = subprocess.call(local_exec, shell=False)
255+ if retcode < 0:
256+ print >> sys.stderr, "Child was terminated by signal", -retcode
257+ elif retcode > 0:
258+ print >> sys.stderr, "Child returned", retcode
259+ except OSError, e:
260+ print >> sys.stderr, "Execution failed: %s: %s" % (e, local_exec)
261+ exit(1)
262+
263
264 if __name__ == "__main__":
265 stop_couchdb()
266
267=== modified file 'desktopcouch/tests/__init__.py'
268--- desktopcouch/tests/__init__.py 2009-11-11 16:24:22 +0000
269+++ desktopcouch/tests/__init__.py 2010-02-05 00:09:13 +0000
270@@ -29,8 +29,7 @@
271 os.environ["XDG_CONFIG_DIRS"] = SOURCE_TREE_ETC_FOLDER
272
273 def stop_test_couch(temp_dir, ctx):
274- pid = read_pidfile(ctx)
275- stop_couchdb(pid=pid)
276+ stop_couchdb(ctx)
277 shutil.rmtree(temp_dir)
278
279 start_couchdb(ctx=new_context)

Subscribers

People subscribed via source and target branches