Merge lp:~alex-idereal/bzr-xmloutput/fix-xmlmissing-exception into lp:bzr-xmloutput

Proposed by Piotr Piastucki
Status: Needs review
Proposed branch: lp:~alex-idereal/bzr-xmloutput/fix-xmlmissing-exception
Merge into: lp:bzr-xmloutput
Diff against target: 478 lines (+236/-47)
10 files modified
info.py (+1/-1)
installer/bzr-xmloutput-setup.nsi (+1/-1)
lsxml.py (+22/-5)
missingxml.py (+1/-1)
service.py (+40/-6)
shelvexml.py (+15/-11)
tagsxml.py (+23/-19)
tests/test_ls_xml.py (+59/-1)
tests/test_progress.py (+48/-0)
uifactory.py (+26/-2)
To merge this branch: bzr merge lp:~alex-idereal/bzr-xmloutput/fix-xmlmissing-exception
Reviewer Review Type Date Requested Status
Guillermo Gonzalez Pending
Review via email: mp+192807@code.launchpad.net

Description of the change

missingxml: Don't throw exception if local branch has no parent.
Use other_branch to fill in <last_location> URL instead of parent.
This seems correct since it's the branch being used to calculate what's missing, and it avoids an exception when parent is None. Hopefully nothing depends on the previous broken behaviour.

To post a comment you must log in.

Unmerged revisions

183. By Alexander Taler

missingxml: Don't throw exception if local branch has no parent.

Use other_branch to fill in <last_location> URL instead of parent.

This seems correct since it's the branch being used to calculate what's missing, and it avoids an exception when parent is None. Hopefully nothing depends on the previous broken behaviour.

182. By Piotr Piastucki

Increase version number to 0.9.1

181. By Piotr Piastucki

Merge lp:~rom1-chal/bzr-xmloutput/bugfix-persistent-ssh
Add an experimental workaround for bzr not closing ssh connections.
This is not a real fix but it seems to work.

180. By Piotr Piastucki

Merge lp:~bzr-eclipse/bzr-xmloutput/xmlls-verbose-mode

179. By Piotr Piastucki

Merge lp:~piastucki/bzr-xmloutput/missing-locks

178. By Piotr Piastucki

Sync with main branch

177. By Piotr Piastucki

Merge lp:~piastucki/bzr-xmloutput/fix-551351-ignored-in-symlink-root

176. By Piotr Piastucki

Fix handling of files with execute bit changed in xmlstatus
Introduce new attribute called meta_modfied instead of changing the file path and appending an asterisk for files with changes in execute bit.

175. By Piotr Piastucki

Fix no _encoding attribute issue due to changes between bzr 2.6b1 and 2.6b3

174. By Alexander Taler

Increase version number to 0.9.0.

To support bzr-eclipse release 1.2.0

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'info.py'
2--- info.py 2013-03-05 12:38:17 +0000
3+++ info.py 2013-10-27 06:44:02 +0000
4@@ -17,7 +17,7 @@
5 bzr_plugin_name = "xmloutput"
6
7 # See bzrlib/__init__.py for the definition of version tuple format
8-bzr_plugin_version = (0, 8, 9, 'final', 0)
9+bzr_plugin_version = (0, 9, 1, 'final', 0)
10
11 bzr_commands = ['xmlannotate', 'xmlconflicts', 'xmlinfo', 'xmlmissing', 'xmllog', 'xmlls',
12 'xmlplugins', 'xmlshelvelist', 'xmltags', 'xmlversion', 'start-xmlrpc', 'stop-xmlrpc']
13
14=== modified file 'installer/bzr-xmloutput-setup.nsi'
15--- installer/bzr-xmloutput-setup.nsi 2011-11-05 05:17:49 +0000
16+++ installer/bzr-xmloutput-setup.nsi 2013-10-27 06:44:02 +0000
17@@ -1,5 +1,5 @@
18 !define PRODUCT_NAME "bzr-xmloutput"
19-!define PRODUCT_VERSION "0.8.8"
20+!define PRODUCT_VERSION "0.9.1"
21 !define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
22 !define PRODUCT_UNINST_ROOT_KEY "HKLM"
23
24
25=== modified file 'lsxml.py'
26--- lsxml.py 2013-07-04 21:31:29 +0000
27+++ lsxml.py 2013-10-27 06:44:02 +0000
28@@ -57,10 +57,13 @@
29 prefix = fs_path + '/'
30
31 if revision is not None:
32- tree = branch.repository.revision_tree(
33+ tree = r_tree = branch.repository.revision_tree(
34 revision[0].as_revision_id(branch))
35- elif tree is None:
36- tree = branch.basis_tree()
37+ else:
38+ if tree is None:
39+ tree = branch.basis_tree()
40+ if verbose:
41+ r_tree = branch.basis_tree()
42
43 tree.lock_read()
44 try:
45@@ -79,15 +82,29 @@
46 pattern = ''
47 if prefix:
48 fp = osutils.pathjoin(prefix, fp)
49+ verbosestr = ''
50 if fid is None:
51 fid = ''
52 else:
53+ if verbose:
54+ try:
55+ revid = r_tree.get_file_revision(fid)
56+ revno = branch.revision_id_to_dotted_revno(revid)
57+ if isinstance(revno, tuple):
58+ revno = '.'.join(map(str, revno))
59+ rev = branch.repository.get_revision(revid)
60+ date_str = osutils.format_date(rev.timestamp, rev.timezone or 0)
61+ verbosestr='<log><revno>%s</revno><committer>%s</committer><timestamp>%s</timestamp></log>' \
62+ % (revno, _escape_cdata(rev.committer), date_str)
63+ except:
64+ # e.g. newly added file not existing in any revision yet
65+ pass
66 fid = '<id>%s</id>' % _escape_cdata(fid)
67 fkind = '<kind>%s</kind>' % fkind
68 status_kind = '<status_kind>%s</status_kind>' % long_status_kind[fc]
69 fpath = '<path>%s</path>' % _escape_cdata(fp)
70- outstring = '<item>%s%s%s%s%s</item>' % (fid, fkind, fpath,
71- status_kind, pattern)
72+ outstring = '<item>%s%s%s%s%s%s</item>' % (fid, fkind, fpath,
73+ status_kind, pattern, verbosestr)
74 outf.write(outstring)
75 finally:
76 outf.write('</list>')
77
78=== modified file 'missingxml.py'
79--- missingxml.py 2010-02-08 04:37:36 +0000
80+++ missingxml.py 2013-10-27 06:44:02 +0000
81@@ -52,7 +52,7 @@
82 if other_branch is None:
83 raise errors.BzrCommandError("No peer location known"
84 " or specified.")
85- display_url = urlutils.unescape_for_display(parent,
86+ display_url = urlutils.unescape_for_display(other_branch,
87 self.outf.encoding)
88
89 remote_branch = Branch.open(other_branch)
90
91=== modified file 'service.py'
92--- service.py 2013-02-16 15:30:39 +0000
93+++ service.py 2013-10-27 06:44:02 +0000
94@@ -36,20 +36,49 @@
95 import logging
96 import traceback
97 from cStringIO import StringIO
98+import gc
99 """)
100
101 from bzrlib.plugins.xmloutput.xml_errors import XMLError
102 from xmlrpclib import Fault, Binary
103 from SimpleXMLRPCServer import SimpleXMLRPCServer
104+import threading
105
106 run_dir = os.getcwdu()
107
108+class BzrXMLRPCProgressServer(SimpleXMLRPCServer):
109+ """ Very simple xmlrpc server to handle progress reporting"""
110+
111+ finished = False
112+
113+ def __init__(self, addr, logRequests=False, to_file=None):
114+ SimpleXMLRPCServer.__init__(self, addr=addr,
115+ logRequests=logRequests)
116+ self.register_function(self.get_bzr_progress)
117+
118+ def shutdown(self):
119+ """ stop serving and return 1 """
120+ self.finished = True
121+ self.server_close()
122+ return 1
123+
124+ def serve_forever(self):
125+ """Start serving, and block"""
126+ while not self.finished:
127+ self.handle_request()
128+
129+ def get_bzr_progress(self, argv):
130+ """get bzr command progress"""
131+ import uifactory
132+ progress = uifactory.current_progress.get('|'.join(argv), '')
133+ return progress
134
135 class BzrXMLRPCServer(SimpleXMLRPCServer):
136 """ Very simple xmlrpc server to handle bzr commands and search"""
137
138 finished = False
139-
140+ progress_server = None
141+
142 def __init__(self, addr, logRequests=False, to_file=None):
143 SimpleXMLRPCServer.__init__(self, addr=addr,
144 logRequests=logRequests)
145@@ -74,10 +103,18 @@
146 """ stop serving and return 1 """
147 self.finished = True
148 self.server_close()
149+ if self.progress_server is not None:
150+ self.progress_server.shutdown()
151 return 1
152
153 def serve_forever(self):
154 """Start serving, and block"""
155+ if os.environ.get('BZR_PROGRESS_BAR') == 'xmlrpc':
156+ host, port = self.socket.getsockname()
157+ self.progress_server = BzrXMLRPCProgressServer((host, port + 1), False)
158+ thread = threading.Thread(target=self.progress_server.serve_forever)
159+ thread.setDaemon(True)
160+ thread.start()
161 import bzrlib.osutils
162 default_encoding = 'UTF-8'
163 if hasattr(bzrlib, 'user_encoding'):
164@@ -95,7 +132,6 @@
165 """ simple reply to hello request, 'world!'"""
166 return 'world!'
167
168-
169 class redirect_output(object):
170 """decorator to redirect stdout/err to a StringIO"""
171
172@@ -136,7 +172,6 @@
173 """run a regular bzr command"""
174 return _run_bzr(argv, workdir, False)
175
176-
177 @redirect_output
178 def run_bzr_xml(argv, workdir):
179 """run a bzr command, but handle errors using XMLError"""
180@@ -155,6 +190,7 @@
181 exitval = custom_commands_main(argv, username, password)
182 else:
183 exitval = commands.main(argv)
184+ gc.collect()
185 sys.stderr.flush()
186 sys.stdout.flush()
187 if isinstance(exitval, Fault):
188@@ -171,12 +207,11 @@
189 traceback.print_exc(file=sys.__stderr__)
190 raise
191
192-
193 def custom_commands_main(argv, username=None, password=None):
194 """custom commands.main that handle errors using XMLError"""
195 import bzrlib.ui
196 from uifactory import AuthenticatingUIFactory
197- bzrlib.ui.ui_factory = AuthenticatingUIFactory(sys.stdin, sys.stdout, sys.stderr, username, password)
198+ bzrlib.ui.ui_factory = AuthenticatingUIFactory(sys.stdin, sys.stdout, sys.stderr, username, password, argv)
199 try:
200 _argv = []
201 for a in argv[1:]:
202@@ -192,7 +227,6 @@
203 traceback.print_exc(file=sys.__stderr__)
204 raise Fault(32, str(XMLError(e)))
205
206-
207 def register_functions(server):
208 """register functions exposed via xmlrpc."""
209 server.register_function(run_bzr, 'run_bzr_command')
210
211=== modified file 'shelvexml.py'
212--- shelvexml.py 2013-02-27 13:38:55 +0000
213+++ shelvexml.py 2013-10-27 06:44:02 +0000
214@@ -29,16 +29,20 @@
215
216 def list_xml(outf, directory='.'):
217 tree = WorkingTree.open_containing(directory)[0]
218- manager = tree.get_shelf_manager()
219- shelves = manager.active_shelves()
220- outf.write('<?xml version="1.0" encoding="%s"?>' % \
221- bzrlib.osutils.get_user_encoding())
222- outf.write('<shelves>')
223- for shelf_id in reversed(shelves):
224- message = manager.get_metadata(shelf_id).get('message')
225- if message is None:
226- message = ''
227- outf.write('<shelf><id>%s</id><message>%s</message></shelf>' % (shelf_id, _escape_cdata(message)))
228- outf.write('</shelves>')
229+ tree.lock_read()
230+ try:
231+ manager = tree.get_shelf_manager()
232+ shelves = manager.active_shelves()
233+ outf.write('<?xml version="1.0" encoding="%s"?>' % \
234+ bzrlib.osutils.get_user_encoding())
235+ outf.write('<shelves>')
236+ for shelf_id in reversed(shelves):
237+ message = manager.get_metadata(shelf_id).get('message')
238+ if message is None:
239+ message = ''
240+ outf.write('<shelf><id>%s</id><message>%s</message></shelf>' % (shelf_id, _escape_cdata(message)))
241+ outf.write('</shelves>')
242+ finally:
243+ tree.unlock()
244
245
246
247=== modified file 'tagsxml.py'
248--- tagsxml.py 2013-02-22 21:13:54 +0000
249+++ tagsxml.py 2013-10-27 06:44:02 +0000
250@@ -37,25 +37,29 @@
251 bzrlib.osutils.get_user_encoding())
252 outf.write('<tags>')
253 if tags:
254- if sort is None:
255- sort = tag_sort_methods.get()
256- sort(branch, tags)
257- if not show_ids:
258- # [ (tag, revid), ... ] -> [ (tag, dotted_revno), ... ]
259- for index, (tag, revid) in enumerate(tags):
260- try:
261- revno = branch.revision_id_to_dotted_revno(revid)
262- if isinstance(revno, tuple):
263- revno = '.'.join(map(str, revno))
264- except (errors.NoSuchRevision,
265- errors.GhostRevisionsHaveNoRevno,
266- errors.UnsupportedOperation):
267- # Bad tag data/merges can lead to tagged revisions
268- # which are not in this branch. Fail gracefully ...
269- revno = '?'
270- tags[index] = (tag, revno)
271- for tag, revspec in tags:
272- outf.write('<tag><name>%s</name><revision>%s</revision></tag>' % (_escape_cdata(tag), _escape_cdata(revspec)))
273+ branch.lock_read()
274+ try:
275+ if sort is None:
276+ sort = tag_sort_methods.get()
277+ sort(branch, tags)
278+ if not show_ids:
279+ # [ (tag, revid), ... ] -> [ (tag, dotted_revno), ... ]
280+ for index, (tag, revid) in enumerate(tags):
281+ try:
282+ revno = branch.revision_id_to_dotted_revno(revid)
283+ if isinstance(revno, tuple):
284+ revno = '.'.join(map(str, revno))
285+ except (errors.NoSuchRevision,
286+ errors.GhostRevisionsHaveNoRevno,
287+ errors.UnsupportedOperation):
288+ # Bad tag data/merges can lead to tagged revisions
289+ # which are not in this branch. Fail gracefully ...
290+ revno = '?'
291+ tags[index] = (tag, revno)
292+ for tag, revspec in tags:
293+ outf.write('<tag><name>%s</name><revision>%s</revision></tag>' % (_escape_cdata(tag), _escape_cdata(revspec)))
294+ finally:
295+ branch.unlock()
296 outf.write('</tags>')
297
298
299
300=== modified file 'tests/test_ls_xml.py'
301--- tests/test_ls_xml.py 2013-08-26 18:53:37 +0000
302+++ tests/test_ls_xml.py 2013-10-27 06:44:02 +0000
303@@ -51,7 +51,12 @@
304 for item_elem in lst.findall('item'):
305 item = {}
306 for attr in item_elem:
307- item[attr.tag] = attr.text
308+ if attr.tag == 'log':
309+ for log_item_elem in attr:
310+ if log_item_elem.tag != 'timestamp':
311+ item['log.' + log_item_elem.tag] = log_item_elem.text
312+ else:
313+ item[attr.tag] = attr.text
314 items.append(item)
315 return items
316
317@@ -335,4 +340,57 @@
318 'status_kind': 'ignored'}]
319 self.assertEquals(expected_items, self.run_xmlls('--ignored ' + symlink))
320
321+ def test_lsxml_verbose(self):
322+ self.build_tree(['b', 'c', 'd', 'blah.pyo'])
323+ self.wt.add(['a', '.bzrignore'], ['a-id', 'bzrignore-id'])
324+ self.wt.commit('commit 1', committer='Paul')
325+ self.wt.add(['d'], ['d-id'])
326+ self.wt.commit('commit 2', committer='John')
327+ self.wt.add(['c'], ['c-id'])
328+ expected_items = [{'id': 'bzrignore-id',
329+ 'kind': 'file',
330+ 'log.committer': 'Paul',
331+ 'log.revno': '1',
332+ 'path': '.bzrignore',
333+ 'status_kind': 'versioned'},
334+ {'id': 'a-id',
335+ 'kind': 'file',
336+ 'log.committer': 'Paul',
337+ 'log.revno': '1',
338+ 'path': 'a',
339+ 'status_kind': 'versioned'},
340+ {'kind': 'file',
341+ 'path': 'b',
342+ 'status_kind': 'unknown'},
343+ {'kind': 'file',
344+ 'path': 'blah.pyo',
345+ 'status_kind': 'ignored'},
346+ {'id': 'c-id',
347+ 'kind': 'file',
348+ 'path': 'c',
349+ 'status_kind': 'versioned'},
350+ {'id': 'd-id',
351+ 'kind': 'file',
352+ 'log.committer': 'John',
353+ 'log.revno': '2',
354+ 'path': 'd',
355+ 'status_kind': 'versioned'}]
356+ self.assertEquals(expected_items, self.run_xmlls('--verbose'))
357+
358+ def test_lsxml_ignored_symlink(self):
359+ # Ignored files inside a symlink directory
360+ self.wt.add(['a', '.bzrignore'], ['a-id', 'bzrignore-id'])
361+ self.build_tree(['blah.py', 'blah.pyo', 'user-ignore'])
362+ symlink = self.test_dir + '_symlink'
363+ os.symlink(self.test_dir, symlink)
364+ expected_items = [{'kind': 'file',
365+ 'path': os.path.join(symlink, 'blah.pyo'),
366+ 'pattern': '*.pyo',
367+ 'status_kind': 'ignored'},
368+ {'kind': 'file',
369+ 'path': os.path.join(symlink, 'user-ignore'),
370+ 'pattern': 'user-ignore',
371+ 'status_kind': 'ignored'}]
372+ self.assertEquals(expected_items, self.run_xmlls('--ignored ' + symlink))
373+
374
375
376=== added file 'tests/test_progress.py'
377--- tests/test_progress.py 1970-01-01 00:00:00 +0000
378+++ tests/test_progress.py 2013-10-27 06:44:02 +0000
379@@ -0,0 +1,48 @@
380+# -*- encoding: utf-8 -*-
381+
382+import xmlrpclib
383+import threading
384+
385+from bzrlib import (
386+ tests,
387+ ui
388+ )
389+from bzrlib.plugins.xmloutput.service import *
390+from bzrlib.plugins.xmloutput.uifactory import current_progress
391+
392+class TestXmlRpcServer(tests.TestCase):
393+
394+ def setUp(self):
395+ tests.TestCase.setUp(self)
396+ self.host = 'localhost'
397+ self.port = 0
398+ self._start_server()
399+ self.client = xmlrpclib.Server("http://%s:%s" % (self.host,
400+ str(self.port)))
401+
402+ def _start_server(self):
403+ os.environ['BZR_PROGRESS_BAR'] = 'xmlrpc'
404+ self.server = BzrXMLRPCServer((self.host, self.port))
405+ self.thread = threading.Thread(target=self.server.serve_forever)
406+ self.thread.setDaemon(True)
407+ self.thread.start()
408+ self.host, self.port = self.server.socket.getsockname()
409+
410+ def tearDown(self):
411+ response = self.client.quit()
412+ self.thread.join()
413+ tests.TestCase.tearDown(self)
414+
415+ def test_hello(self):
416+ response = self.client.hello()
417+ self.assertEquals(response, "world!")
418+
419+ def test_get_bzr_progress(self):
420+ global current_progress
421+ client = xmlrpclib.Server("http://%s:%s" % (self.host, str(self.port + 1)))
422+ current_progress['TEST'] = '123'
423+ cmdline = []
424+ cmdline.append('TEST')
425+ progress = client.get_bzr_progress(cmdline)
426+ self.assertEquals(progress, '123')
427+
428
429=== modified file 'uifactory.py'
430--- uifactory.py 2013-02-16 15:30:39 +0000
431+++ uifactory.py 2013-10-27 06:44:02 +0000
432@@ -17,8 +17,12 @@
433 # along with this program; if not, write to the Free Software
434 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
435
436-from bzrlib import ui
437 from bzrlib.ui.text import TextUIFactory
438+from bzrlib.ui.text import TextProgressView
439+from bzrlib.ui import NullProgressView
440+from cStringIO import StringIO
441+
442+current_progress = {}
443
444 class AuthenticatingUIFactory(TextUIFactory):
445
446@@ -27,7 +31,12 @@
447 stdout=None,
448 stderr=None,
449 username=None,
450- password=None):
451+ password=None,
452+ argv=None):
453+ if argv is not None:
454+ self.cmd_id = '|'.join(argv)
455+ else:
456+ self.cmd_id = ''
457 super(AuthenticatingUIFactory, self).__init__(stdin, stdout, stderr)
458 self.username = username
459 self.password = password
460@@ -49,3 +58,18 @@
461 raise ValueError('XMLRPC authentication username:' + self.get_prompt_text(prompt, **kwargs))
462 return self.username
463
464+ def make_progress_view(self):
465+ return XmlRpcProgressView(self.cmd_id)
466+
467+class XmlRpcProgressView(TextProgressView):
468+
469+ def __init__(self, cmd_id):
470+ self.cmd_id = cmd_id
471+ super(XmlRpcProgressView, self).__init__(StringIO())
472+
473+ def _show_line(self, u):
474+ global current_progress
475+ #s = u.encode(self._encoding, self._encoding_errors)
476+ current_progress.clear()
477+ current_progress[self.cmd_id] = u
478+

Subscribers

People subscribed via source and target branches

to all changes: