Code review comment for lp:~al-maisan/bzr-builddeb/merge-package

Revision history for this message
Muharem Hrnjadovic (al-maisan) wrote :

James Westby wrote:
> Excerpts from Muharem Hrnjadovic's message of Fri Aug 21 12:51:08 UTC 2009:
>>> This is the big question I have left though. How does the user continue
>>> after this? There should be a clear way to continue once they have committed,
>>> and the exception should tell them how to proceed.
>> How about this?
>>
>> {{{
>> The "merge-package" command has detected diverged upstream
>> branches for the merge source and target. A shared upstream
>> revision was constructed to remedy the problem.
>>
>> However, merging the shared upstream revision into the merge
>> target resulted in conflicts.
>>
>> Please proceed as follows:
>>
>> 1 - Resolve the current merge conflicts in the merge target
>> directory and commit the changes.
>> 2 - Perform a plain "bzr merge <source-packaging-branch>"
>> command, resolve any ensuing packaging branch conflicts
>> and commit once satisfied with the changes.
>> }}}
>
> For starters this is bit verbose, we can't really format it like that
> in an error message, so it needs to be a couple of sentences.
>
> I don't think they need to know that a new "shared upstream" was
> created, you can just say that there are conflicts but they are
> not finished.
>
> Should we direct them to "bzr merge-package" again? It becomes
> equivalent, but I think it's better to not confuse them with
> when they can use "bzr merge" and when they can't.
>
> You don't need to tell them what to do after they've run that again,
> it can just tell them when it is done.
>
> Would it be worth saying that if they don't like what they see
> they can just "bzr revert" to get back to where they started?

Hello James,

thank you very much for your suggestions above. They are all good. I
hope the following text is more suitable.

{{{
The upstream branches for the merge source and target have diverged.
Unfortunately, the attempt to fix this problem resulted in conflicts.
Please resolve these and re-run the "merge-package" command to finish.
Alternatively, you can restore the original merge target state by
running "bzr revert".
}}}

>
> Looking at the incremental diff the major issue I see remaining
> is that you lock and unlock the tree, only to lock it again.
> Lock it once, and hold that lock until you don't reference the
> tree or anything that makes use of it any more.

Done.

> Writing this mail also interested me in whether you ever get any
> conflicts in the case when merging the faked upstream merge
> in to the packaging branch in the case where your upstream
> version was newer than the other upstream version.

That would be the test_debian_upstream_older() test, and, no, I did not
get any conflicts.

Please find the incremental diff enclosed.

Best regards

--
Muharem Hrnjadovic <email address hidden>
Public key id : B2BBFCFC
Key fingerprint : A5A3 CC67 2B87 D641 103F 5602 219F 6B60 B2BB FCFC

1=== modified file 'cmds.py'
2--- cmds.py 2009-08-19 09:06:47 +0000
3+++ cmds.py 2009-08-24 10:28:15 +0000
4@@ -901,7 +901,13 @@
5 fix_ancestry_as_needed(tree, source_branch)
6
7 # Merge source packaging branch in to the target packaging branch.
8- tree.merge_from_branch(source_branch)
9+ conflicts = tree.merge_from_branch(source_branch)
10+ if conflicts > 0:
11+ info('The merge resulted in %s conflicts. Please resolve these '
12+ 'and commit the changes with "bzr commit".' % conflicts)
13+ else:
14+ info('The merge resulted in no conflicts. You may commit the '
15+ 'changes by running "bzr commit".')
16
17
18 class cmd_test_builddeb(Command):
19
20=== modified file 'errors.py'
21--- errors.py 2009-08-19 14:09:53 +0000
22+++ errors.py 2009-08-24 10:36:04 +0000
23@@ -179,18 +179,5 @@
24
25 class SharedUpstreamConflictsWithTargetPackaging(BzrError):
26 _fmt = ('''\
27- The "merge-package" command has detected diverged upstream
28- branches for the merge source and target. A shared upstream
29- revision was constructed to remedy the problem.
30-
31- However, merging the shared upstream revision into the merge
32- target resulted in conflicts.
33-
34- Please proceed as follows:
35-
36- 1 - Resolve the current merge conflicts in the merge target
37- directory and commit the changes.
38- 2 - Perform a plain "bzr merge <source-packaging-branch>"
39- command, resolve any ensuing packaging branch conflicts
40- and commit once satisfied with the changes.
41- ''')
42+The upstream branches for the merge source and target have diverged. Unfortunately, the attempt to fix this problem resulted in conflicts. Please resolve these and re-run the "merge-package" command to finish.
43+Alternatively, you can restore the original merge target state by running "bzr revert".''')
44
45=== modified file 'merge_package.py'
46--- merge_package.py 2009-08-20 07:39:39 +0000
47+++ merge_package.py 2009-08-24 10:22:13 +0000
48@@ -110,7 +110,7 @@
49
50 source.lock_read()
51 try:
52- tree.lock_read()
53+ tree.lock_write()
54 try:
55 # "Unpack" the upstream versions and revision ids for the merge
56 # source and target branch respectively.
57@@ -119,53 +119,50 @@
58 # Did the upstream branches of the merge source/target diverge?
59 graph = source.repository.get_graph(target.repository)
60 upstreams_diverged = (len(graph.heads([us_revid, ut_revid])) > 1)
61+
62+ # No, we're done!
63+ if not upstreams_diverged:
64+ return (upstreams_diverged, t_upstream_reverted)
65+
66+ # Instantiate a `DistributionBranch` object for the merge target
67+ # (packaging) branch.
68+ db = DistributionBranch(tree.branch, tree.branch)
69+ tempdir = tempfile.mkdtemp(dir=os.path.join(tree.basedir, '..'))
70+
71+ # Extract the merge target's upstream tree into a temporary
72+ # directory.
73+ db.extract_upstream_tree(ut_revid, tempdir)
74+ tmp_target_utree = db.upstream_tree
75+
76+ # Merge upstream branch tips to obtain a shared upstream parent.
77+ # This will add revision K (see graph above) to a temporary merge
78+ # target upstream tree.
79+ tmp_target_utree.lock_write()
80+ try:
81+ if us_ver > ut_ver:
82+ # The source upstream tree is more recent and the
83+ # temporary target tree needs to be reshaped to match it.
84+ tmp_target_utree.revert(
85+ None, source.repository.revision_tree(us_revid))
86+ t_upstream_reverted = True
87+
88+ tmp_target_utree.set_parent_ids((ut_revid, us_revid))
89+ tmp_target_utree.commit(
90+ 'Prepared upstream tree for merging into target branch.')
91+ finally:
92+ tmp_target_utree.unlock()
93+
94+ # Merge shared upstream parent into the target merge branch. This
95+ # creates revison L in the digram above.
96+ conflicts = tree.merge_from_branch(tmp_target_utree.branch)
97+ if conflicts > 0:
98+ raise errors.SharedUpstreamConflictsWithTargetPackaging()
99+ else:
100+ tree.commit('Merging shared upstream rev into target branch.')
101+
102 finally:
103 tree.unlock()
104 finally:
105 source.unlock()
106
107- if not upstreams_diverged:
108- return (upstreams_diverged, t_upstream_reverted)
109-
110- # Instantiate a `DistributionBranch` object for the merge target
111- # (packaging) branch.
112- db = DistributionBranch(tree.branch, tree.branch)
113- tempdir = tempfile.mkdtemp(dir=os.path.join(tree.basedir, '..'))
114-
115- # Extract the merge target's upstream tree into a temporary directory.
116- db.extract_upstream_tree(ut_revid, tempdir)
117- tmp_target_upstream_tree = db.upstream_tree
118-
119- # Merge upstream branch tips to obtain a shared upstream parent. This
120- # will add revision K (see graph above) to a temporary merge target
121- # upstream tree.
122- tmp_target_upstream_tree.lock_write()
123- try:
124- if us_ver > ut_ver:
125- # The source upstream tree is more recent and the temporary
126- # target tree needs to be reshaped to match it.
127- tmp_target_upstream_tree.revert(
128- None, source.repository.revision_tree(us_revid))
129- t_upstream_reverted = True
130-
131- tmp_target_upstream_tree.set_parent_ids(
132- (ut_revid, us_revid))
133-
134- tmp_target_upstream_tree.commit(
135- 'Consolidated upstream tree for merging into target branch')
136- finally:
137- tmp_target_upstream_tree.unlock()
138-
139- # Merge shared upstream parent into the target merge branch. This creates
140- # revison L in the digram above.
141- tree.lock_write()
142- try:
143- conflicts = tree.merge_from_branch(tmp_target_upstream_tree.branch)
144- if conflicts > 0:
145- raise errors.SharedUpstreamConflictsWithTargetPackaging()
146- else:
147- tree.commit('Merging shared upstream rev in to target branch.')
148- finally:
149- tree.unlock()
150-
151 return (upstreams_diverged, t_upstream_reverted)
152
153=== modified file 'tests/test_merge_package.py'
154--- tests/test_merge_package.py 2009-08-21 12:41:34 +0000
155+++ tests/test_merge_package.py 2009-08-24 10:44:31 +0000
156@@ -173,23 +173,23 @@
157 The upstream conflict will be resolved by fix_ancestry_as_needed().
158 Please note that the debian ancestry is older in this case.
159 """
160- ubup_n, debp_o = self._setup_debian_upstream_older()
161+ ubup, debp, _ubuu, _debu = self._setup_debian_upstream_older()
162
163 # Attempt a plain merge first.
164- conflicts = ubup_n.merge_from_branch(
165- debp_o.branch, to_revision=self.revid_debp_o_C)
166+ conflicts = ubup.merge_from_branch(
167+ debp.branch, to_revision=self.revid_debp_o_C)
168
169 # There are two conflicts in the 'c' and the 'debian/changelog' files
170 # respectively.
171 self.assertEquals(conflicts, 2)
172- conflict_paths = sorted([c.path for c in ubup_n.conflicts()])
173+ conflict_paths = sorted([c.path for c in ubup.conflicts()])
174 self.assertEquals(conflict_paths, [u'c.moved', u'debian/changelog'])
175
176 # Undo the failed merge.
177- ubup_n.revert()
178+ ubup.revert()
179
180 # The first conflict is resolved by calling fix_ancestry_as_needed().
181- upstreams_diverged, t_upstream_reverted = MP.fix_ancestry_as_needed(ubup_n, debp_o.branch)
182+ upstreams_diverged, t_upstream_reverted = MP.fix_ancestry_as_needed(ubup, debp.branch)
183
184 # The ancestry did diverge and needed to be fixed.
185 self.assertEquals(upstreams_diverged, True)
186@@ -198,12 +198,12 @@
187 self.assertEquals(t_upstream_reverted, False)
188
189 # Try merging again.
190- conflicts = ubup_n.merge_from_branch(
191- debp_o.branch, to_revision=self.revid_debp_o_C)
192+ conflicts = ubup.merge_from_branch(
193+ debp.branch, to_revision=self.revid_debp_o_C)
194
195 # And, voila, only the packaging branch conflict remains.
196 self.assertEquals(conflicts, 1)
197- conflict_paths = sorted([c.path for c in ubup_n.conflicts()])
198+ conflict_paths = sorted([c.path for c in ubup.conflicts()])
199 self.assertEquals(conflict_paths, [u'debian/changelog'])
200
201 def test_upstreams_not_diverged(self):
202@@ -394,7 +394,7 @@
203 self._setup_branch(name, vdata, ubup_n, 'u')
204
205 # Return the ubuntu and the debian packaging branches.
206- return (ubup_n, debp_o)
207+ return (ubup_n, debp_o, ubuu_n, debu_o)
208
209 def _setup_upstreams_not_diverged(self):
210 """

« Back to merge proposal