Merge lp://qastaging/~thisfred/desktopcouch/any_port_in_a_storm into lp://qastaging/desktopcouch
- any_port_in_a_storm
- Merge into trunk
Proposed by
Eric Casteleijn
Status: | Merged |
---|---|
Approved by: | Eric Casteleijn |
Approved revision: | 47 |
Merged at revision: | not available |
Proposed branch: | lp://qastaging/~thisfred/desktopcouch/any_port_in_a_storm |
Merge into: | lp://qastaging/desktopcouch |
Diff against target: | None lines |
To merge this branch: | bzr merge lp://qastaging/~thisfred/desktopcouch/any_port_in_a_storm |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Stuart Langridge (community) | Approve | ||
Chad Miller (community) | Approve | ||
Review via email:
|
Commit message
Reads the portnumber from the logfile, now that it is written there by couchdb.
Description of the change
To post a comment you must log in.
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Eric Casteleijn (thisfred) wrote : | # |
- 46. By Eric Casteleijn
-
non premature optimization as suggested by Chad
- 47. By Eric Casteleijn
-
return None when not found
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Stuart Langridge (sil) wrote : | # |
Looks good (and way simpler!) to me.
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'desktopcouch/__init__.py' |
2 | --- desktopcouch/__init__.py 2009-08-21 21:57:37 +0000 |
3 | +++ desktopcouch/__init__.py 2009-08-24 20:42:37 +0000 |
4 | @@ -16,7 +16,7 @@ |
5 | "Desktop Couch helper files" |
6 | |
7 | from __future__ import with_statement |
8 | -import os, re, time |
9 | +import os, time |
10 | |
11 | |
12 | def find_pid(start_if_not_running=True): |
13 | @@ -80,61 +80,19 @@ |
14 | |
15 | return True |
16 | |
17 | - |
18 | -def find_port__linux(pid): |
19 | - # Look in the CouchDB log to find the port number, someday. |
20 | - # Currently, we have to grovel around in /proc instead. |
21 | - # Oh, the huge manatee... (this replaced an lsof shell recipe |
22 | - # which was shorter but less reliable) |
23 | - |
24 | - proc_dir = "/proc/%s" % (pid,) |
25 | - |
26 | - # enumerate the process' file descriptors |
27 | - fd_dir = os.path.join(proc_dir, 'fd') |
28 | - try: |
29 | - fd_paths = [os.readlink(os.path.join(fd_dir, fd)) |
30 | - for fd in os.listdir(fd_dir)] |
31 | - except OSError: |
32 | - raise RuntimeError("Unable to find file descriptors in /proc") |
33 | - |
34 | - |
35 | - # identify socket fds |
36 | - socket_matches = [re.match('socket:\\[([0-9]+)\\]', p) for p in fd_paths] |
37 | - # extract their inode numbers |
38 | - socket_inodes = [m.group(1) for m in socket_matches if m is not None] |
39 | - |
40 | - # construct a subexpression which matches any one of these inodes |
41 | - inode_subexp = "|".join(socket_inodes) |
42 | - # construct regexp to match /proc/net/tcp entries which are listening |
43 | - # sockets having one of the given inode numbers |
44 | - listening_regexp = re.compile(r''' |
45 | - \s*\d+:\s* # sl |
46 | - 0100007F:([0-9A-F]{4})\s+ # local_address |
47 | - 00000000:0000\s+ # rem_address |
48 | - 0A\s+ # st (0A = listening) |
49 | - [0-9A-F]{8}: # tx_queue |
50 | - [0-9A-F]{8}\s+ # rx_queue |
51 | - [0-9A-F]{2}: # tr |
52 | - [0-9A-F]{8}\s+ # tm->when |
53 | - [0-9A-F]{8}\s* # retrnsmt |
54 | - \d+\s+\d+\s+ # uid, timeout |
55 | - (?:%s)\s+ # inode |
56 | - ''' % (inode_subexp,), re.VERBOSE) |
57 | - |
58 | - # extract the TCP port from the first matching line in /proc/$pid/net/tcp |
59 | - port = None |
60 | - with open(os.path.join(proc_dir, 'net', 'tcp')) as tcp_file: |
61 | - for line in tcp_file: |
62 | - match = listening_regexp.match(line) |
63 | - if match is not None: |
64 | - port = str(int(match.group(1), 16)) |
65 | +def find_port(): |
66 | + """Look in the CouchDB log to find the port number.""" |
67 | + |
68 | + from desktopcouch.local_files import FILE_LOG |
69 | + with open(FILE_LOG, 'r') as log_file: |
70 | + port = None |
71 | + for line in reversed(log_file.readlines()): |
72 | + if 'Apache CouchDB has started on http://' in line: |
73 | + port = line.split(':')[-1].strip() |
74 | + if port.endswith('/'): |
75 | + port = port[:-1] |
76 | break |
77 | - if port is None: |
78 | - raise RuntimeError("Unable to find listening port") |
79 | - |
80 | - return port |
81 | - |
82 | - |
83 | + return int(port) |
84 | |
85 | import platform |
86 | os_name = platform.system() |
87 | @@ -142,9 +100,5 @@ |
88 | process_is_couchdb = { |
89 | "Linux": process_is_couchdb__linux |
90 | } [os_name] |
91 | - |
92 | - find_port = { |
93 | - "Linux": find_port__linux |
94 | - } [os_name] |
95 | except KeyError: |
96 | raise NotImplementedError("os %r is not yet supported" % (os_name,)) |
97 | |
98 | === modified file 'desktopcouch/contacts/contactspicker.py' |
99 | --- desktopcouch/contacts/contactspicker.py 2009-08-22 17:22:02 +0000 |
100 | +++ desktopcouch/contacts/contactspicker.py 2009-08-24 20:35:25 +0000 |
101 | @@ -19,17 +19,15 @@ |
102 | """A widget to allow users to pick contacts""" |
103 | |
104 | import gtk |
105 | -from desktopcouch.contacts.record import ( |
106 | - Contact, |
107 | - CONTACT_RECORD_TYPE) |
108 | +from desktopcouch.contacts.record import CONTACT_RECORD_TYPE |
109 | from desktopcouch.records.couchgrid import CouchGrid |
110 | |
111 | + |
112 | class ContactsPicker(gtk.VBox): |
113 | + """A contacts picker""" |
114 | |
115 | - def __init__(self): |
116 | - """Create a new ContactsPicker widget |
117 | - |
118 | - """ |
119 | + def __init__(self, uri=None): |
120 | + """Create a new ContactsPicker widget.""" |
121 | |
122 | gtk.VBox.__init__(self) |
123 | |
124 | @@ -40,11 +38,12 @@ |
125 | self.search_entry = gtk.Entry() |
126 | hbox.pack_start(self.search_entry, True, True, 3) |
127 | |
128 | - self.search_button = gtk.Button(stock=gtk.STOCK_FIND, use_underline=True) |
129 | + self.search_button = gtk.Button( |
130 | + stock=gtk.STOCK_FIND, use_underline=True) |
131 | hbox.pack_start(self.search_button, False, False, 3) |
132 | |
133 | # Create CouchGrid to contain list of contacts |
134 | - self.contacts_list = CouchGrid('contacts') |
135 | + self.contacts_list = CouchGrid('contacts', uri=uri) |
136 | self.contacts_list.editable = False |
137 | self.contacts_list.keys = [ "first_name", "last_name" ] |
138 | self.contacts_list.record_type = CONTACT_RECORD_TYPE |
139 | |
140 | === modified file 'desktopcouch/contacts/tests/test_contactspicker.py' |
141 | --- desktopcouch/contacts/tests/test_contactspicker.py 2009-08-22 17:22:02 +0000 |
142 | +++ desktopcouch/contacts/tests/test_contactspicker.py 2009-08-24 20:35:25 +0000 |
143 | @@ -21,10 +21,24 @@ |
144 | import testtools |
145 | import gtk |
146 | from desktopcouch.contacts.contactspicker import ContactsPicker |
147 | +from desktopcouch.records.server import CouchDatabase |
148 | +from desktopcouch.records.tests import get_uri |
149 | + |
150 | +URI = get_uri() |
151 | |
152 | class TestContactsPicker(testtools.TestCase): |
153 | """Test the Contact Picker Window.""" |
154 | |
155 | + def setUp(self): |
156 | + """setup each test""" |
157 | + # Connect to CouchDB server |
158 | + self.dbname = 'contacts' |
159 | + self.database = CouchDatabase(self.dbname, create=True, uri=URI) |
160 | + |
161 | + def tearDown(self): |
162 | + """tear down each test""" |
163 | + del self.database._server[self.dbname] |
164 | + |
165 | def test_can_contruct_contactspicker(self): |
166 | """Test that we can build the window""" |
167 | # Create and show a test window |
168 | @@ -34,8 +48,8 @@ |
169 | win.resize(300, 450) |
170 | |
171 | # Create the contacts picker widget |
172 | - picker = ContactsPicker() |
173 | + picker = ContactsPicker(uri=URI) |
174 | win.get_content_area().pack_start(picker, True, True, 3) |
175 | - self.assert_(picker.get_contacts_list()) |
176 | + self.assert_(picker.get_contacts_list()) |
177 | |
178 | |
179 | |
180 | === modified file 'desktopcouch/records/server.py' |
181 | --- desktopcouch/records/server.py 2009-08-21 22:45:24 +0000 |
182 | +++ desktopcouch/records/server.py 2009-08-24 20:35:25 +0000 |
183 | @@ -49,8 +49,8 @@ |
184 | |
185 | def __init__(self, database, uri=None, record_factory=None, create=False): |
186 | if not uri: |
187 | - pid = desktopcouch.find_pid() |
188 | - port = desktopcouch.find_port(pid) |
189 | + desktopcouch.find_pid() |
190 | + port = desktopcouch.find_port() |
191 | self.server_uri = "http://localhost:%s" % port |
192 | else: |
193 | self.server_uri = uri |
194 | |
195 | === modified file 'desktopcouch/records/tests/__init__.py' |
196 | --- desktopcouch/records/tests/__init__.py 2009-08-21 22:47:25 +0000 |
197 | +++ desktopcouch/records/tests/__init__.py 2009-08-24 20:35:25 +0000 |
198 | @@ -15,26 +15,36 @@ |
199 | # along with desktopcouch. If not, see <http://www.gnu.org/licenses/>. |
200 | """Tests for Documents API""" |
201 | |
202 | -import os, tempfile |
203 | -from desktopcouch.local_files import COUCH_EXE, couch_chain_flag |
204 | +import os, tempfile, time, urllib2 |
205 | +from desktopcouch import local_files |
206 | from desktopcouch.start_local_couchdb import create_ini_file, run_couchdb |
207 | |
208 | directory = tempfile.mkdtemp() |
209 | -ini_path = os.path.join(directory, "test_couchdb.ini") |
210 | -log_path = os.path.join(directory, "test_couchdb.log") |
211 | -pid_path = os.path.join(directory, "test_couchdb.pid") |
212 | -stdout_path = os.path.join(directory, "test_couchdb.stdout") |
213 | -stderr_path = os.path.join(directory, "test_couchdb.stderr") |
214 | - |
215 | -db_dir = os.path.join(directory, "test_couchdb") |
216 | -os.mkdir(db_dir) |
217 | - |
218 | -port = "21224" |
219 | -create_ini_file( |
220 | - ini_path=ini_path, db_dir=db_dir, log_path=log_path, port=port) |
221 | -exec_command = [ |
222 | - COUCH_EXE, couch_chain_flag(), ini_path, '-p', pid_path, '-o', stdout_path, |
223 | - '-e', stderr_path] |
224 | -exec_command[2] = ini_path |
225 | -run_couchdb(exec_command=exec_command) |
226 | -URI = "htpp://localhost:%s" % port |
227 | +local_files.FILE_INI = os.path.join(directory, "test_couchdb.ini") |
228 | +local_files.FILE_LOG = os.path.join(directory, "test_couchdb.log") |
229 | +local_files.FILE_PID = os.path.join(directory, "test_couchdb.pid") |
230 | +local_files.FILE_STDOUT = os.path.join(directory, "test_couchdb.stdout") |
231 | +local_files.FILE_STDERR = os.path.join(directory, "test_couchdb.stderr") |
232 | + |
233 | +local_files.DIR_DB = os.path.join(directory, "test_couchdb") |
234 | +os.mkdir(local_files.DIR_DB) |
235 | + |
236 | +PORT = "21224" |
237 | +create_ini_file(port=PORT) |
238 | +local_files.COUCH_EXEC_COMMAND = [ |
239 | + local_files.COUCH_EXE, local_files.couch_chain_flag(), local_files.FILE_INI, |
240 | + '-p', local_files.FILE_PID, '-o', local_files.FILE_STDOUT, '-e', |
241 | + local_files.FILE_STDERR] |
242 | +run_couchdb() |
243 | + |
244 | +def get_uri(): |
245 | + uri = 'http://localhost:%s' % PORT |
246 | + i = 0 |
247 | + while i < 100: |
248 | + try: |
249 | + urllib2.urlopen(uri) |
250 | + break |
251 | + except: |
252 | + time.sleep(0.1) |
253 | + i += 1 |
254 | + return uri |
255 | |
256 | === modified file 'desktopcouch/records/tests/test_couchgrid.py' |
257 | --- desktopcouch/records/tests/test_couchgrid.py 2009-08-22 17:22:02 +0000 |
258 | +++ desktopcouch/records/tests/test_couchgrid.py 2009-08-24 20:35:25 +0000 |
259 | @@ -22,8 +22,9 @@ |
260 | from desktopcouch.records.record import Record |
261 | from desktopcouch.records.server import CouchDatabase |
262 | from desktopcouch.records.couchgrid import CouchGrid |
263 | -from desktopcouch.records.tests import URI |
264 | +from desktopcouch.records.tests import get_uri |
265 | |
266 | +URI = get_uri() |
267 | |
268 | class TestCouchGrid(TestCase): |
269 | """Test the CouchGrid functionality""" |
270 | |
271 | === modified file 'desktopcouch/records/tests/test_server.py' |
272 | --- desktopcouch/records/tests/test_server.py 2009-08-21 22:45:24 +0000 |
273 | +++ desktopcouch/records/tests/test_server.py 2009-08-24 20:35:25 +0000 |
274 | @@ -20,7 +20,9 @@ |
275 | import testtools |
276 | from desktopcouch.records.server import CouchDatabase |
277 | from desktopcouch.records.record import Record |
278 | -from desktopcouch.records.tests import URI |
279 | +from desktopcouch.records.tests import get_uri |
280 | + |
281 | +URI = get_uri() |
282 | |
283 | FAKE_RECORD_TYPE = "http://example.org/test" |
284 | |
285 | |
286 | === modified file 'desktopcouch/start_local_couchdb.py' |
287 | --- desktopcouch/start_local_couchdb.py 2009-08-21 22:45:24 +0000 |
288 | +++ desktopcouch/start_local_couchdb.py 2009-08-24 20:35:25 +0000 |
289 | @@ -56,12 +56,12 @@ |
290 | fd.write("\n") |
291 | fd.close() |
292 | |
293 | -def create_ini_file( |
294 | - ini_path=local_files.FILE_INI, db_dir=local_files.DIR_DB, |
295 | - log_path=local_files.FILE_LOG, port="0"): |
296 | +def create_ini_file(port="0"): |
297 | """Write CouchDB ini file if not already present""" |
298 | + ini_path = local_files.FILE_INI |
299 | if os.path.exists(ini_path): |
300 | return |
301 | + db_dir = local_files.DIR_DB |
302 | ini = { |
303 | 'couchdb': { |
304 | 'database_dir': db_dir, |
305 | @@ -72,15 +72,15 @@ |
306 | 'port': port, |
307 | }, |
308 | 'log': { |
309 | - 'file': log_path, |
310 | + 'file': local_files.FILE_LOG, |
311 | 'level': 'info', |
312 | }, |
313 | } |
314 | dump_ini(ini, ini_path) |
315 | |
316 | -def run_couchdb(exec_command=local_files.COUCH_EXEC_COMMAND): |
317 | +def run_couchdb(): |
318 | """Actually start the CouchDB process""" |
319 | - local_exec = exec_command + ['-b'] |
320 | + local_exec = local_files.COUCH_EXEC_COMMAND + ['-b'] |
321 | try: |
322 | # subprocess is buggy. Chad patched, but that takes time to propagate. |
323 | proc = subprocess.Popen(local_exec) |
324 | @@ -165,12 +165,12 @@ |
325 | for retry in xrange(10000, 0, -1): |
326 | pid = desktopcouch.find_pid(start_if_not_running=False) |
327 | try: |
328 | - port = desktopcouch.find_port(pid) |
329 | + port = desktopcouch.find_port() |
330 | break |
331 | - except RuntimeError, e: |
332 | + except IOError: |
333 | if retry == 1: |
334 | raise |
335 | - time.sleep(0.01) |
336 | + time.sleep(0.1) |
337 | continue |
338 | |
339 | if port is None: |
340 | @@ -193,8 +193,8 @@ |
341 | run_couchdb() |
342 | # Note that we do not call update_design_documents here. This is because |
343 | # Couch won't actually have started yet, so when update_design_documents |
344 | - # calls the Records API, that will call back into get_pid and we end up |
345 | - # starting Couch again. Instead, get_pid calls update_design_documents |
346 | + # calls the Records API, that will call back into get_port and we end up |
347 | + # starting Couch again. Instead, get_port calls update_design_documents |
348 | # *after* Couch startup has occurred. |
349 | write_bookmark_file() |
350 |
This reads the portnumber the user's couchdb is running on from the logfile, now that couchdb writes it there. Not pretty, but less complicated at least. Stupider is better than smarter.