Merge lp:~piastucki/bzr-xmloutput/xmlconflicts into lp:bzr-xmloutput

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
Reviewer Review Type Date Requested Status
Guillermo Gonzalez Approve
Review via email: mp+154371@code.launchpad.net

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.
Revision history for this message
Guillermo Gonzalez (verterok) wrote :

+1

review: Approve

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+

Subscribers

People subscribed via source and target branches

to all changes: