Merge lp:~abentley/launchpad/incremental-diffs into lp:launchpad/db-devel
- incremental-diffs
- Merge into db-devel
Status: | Merged |
---|---|
Approved by: | Leonard Richardson |
Approved revision: | no longer in the source branch. |
Merged at revision: | 9950 |
Proposed branch: | lp:~abentley/launchpad/incremental-diffs |
Merge into: | lp:launchpad/db-devel |
Diff against target: |
462 lines (+271/-5) 8 files modified
lib/lp/code/configure.zcml (+7/-1) lib/lp/code/interfaces/diff.py (+19/-0) lib/lp/code/model/branchmergeproposal.py (+41/-1) lib/lp/code/model/diff.py (+66/-3) lib/lp/code/model/tests/test_branchmergeproposal.py (+41/-0) lib/lp/code/model/tests/test_diff.py (+84/-0) lib/lp/testing/factory.py (+12/-0) utilities/sourcedeps.conf (+1/-0) |
To merge this branch: | bzr merge lp:~abentley/launchpad/incremental-diffs |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Leonard Richardson (community) | Approve | ||
Review via email: mp+36875@code.launchpad.net |
Commit message
Implement incremental diff generation.
Description of the change
= Summary =
Implement incremental diff generation
== Proposed fix ==
See above
== Pre-implementation notes ==
Mid-implementation with thumper
== Implementation details ==
The generation of incremental diffs is handled by the Difftacular bzr plugin,
and the full testing of its behaviour is provided by its test suite.
I implemented the diff_changes test method to get a clearer idea what was added
and removed by a given diff.
== Tests ==
bin/test -t TestIncrementalDiff -t TestBranchMerge
== Demo and Q/A ==
None
= Launchpad lint =
Checking for conflicts and issues in changed files.
Linting changed files:
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
utilities/
lib/lp/
./lib/lp/
192: E231 missing whitespace after ','
194: E231 missing whitespace after ','
./lib/lp/
166: E301 expected 1 blank line, found 0
Leonard Richardson (leonardr) wrote : | # |
Oh, another change I suggested which Aaron carried through was removing the exported() calls from IIncrementalDiff. Those are for publishing fields through the web service, and IIncrementalDiff isn't being published yet.
Leonard Richardson (leonardr) wrote : | # |
OK, I've done a review of the difftastic codebase and I see no reason why it can't be used in Launchpad. I do have one possible performance improvement, and a number of changes to make the tests more clear.
1. "foo" and "bar" are fine for filenames within the test branches,
but they really hurt comprehension when used as variable names
for the branches themselves. In the helper methods, can you call
the branches 'initial' and 'merged_in' or something that reflects
their history?
Outside the helper methods, you can call them whatever's
helpful. For instance, in test_mainline_diff, I believe
'foo' (aka 'initial') could be called 'mainline' and 'bar' (aka
'merged_in') could be called 'ignored'.
2. typo: "emtpy commit"
3. test_diff_
create_
like a contradiction, but we're actually checking that only
*specified* branches are ignored. A docstring would make it clear
that we're checking that the diff ignores the merge of the "bar"
branch, but not the merge of the "unignored" branch. Similarly
for ignore_
included? It's hard to figure out.
Making the commits that are being ignored really obviously
destructive would also help.
3. In generate_
merger.
within the for loop? Unless those methods modify 'merger'
in-place, I think they can be moved outside and run only once.
Aaron Bentley (abentley) wrote : | # |
1. "foo" is actually the tree whose branch will be diffed. I don't think "initial" describes that any better than "foo". "merged_in" is fine, but I think "merge_input" is better.
2. Sure
3. Yes, I need it. The output of get_preview_tree is fed back into the subsequent merge. Without that, you would generate a bogus merge and likely violate the TreeTransform API.
Brad Crittenden (bac) wrote : | # |
Is this approved branch ready to land or are you blocked? If you have abandoned the work please change the MP status to "Rejected."
Aaron Bentley (abentley) wrote : | # |
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
On 11/04/2010 11:08 PM, Brad Crittenden wrote:
> Is this approved branch ready to land or are you blocked? If you have abandoned the work please change the MP status to "Rejected."
These changes will be landed as part of the follow-on branch
incremental-
https:/
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://
iEYEARECAAYFAkz
9n4AnRU1u4d8MDX
=mGMI
-----END PGP SIGNATURE-----
Preview Diff
1 | === added symlink 'bzrplugins/difftacular' |
2 | === target is u'../sourcecode/difftacular/' |
3 | === modified file 'lib/lp/code/configure.zcml' |
4 | --- lib/lp/code/configure.zcml 2010-10-26 13:52:43 +0000 |
5 | +++ lib/lp/code/configure.zcml 2010-10-29 15:33:57 +0000 |
6 | @@ -233,6 +233,7 @@ |
7 | review_diff |
8 | next_preview_diff_job |
9 | preview_diff |
10 | + getIncrementalDiffs |
11 | votes |
12 | all_comments |
13 | related_bugs |
14 | @@ -245,7 +246,8 @@ |
15 | isValidTransition |
16 | getUnlandedSourceBranchRevisions |
17 | root_message_id |
18 | - getUsersVoteReference"/> |
19 | + getUsersVoteReference |
20 | + generateIncrementalDiff"/> |
21 | <allow interface="lp.code.interfaces.branchtarget.IHasBranchTarget"/> |
22 | <require |
23 | permission="launchpad.Edit" |
24 | @@ -879,6 +881,10 @@ |
25 | <class class="lp.code.model.diff.Diff"> |
26 | <allow interface="lp.code.interfaces.diff.IDiff" /> |
27 | </class> |
28 | + <class class="lp.code.model.diff.IncrementalDiff"> |
29 | + <allow interface="lp.code.interfaces.diff.IDiff" /> |
30 | + <allow interface="lp.code.interfaces.diff.IIncrementalDiff" /> |
31 | + </class> |
32 | <class class="lp.code.model.diff.StaticDiff"> |
33 | <allow interface="lp.code.interfaces.diff.IStaticDiff" /> |
34 | </class> |
35 | |
36 | === modified file 'lib/lp/code/interfaces/diff.py' |
37 | --- lib/lp/code/interfaces/diff.py 2010-08-20 20:31:18 +0000 |
38 | +++ lib/lp/code/interfaces/diff.py 2010-10-29 15:33:57 +0000 |
39 | @@ -9,6 +9,7 @@ |
40 | |
41 | __all__ = [ |
42 | 'IDiff', |
43 | + 'IIncrementalDiff', |
44 | 'IPreviewDiff', |
45 | 'IStaticDiff', |
46 | 'IStaticDiffSource', |
47 | @@ -29,6 +30,7 @@ |
48 | ) |
49 | |
50 | from canonical.launchpad import _ |
51 | +from lp.code.interfaces.revision import IRevision |
52 | |
53 | |
54 | class IDiff(Interface): |
55 | @@ -62,6 +64,23 @@ |
56 | readonly=True)) |
57 | |
58 | |
59 | +class IIncrementalDiff(Interface): |
60 | + """An incremental diff for a merge proposal.""" |
61 | + |
62 | + diff = Reference(IDiff, title=_('The Diff object.'), readonly=True) |
63 | + |
64 | + # The schema for the Reference gets patched in _schema_circular_imports. |
65 | + branch_merge_proposal = Reference( |
66 | + Interface, readonly=True, |
67 | + title=_('The branch merge proposal that diff relates to.')) |
68 | + |
69 | + old_revision = Reference( |
70 | + IRevision, readonly=True, title=_('The old revision of the diff.')) |
71 | + |
72 | + new_revision = Reference( |
73 | + IRevision, readonly=True, title=_('The new revision of the diff.')) |
74 | + |
75 | + |
76 | class IStaticDiff(Interface): |
77 | """A diff with a fixed value, i.e. between two revisions.""" |
78 | |
79 | |
80 | === modified file 'lib/lp/code/model/branchmergeproposal.py' |
81 | --- lib/lp/code/model/branchmergeproposal.py 2010-10-19 00:44:24 +0000 |
82 | +++ lib/lp/code/model/branchmergeproposal.py 2010-10-29 15:33:57 +0000 |
83 | @@ -50,6 +50,7 @@ |
84 | SQLBase, |
85 | sqlvalues, |
86 | ) |
87 | +from canonical.launchpad.interfaces.lpstorm import IMasterStore |
88 | from lp.code.enums import ( |
89 | BranchMergeProposalStatus, |
90 | CodeReviewVote, |
91 | @@ -78,7 +79,7 @@ |
92 | from lp.code.model.branchrevision import BranchRevision |
93 | from lp.code.model.codereviewcomment import CodeReviewComment |
94 | from lp.code.model.codereviewvote import CodeReviewVoteReference |
95 | -from lp.code.model.diff import PreviewDiff |
96 | +from lp.code.model.diff import Diff, IncrementalDiff, PreviewDiff |
97 | from lp.registry.interfaces.person import ( |
98 | IPerson, |
99 | validate_public_person, |
100 | @@ -783,6 +784,45 @@ |
101 | Store.of(self).flush() |
102 | return self.preview_diff |
103 | |
104 | + def generateIncrementalDiff(self, old_revision, new_revision, diff=None): |
105 | + """Generate an incremental diff for the merge proposal. |
106 | + |
107 | + :param old_revision: The `Revision` to generate the diff from. |
108 | + :param new_revision: The `Revision` to generate the diff to. |
109 | + :param diff: If supplied, a pregenerated `Diff`. |
110 | + """ |
111 | + if diff is None: |
112 | + source_branch = self.source_branch.getBzrBranch() |
113 | + ignore_branches = [self.target_branch.getBzrBranch()] |
114 | + if self.prerequisite_branch is not None: |
115 | + ignore_branches.append( |
116 | + self.prerequisite_branch.getBzrBranch()) |
117 | + diff = Diff.generateIncrementalDiff( |
118 | + old_revision, new_revision, source_branch, ignore_branches) |
119 | + incremental_diff = IncrementalDiff() |
120 | + incremental_diff.diff = diff |
121 | + incremental_diff.branch_merge_proposal = self |
122 | + incremental_diff.old_revision = old_revision |
123 | + incremental_diff.new_revision = new_revision |
124 | + IMasterStore(IncrementalDiff).add(incremental_diff) |
125 | + return incremental_diff |
126 | + |
127 | + def getIncrementalDiffs(self, revision_list): |
128 | + """Return a list of diffs for the specified revisions. |
129 | + |
130 | + :param revision_list: A list of tuples of (`Revision`, `Revision`). |
131 | + The first revision in the tuple is the old revision. The second |
132 | + is the new revision. |
133 | + :return: A list of IncrementalDiffs in the same order as the supplied |
134 | + Revisions. |
135 | + """ |
136 | + diffs = Store.of(self).find(IncrementalDiff, |
137 | + IncrementalDiff.branch_merge_proposal_id == self.id) |
138 | + diff_dict = dict( |
139 | + ((diff.old_revision, diff.new_revision), diff) |
140 | + for diff in diffs) |
141 | + return [diff_dict.get(revisions) for revisions in revision_list] |
142 | + |
143 | @property |
144 | def revision_end_date(self): |
145 | """The cutoff date for showing revisions. |
146 | |
147 | === modified file 'lib/lp/code/model/diff.py' |
148 | --- lib/lp/code/model/diff.py 2010-10-03 15:30:06 +0000 |
149 | +++ lib/lp/code/model/diff.py 2010-10-29 15:33:57 +0000 |
150 | @@ -4,10 +4,11 @@ |
151 | """Implementation classes for IDiff, etc.""" |
152 | |
153 | __metaclass__ = type |
154 | -__all__ = ['Diff', 'PreviewDiff', 'StaticDiff'] |
155 | +__all__ = ['Diff', 'IncrementalDiff', 'PreviewDiff', 'StaticDiff'] |
156 | |
157 | +from contextlib import nested |
158 | +from cStringIO import StringIO |
159 | import sys |
160 | -from cStringIO import StringIO |
161 | |
162 | from uuid import uuid1 |
163 | |
164 | @@ -18,6 +19,7 @@ |
165 | parse_patches, |
166 | Patch, |
167 | ) |
168 | +from bzrlib.plugins.difftacular.generate_diff import diff_ignore_branches |
169 | from lazr.delegates import delegates |
170 | import simplejson |
171 | from sqlobject import ( |
172 | @@ -44,10 +46,12 @@ |
173 | from lp.app.errors import NotFoundError |
174 | from lp.code.interfaces.diff import ( |
175 | IDiff, |
176 | + IIncrementalDiff, |
177 | IPreviewDiff, |
178 | IStaticDiff, |
179 | IStaticDiffSource, |
180 | ) |
181 | +from lp.codehosting.bzrutils import read_locked |
182 | |
183 | |
184 | class Diff(SQLBase): |
185 | @@ -194,9 +198,14 @@ |
186 | diff_content = StringIO() |
187 | show_diff_trees(from_tree, to_tree, diff_content, old_label='', |
188 | new_label='') |
189 | + return klass.fromFileAtEnd(diff_content, filename) |
190 | + |
191 | + @classmethod |
192 | + def fromFileAtEnd(cls, diff_content, filename=None): |
193 | + """Make a Diff from a file object that is currently at its end.""" |
194 | size = diff_content.tell() |
195 | diff_content.seek(0) |
196 | - return klass.fromFile(diff_content, size, filename) |
197 | + return cls.fromFile(diff_content, size, filename) |
198 | |
199 | @classmethod |
200 | def fromFile(cls, diff_content, size, filename=None): |
201 | @@ -257,6 +266,30 @@ |
202 | file_stats[path] = tuple(patch.stats_values()[:2]) |
203 | return file_stats |
204 | |
205 | + @classmethod |
206 | + def generateIncrementalDiff(cls, old_revision, new_revision, |
207 | + source_branch, ignore_branches): |
208 | + """Return a Diff whose contents are an incremental diff. |
209 | + |
210 | + The Diff's contents will show the changes made between old_revision |
211 | + and new_revision, except those changes introduced by the |
212 | + ignore_branches. |
213 | + |
214 | + :param old_revision: The `Revision` to show changes from. |
215 | + :param new_revision: The `Revision` to show changes to. |
216 | + :param source_branch: The bzr branch containing these revisions. |
217 | + :param ignore_brances: A collection of branches to ignore merges from. |
218 | + :return: a `Diff`. |
219 | + """ |
220 | + diff_content = StringIO() |
221 | + read_locks = [read_locked(branch) for branch in [source_branch] + |
222 | + ignore_branches] |
223 | + with nested(*read_locks): |
224 | + diff_ignore_branches( |
225 | + source_branch, ignore_branches, old_revision.revision_id, |
226 | + new_revision.revision_id, diff_content) |
227 | + return cls.fromFileAtEnd(diff_content) |
228 | + |
229 | |
230 | class StaticDiff(SQLBase): |
231 | """A diff from one revision to another.""" |
232 | @@ -305,6 +338,36 @@ |
233 | diff.destroySelf() |
234 | |
235 | |
236 | +class IncrementalDiff(Storm): |
237 | + """See `IIncrementalDiff.""" |
238 | + |
239 | + implements(IIncrementalDiff) |
240 | + |
241 | + delegates(IDiff, context='diff') |
242 | + |
243 | + __storm_table__ = 'IncrementalDiff' |
244 | + |
245 | + id = Int(primary=True, allow_none=False) |
246 | + |
247 | + diff_id = Int(name='diff', allow_none=False) |
248 | + |
249 | + diff = Reference(diff_id, 'Diff.id') |
250 | + |
251 | + branch_merge_proposal_id = Int( |
252 | + name='branch_merge_proposal', allow_none=False) |
253 | + |
254 | + branch_merge_proposal = Reference( |
255 | + branch_merge_proposal_id, "BranchMergeProposal.id") |
256 | + |
257 | + old_revision_id = Int(name='old_revision', allow_none=False) |
258 | + |
259 | + old_revision = Reference(old_revision_id, 'Revision.id') |
260 | + |
261 | + new_revision_id = Int(name='new_revision', allow_none=False) |
262 | + |
263 | + new_revision = Reference(new_revision_id, 'Revision.id') |
264 | + |
265 | + |
266 | class PreviewDiff(Storm): |
267 | """See `IPreviewDiff`.""" |
268 | implements(IPreviewDiff) |
269 | |
270 | === modified file 'lib/lp/code/model/tests/test_branchmergeproposal.py' |
271 | --- lib/lp/code/model/tests/test_branchmergeproposal.py 2010-10-27 14:20:21 +0000 |
272 | +++ lib/lp/code/model/tests/test_branchmergeproposal.py 2010-10-29 15:33:57 +0000 |
273 | @@ -1829,5 +1829,46 @@ |
274 | self.assertRevisionGroups(bmp, expected_groups) |
275 | |
276 | |
277 | +class TestBranchMergeProposalGetIncrementalDiffs(TestCaseWithFactory): |
278 | + |
279 | + layer = LaunchpadFunctionalLayer |
280 | + |
281 | + def test_getIncrementalDiffs(self): |
282 | + """getIncrementalDiffs returns the requested values or None. |
283 | + |
284 | + None is returned if there is no IncrementalDiff for the requested |
285 | + revision pair and branch_merge_proposal. |
286 | + """ |
287 | + bmp = self.factory.makeBranchMergeProposal() |
288 | + diff1 = self.factory.makeIncrementalDiff(merge_proposal=bmp) |
289 | + diff2 = self.factory.makeIncrementalDiff(merge_proposal=bmp) |
290 | + diff3 = self.factory.makeIncrementalDiff() |
291 | + result = bmp.getIncrementalDiffs([ |
292 | + (diff1.old_revision, diff1.new_revision), |
293 | + (diff2.old_revision, diff2.new_revision), |
294 | + # Wrong merge proposal |
295 | + (diff3.old_revision, diff3.new_revision), |
296 | + # Mismatched revisions |
297 | + (diff1.old_revision, diff2.new_revision), |
298 | + ]) |
299 | + self.assertEqual([diff1, diff2, None, None], result) |
300 | + |
301 | + def test_getIncrementalDiffs_respects_input_order(self): |
302 | + """The order of the output follows the input order.""" |
303 | + bmp = self.factory.makeBranchMergeProposal() |
304 | + diff1 = self.factory.makeIncrementalDiff(merge_proposal=bmp) |
305 | + diff2 = self.factory.makeIncrementalDiff(merge_proposal=bmp) |
306 | + result = bmp.getIncrementalDiffs([ |
307 | + (diff1.old_revision, diff1.new_revision), |
308 | + (diff2.old_revision, diff2.new_revision), |
309 | + ]) |
310 | + self.assertEqual([diff1, diff2], result) |
311 | + result = bmp.getIncrementalDiffs([ |
312 | + (diff2.old_revision, diff2.new_revision), |
313 | + (diff1.old_revision, diff1.new_revision), |
314 | + ]) |
315 | + self.assertEqual([diff2, diff1], result) |
316 | + |
317 | + |
318 | def test_suite(): |
319 | return TestLoader().loadTestsFromName(__name__) |
320 | |
321 | === modified file 'lib/lp/code/model/tests/test_diff.py' |
322 | --- lib/lp/code/model/tests/test_diff.py 2010-10-26 15:47:24 +0000 |
323 | +++ lib/lp/code/model/tests/test_diff.py 2010-10-29 15:33:57 +0000 |
324 | @@ -12,6 +12,7 @@ |
325 | from unittest import TestLoader |
326 | |
327 | from bzrlib import trace |
328 | +from bzrlib.patches import InsertLine, parse_patches, RemoveLine |
329 | import transaction |
330 | from zope.security.proxy import removeSecurityProxy |
331 | |
332 | @@ -24,6 +25,7 @@ |
333 | from lp.app.errors import NotFoundError |
334 | from lp.code.interfaces.diff import ( |
335 | IDiff, |
336 | + IIncrementalDiff, |
337 | IPreviewDiff, |
338 | IStaticDiff, |
339 | IStaticDiffSource, |
340 | @@ -521,5 +523,87 @@ |
341 | NotFoundError, diff.getFileByName, 'preview.diff') |
342 | |
343 | |
344 | +class TestIncrementalDiff(DiffTestCase): |
345 | + """Test that IncrementalDiff objects work.""" |
346 | + |
347 | + layer = LaunchpadFunctionalLayer |
348 | + |
349 | + def test_providesInterface(self): |
350 | + incremental_diff = self.factory.makeIncrementalDiff() |
351 | + verifyObject(IIncrementalDiff, incremental_diff) |
352 | + |
353 | + @staticmethod |
354 | + def diff_changes(diff_bytes): |
355 | + inserted = [] |
356 | + removed = [] |
357 | + for patch in parse_patches(diff_bytes.splitlines(True)): |
358 | + for hunk in patch.hunks: |
359 | + for line in hunk.lines: |
360 | + if isinstance(line, InsertLine): |
361 | + inserted.append(line.contents) |
362 | + if isinstance(line, RemoveLine): |
363 | + removed.append(line.contents) |
364 | + return inserted, removed |
365 | + |
366 | + def test_generateIncrementalDiff(self): |
367 | + """generateIncrementalDiff works. |
368 | + |
369 | + Changes merged from the prerequisite and target are ignored in the |
370 | + diff. |
371 | + |
372 | + We generate an incremental diff from old_revision_id to |
373 | + new_revision_id. |
374 | + |
375 | + old_revision_id has: |
376 | + a |
377 | + b |
378 | + e |
379 | + |
380 | + new_revision_id has: |
381 | + d |
382 | + a |
383 | + c |
384 | + e |
385 | + f |
386 | + |
387 | + Because the prerequisite branch adds "d", this change is ignored. |
388 | + Because the target branch adds "f", this change is ignored. |
389 | + So the incremental diff shows that "c" was added and "b" was removed. |
390 | + """ |
391 | + self.useBzrBranches(direct_database=True) |
392 | + prerequisite_branch = self.factory.makeAnyBranch() |
393 | + bmp = self.factory.makeBranchMergeProposal( |
394 | + prerequisite_branch=prerequisite_branch) |
395 | + target_branch = self.createBzrBranch(bmp.target_branch) |
396 | + old_revision_id = self.commitFile( |
397 | + bmp.target_branch, 'foo', 'a\nb\ne\n') |
398 | + old_revision = self.factory.makeRevision(rev_id=old_revision_id) |
399 | + source_branch = self.createBzrBranch( |
400 | + bmp.source_branch, target_branch) |
401 | + self.commitFile(bmp.source_branch, 'foo', 'a\nc\ne\n') |
402 | + prerequisite = self.createBzrBranch( |
403 | + bmp.prerequisite_branch, target_branch) |
404 | + prerequisite_revision = self.commitFile(bmp.prerequisite_branch, |
405 | + 'foo', 'd\na\nb\ne\n') |
406 | + merge_parent = self.commitFile(bmp.target_branch, 'foo', |
407 | + 'a\nb\ne\nf\n') |
408 | + source_branch.repository.fetch(target_branch.repository, |
409 | + revision_id=merge_parent) |
410 | + self.commitFile( |
411 | + bmp.source_branch, 'foo', 'a\nc\ne\nf\n', [merge_parent]) |
412 | + source_branch.repository.fetch(prerequisite.repository, |
413 | + revision_id=prerequisite_revision) |
414 | + new_revision_id = self.commitFile( |
415 | + bmp.source_branch, 'foo', 'd\na\nc\ne\nf\n', |
416 | + [prerequisite_revision]) |
417 | + new_revision = self.factory.makeRevision(rev_id=new_revision_id) |
418 | + incremental_diff = bmp.generateIncrementalDiff( |
419 | + old_revision, new_revision) |
420 | + transaction.commit() |
421 | + inserted, removed = self.diff_changes(incremental_diff.text) |
422 | + self.assertEqual(['c\n'], inserted) |
423 | + self.assertEqual(['b\n'], removed) |
424 | + |
425 | + |
426 | def test_suite(): |
427 | return TestLoader().loadTestsFromName(__name__) |
428 | |
429 | === modified file 'lib/lp/testing/factory.py' |
430 | --- lib/lp/testing/factory.py 2010-10-28 09:11:36 +0000 |
431 | +++ lib/lp/testing/factory.py 2010-10-29 15:33:57 +0000 |
432 | @@ -1266,6 +1266,18 @@ |
433 | preview_diff.target_revision_id = self.getUniqueUnicode() |
434 | return preview_diff |
435 | |
436 | + def makeIncrementalDiff(self, merge_proposal=None, old_revision=None, |
437 | + new_revision=None): |
438 | + diff = self.makeDiff() |
439 | + if merge_proposal is None: |
440 | + merge_proposal = self.makeBranchMergeProposal() |
441 | + if old_revision is None: |
442 | + old_revision = self.makeRevision() |
443 | + if new_revision is None: |
444 | + new_revision = self.makeRevision() |
445 | + return merge_proposal.generateIncrementalDiff( |
446 | + old_revision, new_revision, diff) |
447 | + |
448 | def makeStaticDiff(self): |
449 | return StaticDiff.acquireFromText( |
450 | self.getUniqueUnicode(), self.getUniqueUnicode(), |
451 | |
452 | === modified file 'utilities/sourcedeps.conf' |
453 | --- utilities/sourcedeps.conf 2010-10-25 15:23:38 +0000 |
454 | +++ utilities/sourcedeps.conf 2010-10-29 15:33:57 +0000 |
455 | @@ -5,6 +5,7 @@ |
456 | bzr-svn lp:~launchpad-pqm/bzr-svn/devel;revno=2710 |
457 | cscvs lp:~launchpad-pqm/launchpad-cscvs/devel;revno=432 |
458 | dulwich lp:~launchpad-pqm/dulwich/devel;revno=424 |
459 | +difftacular lp:difftacular;revno=6 |
460 | loggerhead lp:~launchpad-pqm/loggerhead/devel;revno=176 |
461 | lpreview lp:~launchpad-pqm/bzr-lpreview/devel;revno=23 |
462 | mailman lp:~launchpad-pqm/mailman/2.1;revno=976 |
This branch looks good with some trivial cleanup suggested in IRC, one minor change also suggested in IRC, and one major caveat:
The minor change: test_generateIn crementalDiff is pretty confusing, with lots of branches and lots of nearly-identical commits. It needs at least a comment up-front describing what's in the two revisions being diffed, and how the precursor and prerequisite branches affect this.
It might also be easier to understand if you defined a helper method to create a new branch *and its first commit*. This would make it clear which commits are setup, reflecting the "initial" states of the branches, and which commits are the ones leading up to the endpoint of the incremental diff. But an explanatory comment is good enough to get my approval.
The caveat: this branch introduces a new source dependency, difftacular, which was written by Aaron in July. Since it was written in-house, I think difftacular needs to go through the code review process, just like the lazr packages that are used in Launchpad. Fortunately, the entire difftacular project isn't much longer than 800 lines, so it shouldn't be too difficult for me to do the review.