Merge lp:~ryorke/bzr/202374-pull-update-showbase into lp:bzr

Proposed by Rory Yorke
Status: Merged
Approved by: Martin Pool
Approved revision: no longer in the source branch.
Merged at revision: 5455
Proposed branch: lp:~ryorke/bzr/202374-pull-update-showbase
Merge into: lp:bzr
Diff against target: 263 lines (+118/-12)
5 files modified
NEWS (+9/-0)
bzrlib/builtins.py (+16/-5)
bzrlib/tests/blackbox/test_pull.py (+43/-0)
bzrlib/tests/blackbox/test_update.py (+38/-0)
bzrlib/workingtree.py (+12/-7)
To merge this branch: bzr merge lp:~ryorke/bzr/202374-pull-update-showbase
Reviewer Review Type Date Requested Status
Martin Packman (community) Approve
bzr-core Pending
Review via email: mp+36571@code.launchpad.net

Commit message

Enable use of 3-way conflict markers in pull and update by adding --show-base option

Description of the change

Fixes bug 202374, --show-base for pull and update.

Code more-or-less copied from builtins.cmd_merge. In both cases show_base gets passed down to merge.merge_inner in the appropriate WorkingTree method.

Disallow --show-base for pull if not invoked on a working tree.

Tests added in tests/blackbox/test_pull.py and test_update.py.

Default unchange (i.e., by default don't show-base). The bug reporter asked for --show-base to be the default, which may be sensible, but that is a design decision that I won't take.

I've run './bzr --no-plugins selftest --parallel=fork' on my system which selftest reports as

  bzr-2.3.0dev1 python-2.6.4 Linux-2.6.31-22-generic-i686-with-Ubuntu-9.10-karmic

I get some odd results, including maximum recursion depth exceeded, and a few errors in test_test_server. I hope these are unrelated to my changes.

Running

'./bzr --no-plugins selftest --parallel=fork blackbox'

gives

OK (known_failures=2)
22 tests skipped

To post a comment you must log in.
Revision history for this message
Martin Packman (gz) wrote :

Thanks for working on this Rory, the change looks pretty good to me.

You'll want to add a NEWS entry for this, see the 'Documenting Changes' section of doc/developers/HACKING.txt for details.

> I get some odd results, including maximum recursion depth exceeded, and a few errors in > test_test_server. I hope these are unrelated to my changes.

Almost certainly unrelated, but it might be worth checking if there are open bugs on any of these failures and filing if not.

Some nitpicks on the diff:

+ def run(self, dir='.', revision=None,show_base=None):

PEP 8, you want a space before show_base there.

+ open(pathjoin('a', 'hello'),'wt').write('fee')

The test lines like this are relying on refcounting to do the right thing, which is fine, and as you care about the content for these tests I see why you didn't use the normal make_branch_and_tree options, but a different spelling would be preferable.

+ #tree.update() gives no such revision, so ...
+ self.run_bzr(['update','-r1'])

As your comment notes, this isn't ideal, we only really want to be using run_bzr for commands we're actually testing. Perhaps another reviewer can suggest a better option.

Tests pass here, just need that news added and another reviewer's opinion.

review: Needs Fixing
Revision history for this message
Martin Packman (gz) wrote :

Great, thanks.

review: Approve
Revision history for this message
Martin Pool (mbp) wrote :

It would be nice to put that into per-process-context configuration,
which would avoid passing so many parameters around, but the
infrastructure for that isn't here yet.

(more review later)

--
Martin

Revision history for this message
Martin Packman (gz) wrote :

sent to pqm by email

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'NEWS'
2--- NEWS 2010-09-27 19:31:45 +0000
3+++ NEWS 2010-09-27 20:26:42 +0000
4@@ -240,6 +240,10 @@
5 * New development format ``development8-subtree`` which is similar to the
6 ``2a`` format and adds subtree support. (Jelmer Vernooij)
7
8+* The ``pull`` and ``update`` commands now take a ``-show-base``
9+ option that, in the case of conflicts, shows the base revision text.
10+ (Rory Yorke, #202374)
11+
12 Bug Fixes
13 *********
14
15@@ -442,6 +446,11 @@
16 constructor has been deprecated, use the ``file_name`` parameter instead.
17 (Vincent Ladeuil)
18
19+* ``WorkingTree`` methods ``pull``, ``update``, and ``_update_tree``
20+ now have an optional argument, ``show_base``, which is by default
21+ False. This is flag is ultimately passed to ``merge.merge_inner``
22+ in each case. (Rory Yorke, #202374)
23+
24 Internals
25 *********
26
27
28=== modified file 'bzrlib/builtins.py'
29--- bzrlib/builtins.py 2010-09-24 12:53:00 +0000
30+++ bzrlib/builtins.py 2010-09-27 20:26:42 +0000
31@@ -923,13 +923,16 @@
32 "branch. Local pulls are not applied to "
33 "the master branch."
34 ),
35+ Option('show-base',
36+ help="Show base revision text in conflicts.")
37 ]
38 takes_args = ['location?']
39 encoding_type = 'replace'
40
41 def run(self, location=None, remember=False, overwrite=False,
42 revision=None, verbose=False,
43- directory=None, local=False):
44+ directory=None, local=False,
45+ show_base=False):
46 # FIXME: too much stuff is in the command class
47 revision_id = None
48 mergeable = None
49@@ -944,6 +947,9 @@
50 branch_to = Branch.open_containing(directory)[0]
51 self.add_cleanup(branch_to.lock_write().unlock)
52
53+ if tree_to is None and show_base:
54+ raise errors.BzrCommandError("Need working tree for --show-base.")
55+
56 if local and not branch_to.get_bound_location():
57 raise errors.LocalRequiresBoundBranch()
58
59@@ -994,7 +1000,8 @@
60 view_info=view_info)
61 result = tree_to.pull(
62 branch_from, overwrite, revision_id, change_reporter,
63- possible_transports=possible_transports, local=local)
64+ possible_transports=possible_transports, local=local,
65+ show_base=show_base)
66 else:
67 result = branch_to.pull(
68 branch_from, overwrite, revision_id, local=local)
69@@ -1363,10 +1370,13 @@
70
71 _see_also = ['pull', 'working-trees', 'status-flags']
72 takes_args = ['dir?']
73- takes_options = ['revision']
74+ takes_options = ['revision',
75+ Option('show-base',
76+ help="Show base revision text in conflicts."),
77+ ]
78 aliases = ['up']
79
80- def run(self, dir='.', revision=None):
81+ def run(self, dir='.', revision=None, show_base=None):
82 if revision is not None and len(revision) != 1:
83 raise errors.BzrCommandError(
84 "bzr update --revision takes exactly one revision")
85@@ -1412,7 +1422,8 @@
86 change_reporter,
87 possible_transports=possible_transports,
88 revision=revision_id,
89- old_tip=old_tip)
90+ old_tip=old_tip,
91+ show_base=show_base)
92 except errors.NoSuchRevision, e:
93 raise errors.BzrCommandError(
94 "branch has no revision %s\n"
95
96=== modified file 'bzrlib/tests/blackbox/test_pull.py'
97--- bzrlib/tests/blackbox/test_pull.py 2010-06-11 07:32:12 +0000
98+++ bzrlib/tests/blackbox/test_pull.py 2010-09-27 20:26:42 +0000
99@@ -453,3 +453,46 @@
100 out, err = self.run_bzr(['pull', '-d', 'to', 'from'])
101 self.assertContainsRe(err,
102 "(?m)Fetching into experimental format")
103+
104+ def test_pull_show_base(self):
105+ """bzr pull supports --show-base
106+
107+ see https://bugs.launchpad.net/bzr/+bug/202374"""
108+ # create two trees with conflicts, setup conflict, check that
109+ # conflicted file looks correct
110+ a_tree = self.example_branch('a')
111+ b_tree = a_tree.bzrdir.sprout('b').open_workingtree()
112+
113+ f = open(pathjoin('a', 'hello'),'wt')
114+ f.write('fee')
115+ f.close()
116+ a_tree.commit('fee')
117+
118+ f = open(pathjoin('b', 'hello'),'wt')
119+ f.write('fie')
120+ f.close()
121+
122+ out,err=self.run_bzr(['pull','-d','b','a','--show-base'])
123+
124+ # check for message here
125+ self.assertEqual(err,
126+ ' M hello\nText conflict in hello\n1 conflicts encountered.\n')
127+
128+ self.assertEqualDiff('<<<<<<< TREE\n'
129+ 'fie||||||| BASE-REVISION\n'
130+ 'foo=======\n'
131+ 'fee>>>>>>> MERGE-SOURCE\n',
132+ open(pathjoin('b', 'hello')).read())
133+
134+ def test_pull_show_base_working_tree_only(self):
135+ """--show-base only allowed if there's a working tree
136+
137+ see https://bugs.launchpad.net/bzr/+bug/202374"""
138+ # create a branch, see that --show-base fails
139+ self.make_branch('from')
140+ self.make_branch('to')
141+ out=self.run_bzr(['pull','-d','to','from','--show-base'],retcode=3)
142+ self.assertEqual(out,
143+ ('','bzr: ERROR: Need working tree for --show-base.\n'))
144+
145+
146
147=== modified file 'bzrlib/tests/blackbox/test_update.py'
148--- bzrlib/tests/blackbox/test_update.py 2010-04-14 04:48:00 +0000
149+++ bzrlib/tests/blackbox/test_update.py 2010-09-27 20:26:42 +0000
150@@ -359,6 +359,44 @@
151 2>Updated to revision 2 of branch .../master
152 ''')
153
154+ def test_update_show_base(self):
155+ """bzr update support --show-base
156+
157+ see https://bugs.launchpad.net/bzr/+bug/202374"""
158+
159+ tree=self.make_branch_and_tree('.')
160+
161+ f = open('hello','wt')
162+ f.write('foo')
163+ f.close()
164+ tree.add('hello')
165+ tree.commit('fie')
166+
167+ f = open('hello','wt')
168+ f.write('fee')
169+ f.close()
170+ tree.commit('fee')
171+
172+ #tree.update() gives no such revision, so ...
173+ self.run_bzr(['update','-r1'])
174+
175+ #create conflict
176+ f = open('hello','wt')
177+ f.write('fie')
178+ f.close()
179+
180+ out, err = self.run_bzr(['update','--show-base'],retcode=1)
181+
182+ # check for conflict notification
183+ self.assertContainsString(err,
184+ ' M hello\nText conflict in hello\n1 conflicts encountered.\n')
185+
186+ self.assertEqualDiff('<<<<<<< TREE\n'
187+ 'fie||||||| BASE-REVISION\n'
188+ 'foo=======\n'
189+ 'fee>>>>>>> MERGE-SOURCE\n',
190+ open('hello').read())
191+
192 def test_update_checkout_prevent_double_merge(self):
193 """"Launchpad bug 113809 in bzr "update performs two merges"
194 https://launchpad.net/bugs/113809"""
195
196=== modified file 'bzrlib/workingtree.py'
197--- bzrlib/workingtree.py 2010-08-20 19:07:17 +0000
198+++ bzrlib/workingtree.py 2010-09-27 20:26:42 +0000
199@@ -1663,7 +1663,8 @@
200
201 @needs_write_lock
202 def pull(self, source, overwrite=False, stop_revision=None,
203- change_reporter=None, possible_transports=None, local=False):
204+ change_reporter=None, possible_transports=None, local=False,
205+ show_base=False):
206 source.lock_read()
207 try:
208 old_revision_info = self.branch.last_revision_info()
209@@ -1683,7 +1684,8 @@
210 basis_tree,
211 this_tree=self,
212 pb=None,
213- change_reporter=change_reporter)
214+ change_reporter=change_reporter,
215+ show_base=show_base)
216 basis_root_id = basis_tree.get_root_id()
217 new_root_id = new_basis_tree.get_root_id()
218 if basis_root_id != new_root_id:
219@@ -2261,7 +2263,7 @@
220 _marker = object()
221
222 def update(self, change_reporter=None, possible_transports=None,
223- revision=None, old_tip=_marker):
224+ revision=None, old_tip=_marker, show_base=False):
225 """Update a working tree along its branch.
226
227 This will update the branch if its bound too, which means we have
228@@ -2304,12 +2306,13 @@
229 else:
230 if old_tip is self._marker:
231 old_tip = None
232- return self._update_tree(old_tip, change_reporter, revision)
233+ return self._update_tree(old_tip, change_reporter, revision, show_base)
234 finally:
235 self.unlock()
236
237 @needs_tree_write_lock
238- def _update_tree(self, old_tip=None, change_reporter=None, revision=None):
239+ def _update_tree(self, old_tip=None, change_reporter=None, revision=None,
240+ show_base=False):
241 """Update a tree to the master branch.
242
243 :param old_tip: if supplied, the previous tip revision the branch,
244@@ -2342,7 +2345,8 @@
245 other_tree = self.branch.repository.revision_tree(old_tip)
246 nb_conflicts = merge.merge_inner(self.branch, other_tree,
247 base_tree, this_tree=self,
248- change_reporter=change_reporter)
249+ change_reporter=change_reporter,
250+ show_base=show_base)
251 if nb_conflicts:
252 self.add_parent_tree((old_tip, other_tree))
253 trace.note('Rerun update after fixing the conflicts.')
254@@ -2372,7 +2376,8 @@
255
256 nb_conflicts = merge.merge_inner(self.branch, to_tree, base_tree,
257 this_tree=self,
258- change_reporter=change_reporter)
259+ change_reporter=change_reporter,
260+ show_base=show_base)
261 self.set_last_revision(revision)
262 # TODO - dedup parents list with things merged by pull ?
263 # reuse the tree we've updated to to set the basis: