Merge lp:~piastucki/bzr-xmloutput/xmlconflicts into lp:bzr-xmloutput
- xmlconflicts
- Merge into trunk
Proposed by
Piotr Piastucki
Status: | Merged |
---|---|
Approved by: | Guillermo Gonzalez |
Approved revision: | 168 |
Merged at revision: | 170 |
Proposed branch: | lp:~piastucki/bzr-xmloutput/xmlconflicts |
Merge into: | lp:bzr-xmloutput |
Diff against target: |
424 lines (+374/-3) 7 files modified
__init__.py (+3/-1) cmds.py (+44/-0) conflictsxml.py (+41/-0) info.py (+2/-2) shelvexml.py (+44/-0) tests/test_conflicts_xml.py (+139/-0) tests/test_shelve_xml.py (+101/-0) |
To merge this branch: | bzr merge lp:~piastucki/bzr-xmloutput/xmlconflicts |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Guillermo Gonzalez | Approve | ||
Review via email: mp+154371@code.launchpad.net |
Commit message
Description of the change
This branch adds support for xmlconflicts command.
The branch is based on lp:~piastucki/bzr-xmloutput/xml-shelve-list and hence can be merge if lp:~piastucki/bzr-xmloutput/xml-shelve-list gets merged unmodifed.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file '__init__.py' |
2 | --- __init__.py 2013-02-12 18:38:52 +0000 |
3 | +++ __init__.py 2013-03-20 13:36:31 +0000 |
4 | @@ -50,7 +50,9 @@ |
5 | "stop_xmlrpc", |
6 | "xmllog", |
7 | "xmlls", |
8 | - "xmltags"]: |
9 | + "xmltags", |
10 | + "xmlshelvelist", |
11 | + "xmlconflicts"]: |
12 | plugin_cmds.register_lazy( |
13 | "cmd_%s" % cmd, [], |
14 | "bzrlib.plugins.xmloutput.cmds") |
15 | |
16 | === modified file 'cmds.py' |
17 | --- cmds.py 2013-02-16 23:15:33 +0000 |
18 | +++ cmds.py 2013-03-20 13:36:31 +0000 |
19 | @@ -465,3 +465,47 @@ |
20 | self.outf.write('\0') |
21 | self.outf.write('\n') |
22 | |
23 | +class cmd_xmlshelvelist(Command): |
24 | + """List shelved changes. |
25 | + This command lists previously-shelved changes. |
26 | + """ |
27 | + hidden = True |
28 | + _see_also = ['unshelve', 'configuration'] |
29 | + takes_options = [ |
30 | + 'directory', |
31 | + null_option |
32 | + ] |
33 | + encoding_type = 'replace' |
34 | + |
35 | + @display_command |
36 | + @handle_error_xml |
37 | + def run(self, *args, **kwargs): |
38 | + import shelvexml |
39 | + null = kwargs.pop('null', False) |
40 | + shelvexml.list_xml(self.outf, *args, **kwargs) |
41 | + if null: |
42 | + self.outf.write('\0') |
43 | + self.outf.write('\n') |
44 | + |
45 | +class cmd_xmlconflicts(Command): |
46 | + """List files with conflicts.""" |
47 | + hidden = True |
48 | + _see_also = ['resolve', 'conflict-types'] |
49 | + takes_options = [ |
50 | + 'directory', |
51 | + Option('text', |
52 | + help='List text conflicts only.'), |
53 | + null_option |
54 | + ] |
55 | + encoding_type = 'replace' |
56 | + |
57 | + @display_command |
58 | + @handle_error_xml |
59 | + def run(self, *args, **kwargs): |
60 | + import conflictsxml |
61 | + null = kwargs.pop('null', False) |
62 | + conflictsxml.conflicts_xml(self.outf, *args, **kwargs) |
63 | + if null: |
64 | + self.outf.write('\0') |
65 | + self.outf.write('\n') |
66 | + |
67 | |
68 | === added file 'conflictsxml.py' |
69 | --- conflictsxml.py 1970-01-01 00:00:00 +0000 |
70 | +++ conflictsxml.py 2013-03-20 13:36:31 +0000 |
71 | @@ -0,0 +1,41 @@ |
72 | +#!/usr/bin/env python |
73 | +# -*- encoding: utf-8 -*- |
74 | +# |
75 | +# Copyright (C) 2013 Piotr Piastucki |
76 | +# |
77 | +# The code taken from bzrlib is under: Copyright (C) 2005-2007 Canonical Ltd |
78 | +# |
79 | +# This program is free software; you can redistribute it and/or modify |
80 | +# it under the terms of the GNU General Public License as published by |
81 | +# the Free Software Foundation; either version 2 of the License, or |
82 | +# (at your option) any later version. |
83 | +# |
84 | +# This program is distributed in the hope that it will be useful, |
85 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
86 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
87 | +# GNU General Public License for more details. |
88 | +# |
89 | +# You should have received a copy of the GNU General Public License |
90 | +# along with this program; if not, write to the Free Software |
91 | +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
92 | +# |
93 | + |
94 | +"""modified conflicts command to generate xml output""" |
95 | + |
96 | +import bzrlib |
97 | +from bzrlib import errors |
98 | +from bzrlib import workingtree |
99 | +from writer import _escape_cdata |
100 | + |
101 | +def conflicts_xml(outf, text=False, directory=u'.'): |
102 | + wt = workingtree.WorkingTree.open_containing(directory)[0] |
103 | + outf.write('<?xml version="1.0" encoding="%s"?>' % \ |
104 | + bzrlib.osutils.get_user_encoding()) |
105 | + outf.write('<conflicts>') |
106 | + for conflict in wt.conflicts(): |
107 | + if text and conflict.typestring != 'text conflict': |
108 | + continue |
109 | + outf.write('<conflict><type>%s</type><path>%s</path><message>%s</message></conflict>' % (_escape_cdata(conflict.typestring), _escape_cdata(conflict.path), _escape_cdata(unicode(conflict)))) |
110 | + outf.write('</conflicts>') |
111 | + |
112 | + |
113 | |
114 | === modified file 'info.py' |
115 | --- info.py 2013-02-12 18:38:52 +0000 |
116 | +++ info.py 2013-03-20 13:36:31 +0000 |
117 | @@ -19,6 +19,6 @@ |
118 | # See bzrlib/__init__.py for the definition of version tuple format |
119 | bzr_plugin_version = (0, 8, 9, 'final', 0) |
120 | |
121 | -bzr_commands = ['xmlannotate', 'xmlinfo', 'xmlmissing', 'xmllog', 'xmlls', |
122 | - 'xmlplugins', 'xmltags', 'xmlversion', 'start-xmlrpc', 'stop-xmlrpc'] |
123 | +bzr_commands = ['xmlannotate', 'xmlconflicts', 'xmlinfo', 'xmlmissing', 'xmllog', 'xmlls', |
124 | + 'xmlplugins', 'xmlshelvelist', 'xmltags', 'xmlversion', 'start-xmlrpc', 'stop-xmlrpc'] |
125 | |
126 | |
127 | === added file 'shelvexml.py' |
128 | --- shelvexml.py 1970-01-01 00:00:00 +0000 |
129 | +++ shelvexml.py 2013-03-20 13:36:31 +0000 |
130 | @@ -0,0 +1,44 @@ |
131 | +#!/usr/bin/env python |
132 | +# -*- encoding: utf-8 -*- |
133 | +# |
134 | +# Copyright (C) 2013 Piotr Piastucki |
135 | +# |
136 | +# The code taken from bzrlib is under: Copyright (C) 2005-2007 Canonical Ltd |
137 | +# |
138 | +# This program is free software; you can redistribute it and/or modify |
139 | +# it under the terms of the GNU General Public License as published by |
140 | +# the Free Software Foundation; either version 2 of the License, or |
141 | +# (at your option) any later version. |
142 | +# |
143 | +# This program is distributed in the hope that it will be useful, |
144 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
145 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
146 | +# GNU General Public License for more details. |
147 | +# |
148 | +# You should have received a copy of the GNU General Public License |
149 | +# along with this program; if not, write to the Free Software |
150 | +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
151 | +# |
152 | + |
153 | +"""modified shelve --list command to generate xml output""" |
154 | + |
155 | +import bzrlib |
156 | +from bzrlib import errors |
157 | +from bzrlib.workingtree import WorkingTree |
158 | +from writer import _escape_cdata |
159 | + |
160 | +def list_xml(outf, directory='.'): |
161 | + tree = WorkingTree.open_containing(directory)[0] |
162 | + manager = tree.get_shelf_manager() |
163 | + shelves = manager.active_shelves() |
164 | + outf.write('<?xml version="1.0" encoding="%s"?>' % \ |
165 | + bzrlib.osutils.get_user_encoding()) |
166 | + outf.write('<shelves>') |
167 | + for shelf_id in reversed(shelves): |
168 | + message = manager.get_metadata(shelf_id).get('message') |
169 | + if message is None: |
170 | + message = '' |
171 | + outf.write('<shelf><id>%s</id><message>%s</message></shelf>' % (shelf_id, _escape_cdata(message))) |
172 | + outf.write('</shelves>') |
173 | + |
174 | + |
175 | |
176 | === added file 'tests/test_conflicts_xml.py' |
177 | --- tests/test_conflicts_xml.py 1970-01-01 00:00:00 +0000 |
178 | +++ tests/test_conflicts_xml.py 2013-03-20 13:36:31 +0000 |
179 | @@ -0,0 +1,139 @@ |
180 | +# Copyright (C) 2005, 2006, 2007, 2008, 2009 Canonical Ltd |
181 | +# Copyright (C) 2013 Piotr Piastucki |
182 | +# -*- coding: utf-8 -*- |
183 | +# |
184 | +# This program is free software; you can redistribute it and/or modify |
185 | +# it under the terms of the GNU General Public License as published by |
186 | +# the Free Software Foundation; either version 2 of the License, or |
187 | +# (at your option) any later version. |
188 | +# |
189 | +# This program is distributed in the hope that it will be useful, |
190 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
191 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
192 | +# GNU General Public License for more details. |
193 | +# |
194 | +# You should have received a copy of the GNU General Public License |
195 | +# along with this program; if not, write to the Free Software |
196 | +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
197 | + |
198 | + |
199 | +"""Tests for bzr xmlconflicts.""" |
200 | + |
201 | +import os |
202 | +import sys |
203 | +import bzrlib |
204 | +from bzrlib import osutils |
205 | +from bzrlib.tests.blackbox import ExternalBase |
206 | +from bzrlib.tests import TestCaseInTempDir, TestCaseWithTransport |
207 | +from bzrlib.xml_serializer import elementtree as elementtree |
208 | +fromstring = elementtree.fromstring |
209 | +elementtree_tostring = elementtree.tostring |
210 | + |
211 | +class TestConflicts(ExternalBase): |
212 | + |
213 | + def _prepare(self): |
214 | + # This scenario will create: |
215 | + # 2 text conflicts |
216 | + # 1 content conflict (file renamed-modified/deleted) |
217 | + # 1 path conflict (renamed/deleted) |
218 | + # 1 duplicate entry conflict (file created with different IDs) |
219 | + base_actions = [('add', ('file', 'file-id-1', 'file', 'trunk content\n')), |
220 | + ('add', ('dir', 'dir-id', 'directory', '')), |
221 | + ('add', ('dir/file', 'file-id-2', 'file', 'trunk content\n')), |
222 | + ('add', ('content-conflict', 'file-id-3', 'file', 'trunk content\n')), |
223 | + ('add', ('path-conflict', 'file-id-4', 'file', 'trunk content\n')) |
224 | + ] |
225 | + other_actions = [('modify', ('file-id-1', 'trunk content\nfeature A\n')), |
226 | + ('modify', ('file-id-2', 'trunk content\nfeature A\n')), |
227 | + ('modify', ('file-id-3', 'trunk content\nmore content\n')), |
228 | + ('unversion', 'file-id-4'), |
229 | + ('add', ('duplicate-conflict', 'file-id-5', 'file', 'trunk content\n')) |
230 | + ] |
231 | + |
232 | + this_actions = [('modify', ('file-id-1', 'trunk content\nfeature B\n')), |
233 | + ('modify', ('file-id-2', 'trunk content\nfeature B\n')), |
234 | + ('unversion', 'file-id-3'), |
235 | + ('rename', ('path-conflict', 'path-conflict-new')), |
236 | + ('add', ('duplicate-conflict', 'file-id-6', 'file', 'trunk content\n')) |
237 | + ] |
238 | + |
239 | + builder = self.make_branch_builder('trunk') |
240 | + builder.start_series() |
241 | + # Create an empty trunk |
242 | + builder.build_snapshot('start', None, [ |
243 | + ('add', ('', 'root-id', 'directory', ''))]) |
244 | + # Add a minimal base content |
245 | + builder.build_snapshot('base', ['start'], base_actions) |
246 | + # Modify the base content in branch |
247 | + builder.build_snapshot('other', ['base'], other_actions) |
248 | + # Modify the base content in trunk |
249 | + builder.build_snapshot('this', ['base'], this_actions) |
250 | + # builder.get_branch() tip is now 'this' |
251 | + |
252 | + builder.finish_series() |
253 | + b = builder.get_branch() |
254 | + wt = b.bzrdir.sprout('branch').open_workingtree() |
255 | + wt.merge_from_branch(b, 'other') |
256 | + return wt |
257 | + |
258 | + def validate(self, conflicts_xml, expected): |
259 | + for conflict in conflicts_xml: |
260 | + self.assertEquals(conflict[0].tag, 'type') |
261 | + self.assertEquals(conflict[1].tag, 'path') |
262 | + self.assertEquals(conflict[2].tag, 'message') |
263 | + found = False |
264 | + for i in range(0, len(expected)): |
265 | + if expected[i][0] == conflict[0].text and \ |
266 | + expected[i][1] == conflict[1].text: |
267 | + expected.remove(expected[i]) |
268 | + found = True |
269 | + break |
270 | + self.assertEquals(found, True) |
271 | + |
272 | + def test_text_conflicts(self): |
273 | + self._prepare() |
274 | + conflicts_xml = fromstring(self.run_bzr('xmlconflicts --text --directory=branch')[0]) |
275 | + self.assertEquals(conflicts_xml.tag, 'conflicts') |
276 | + self.assertEquals(len(conflicts_xml), 2) |
277 | + expected=[('text conflict', 'file'), |
278 | + ('text conflict', 'dir/file')] |
279 | + self.validate(conflicts_xml, expected) |
280 | + |
281 | + def test_mixed_conflicts(self): |
282 | + self._prepare() |
283 | + conflicts_xml = fromstring(self.run_bzr('xmlconflicts --directory=branch')[0]) |
284 | + self.assertEquals(conflicts_xml.tag, 'conflicts') |
285 | + self.assertEquals(len(conflicts_xml), 5) |
286 | + expected=[('text conflict', 'file'), |
287 | + ('text conflict', 'dir/file'), |
288 | + ('contents conflict', 'content-conflict'), |
289 | + ('path conflict', 'path-conflict-new'), |
290 | + ('duplicate', 'duplicate-conflict.moved'), |
291 | +] |
292 | + self.validate(conflicts_xml, expected) |
293 | + |
294 | + def test_empty(self): |
295 | + conflicts_xml = fromstring(self.run_bzr('xmlconflicts')[0]) |
296 | + self.assertEquals(conflicts_xml.tag, 'conflicts') |
297 | + self.assertEquals(len(conflicts_xml), 0) |
298 | + |
299 | + def test_conflicts_outside_branch(self): |
300 | + # we disable isolation because the error we want to catch is triggered |
301 | + # outside of the jail |
302 | + self.disable_directory_isolation() |
303 | + if sys.platform == "win32": |
304 | + location = "C:/i/do/not/exist/" |
305 | + else: |
306 | + location = "/i/do/not/exist/" |
307 | + out, err = self.run_bzr('xmltags --directory='+ location, retcode=3) |
308 | + self.assertEqual(out, '') |
309 | + self.assertEqual( |
310 | + '<?xml version="1.0" encoding="%s"?><error>' |
311 | + '<class>NotBranchError</class><dict><key>path</key><value>' |
312 | + '%s</value><key>extra</key><value></value>' |
313 | + '<key>detail</key><value></value></dict>' |
314 | + '<message>Not a branch: "%s".</message>' |
315 | + '</error>' % (osutils.get_user_encoding(), |
316 | + location, location), err) |
317 | + |
318 | + |
319 | |
320 | === added file 'tests/test_shelve_xml.py' |
321 | --- tests/test_shelve_xml.py 1970-01-01 00:00:00 +0000 |
322 | +++ tests/test_shelve_xml.py 2013-03-20 13:36:31 +0000 |
323 | @@ -0,0 +1,101 @@ |
324 | +# Copyright (C) 2005, 2006, 2007, 2008, 2009 Canonical Ltd |
325 | +# Copyright (C) 2013 Piotr Piastucki |
326 | +# -*- coding: utf-8 -*- |
327 | +# |
328 | +# This program is free software; you can redistribute it and/or modify |
329 | +# it under the terms of the GNU General Public License as published by |
330 | +# the Free Software Foundation; either version 2 of the License, or |
331 | +# (at your option) any later version. |
332 | +# |
333 | +# This program is distributed in the hope that it will be useful, |
334 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
335 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
336 | +# GNU General Public License for more details. |
337 | +# |
338 | +# You should have received a copy of the GNU General Public License |
339 | +# along with this program; if not, write to the Free Software |
340 | +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
341 | + |
342 | + |
343 | +"""Black-box tests for bzr shelve list.""" |
344 | + |
345 | +import os |
346 | +import sys |
347 | +import bzrlib |
348 | +from bzrlib import osutils |
349 | +from bzrlib import shelf |
350 | +from bzrlib.tests.blackbox import ExternalBase |
351 | +from bzrlib.tests import TestCaseInTempDir, TestCaseWithTransport |
352 | +from bzrlib.xml_serializer import elementtree as elementtree |
353 | +fromstring = elementtree.fromstring |
354 | +elementtree_tostring = elementtree.tostring |
355 | + |
356 | +class TestShelveList(ExternalBase): |
357 | + |
358 | + def prepare_shelves(self): |
359 | + tree = self.make_branch_and_tree('.') |
360 | + tree.lock_write() |
361 | + self.addCleanup(tree.unlock) |
362 | + self.build_tree(['foo/', 'bar/', 'foo/baz', 'foo/text']) |
363 | + self.build_tree_contents([('foo/text', 'a\n')]) |
364 | + tree.add(['foo', 'bar', 'foo/baz', 'foo/text'], ['foo-id', 'bar-id', 'baz-id', 'text-id']) |
365 | + tree.commit('Committed foo') |
366 | + self.build_tree_contents([('foo/text', 'b\na\nc\n')]) |
367 | + # shelf #1 - content change |
368 | + creator = shelf.ShelfCreator(tree, tree.basis_tree()) |
369 | + creator.shelve_all() |
370 | + manager = tree.get_shelf_manager() |
371 | + manager.shelve_changes(creator, 'message1') |
372 | + creator.finalize() |
373 | + tree.rename_one('foo/baz', 'bar/baz') |
374 | + # shelf #2 - rename |
375 | + creator = shelf.ShelfCreator(tree, tree.basis_tree()) |
376 | + creator.shelve_all() |
377 | + manager.shelve_changes(creator, 'message2') |
378 | + creator.finalize() |
379 | + return tree |
380 | + |
381 | + def test_list_all(self): |
382 | + tree = self.prepare_shelves() |
383 | + shelves_xml = fromstring(self.run_bzr('xmlshelvelist')[0]) |
384 | + # tree = WorkingTree.open_containing('.')[0] |
385 | + manager = tree.get_shelf_manager() |
386 | + shelves = manager.active_shelves() |
387 | + self.assertEquals(shelves_xml.tag, 'shelves') |
388 | + self.assertEquals(len(shelves_xml), 2) |
389 | + self.assertEquals(shelves_xml[0].tag, 'shelf') |
390 | + self.assertEquals(shelves_xml[0][0].tag, 'id') |
391 | + self.assertEquals(shelves_xml[0][0].text, '2') |
392 | + self.assertEquals(shelves_xml[0][1].tag, 'message') |
393 | + self.assertEquals(shelves_xml[0][1].text, 'message2') |
394 | + self.assertEquals(shelves_xml[1].tag, 'shelf') |
395 | + self.assertEquals(shelves_xml[1][0].tag, 'id') |
396 | + self.assertEquals(shelves_xml[1][0].text, '1') |
397 | + self.assertEquals(shelves_xml[1][1].tag, 'message') |
398 | + self.assertEquals(shelves_xml[1][1].text, 'message1') |
399 | + |
400 | + def test_empty(self): |
401 | + shelves_xml = fromstring(self.run_bzr('xmlshelvelist')[0]) |
402 | + self.assertEquals(shelves_xml.tag, 'shelves') |
403 | + self.assertEquals(len(shelves_xml), 0) |
404 | + |
405 | + def test_shelve_list_outside_branch(self): |
406 | + # we disable isolation because the error we want to catch is triggered |
407 | + # outside of the jail |
408 | + self.disable_directory_isolation() |
409 | + if sys.platform == "win32": |
410 | + location = "C:/i/do/not/exist/" |
411 | + else: |
412 | + location = "/i/do/not/exist/" |
413 | + out, err = self.run_bzr('xmlshelvelist --directory='+ location, retcode=3) |
414 | + self.assertEqual(out, '') |
415 | + self.assertEqual( |
416 | + '<?xml version="1.0" encoding="%s"?><error>' |
417 | + '<class>NotBranchError</class><dict><key>path</key><value>' |
418 | + '%s</value><key>extra</key><value></value>' |
419 | + '<key>detail</key><value></value></dict>' |
420 | + '<message>Not a branch: "%s".</message>' |
421 | + '</error>' % (osutils.get_user_encoding(), |
422 | + location, location), err) |
423 | + |
424 | + |
+1