Merge lp:~jelmer/brz/remove-record-entry-contents into lp:brz
- remove-record-entry-contents
- Merge into trunk
Proposed by
Jelmer Vernooij
Status: | Merged |
---|---|
Approved by: | Jelmer Vernooij |
Approved revision: | no longer in the source branch. |
Merge reported by: | The Breezy Bot |
Merged at revision: | not available |
Proposed branch: | lp:~jelmer/brz/remove-record-entry-contents |
Merge into: | lp:brz |
Prerequisite: | lp:~jelmer/brz/iter-changes-all-the-way |
Diff against target: |
1633 lines (+37/-1096) 9 files modified
breezy/bzr/vf_repository.py (+10/-281) breezy/commit.py (+8/-247) breezy/plugins/fastimport/revision_store.py (+1/-1) breezy/repository.py (+0/-2) breezy/tests/per_repository/test_commit_builder.py (+6/-555) breezy/tests/per_workingtree/test_commit.py (+1/-0) breezy/tests/test_foreign.py (+6/-10) breezy/tests/test_merge.py (+2/-0) doc/en/release-notes/brz-3.0.txt (+3/-0) |
To merge this branch: | bzr merge lp:~jelmer/brz/remove-record-entry-contents |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Martin Packman | Approve | ||
Review via email: mp+325968@code.launchpad.net |
Commit message
Remove remaining implementations of CommitBuilder.
Description of the change
Remove remaining implementations of CommitBuilder.
... and all their tests.
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 'breezy/bzr/vf_repository.py' | |||
2 | --- breezy/bzr/vf_repository.py 2017-06-20 00:39:00 +0000 | |||
3 | +++ breezy/bzr/vf_repository.py 2017-06-20 22:39:47 +0000 | |||
4 | @@ -112,9 +112,6 @@ | |||
5 | 112 | """Commit builder implementation for versioned files based repositories. | 112 | """Commit builder implementation for versioned files based repositories. |
6 | 113 | """ | 113 | """ |
7 | 114 | 114 | ||
8 | 115 | # this commit builder supports the record_entry_contents interface | ||
9 | 116 | supports_record_entry_contents = True | ||
10 | 117 | |||
11 | 118 | # the default CommitBuilder does not manage trees whose root is versioned. | 115 | # the default CommitBuilder does not manage trees whose root is versioned. |
12 | 119 | _versioned_root = False | 116 | _versioned_root = False |
13 | 120 | 117 | ||
14 | @@ -129,7 +126,7 @@ | |||
15 | 129 | except IndexError: | 126 | except IndexError: |
16 | 130 | basis_id = _mod_revision.NULL_REVISION | 127 | basis_id = _mod_revision.NULL_REVISION |
17 | 131 | self.basis_delta_revision = basis_id | 128 | self.basis_delta_revision = basis_id |
19 | 132 | self.new_inventory = Inventory(None) | 129 | self._new_inventory = None |
20 | 133 | self._basis_delta = [] | 130 | self._basis_delta = [] |
21 | 134 | self.__heads = graph.HeadsCache(repository.get_graph()).heads | 131 | self.__heads = graph.HeadsCache(repository.get_graph()).heads |
22 | 135 | # memo'd check for no-op commits. | 132 | # memo'd check for no-op commits. |
23 | @@ -220,11 +217,11 @@ | |||
24 | 220 | require deserializing the inventory, while we already have a copy in | 217 | require deserializing the inventory, while we already have a copy in |
25 | 221 | memory. | 218 | memory. |
26 | 222 | """ | 219 | """ |
29 | 223 | if self.new_inventory is None: | 220 | if self._new_inventory is None: |
30 | 224 | self.new_inventory = self.repository.get_inventory( | 221 | self._new_inventory = self.repository.get_inventory( |
31 | 225 | self._new_revision_id) | 222 | self._new_revision_id) |
32 | 226 | return inventorytree.InventoryRevisionTree(self.repository, | 223 | return inventorytree.InventoryRevisionTree(self.repository, |
34 | 227 | self.new_inventory, self._new_revision_id) | 224 | self._new_inventory, self._new_revision_id) |
35 | 228 | 225 | ||
36 | 229 | def finish_inventory(self): | 226 | def finish_inventory(self): |
37 | 230 | """Tell the builder that the inventory is finished. | 227 | """Tell the builder that the inventory is finished. |
38 | @@ -232,42 +229,14 @@ | |||
39 | 232 | :return: The inventory id in the repository, which can be used with | 229 | :return: The inventory id in the repository, which can be used with |
40 | 233 | repository.get_inventory. | 230 | repository.get_inventory. |
41 | 234 | """ | 231 | """ |
63 | 235 | if self.new_inventory is None: | 232 | # an inventory delta was accumulated without creating a new |
64 | 236 | # an inventory delta was accumulated without creating a new | 233 | # inventory. |
65 | 237 | # inventory. | 234 | basis_id = self.basis_delta_revision |
66 | 238 | basis_id = self.basis_delta_revision | 235 | self.inv_sha1, self._new_inventory = self.repository.add_inventory_by_delta( |
67 | 239 | # We ignore the 'inventory' returned by add_inventory_by_delta | 236 | basis_id, self._basis_delta, self._new_revision_id, |
68 | 240 | # because self.new_inventory is used to hint to the rest of the | 237 | self.parents) |
48 | 241 | # system what code path was taken | ||
49 | 242 | self.inv_sha1, _ = self.repository.add_inventory_by_delta( | ||
50 | 243 | basis_id, self._basis_delta, self._new_revision_id, | ||
51 | 244 | self.parents) | ||
52 | 245 | else: | ||
53 | 246 | if self.new_inventory.root is None: | ||
54 | 247 | raise AssertionError('Root entry should be supplied to' | ||
55 | 248 | ' record_entry_contents, as of bzr 0.10.') | ||
56 | 249 | self.new_inventory.add(InventoryDirectory(ROOT_ID, '', None)) | ||
57 | 250 | self.new_inventory.revision_id = self._new_revision_id | ||
58 | 251 | self.inv_sha1 = self.repository.add_inventory( | ||
59 | 252 | self._new_revision_id, | ||
60 | 253 | self.new_inventory, | ||
61 | 254 | self.parents | ||
62 | 255 | ) | ||
69 | 256 | return self._new_revision_id | 238 | return self._new_revision_id |
70 | 257 | 239 | ||
71 | 258 | def _check_root(self, ie, parent_invs, tree): | ||
72 | 259 | """Helper for record_entry_contents. | ||
73 | 260 | |||
74 | 261 | :param ie: An entry being added. | ||
75 | 262 | :param parent_invs: The inventories of the parent revisions of the | ||
76 | 263 | commit. | ||
77 | 264 | :param tree: The tree that is being committed. | ||
78 | 265 | """ | ||
79 | 266 | # In this revision format, root entries have no knit or weave When | ||
80 | 267 | # serializing out to disk and back in root.revision is always | ||
81 | 268 | # _new_revision_id | ||
82 | 269 | ie.revision = self._new_revision_id | ||
83 | 270 | |||
84 | 271 | def _require_root_change(self, tree): | 240 | def _require_root_change(self, tree): |
85 | 272 | """Enforce an appropriate root object change. | 241 | """Enforce an appropriate root object change. |
86 | 273 | 242 | ||
87 | @@ -311,241 +280,11 @@ | |||
88 | 311 | def get_basis_delta(self): | 280 | def get_basis_delta(self): |
89 | 312 | """Return the complete inventory delta versus the basis inventory. | 281 | """Return the complete inventory delta versus the basis inventory. |
90 | 313 | 282 | ||
91 | 314 | This has been built up with the calls to record_delete and | ||
92 | 315 | record_entry_contents. | ||
93 | 316 | |||
94 | 317 | :return: An inventory delta, suitable for use with apply_delta, or | 283 | :return: An inventory delta, suitable for use with apply_delta, or |
95 | 318 | Repository.add_inventory_by_delta, etc. | 284 | Repository.add_inventory_by_delta, etc. |
96 | 319 | """ | 285 | """ |
97 | 320 | return self._basis_delta | 286 | return self._basis_delta |
98 | 321 | 287 | ||
99 | 322 | def record_delete(self, path, file_id): | ||
100 | 323 | """Record that a delete occured against a basis tree. | ||
101 | 324 | |||
102 | 325 | This is an optional API - when used it adds items to the basis_delta | ||
103 | 326 | being accumulated by the commit builder. | ||
104 | 327 | |||
105 | 328 | :param path: The path of the thing deleted. | ||
106 | 329 | :param file_id: The file id that was deleted. | ||
107 | 330 | """ | ||
108 | 331 | delta = (path, None, file_id, None) | ||
109 | 332 | self._basis_delta.append(delta) | ||
110 | 333 | self._any_changes = True | ||
111 | 334 | return delta | ||
112 | 335 | |||
113 | 336 | def record_entry_contents(self, ie, parent_invs, path, tree, | ||
114 | 337 | content_summary): | ||
115 | 338 | """Record the content of ie from tree into the commit if needed. | ||
116 | 339 | |||
117 | 340 | Side effect: sets ie.revision when unchanged | ||
118 | 341 | |||
119 | 342 | :param ie: An inventory entry present in the commit. | ||
120 | 343 | :param parent_invs: The inventories of the parent revisions of the | ||
121 | 344 | commit. | ||
122 | 345 | :param path: The path the entry is at in the tree. | ||
123 | 346 | :param tree: The tree which contains this entry and should be used to | ||
124 | 347 | obtain content. | ||
125 | 348 | :param content_summary: Summary data from the tree about the paths | ||
126 | 349 | content - stat, length, exec, sha/link target. This is only | ||
127 | 350 | accessed when the entry has a revision of None - that is when it is | ||
128 | 351 | a candidate to commit. | ||
129 | 352 | :return: A tuple (change_delta, version_recorded, fs_hash). | ||
130 | 353 | change_delta is an inventory_delta change for this entry against | ||
131 | 354 | the basis tree of the commit, or None if no change occured against | ||
132 | 355 | the basis tree. | ||
133 | 356 | version_recorded is True if a new version of the entry has been | ||
134 | 357 | recorded. For instance, committing a merge where a file was only | ||
135 | 358 | changed on the other side will return (delta, False). | ||
136 | 359 | fs_hash is either None, or the hash details for the path (currently | ||
137 | 360 | a tuple of the contents sha1 and the statvalue returned by | ||
138 | 361 | tree.get_file_with_stat()). | ||
139 | 362 | """ | ||
140 | 363 | if self.new_inventory.root is None: | ||
141 | 364 | if ie.parent_id is not None: | ||
142 | 365 | raise errors.RootMissing() | ||
143 | 366 | self._check_root(ie, parent_invs, tree) | ||
144 | 367 | if ie.revision is None: | ||
145 | 368 | kind = content_summary[0] | ||
146 | 369 | else: | ||
147 | 370 | # ie is carried over from a prior commit | ||
148 | 371 | kind = ie.kind | ||
149 | 372 | # XXX: repository specific check for nested tree support goes here - if | ||
150 | 373 | # the repo doesn't want nested trees we skip it ? | ||
151 | 374 | if (kind == 'tree-reference' and | ||
152 | 375 | not self.repository._format.supports_tree_reference): | ||
153 | 376 | # mismatch between commit builder logic and repository: | ||
154 | 377 | # this needs the entry creation pushed down into the builder. | ||
155 | 378 | raise NotImplementedError('Missing repository subtree support.') | ||
156 | 379 | self.new_inventory.add(ie) | ||
157 | 380 | |||
158 | 381 | # TODO: slow, take it out of the inner loop. | ||
159 | 382 | try: | ||
160 | 383 | basis_inv = parent_invs[0] | ||
161 | 384 | except IndexError: | ||
162 | 385 | basis_inv = Inventory(root_id=None) | ||
163 | 386 | |||
164 | 387 | # ie.revision is always None if the InventoryEntry is considered | ||
165 | 388 | # for committing. We may record the previous parents revision if the | ||
166 | 389 | # content is actually unchanged against a sole head. | ||
167 | 390 | if ie.revision is not None: | ||
168 | 391 | if not self._versioned_root and path == '': | ||
169 | 392 | # repositories that do not version the root set the root's | ||
170 | 393 | # revision to the new commit even when no change occurs (more | ||
171 | 394 | # specifically, they do not record a revision on the root; and | ||
172 | 395 | # the rev id is assigned to the root during deserialisation - | ||
173 | 396 | # this masks when a change may have occurred against the basis. | ||
174 | 397 | # To match this we always issue a delta, because the revision | ||
175 | 398 | # of the root will always be changing. | ||
176 | 399 | if basis_inv.has_id(ie.file_id): | ||
177 | 400 | delta = (basis_inv.id2path(ie.file_id), path, | ||
178 | 401 | ie.file_id, ie) | ||
179 | 402 | else: | ||
180 | 403 | # add | ||
181 | 404 | delta = (None, path, ie.file_id, ie) | ||
182 | 405 | self._basis_delta.append(delta) | ||
183 | 406 | return delta, False, None | ||
184 | 407 | else: | ||
185 | 408 | # we don't need to commit this, because the caller already | ||
186 | 409 | # determined that an existing revision of this file is | ||
187 | 410 | # appropriate. If it's not being considered for committing then | ||
188 | 411 | # it and all its parents to the root must be unaltered so | ||
189 | 412 | # no-change against the basis. | ||
190 | 413 | if ie.revision == self._new_revision_id: | ||
191 | 414 | raise AssertionError("Impossible situation, a skipped " | ||
192 | 415 | "inventory entry (%r) claims to be modified in this " | ||
193 | 416 | "commit (%r).", (ie, self._new_revision_id)) | ||
194 | 417 | return None, False, None | ||
195 | 418 | # XXX: Friction: parent_candidates should return a list not a dict | ||
196 | 419 | # so that we don't have to walk the inventories again. | ||
197 | 420 | parent_candidate_entries = ie.parent_candidates(parent_invs) | ||
198 | 421 | head_set = self._heads(ie.file_id, parent_candidate_entries) | ||
199 | 422 | heads = [] | ||
200 | 423 | for inv in parent_invs: | ||
201 | 424 | if inv.has_id(ie.file_id): | ||
202 | 425 | old_rev = inv[ie.file_id].revision | ||
203 | 426 | if old_rev in head_set: | ||
204 | 427 | heads.append(inv[ie.file_id].revision) | ||
205 | 428 | head_set.remove(inv[ie.file_id].revision) | ||
206 | 429 | |||
207 | 430 | store = False | ||
208 | 431 | # now we check to see if we need to write a new record to the | ||
209 | 432 | # file-graph. | ||
210 | 433 | # We write a new entry unless there is one head to the ancestors, and | ||
211 | 434 | # the kind-derived content is unchanged. | ||
212 | 435 | |||
213 | 436 | # Cheapest check first: no ancestors, or more the one head in the | ||
214 | 437 | # ancestors, we write a new node. | ||
215 | 438 | if len(heads) != 1: | ||
216 | 439 | store = True | ||
217 | 440 | if not store: | ||
218 | 441 | # There is a single head, look it up for comparison | ||
219 | 442 | parent_entry = parent_candidate_entries[heads[0]] | ||
220 | 443 | # if the non-content specific data has changed, we'll be writing a | ||
221 | 444 | # node: | ||
222 | 445 | if (parent_entry.parent_id != ie.parent_id or | ||
223 | 446 | parent_entry.name != ie.name): | ||
224 | 447 | store = True | ||
225 | 448 | # now we need to do content specific checks: | ||
226 | 449 | if not store: | ||
227 | 450 | # if the kind changed the content obviously has | ||
228 | 451 | if kind != parent_entry.kind: | ||
229 | 452 | store = True | ||
230 | 453 | # Stat cache fingerprint feedback for the caller - None as we usually | ||
231 | 454 | # don't generate one. | ||
232 | 455 | fingerprint = None | ||
233 | 456 | if kind == 'file': | ||
234 | 457 | if content_summary[2] is None: | ||
235 | 458 | raise ValueError("Files must not have executable = None") | ||
236 | 459 | if not store: | ||
237 | 460 | # We can't trust a check of the file length because of content | ||
238 | 461 | # filtering... | ||
239 | 462 | if (# if the exec bit has changed we have to store: | ||
240 | 463 | parent_entry.executable != content_summary[2]): | ||
241 | 464 | store = True | ||
242 | 465 | elif parent_entry.text_sha1 == content_summary[3]: | ||
243 | 466 | # all meta and content is unchanged (using a hash cache | ||
244 | 467 | # hit to check the sha) | ||
245 | 468 | ie.revision = parent_entry.revision | ||
246 | 469 | ie.text_size = parent_entry.text_size | ||
247 | 470 | ie.text_sha1 = parent_entry.text_sha1 | ||
248 | 471 | ie.executable = parent_entry.executable | ||
249 | 472 | return self._get_delta(ie, basis_inv, path), False, None | ||
250 | 473 | else: | ||
251 | 474 | # Either there is only a hash change(no hash cache entry, | ||
252 | 475 | # or same size content change), or there is no change on | ||
253 | 476 | # this file at all. | ||
254 | 477 | # Provide the parent's hash to the store layer, so that the | ||
255 | 478 | # content is unchanged we will not store a new node. | ||
256 | 479 | nostore_sha = parent_entry.text_sha1 | ||
257 | 480 | if store: | ||
258 | 481 | # We want to record a new node regardless of the presence or | ||
259 | 482 | # absence of a content change in the file. | ||
260 | 483 | nostore_sha = None | ||
261 | 484 | ie.executable = content_summary[2] | ||
262 | 485 | file_obj, stat_value = tree.get_file_with_stat(ie.file_id, path) | ||
263 | 486 | try: | ||
264 | 487 | text = file_obj.read() | ||
265 | 488 | finally: | ||
266 | 489 | file_obj.close() | ||
267 | 490 | try: | ||
268 | 491 | ie.text_sha1, ie.text_size = self._add_text_to_weave( | ||
269 | 492 | ie.file_id, text, heads, nostore_sha) | ||
270 | 493 | # Let the caller know we generated a stat fingerprint. | ||
271 | 494 | fingerprint = (ie.text_sha1, stat_value) | ||
272 | 495 | except errors.ExistingContent: | ||
273 | 496 | # Turns out that the file content was unchanged, and we were | ||
274 | 497 | # only going to store a new node if it was changed. Carry over | ||
275 | 498 | # the entry. | ||
276 | 499 | ie.revision = parent_entry.revision | ||
277 | 500 | ie.text_size = parent_entry.text_size | ||
278 | 501 | ie.text_sha1 = parent_entry.text_sha1 | ||
279 | 502 | ie.executable = parent_entry.executable | ||
280 | 503 | return self._get_delta(ie, basis_inv, path), False, None | ||
281 | 504 | elif kind == 'directory': | ||
282 | 505 | if not store: | ||
283 | 506 | # all data is meta here, nothing specific to directory, so | ||
284 | 507 | # carry over: | ||
285 | 508 | ie.revision = parent_entry.revision | ||
286 | 509 | return self._get_delta(ie, basis_inv, path), False, None | ||
287 | 510 | self._add_text_to_weave(ie.file_id, '', heads, None) | ||
288 | 511 | elif kind == 'symlink': | ||
289 | 512 | current_link_target = content_summary[3] | ||
290 | 513 | if not store: | ||
291 | 514 | # symlink target is not generic metadata, check if it has | ||
292 | 515 | # changed. | ||
293 | 516 | if current_link_target != parent_entry.symlink_target: | ||
294 | 517 | store = True | ||
295 | 518 | if not store: | ||
296 | 519 | # unchanged, carry over. | ||
297 | 520 | ie.revision = parent_entry.revision | ||
298 | 521 | ie.symlink_target = parent_entry.symlink_target | ||
299 | 522 | return self._get_delta(ie, basis_inv, path), False, None | ||
300 | 523 | ie.symlink_target = current_link_target | ||
301 | 524 | self._add_text_to_weave(ie.file_id, '', heads, None) | ||
302 | 525 | elif kind == 'tree-reference': | ||
303 | 526 | if not store: | ||
304 | 527 | if content_summary[3] != parent_entry.reference_revision: | ||
305 | 528 | store = True | ||
306 | 529 | if not store: | ||
307 | 530 | # unchanged, carry over. | ||
308 | 531 | ie.reference_revision = parent_entry.reference_revision | ||
309 | 532 | ie.revision = parent_entry.revision | ||
310 | 533 | return self._get_delta(ie, basis_inv, path), False, None | ||
311 | 534 | ie.reference_revision = content_summary[3] | ||
312 | 535 | if ie.reference_revision is None: | ||
313 | 536 | raise AssertionError("invalid content_summary for nested tree: %r" | ||
314 | 537 | % (content_summary,)) | ||
315 | 538 | self._add_text_to_weave(ie.file_id, '', heads, None) | ||
316 | 539 | else: | ||
317 | 540 | raise NotImplementedError('unknown kind') | ||
318 | 541 | ie.revision = self._new_revision_id | ||
319 | 542 | # The initial commit adds a root directory, but this in itself is not | ||
320 | 543 | # a worthwhile commit. | ||
321 | 544 | if (self.basis_delta_revision != _mod_revision.NULL_REVISION or | ||
322 | 545 | path != ""): | ||
323 | 546 | self._any_changes = True | ||
324 | 547 | return self._get_delta(ie, basis_inv, path), True, fingerprint | ||
325 | 548 | |||
326 | 549 | def record_iter_changes(self, tree, basis_revision_id, iter_changes, | 288 | def record_iter_changes(self, tree, basis_revision_id, iter_changes, |
327 | 550 | _entry_factory=entry_factory): | 289 | _entry_factory=entry_factory): |
328 | 551 | """Record a new tree via iter_changes. | 290 | """Record a new tree via iter_changes. |
329 | @@ -805,7 +544,6 @@ | |||
330 | 805 | inv_delta.append((change[1][0], new_path, change[0], entry)) | 544 | inv_delta.append((change[1][0], new_path, change[0], entry)) |
331 | 806 | if new_path == '': | 545 | if new_path == '': |
332 | 807 | seen_root = True | 546 | seen_root = True |
333 | 808 | self.new_inventory = None | ||
334 | 809 | # The initial commit adds a root directory, but this in itself is not | 547 | # The initial commit adds a root directory, but this in itself is not |
335 | 810 | # a worthwhile commit. | 548 | # a worthwhile commit. |
336 | 811 | if ((len(inv_delta) > 0 and basis_revision_id != _mod_revision.NULL_REVISION) or | 549 | if ((len(inv_delta) > 0 and basis_revision_id != _mod_revision.NULL_REVISION) or |
337 | @@ -832,15 +570,6 @@ | |||
338 | 832 | # the root entry gets versioned properly by this builder. | 570 | # the root entry gets versioned properly by this builder. |
339 | 833 | _versioned_root = True | 571 | _versioned_root = True |
340 | 834 | 572 | ||
341 | 835 | def _check_root(self, ie, parent_invs, tree): | ||
342 | 836 | """Helper for record_entry_contents. | ||
343 | 837 | |||
344 | 838 | :param ie: An entry being added. | ||
345 | 839 | :param parent_invs: The inventories of the parent revisions of the | ||
346 | 840 | commit. | ||
347 | 841 | :param tree: The tree that is being committed. | ||
348 | 842 | """ | ||
349 | 843 | |||
350 | 844 | def _require_root_change(self, tree): | 573 | def _require_root_change(self, tree): |
351 | 845 | """Enforce an appropriate root object change. | 574 | """Enforce an appropriate root object change. |
352 | 846 | 575 | ||
353 | 847 | 576 | ||
354 | === modified file 'breezy/commit.py' | |||
355 | --- breezy/commit.py 2017-06-20 22:29:58 +0000 | |||
356 | +++ breezy/commit.py 2017-06-20 22:39:47 +0000 | |||
357 | @@ -344,9 +344,6 @@ | |||
358 | 344 | self.work_tree.lock_write() | 344 | self.work_tree.lock_write() |
359 | 345 | operation.add_cleanup(self.work_tree.unlock) | 345 | operation.add_cleanup(self.work_tree.unlock) |
360 | 346 | self.parents = self.work_tree.get_parent_ids() | 346 | self.parents = self.work_tree.get_parent_ids() |
361 | 347 | # We can use record_iter_changes IFF no tree references are involved. | ||
362 | 348 | self.use_record_iter_changes = ( | ||
363 | 349 | not self.branch.repository._format.supports_tree_reference) | ||
364 | 350 | self.pb = ui.ui_factory.nested_progress_bar() | 347 | self.pb = ui.ui_factory.nested_progress_bar() |
365 | 351 | operation.add_cleanup(self.pb.finished) | 348 | operation.add_cleanup(self.pb.finished) |
366 | 352 | self.basis_revid = self.work_tree.last_revision() | 349 | self.basis_revid = self.work_tree.last_revision() |
367 | @@ -371,8 +368,6 @@ | |||
368 | 371 | if self.config_stack is None: | 368 | if self.config_stack is None: |
369 | 372 | self.config_stack = self.work_tree.get_config_stack() | 369 | self.config_stack = self.work_tree.get_config_stack() |
370 | 373 | 370 | ||
371 | 374 | self._set_specific_file_ids() | ||
372 | 375 | |||
373 | 376 | # Setup the progress bar. As the number of files that need to be | 371 | # Setup the progress bar. As the number of files that need to be |
374 | 377 | # committed in unknown, progress is reported as stages. | 372 | # committed in unknown, progress is reported as stages. |
375 | 378 | # We keep track of entries separately though and include that | 373 | # We keep track of entries separately though and include that |
376 | @@ -390,7 +385,6 @@ | |||
377 | 390 | self.pb.show_count = True | 385 | self.pb.show_count = True |
378 | 391 | self.pb.show_bar = True | 386 | self.pb.show_bar = True |
379 | 392 | 387 | ||
380 | 393 | self._gather_parents() | ||
381 | 394 | # After a merge, a selected file commit is not supported. | 388 | # After a merge, a selected file commit is not supported. |
382 | 395 | # See 'bzr help merge' for an explanation as to why. | 389 | # See 'bzr help merge' for an explanation as to why. |
383 | 396 | if len(self.parents) > 1 and self.specific_files is not None: | 390 | if len(self.parents) > 1 and self.specific_files is not None: |
384 | @@ -654,44 +648,21 @@ | |||
385 | 654 | old_revno, old_revid, new_revno, self.rev_id, | 648 | old_revno, old_revid, new_revno, self.rev_id, |
386 | 655 | tree_delta, future_tree) | 649 | tree_delta, future_tree) |
387 | 656 | 650 | ||
388 | 657 | def _gather_parents(self): | ||
389 | 658 | """Record the parents of a merge for merge detection.""" | ||
390 | 659 | # TODO: Make sure that this list doesn't contain duplicate | ||
391 | 660 | # entries and the order is preserved when doing this. | ||
392 | 661 | if self.use_record_iter_changes: | ||
393 | 662 | return | ||
394 | 663 | self.basis_inv = self.basis_tree.root_inventory | ||
395 | 664 | self.parent_invs = [self.basis_inv] | ||
396 | 665 | for revision in self.parents[1:]: | ||
397 | 666 | if self.branch.repository.has_revision(revision): | ||
398 | 667 | mutter('commit parent revision {%s}', revision) | ||
399 | 668 | inventory = self.branch.repository.get_inventory(revision) | ||
400 | 669 | self.parent_invs.append(inventory) | ||
401 | 670 | else: | ||
402 | 671 | mutter('commit parent ghost revision {%s}', revision) | ||
403 | 672 | |||
404 | 673 | def _update_builder_with_changes(self): | 651 | def _update_builder_with_changes(self): |
405 | 674 | """Update the commit builder with the data about what has changed. | 652 | """Update the commit builder with the data about what has changed. |
406 | 675 | """ | 653 | """ |
407 | 676 | exclude = self.exclude | ||
408 | 677 | specific_files = self.specific_files | 654 | specific_files = self.specific_files |
409 | 678 | mutter("Selecting files for commit with filter %r", specific_files) | 655 | mutter("Selecting files for commit with filter %r", specific_files) |
410 | 679 | 656 | ||
411 | 680 | self._check_strict() | 657 | self._check_strict() |
426 | 681 | if self.use_record_iter_changes: | 658 | iter_changes = self.work_tree.iter_changes(self.basis_tree, |
427 | 682 | iter_changes = self.work_tree.iter_changes(self.basis_tree, | 659 | specific_files=specific_files) |
428 | 683 | specific_files=specific_files) | 660 | if self.exclude: |
429 | 684 | if self.exclude: | 661 | iter_changes = filter_excluded(iter_changes, self.exclude) |
430 | 685 | iter_changes = filter_excluded(iter_changes, self.exclude) | 662 | iter_changes = self._filter_iter_changes(iter_changes) |
431 | 686 | iter_changes = self._filter_iter_changes(iter_changes) | 663 | for file_id, path, fs_hash in self.builder.record_iter_changes( |
432 | 687 | for file_id, path, fs_hash in self.builder.record_iter_changes( | 664 | self.work_tree, self.basis_revid, iter_changes): |
433 | 688 | self.work_tree, self.basis_revid, iter_changes): | 665 | self.work_tree._observed_sha1(file_id, path, fs_hash) |
420 | 689 | self.work_tree._observed_sha1(file_id, path, fs_hash) | ||
421 | 690 | else: | ||
422 | 691 | # Build the new inventory | ||
423 | 692 | self._populate_from_inventory() | ||
424 | 693 | self._record_unselected() | ||
425 | 694 | self._report_and_accumulate_deletes() | ||
434 | 695 | 666 | ||
435 | 696 | def _filter_iter_changes(self, iter_changes): | 667 | def _filter_iter_changes(self, iter_changes): |
436 | 697 | """Process iter_changes. | 668 | """Process iter_changes. |
437 | @@ -745,55 +716,6 @@ | |||
438 | 745 | # Unversion IDs that were found to be deleted | 716 | # Unversion IDs that were found to be deleted |
439 | 746 | self.deleted_ids = deleted_ids | 717 | self.deleted_ids = deleted_ids |
440 | 747 | 718 | ||
441 | 748 | def _record_unselected(self): | ||
442 | 749 | # If specific files are selected, then all un-selected files must be | ||
443 | 750 | # recorded in their previous state. For more details, see | ||
444 | 751 | # https://lists.ubuntu.com/archives/bazaar/2007q3/028476.html. | ||
445 | 752 | if self.specific_files or self.exclude: | ||
446 | 753 | specific_files = self.specific_files or [] | ||
447 | 754 | for path, old_ie in self.basis_inv.iter_entries(): | ||
448 | 755 | if self.builder.new_inventory.has_id(old_ie.file_id): | ||
449 | 756 | # already added - skip. | ||
450 | 757 | continue | ||
451 | 758 | if (is_inside_any(specific_files, path) | ||
452 | 759 | and not is_inside_any(self.exclude, path)): | ||
453 | 760 | # was inside the selected path, and not excluded - if not | ||
454 | 761 | # present it has been deleted so skip. | ||
455 | 762 | continue | ||
456 | 763 | # From here down it was either not selected, or was excluded: | ||
457 | 764 | # We preserve the entry unaltered. | ||
458 | 765 | ie = old_ie.copy() | ||
459 | 766 | # Note: specific file commits after a merge are currently | ||
460 | 767 | # prohibited. This test is for sanity/safety in case it's | ||
461 | 768 | # required after that changes. | ||
462 | 769 | if len(self.parents) > 1: | ||
463 | 770 | ie.revision = None | ||
464 | 771 | self.builder.record_entry_contents(ie, self.parent_invs, path, | ||
465 | 772 | self.basis_tree, None) | ||
466 | 773 | |||
467 | 774 | def _report_and_accumulate_deletes(self): | ||
468 | 775 | if (isinstance(self.basis_inv, Inventory) | ||
469 | 776 | and isinstance(self.builder.new_inventory, Inventory)): | ||
470 | 777 | # the older Inventory classes provide a _byid dict, and building a | ||
471 | 778 | # set from the keys of this dict is substantially faster than even | ||
472 | 779 | # getting a set of ids from the inventory | ||
473 | 780 | # | ||
474 | 781 | # <lifeless> set(dict) is roughly the same speed as | ||
475 | 782 | # set(iter(dict)) and both are significantly slower than | ||
476 | 783 | # set(dict.keys()) | ||
477 | 784 | deleted_ids = set(self.basis_inv._byid.keys()) - \ | ||
478 | 785 | set(self.builder.new_inventory._byid.keys()) | ||
479 | 786 | else: | ||
480 | 787 | deleted_ids = set(self.basis_inv) - set(self.builder.new_inventory) | ||
481 | 788 | if deleted_ids: | ||
482 | 789 | self.any_entries_deleted = True | ||
483 | 790 | deleted = sorted([(self.basis_tree.id2path(file_id), file_id) | ||
484 | 791 | for file_id in deleted_ids]) | ||
485 | 792 | # XXX: this is not quite directory-order sorting | ||
486 | 793 | for path, file_id in deleted: | ||
487 | 794 | self.builder.record_delete(path, file_id) | ||
488 | 795 | self.reporter.deleted(path) | ||
489 | 796 | |||
490 | 797 | def _check_strict(self): | 719 | def _check_strict(self): |
491 | 798 | # XXX: when we use iter_changes this would likely be faster if | 720 | # XXX: when we use iter_changes this would likely be faster if |
492 | 799 | # iter_changes would check for us (even in the presence of | 721 | # iter_changes would check for us (even in the presence of |
493 | @@ -803,107 +725,6 @@ | |||
494 | 803 | for unknown in self.work_tree.unknowns(): | 725 | for unknown in self.work_tree.unknowns(): |
495 | 804 | raise StrictCommitFailed() | 726 | raise StrictCommitFailed() |
496 | 805 | 727 | ||
497 | 806 | def _populate_from_inventory(self): | ||
498 | 807 | """Populate the CommitBuilder by walking the working tree inventory.""" | ||
499 | 808 | # Build the revision inventory. | ||
500 | 809 | # | ||
501 | 810 | # This starts by creating a new empty inventory. Depending on | ||
502 | 811 | # which files are selected for commit, and what is present in the | ||
503 | 812 | # current tree, the new inventory is populated. inventory entries | ||
504 | 813 | # which are candidates for modification have their revision set to | ||
505 | 814 | # None; inventory entries that are carried over untouched have their | ||
506 | 815 | # revision set to their prior value. | ||
507 | 816 | # | ||
508 | 817 | # ESEPARATIONOFCONCERNS: this function is diffing and using the diff | ||
509 | 818 | # results to create a new inventory at the same time, which results | ||
510 | 819 | # in bugs like #46635. Any reason not to use/enhance Tree.changes_from? | ||
511 | 820 | # ADHB 11-07-2006 | ||
512 | 821 | |||
513 | 822 | specific_files = self.specific_files | ||
514 | 823 | exclude = self.exclude | ||
515 | 824 | report_changes = self.reporter.is_verbose() | ||
516 | 825 | deleted_ids = [] | ||
517 | 826 | # A tree of paths that have been deleted. E.g. if foo/bar has been | ||
518 | 827 | # deleted, then we have {'foo':{'bar':{}}} | ||
519 | 828 | deleted_paths = {} | ||
520 | 829 | # XXX: Note that entries may have the wrong kind because the entry does | ||
521 | 830 | # not reflect the status on disk. | ||
522 | 831 | # NB: entries will include entries within the excluded ids/paths | ||
523 | 832 | # because iter_entries_by_dir has no 'exclude' facility today. | ||
524 | 833 | entries = self.work_tree.iter_entries_by_dir( | ||
525 | 834 | specific_file_ids=self.specific_file_ids, yield_parents=True) | ||
526 | 835 | for path, existing_ie in entries: | ||
527 | 836 | file_id = existing_ie.file_id | ||
528 | 837 | name = existing_ie.name | ||
529 | 838 | parent_id = existing_ie.parent_id | ||
530 | 839 | kind = existing_ie.kind | ||
531 | 840 | # Skip files that have been deleted from the working tree. | ||
532 | 841 | # The deleted path ids are also recorded so they can be explicitly | ||
533 | 842 | # unversioned later. | ||
534 | 843 | if deleted_paths: | ||
535 | 844 | path_segments = splitpath(path) | ||
536 | 845 | deleted_dict = deleted_paths | ||
537 | 846 | for segment in path_segments: | ||
538 | 847 | deleted_dict = deleted_dict.get(segment, None) | ||
539 | 848 | if not deleted_dict: | ||
540 | 849 | # We either took a path not present in the dict | ||
541 | 850 | # (deleted_dict was None), or we've reached an empty | ||
542 | 851 | # child dir in the dict, so are now a sub-path. | ||
543 | 852 | break | ||
544 | 853 | else: | ||
545 | 854 | deleted_dict = None | ||
546 | 855 | if deleted_dict is not None: | ||
547 | 856 | # the path has a deleted parent, do not add it. | ||
548 | 857 | continue | ||
549 | 858 | if exclude and is_inside_any(exclude, path): | ||
550 | 859 | # Skip excluded paths. Excluded paths are processed by | ||
551 | 860 | # _update_builder_with_changes. | ||
552 | 861 | continue | ||
553 | 862 | content_summary = self.work_tree.path_content_summary(path) | ||
554 | 863 | kind = content_summary[0] | ||
555 | 864 | # Note that when a filter of specific files is given, we must only | ||
556 | 865 | # skip/record deleted files matching that filter. | ||
557 | 866 | if not specific_files or is_inside_any(specific_files, path): | ||
558 | 867 | if kind == 'missing': | ||
559 | 868 | if not deleted_paths: | ||
560 | 869 | # path won't have been split yet. | ||
561 | 870 | path_segments = splitpath(path) | ||
562 | 871 | deleted_dict = deleted_paths | ||
563 | 872 | for segment in path_segments: | ||
564 | 873 | deleted_dict = deleted_dict.setdefault(segment, {}) | ||
565 | 874 | self.reporter.missing(path) | ||
566 | 875 | self._next_progress_entry() | ||
567 | 876 | deleted_ids.append(file_id) | ||
568 | 877 | continue | ||
569 | 878 | # TODO: have the builder do the nested commit just-in-time IF and | ||
570 | 879 | # only if needed. | ||
571 | 880 | if kind == 'tree-reference': | ||
572 | 881 | # enforce repository nested tree policy. | ||
573 | 882 | if (not self.work_tree.supports_tree_reference() or | ||
574 | 883 | # repository does not support it either. | ||
575 | 884 | not self.branch.repository._format.supports_tree_reference): | ||
576 | 885 | kind = 'directory' | ||
577 | 886 | content_summary = (kind, None, None, None) | ||
578 | 887 | elif self.recursive == 'down': | ||
579 | 888 | nested_revision_id = self._commit_nested_tree( | ||
580 | 889 | file_id, path) | ||
581 | 890 | content_summary = (kind, None, None, nested_revision_id) | ||
582 | 891 | else: | ||
583 | 892 | nested_revision_id = self.work_tree.get_reference_revision(file_id) | ||
584 | 893 | content_summary = (kind, None, None, nested_revision_id) | ||
585 | 894 | |||
586 | 895 | # Record an entry for this item | ||
587 | 896 | # Note: I don't particularly want to have the existing_ie | ||
588 | 897 | # parameter but the test suite currently (28-Jun-07) breaks | ||
589 | 898 | # without it thanks to a unicode normalisation issue. :-( | ||
590 | 899 | definitely_changed = kind != existing_ie.kind | ||
591 | 900 | self._record_entry(path, file_id, specific_files, kind, name, | ||
592 | 901 | parent_id, definitely_changed, existing_ie, report_changes, | ||
593 | 902 | content_summary) | ||
594 | 903 | |||
595 | 904 | # Unversion IDs that were found to be deleted | ||
596 | 905 | self.deleted_ids = deleted_ids | ||
597 | 906 | |||
598 | 907 | def _commit_nested_tree(self, file_id, path): | 728 | def _commit_nested_tree(self, file_id, path): |
599 | 908 | "Commit a nested tree." | 729 | "Commit a nested tree." |
600 | 909 | sub_tree = self.work_tree.get_nested_tree(file_id, path) | 730 | sub_tree = self.work_tree.get_nested_tree(file_id, path) |
601 | @@ -929,49 +750,6 @@ | |||
602 | 929 | except errors.PointlessCommit: | 750 | except errors.PointlessCommit: |
603 | 930 | return self.work_tree.get_reference_revision(file_id) | 751 | return self.work_tree.get_reference_revision(file_id) |
604 | 931 | 752 | ||
605 | 932 | def _record_entry(self, path, file_id, specific_files, kind, name, | ||
606 | 933 | parent_id, definitely_changed, existing_ie, report_changes, | ||
607 | 934 | content_summary): | ||
608 | 935 | "Record the new inventory entry for a path if any." | ||
609 | 936 | # mutter('check %s {%s}', path, file_id) | ||
610 | 937 | # mutter('%s selected for commit', path) | ||
611 | 938 | if definitely_changed or existing_ie is None: | ||
612 | 939 | ie = make_entry(kind, name, parent_id, file_id) | ||
613 | 940 | else: | ||
614 | 941 | ie = existing_ie.copy() | ||
615 | 942 | ie.revision = None | ||
616 | 943 | # For carried over entries we don't care about the fs hash - the repo | ||
617 | 944 | # isn't generating a sha, so we're not saving computation time. | ||
618 | 945 | _, _, fs_hash = self.builder.record_entry_contents( | ||
619 | 946 | ie, self.parent_invs, path, self.work_tree, content_summary) | ||
620 | 947 | if report_changes: | ||
621 | 948 | self._report_change(ie, path) | ||
622 | 949 | if fs_hash: | ||
623 | 950 | self.work_tree._observed_sha1(ie.file_id, path, fs_hash) | ||
624 | 951 | return ie | ||
625 | 952 | |||
626 | 953 | def _report_change(self, ie, path): | ||
627 | 954 | """Report a change to the user. | ||
628 | 955 | |||
629 | 956 | The change that has occurred is described relative to the basis | ||
630 | 957 | inventory. | ||
631 | 958 | """ | ||
632 | 959 | if (self.basis_inv.has_id(ie.file_id)): | ||
633 | 960 | basis_ie = self.basis_inv[ie.file_id] | ||
634 | 961 | else: | ||
635 | 962 | basis_ie = None | ||
636 | 963 | change = ie.describe_change(basis_ie, ie) | ||
637 | 964 | if change in (InventoryEntry.RENAMED, | ||
638 | 965 | InventoryEntry.MODIFIED_AND_RENAMED): | ||
639 | 966 | old_path = self.basis_inv.id2path(ie.file_id) | ||
640 | 967 | self.reporter.renamed(change, old_path, path) | ||
641 | 968 | self._next_progress_entry() | ||
642 | 969 | else: | ||
643 | 970 | if change == gettext('unchanged'): | ||
644 | 971 | return | ||
645 | 972 | self.reporter.snapshot_change(change, path) | ||
646 | 973 | self._next_progress_entry() | ||
647 | 974 | |||
648 | 975 | def _set_progress_stage(self, name, counter=False): | 753 | def _set_progress_stage(self, name, counter=False): |
649 | 976 | """Set the progress stage and emit an update to the progress bar.""" | 754 | """Set the progress stage and emit an update to the progress bar.""" |
650 | 977 | self.pb_stage_name = name | 755 | self.pb_stage_name = name |
651 | @@ -994,20 +772,3 @@ | |||
652 | 994 | else: | 772 | else: |
653 | 995 | text = gettext("%s - Stage") % (self.pb_stage_name, ) | 773 | text = gettext("%s - Stage") % (self.pb_stage_name, ) |
654 | 996 | self.pb.update(text, self.pb_stage_count, self.pb_stage_total) | 774 | self.pb.update(text, self.pb_stage_count, self.pb_stage_total) |
655 | 997 | |||
656 | 998 | def _set_specific_file_ids(self): | ||
657 | 999 | """populate self.specific_file_ids if we will use it.""" | ||
658 | 1000 | if not self.use_record_iter_changes: | ||
659 | 1001 | # If provided, ensure the specified files are versioned | ||
660 | 1002 | if self.specific_files is not None: | ||
661 | 1003 | # Note: This routine is being called because it raises | ||
662 | 1004 | # PathNotVersionedError as a side effect of finding the IDs. We | ||
663 | 1005 | # later use the ids we found as input to the working tree | ||
664 | 1006 | # inventory iterator, so we only consider those ids rather than | ||
665 | 1007 | # examining the whole tree again. | ||
666 | 1008 | # XXX: Dont we have filter_unversioned to do this more | ||
667 | 1009 | # cheaply? | ||
668 | 1010 | self.specific_file_ids = tree.find_ids_across_trees( | ||
669 | 1011 | self.specific_files, [self.basis_tree, self.work_tree]) | ||
670 | 1012 | else: | ||
671 | 1013 | self.specific_file_ids = None | ||
672 | 1014 | 775 | ||
673 | === modified file 'breezy/plugins/fastimport/revision_store.py' | |||
674 | --- breezy/plugins/fastimport/revision_store.py 2017-06-13 00:24:51 +0000 | |||
675 | +++ breezy/plugins/fastimport/revision_store.py 2017-06-20 22:39:47 +0000 | |||
676 | @@ -417,7 +417,7 @@ | |||
677 | 417 | rev.inv_sha1 = builder.inv_sha1 | 417 | rev.inv_sha1 = builder.inv_sha1 |
678 | 418 | config = builder._config_stack | 418 | config = builder._config_stack |
679 | 419 | builder.repository.add_revision(builder._new_revision_id, rev, | 419 | builder.repository.add_revision(builder._new_revision_id, rev, |
681 | 420 | builder.new_inventory) | 420 | builder.revision_tree().root_inventory) |
682 | 421 | if self._graph is not None: | 421 | if self._graph is not None: |
683 | 422 | # TODO: Use StaticTuple and .intern() for these things | 422 | # TODO: Use StaticTuple and .intern() for these things |
684 | 423 | self._graph.add_node(builder._new_revision_id, rev.parent_ids) | 423 | self._graph.add_node(builder._new_revision_id, rev.parent_ids) |
685 | 424 | 424 | ||
686 | === modified file 'breezy/repository.py' | |||
687 | --- breezy/repository.py 2017-06-20 00:39:00 +0000 | |||
688 | +++ breezy/repository.py 2017-06-20 22:39:47 +0000 | |||
689 | @@ -74,8 +74,6 @@ | |||
690 | 74 | 74 | ||
691 | 75 | # all clients should supply tree roots. | 75 | # all clients should supply tree roots. |
692 | 76 | record_root_entry = True | 76 | record_root_entry = True |
693 | 77 | # whether this commit builder supports the record_entry_contents interface | ||
694 | 78 | supports_record_entry_contents = False | ||
695 | 79 | # whether this commit builder will automatically update the branch that is | 77 | # whether this commit builder will automatically update the branch that is |
696 | 80 | # being committed to | 78 | # being committed to |
697 | 81 | updates_branch = False | 79 | updates_branch = False |
698 | 82 | 80 | ||
699 | === modified file 'breezy/tests/per_repository/test_commit_builder.py' | |||
700 | --- breezy/tests/per_repository/test_commit_builder.py 2017-06-20 00:51:07 +0000 | |||
701 | +++ breezy/tests/per_repository/test_commit_builder.py 2017-06-20 22:39:47 +0000 | |||
702 | @@ -47,34 +47,6 @@ | |||
703 | 47 | branch.repository.commit_write_group() | 47 | branch.repository.commit_write_group() |
704 | 48 | branch.repository.unlock() | 48 | branch.repository.unlock() |
705 | 49 | 49 | ||
706 | 50 | def record_root(self, builder, tree): | ||
707 | 51 | if builder.record_root_entry is True: | ||
708 | 52 | tree.lock_read() | ||
709 | 53 | try: | ||
710 | 54 | ie = tree.root_inventory.root | ||
711 | 55 | finally: | ||
712 | 56 | tree.unlock() | ||
713 | 57 | parent_tree = tree.branch.repository.revision_tree( | ||
714 | 58 | _mod_revision.NULL_REVISION) | ||
715 | 59 | parent_invs = [] | ||
716 | 60 | builder.record_entry_contents(ie, parent_invs, '', tree, | ||
717 | 61 | tree.path_content_summary('')) | ||
718 | 62 | |||
719 | 63 | def test_finish_inventory_with_record_root(self): | ||
720 | 64 | tree = self.make_branch_and_tree(".") | ||
721 | 65 | tree.lock_write() | ||
722 | 66 | try: | ||
723 | 67 | builder = tree.branch.get_commit_builder([]) | ||
724 | 68 | if not builder.supports_record_entry_contents: | ||
725 | 69 | raise tests.TestNotApplicable("CommitBuilder doesn't support " | ||
726 | 70 | "record_entry_contents") | ||
727 | 71 | repo = tree.branch.repository | ||
728 | 72 | self.record_root(builder, tree) | ||
729 | 73 | builder.finish_inventory() | ||
730 | 74 | repo.commit_write_group() | ||
731 | 75 | finally: | ||
732 | 76 | tree.unlock() | ||
733 | 77 | |||
734 | 78 | def test_finish_inventory_record_iter_changes(self): | 50 | def test_finish_inventory_record_iter_changes(self): |
735 | 79 | tree = self.make_branch_and_tree(".") | 51 | tree = self.make_branch_and_tree(".") |
736 | 80 | tree.lock_write() | 52 | tree.lock_write() |
737 | @@ -92,20 +64,6 @@ | |||
738 | 92 | finally: | 64 | finally: |
739 | 93 | tree.unlock() | 65 | tree.unlock() |
740 | 94 | 66 | ||
741 | 95 | def test_abort_record_entry_contents(self): | ||
742 | 96 | tree = self.make_branch_and_tree(".") | ||
743 | 97 | tree.lock_write() | ||
744 | 98 | try: | ||
745 | 99 | builder = tree.branch.get_commit_builder([]) | ||
746 | 100 | if not builder.supports_record_entry_contents: | ||
747 | 101 | raise tests.TestNotApplicable("CommitBuilder doesn't support " | ||
748 | 102 | "record_entry_contents") | ||
749 | 103 | self.record_root(builder, tree) | ||
750 | 104 | builder.finish_inventory() | ||
751 | 105 | builder.abort() | ||
752 | 106 | finally: | ||
753 | 107 | tree.unlock() | ||
754 | 108 | |||
755 | 109 | def test_abort_record_iter_changes(self): | 67 | def test_abort_record_iter_changes(self): |
756 | 110 | tree = self.make_branch_and_tree(".") | 68 | tree = self.make_branch_and_tree(".") |
757 | 111 | tree.lock_write() | 69 | tree.lock_write() |
758 | @@ -165,41 +123,6 @@ | |||
759 | 165 | actually_updated_branch = (tree.branch.last_revision() == rev_id) | 123 | actually_updated_branch = (tree.branch.last_revision() == rev_id) |
760 | 166 | self.assertEqual(actually_updated_branch, will_update_branch) | 124 | self.assertEqual(actually_updated_branch, will_update_branch) |
761 | 167 | 125 | ||
762 | 168 | def test_commit_with_revision_id_record_entry_contents(self): | ||
763 | 169 | tree = self.make_branch_and_tree(".") | ||
764 | 170 | tree.lock_write() | ||
765 | 171 | try: | ||
766 | 172 | # use a unicode revision id to test more corner cases. | ||
767 | 173 | # The repository layer is meant to handle this. | ||
768 | 174 | revision_id = u'\xc8abc'.encode('utf8') | ||
769 | 175 | try: | ||
770 | 176 | try: | ||
771 | 177 | builder = tree.branch.get_commit_builder([], | ||
772 | 178 | revision_id=revision_id) | ||
773 | 179 | except errors.NonAsciiRevisionId: | ||
774 | 180 | revision_id = 'abc' | ||
775 | 181 | builder = tree.branch.get_commit_builder([], | ||
776 | 182 | revision_id=revision_id) | ||
777 | 183 | except errors.CannotSetRevisionId: | ||
778 | 184 | # This format doesn't support supplied revision ids | ||
779 | 185 | return | ||
780 | 186 | if not builder.supports_record_entry_contents: | ||
781 | 187 | raise tests.TestNotApplicable("CommitBuilder doesn't support " | ||
782 | 188 | "record_entry_contents") | ||
783 | 189 | self.assertFalse(builder.random_revid) | ||
784 | 190 | self.record_root(builder, tree) | ||
785 | 191 | builder.finish_inventory() | ||
786 | 192 | self.assertEqual(revision_id, builder.commit('foo bar')) | ||
787 | 193 | finally: | ||
788 | 194 | tree.unlock() | ||
789 | 195 | self.assertTrue(tree.branch.repository.has_revision(revision_id)) | ||
790 | 196 | # the revision id must be set on the inventory when saving it. This | ||
791 | 197 | # does not precisely test that - a repository that wants to can add it | ||
792 | 198 | # on deserialisation, but thats all the current contract guarantees | ||
793 | 199 | # anyway. | ||
794 | 200 | self.assertEqual(revision_id, | ||
795 | 201 | tree.branch.repository.get_inventory(revision_id).revision_id) | ||
796 | 202 | |||
797 | 203 | def test_commit_with_revision_id_record_iter_changes(self): | 126 | def test_commit_with_revision_id_record_iter_changes(self): |
798 | 204 | tree = self.make_branch_and_tree(".") | 127 | tree = self.make_branch_and_tree(".") |
799 | 205 | tree.lock_write() | 128 | tree.lock_write() |
800 | @@ -256,64 +179,6 @@ | |||
801 | 256 | finally: | 179 | finally: |
802 | 257 | tree.unlock() | 180 | tree.unlock() |
803 | 258 | 181 | ||
804 | 259 | def test_commit_without_root_or_record_iter_changes_errors(self): | ||
805 | 260 | tree = self.make_branch_and_tree(".") | ||
806 | 261 | tree.lock_write() | ||
807 | 262 | try: | ||
808 | 263 | self.build_tree(['foo']) | ||
809 | 264 | tree.add('foo', 'foo-id') | ||
810 | 265 | builder = tree.branch.get_commit_builder([]) | ||
811 | 266 | if not builder.supports_record_entry_contents: | ||
812 | 267 | raise tests.TestNotApplicable("CommitBuilder doesn't support " | ||
813 | 268 | "record_entry_contents") | ||
814 | 269 | entry = tree.root_inventory['foo-id'] | ||
815 | 270 | self.assertRaises(errors.RootMissing, | ||
816 | 271 | builder.record_entry_contents, entry, [], 'foo', tree, | ||
817 | 272 | tree.path_content_summary('foo')) | ||
818 | 273 | builder.abort() | ||
819 | 274 | finally: | ||
820 | 275 | tree.unlock() | ||
821 | 276 | |||
822 | 277 | def test_commit_unchanged_root_record_entry_contents(self): | ||
823 | 278 | tree = self.make_branch_and_tree(".") | ||
824 | 279 | old_revision_id = tree.commit('') | ||
825 | 280 | tree.lock_write() | ||
826 | 281 | parent_tree = tree.basis_tree() | ||
827 | 282 | parent_tree.lock_read() | ||
828 | 283 | self.addCleanup(parent_tree.unlock) | ||
829 | 284 | builder = tree.branch.get_commit_builder([old_revision_id]) | ||
830 | 285 | try: | ||
831 | 286 | if not builder.supports_record_entry_contents: | ||
832 | 287 | raise tests.TestNotApplicable("CommitBuilder doesn't support " | ||
833 | 288 | "record_entry_contents") | ||
834 | 289 | ie = inventory.make_entry('directory', '', None, | ||
835 | 290 | tree.get_root_id()) | ||
836 | 291 | delta, version_recorded, fs_hash = builder.record_entry_contents( | ||
837 | 292 | ie, [parent_tree.root_inventory], '', tree, | ||
838 | 293 | tree.path_content_summary('')) | ||
839 | 294 | # Regardless of repository root behaviour we should consider this a | ||
840 | 295 | # pointless commit. | ||
841 | 296 | self.assertFalse(builder.any_changes()) | ||
842 | 297 | self.assertFalse(version_recorded) | ||
843 | 298 | # if the repository format recorded a new root revision, that | ||
844 | 299 | # should be in the delta | ||
845 | 300 | got_new_revision = ie.revision != old_revision_id | ||
846 | 301 | if got_new_revision: | ||
847 | 302 | self.assertEqual(('', '', ie.file_id, ie), delta) | ||
848 | 303 | # The delta should be tracked | ||
849 | 304 | self.assertEqual(delta, builder.get_basis_delta()[-1]) | ||
850 | 305 | else: | ||
851 | 306 | self.assertEqual(None, delta) | ||
852 | 307 | # Directories do not get hashed. | ||
853 | 308 | self.assertEqual(None, fs_hash) | ||
854 | 309 | builder.abort() | ||
855 | 310 | except: | ||
856 | 311 | builder.abort() | ||
857 | 312 | tree.unlock() | ||
858 | 313 | raise | ||
859 | 314 | else: | ||
860 | 315 | tree.unlock() | ||
861 | 316 | |||
862 | 317 | def test_commit_unchanged_root_record_iter_changes(self): | 182 | def test_commit_unchanged_root_record_iter_changes(self): |
863 | 318 | tree = self.make_branch_and_tree(".") | 183 | tree = self.make_branch_and_tree(".") |
864 | 319 | old_revision_id = tree.commit('') | 184 | old_revision_id = tree.commit('') |
865 | @@ -338,105 +203,6 @@ | |||
866 | 338 | finally: | 203 | finally: |
867 | 339 | tree.unlock() | 204 | tree.unlock() |
868 | 340 | 205 | ||
869 | 341 | def test_commit_record_entry_contents(self): | ||
870 | 342 | tree = self.make_branch_and_tree(".") | ||
871 | 343 | tree.lock_write() | ||
872 | 344 | try: | ||
873 | 345 | builder = tree.branch.get_commit_builder([]) | ||
874 | 346 | if not builder.supports_record_entry_contents: | ||
875 | 347 | raise tests.TestNotApplicable("CommitBuilder doesn't " | ||
876 | 348 | "support record_entry_contents") | ||
877 | 349 | self.record_root(builder, tree) | ||
878 | 350 | builder.finish_inventory() | ||
879 | 351 | rev_id = builder.commit('foo bar') | ||
880 | 352 | finally: | ||
881 | 353 | tree.unlock() | ||
882 | 354 | self.assertNotEqual(None, rev_id) | ||
883 | 355 | self.assertTrue(tree.branch.repository.has_revision(rev_id)) | ||
884 | 356 | # the revision id must be set on the inventory when saving it. This does not | ||
885 | 357 | # precisely test that - a repository that wants to can add it on deserialisation, | ||
886 | 358 | # but thats all the current contract guarantees anyway. | ||
887 | 359 | self.assertEqual(rev_id, tree.branch.repository.get_inventory(rev_id).revision_id) | ||
888 | 360 | |||
889 | 361 | def test_get_basis_delta(self): | ||
890 | 362 | tree = self.make_branch_and_tree(".") | ||
891 | 363 | self.build_tree(["foo"]) | ||
892 | 364 | tree.add(["foo"], ["foo-id"]) | ||
893 | 365 | old_revision_id = tree.commit("added foo") | ||
894 | 366 | tree.lock_write() | ||
895 | 367 | try: | ||
896 | 368 | self.build_tree(['bar']) | ||
897 | 369 | tree.add(['bar'], ['bar-id']) | ||
898 | 370 | basis = tree.branch.repository.revision_tree(old_revision_id) | ||
899 | 371 | basis.lock_read() | ||
900 | 372 | self.addCleanup(basis.unlock) | ||
901 | 373 | builder = tree.branch.get_commit_builder([old_revision_id]) | ||
902 | 374 | total_delta = [] | ||
903 | 375 | try: | ||
904 | 376 | if not builder.supports_record_entry_contents: | ||
905 | 377 | raise tests.TestNotApplicable("CommitBuilder doesn't " | ||
906 | 378 | "support record_entry_contents") | ||
907 | 379 | parent_invs = [basis.root_inventory] | ||
908 | 380 | if builder.record_root_entry: | ||
909 | 381 | ie = basis.root_inventory.root.copy() | ||
910 | 382 | delta, _, _ = builder.record_entry_contents(ie, parent_invs, | ||
911 | 383 | '', tree, tree.path_content_summary('')) | ||
912 | 384 | if delta is not None: | ||
913 | 385 | total_delta.append(delta) | ||
914 | 386 | delta = builder.record_delete("foo", "foo-id") | ||
915 | 387 | total_delta.append(delta) | ||
916 | 388 | new_bar = inventory.make_entry('file', 'bar', | ||
917 | 389 | parent_id=tree.get_root_id(), file_id='bar-id') | ||
918 | 390 | delta, _, _ = builder.record_entry_contents(new_bar, parent_invs, | ||
919 | 391 | 'bar', tree, tree.path_content_summary('bar')) | ||
920 | 392 | total_delta.append(delta) | ||
921 | 393 | # All actions should have been recorded in the basis_delta | ||
922 | 394 | self.assertEqual(total_delta, builder.get_basis_delta()) | ||
923 | 395 | builder.finish_inventory() | ||
924 | 396 | builder.commit('delete foo, add bar') | ||
925 | 397 | except: | ||
926 | 398 | tree.branch.repository.abort_write_group() | ||
927 | 399 | raise | ||
928 | 400 | finally: | ||
929 | 401 | tree.unlock() | ||
930 | 402 | |||
931 | 403 | def test_record_delete(self): | ||
932 | 404 | tree = self.make_branch_and_tree(".") | ||
933 | 405 | self.build_tree(["foo"]) | ||
934 | 406 | tree.add(["foo"], ["foo-id"]) | ||
935 | 407 | rev_id = tree.commit("added foo") | ||
936 | 408 | # Remove the inventory details for foo-id, because | ||
937 | 409 | # record_entry_contents ends up copying root verbatim. | ||
938 | 410 | tree.unversion(["foo-id"]) | ||
939 | 411 | tree.lock_write() | ||
940 | 412 | try: | ||
941 | 413 | basis = tree.branch.repository.revision_tree(rev_id) | ||
942 | 414 | builder = tree.branch.get_commit_builder([rev_id]) | ||
943 | 415 | try: | ||
944 | 416 | if not builder.supports_record_entry_contents: | ||
945 | 417 | raise tests.TestNotApplicable("CommitBuilder doesn't " | ||
946 | 418 | "support record_entry_contents") | ||
947 | 419 | if builder.record_root_entry is True: | ||
948 | 420 | parent_invs = [basis.root_inventory] | ||
949 | 421 | del basis.root_inventory.root.children['foo'] | ||
950 | 422 | builder.record_entry_contents(basis.root_inventory.root, | ||
951 | 423 | parent_invs, '', tree, tree.path_content_summary('')) | ||
952 | 424 | # the delta should be returned, and recorded in _basis_delta | ||
953 | 425 | delta = builder.record_delete("foo", "foo-id") | ||
954 | 426 | self.assertEqual(("foo", None, "foo-id", None), delta) | ||
955 | 427 | self.assertEqual(delta, builder.get_basis_delta()[-1]) | ||
956 | 428 | builder.finish_inventory() | ||
957 | 429 | rev_id2 = builder.commit('delete foo') | ||
958 | 430 | except: | ||
959 | 431 | tree.branch.repository.abort_write_group() | ||
960 | 432 | raise | ||
961 | 433 | finally: | ||
962 | 434 | tree.unlock() | ||
963 | 435 | rev_tree = builder.revision_tree() | ||
964 | 436 | rev_tree.lock_read() | ||
965 | 437 | self.addCleanup(rev_tree.unlock) | ||
966 | 438 | self.assertFalse(rev_tree.path2id('foo')) | ||
967 | 439 | |||
968 | 440 | def test_record_delete_record_iter_changes(self): | 206 | def test_record_delete_record_iter_changes(self): |
969 | 441 | tree = self.make_branch_and_tree(".") | 207 | tree = self.make_branch_and_tree(".") |
970 | 442 | self.build_tree(["foo"]) | 208 | self.build_tree(["foo"]) |
971 | @@ -466,44 +232,6 @@ | |||
972 | 466 | self.addCleanup(rev_tree.unlock) | 232 | self.addCleanup(rev_tree.unlock) |
973 | 467 | self.assertFalse(rev_tree.path2id('foo')) | 233 | self.assertFalse(rev_tree.path2id('foo')) |
974 | 468 | 234 | ||
975 | 469 | def test_record_delete_without_notification(self): | ||
976 | 470 | tree = self.make_branch_and_tree(".") | ||
977 | 471 | self.build_tree(["foo"]) | ||
978 | 472 | tree.add(["foo"], ["foo-id"]) | ||
979 | 473 | rev_id = tree.commit("added foo") | ||
980 | 474 | tree.lock_write() | ||
981 | 475 | try: | ||
982 | 476 | builder = tree.branch.get_commit_builder([rev_id]) | ||
983 | 477 | try: | ||
984 | 478 | if not builder.supports_record_entry_contents: | ||
985 | 479 | raise tests.TestNotApplicable("CommitBuilder doesn't " | ||
986 | 480 | "support record_entry_contents") | ||
987 | 481 | self.record_root(builder, tree) | ||
988 | 482 | builder.record_delete("foo", "foo-id") | ||
989 | 483 | finally: | ||
990 | 484 | tree.branch.repository.abort_write_group() | ||
991 | 485 | finally: | ||
992 | 486 | tree.unlock() | ||
993 | 487 | |||
994 | 488 | def test_revision_tree_record_entry_contents(self): | ||
995 | 489 | tree = self.make_branch_and_tree(".") | ||
996 | 490 | tree.lock_write() | ||
997 | 491 | try: | ||
998 | 492 | builder = tree.branch.get_commit_builder([]) | ||
999 | 493 | if not builder.supports_record_entry_contents: | ||
1000 | 494 | raise tests.TestNotApplicable("CommitBuilder doesn't " | ||
1001 | 495 | "support record_entry_contents") | ||
1002 | 496 | self.record_root(builder, tree) | ||
1003 | 497 | builder.finish_inventory() | ||
1004 | 498 | rev_id = builder.commit('foo bar') | ||
1005 | 499 | finally: | ||
1006 | 500 | tree.unlock() | ||
1007 | 501 | rev_tree = builder.revision_tree() | ||
1008 | 502 | # Just a couple simple tests to ensure that it actually follows | ||
1009 | 503 | # the RevisionTree api. | ||
1010 | 504 | self.assertEqual(rev_id, rev_tree.get_revision_id()) | ||
1011 | 505 | self.assertEqual([], rev_tree.get_parent_ids()) | ||
1012 | 506 | |||
1013 | 507 | def test_revision_tree_record_iter_changes(self): | 235 | def test_revision_tree_record_iter_changes(self): |
1014 | 508 | tree = self.make_branch_and_tree(".") | 236 | tree = self.make_branch_and_tree(".") |
1015 | 509 | tree.lock_write() | 237 | tree.lock_write() |
1016 | @@ -573,8 +301,6 @@ | |||
1017 | 573 | 301 | ||
1018 | 574 | def _commit_check_unchanged(self, tree, name, file_id, mini_commit=None): | 302 | def _commit_check_unchanged(self, tree, name, file_id, mini_commit=None): |
1019 | 575 | rev1 = tree.commit('') | 303 | rev1 = tree.commit('') |
1020 | 576 | if mini_commit is None: | ||
1021 | 577 | mini_commit = self.mini_commit | ||
1022 | 578 | rev2 = mini_commit(tree, name, name, False, False) | 304 | rev2 = mini_commit(tree, name, name, False, False) |
1023 | 579 | tree1, tree2 = self._get_revtrees(tree, [rev1, rev2]) | 305 | tree1, tree2 = self._get_revtrees(tree, [rev1, rev2]) |
1024 | 580 | self.assertEqual(rev1, tree1.get_file_revision(file_id)) | 306 | self.assertEqual(rev1, tree1.get_file_revision(file_id)) |
1025 | @@ -587,12 +313,6 @@ | |||
1026 | 587 | # committing without changing a dir does not change the last modified. | 313 | # committing without changing a dir does not change the last modified. |
1027 | 588 | tree = self.make_branch_and_tree('.') | 314 | tree = self.make_branch_and_tree('.') |
1028 | 589 | self.build_tree(['dir/']) | 315 | self.build_tree(['dir/']) |
1029 | 590 | self._add_commit_check_unchanged(tree, 'dir') | ||
1030 | 591 | |||
1031 | 592 | def test_last_modified_revision_after_commit_dir_unchanged_ric(self): | ||
1032 | 593 | # committing without changing a dir does not change the last modified. | ||
1033 | 594 | tree = self.make_branch_and_tree('.') | ||
1034 | 595 | self.build_tree(['dir/']) | ||
1035 | 596 | self._add_commit_check_unchanged(tree, 'dir', | 316 | self._add_commit_check_unchanged(tree, 'dir', |
1036 | 597 | mini_commit=self.mini_commit_record_iter_changes) | 317 | mini_commit=self.mini_commit_record_iter_changes) |
1037 | 598 | 318 | ||
1038 | @@ -618,12 +338,6 @@ | |||
1039 | 618 | # committing without changing a file does not change the last modified. | 338 | # committing without changing a file does not change the last modified. |
1040 | 619 | tree = self.make_branch_and_tree('.') | 339 | tree = self.make_branch_and_tree('.') |
1041 | 620 | self.build_tree(['file']) | 340 | self.build_tree(['file']) |
1042 | 621 | self._add_commit_check_unchanged(tree, 'file') | ||
1043 | 622 | |||
1044 | 623 | def test_last_modified_revision_after_commit_file_unchanged_ric(self): | ||
1045 | 624 | # committing without changing a file does not change the last modified. | ||
1046 | 625 | tree = self.make_branch_and_tree('.') | ||
1047 | 626 | self.build_tree(['file']) | ||
1048 | 627 | self._add_commit_check_unchanged(tree, 'file', | 341 | self._add_commit_check_unchanged(tree, 'file', |
1049 | 628 | mini_commit=self.mini_commit_record_iter_changes) | 342 | mini_commit=self.mini_commit_record_iter_changes) |
1050 | 629 | 343 | ||
1051 | @@ -632,13 +346,6 @@ | |||
1052 | 632 | self.requireFeature(features.SymlinkFeature) | 346 | self.requireFeature(features.SymlinkFeature) |
1053 | 633 | tree = self.make_branch_and_tree('.') | 347 | tree = self.make_branch_and_tree('.') |
1054 | 634 | os.symlink('target', 'link') | 348 | os.symlink('target', 'link') |
1055 | 635 | self._add_commit_check_unchanged(tree, 'link') | ||
1056 | 636 | |||
1057 | 637 | def test_last_modified_revision_after_commit_link_unchanged_ric(self): | ||
1058 | 638 | # committing without changing a link does not change the last modified. | ||
1059 | 639 | self.requireFeature(features.SymlinkFeature) | ||
1060 | 640 | tree = self.make_branch_and_tree('.') | ||
1061 | 641 | os.symlink('target', 'link') | ||
1062 | 642 | self._add_commit_check_unchanged(tree, 'link', | 349 | self._add_commit_check_unchanged(tree, 'link', |
1063 | 643 | mini_commit=self.mini_commit_record_iter_changes) | 350 | mini_commit=self.mini_commit_record_iter_changes) |
1064 | 644 | 351 | ||
1065 | @@ -650,18 +357,6 @@ | |||
1066 | 650 | try: | 357 | try: |
1067 | 651 | tree.add_reference(subtree) | 358 | tree.add_reference(subtree) |
1068 | 652 | self._commit_check_unchanged(tree, 'reference', | 359 | self._commit_check_unchanged(tree, 'reference', |
1069 | 653 | subtree.get_root_id()) | ||
1070 | 654 | except errors.UnsupportedOperation: | ||
1071 | 655 | return | ||
1072 | 656 | |||
1073 | 657 | def test_last_modified_revision_after_commit_reference_unchanged_ric(self): | ||
1074 | 658 | # committing without changing a subtree does not change the last | ||
1075 | 659 | # modified. | ||
1076 | 660 | tree = self.make_branch_and_tree('.') | ||
1077 | 661 | subtree = self.make_reference('reference') | ||
1078 | 662 | try: | ||
1079 | 663 | tree.add_reference(subtree) | ||
1080 | 664 | self._commit_check_unchanged(tree, 'reference', | ||
1081 | 665 | subtree.get_root_id(), | 360 | subtree.get_root_id(), |
1082 | 666 | mini_commit=self.mini_commit_record_iter_changes) | 361 | mini_commit=self.mini_commit_record_iter_changes) |
1083 | 667 | except errors.UnsupportedOperation: | 362 | except errors.UnsupportedOperation: |
1084 | @@ -685,12 +380,6 @@ | |||
1085 | 685 | # renaming a dir changes the last modified. | 380 | # renaming a dir changes the last modified. |
1086 | 686 | tree = self.make_branch_and_tree('.') | 381 | tree = self.make_branch_and_tree('.') |
1087 | 687 | self.build_tree(['dir/']) | 382 | self.build_tree(['dir/']) |
1088 | 688 | self._add_commit_renamed_check_changed(tree, 'dir') | ||
1089 | 689 | |||
1090 | 690 | def test_last_modified_revision_after_rename_dir_changes_ric(self): | ||
1091 | 691 | # renaming a dir changes the last modified. | ||
1092 | 692 | tree = self.make_branch_and_tree('.') | ||
1093 | 693 | self.build_tree(['dir/']) | ||
1094 | 694 | self._add_commit_renamed_check_changed(tree, 'dir', | 383 | self._add_commit_renamed_check_changed(tree, 'dir', |
1095 | 695 | mini_commit=self.mini_commit_record_iter_changes) | 384 | mini_commit=self.mini_commit_record_iter_changes) |
1096 | 696 | 385 | ||
1097 | @@ -699,13 +388,6 @@ | |||
1098 | 699 | tree = self.make_branch_and_tree('.') | 388 | tree = self.make_branch_and_tree('.') |
1099 | 700 | self.build_tree(['file']) | 389 | self.build_tree(['file']) |
1100 | 701 | self._add_commit_renamed_check_changed(tree, 'file', | 390 | self._add_commit_renamed_check_changed(tree, 'file', |
1101 | 702 | expect_fs_hash=True) | ||
1102 | 703 | |||
1103 | 704 | def test_last_modified_revision_after_rename_file_changes_ric(self): | ||
1104 | 705 | # renaming a file changes the last modified. | ||
1105 | 706 | tree = self.make_branch_and_tree('.') | ||
1106 | 707 | self.build_tree(['file']) | ||
1107 | 708 | self._add_commit_renamed_check_changed(tree, 'file', | ||
1108 | 709 | expect_fs_hash=True, | 391 | expect_fs_hash=True, |
1109 | 710 | mini_commit=self.mini_commit_record_iter_changes) | 392 | mini_commit=self.mini_commit_record_iter_changes) |
1110 | 711 | 393 | ||
1111 | @@ -714,13 +396,6 @@ | |||
1112 | 714 | self.requireFeature(features.SymlinkFeature) | 396 | self.requireFeature(features.SymlinkFeature) |
1113 | 715 | tree = self.make_branch_and_tree('.') | 397 | tree = self.make_branch_and_tree('.') |
1114 | 716 | os.symlink('target', 'link') | 398 | os.symlink('target', 'link') |
1115 | 717 | self._add_commit_renamed_check_changed(tree, 'link') | ||
1116 | 718 | |||
1117 | 719 | def test_last_modified_revision_after_rename_link_changes_ric(self): | ||
1118 | 720 | # renaming a link changes the last modified. | ||
1119 | 721 | self.requireFeature(features.SymlinkFeature) | ||
1120 | 722 | tree = self.make_branch_and_tree('.') | ||
1121 | 723 | os.symlink('target', 'link') | ||
1122 | 724 | self._add_commit_renamed_check_changed(tree, 'link', | 399 | self._add_commit_renamed_check_changed(tree, 'link', |
1123 | 725 | mini_commit=self.mini_commit_record_iter_changes) | 400 | mini_commit=self.mini_commit_record_iter_changes) |
1124 | 726 | 401 | ||
1125 | @@ -731,17 +406,6 @@ | |||
1126 | 731 | try: | 406 | try: |
1127 | 732 | tree.add_reference(subtree) | 407 | tree.add_reference(subtree) |
1128 | 733 | self._commit_renamed_check_changed(tree, 'reference', | 408 | self._commit_renamed_check_changed(tree, 'reference', |
1129 | 734 | subtree.get_root_id()) | ||
1130 | 735 | except errors.UnsupportedOperation: | ||
1131 | 736 | return | ||
1132 | 737 | |||
1133 | 738 | def test_last_modified_revision_after_rename_ref_changes_ric(self): | ||
1134 | 739 | # renaming a reference changes the last modified. | ||
1135 | 740 | tree = self.make_branch_and_tree('.') | ||
1136 | 741 | subtree = self.make_reference('reference') | ||
1137 | 742 | try: | ||
1138 | 743 | tree.add_reference(subtree) | ||
1139 | 744 | self._commit_renamed_check_changed(tree, 'reference', | ||
1140 | 745 | subtree.get_root_id(), | 409 | subtree.get_root_id(), |
1141 | 746 | mini_commit=self.mini_commit_record_iter_changes) | 410 | mini_commit=self.mini_commit_record_iter_changes) |
1142 | 747 | except errors.UnsupportedOperation: | 411 | except errors.UnsupportedOperation: |
1143 | @@ -760,12 +424,6 @@ | |||
1144 | 760 | # reparenting a dir changes the last modified. | 424 | # reparenting a dir changes the last modified. |
1145 | 761 | tree = self.make_branch_and_tree('.') | 425 | tree = self.make_branch_and_tree('.') |
1146 | 762 | self.build_tree(['dir/']) | 426 | self.build_tree(['dir/']) |
1147 | 763 | self._add_commit_reparent_check_changed(tree, 'dir') | ||
1148 | 764 | |||
1149 | 765 | def test_last_modified_revision_after_reparent_dir_changes_ric(self): | ||
1150 | 766 | # reparenting a dir changes the last modified. | ||
1151 | 767 | tree = self.make_branch_and_tree('.') | ||
1152 | 768 | self.build_tree(['dir/']) | ||
1153 | 769 | self._add_commit_reparent_check_changed(tree, 'dir', | 427 | self._add_commit_reparent_check_changed(tree, 'dir', |
1154 | 770 | mini_commit=self.mini_commit_record_iter_changes) | 428 | mini_commit=self.mini_commit_record_iter_changes) |
1155 | 771 | 429 | ||
1156 | @@ -774,13 +432,6 @@ | |||
1157 | 774 | tree = self.make_branch_and_tree('.') | 432 | tree = self.make_branch_and_tree('.') |
1158 | 775 | self.build_tree(['file']) | 433 | self.build_tree(['file']) |
1159 | 776 | self._add_commit_reparent_check_changed(tree, 'file', | 434 | self._add_commit_reparent_check_changed(tree, 'file', |
1160 | 777 | expect_fs_hash=True) | ||
1161 | 778 | |||
1162 | 779 | def test_last_modified_revision_after_reparent_file_changes_ric(self): | ||
1163 | 780 | # reparenting a file changes the last modified. | ||
1164 | 781 | tree = self.make_branch_and_tree('.') | ||
1165 | 782 | self.build_tree(['file']) | ||
1166 | 783 | self._add_commit_reparent_check_changed(tree, 'file', | ||
1167 | 784 | expect_fs_hash=True, | 435 | expect_fs_hash=True, |
1168 | 785 | mini_commit=self.mini_commit_record_iter_changes) | 436 | mini_commit=self.mini_commit_record_iter_changes) |
1169 | 786 | 437 | ||
1170 | @@ -789,13 +440,6 @@ | |||
1171 | 789 | self.requireFeature(features.SymlinkFeature) | 440 | self.requireFeature(features.SymlinkFeature) |
1172 | 790 | tree = self.make_branch_and_tree('.') | 441 | tree = self.make_branch_and_tree('.') |
1173 | 791 | os.symlink('target', 'link') | 442 | os.symlink('target', 'link') |
1174 | 792 | self._add_commit_reparent_check_changed(tree, 'link') | ||
1175 | 793 | |||
1176 | 794 | def test_last_modified_revision_after_reparent_link_changes_ric(self): | ||
1177 | 795 | # reparenting a link changes the last modified. | ||
1178 | 796 | self.requireFeature(features.SymlinkFeature) | ||
1179 | 797 | tree = self.make_branch_and_tree('.') | ||
1180 | 798 | os.symlink('target', 'link') | ||
1181 | 799 | self._add_commit_reparent_check_changed(tree, 'link', | 443 | self._add_commit_reparent_check_changed(tree, 'link', |
1182 | 800 | mini_commit=self.mini_commit_record_iter_changes) | 444 | mini_commit=self.mini_commit_record_iter_changes) |
1183 | 801 | 445 | ||
1184 | @@ -812,8 +456,6 @@ | |||
1185 | 812 | expect_fs_hash=False, mini_commit=None): | 456 | expect_fs_hash=False, mini_commit=None): |
1186 | 813 | rev1 = tree.commit('') | 457 | rev1 = tree.commit('') |
1187 | 814 | changer() | 458 | changer() |
1188 | 815 | if mini_commit is None: | ||
1189 | 816 | mini_commit = self.mini_commit | ||
1190 | 817 | rev2 = mini_commit(tree, name, tree.id2path(file_id), | 459 | rev2 = mini_commit(tree, name, tree.id2path(file_id), |
1191 | 818 | expect_fs_hash=expect_fs_hash) | 460 | expect_fs_hash=expect_fs_hash) |
1192 | 819 | tree1, tree2 = self._get_revtrees(tree, [rev1, rev2]) | 461 | tree1, tree2 = self._get_revtrees(tree, [rev1, rev2]) |
1193 | @@ -824,97 +466,6 @@ | |||
1194 | 824 | expected_graph[(file_id, rev2)] = ((file_id, rev1),) | 466 | expected_graph[(file_id, rev2)] = ((file_id, rev1),) |
1195 | 825 | self.assertFileGraph(expected_graph, tree, (file_id, rev2)) | 467 | self.assertFileGraph(expected_graph, tree, (file_id, rev2)) |
1196 | 826 | 468 | ||
1197 | 827 | def mini_commit(self, tree, name, new_name, records_version=True, | ||
1198 | 828 | delta_against_basis=True, expect_fs_hash=False): | ||
1199 | 829 | """Perform a miniature commit looking for record entry results. | ||
1200 | 830 | |||
1201 | 831 | :param tree: The tree to commit. | ||
1202 | 832 | :param name: The path in the basis tree of the tree being committed. | ||
1203 | 833 | :param new_name: The path in the tree being committed. | ||
1204 | 834 | :param records_version: True if the commit of new_name is expected to | ||
1205 | 835 | record a new version. | ||
1206 | 836 | :param delta_against_basis: True of the commit of new_name is expected | ||
1207 | 837 | to have a delta against the basis. | ||
1208 | 838 | :param expect_fs_hash: True or false to indicate whether we expect a | ||
1209 | 839 | file hash to be returned from the record_entry_contents call. | ||
1210 | 840 | """ | ||
1211 | 841 | tree.lock_write() | ||
1212 | 842 | try: | ||
1213 | 843 | # mini manual commit here so we can check the return of | ||
1214 | 844 | # record_entry_contents. | ||
1215 | 845 | parent_ids = tree.get_parent_ids() | ||
1216 | 846 | builder = tree.branch.get_commit_builder(parent_ids) | ||
1217 | 847 | try: | ||
1218 | 848 | if not builder.supports_record_entry_contents: | ||
1219 | 849 | raise tests.TestNotApplicable("CommitBuilder doesn't " | ||
1220 | 850 | "support record_entry_contents") | ||
1221 | 851 | parent_tree = tree.basis_tree() | ||
1222 | 852 | parent_tree.lock_read() | ||
1223 | 853 | self.addCleanup(parent_tree.unlock) | ||
1224 | 854 | parent_invs = [parent_tree.root_inventory] | ||
1225 | 855 | for parent_id in parent_ids[1:]: | ||
1226 | 856 | parent_invs.append(tree.branch.repository.revision_tree( | ||
1227 | 857 | parent_id).root_inventory) | ||
1228 | 858 | # root | ||
1229 | 859 | builder.record_entry_contents( | ||
1230 | 860 | inventory.make_entry('directory', '', None, | ||
1231 | 861 | tree.get_root_id()), parent_invs, '', tree, | ||
1232 | 862 | tree.path_content_summary('')) | ||
1233 | 863 | def commit_id(file_id): | ||
1234 | 864 | old_ie = tree.root_inventory[file_id] | ||
1235 | 865 | path = tree.id2path(file_id) | ||
1236 | 866 | ie = inventory.make_entry(tree.kind(file_id), old_ie.name, | ||
1237 | 867 | old_ie.parent_id, file_id) | ||
1238 | 868 | content_summary = tree.path_content_summary(path) | ||
1239 | 869 | if content_summary[0] == 'tree-reference': | ||
1240 | 870 | content_summary = content_summary[:3] + ( | ||
1241 | 871 | tree.get_reference_revision(file_id),) | ||
1242 | 872 | return builder.record_entry_contents(ie, parent_invs, path, | ||
1243 | 873 | tree, content_summary) | ||
1244 | 874 | |||
1245 | 875 | file_id = tree.path2id(new_name) | ||
1246 | 876 | parent_id = tree.root_inventory[file_id].parent_id | ||
1247 | 877 | if parent_id != tree.get_root_id(): | ||
1248 | 878 | commit_id(parent_id) | ||
1249 | 879 | # because a change of some sort is meant to have occurred, | ||
1250 | 880 | # recording the entry must return True. | ||
1251 | 881 | delta, version_recorded, fs_hash = commit_id(file_id) | ||
1252 | 882 | if records_version: | ||
1253 | 883 | self.assertTrue(version_recorded) | ||
1254 | 884 | else: | ||
1255 | 885 | self.assertFalse(version_recorded) | ||
1256 | 886 | if expect_fs_hash: | ||
1257 | 887 | tree_file_stat = tree.get_file_with_stat(file_id) | ||
1258 | 888 | tree_file_stat[0].close() | ||
1259 | 889 | self.assertEqual(2, len(fs_hash)) | ||
1260 | 890 | self.assertEqual(tree.get_file_sha1(file_id), fs_hash[0]) | ||
1261 | 891 | self.assertEqualStat(tree_file_stat[1], fs_hash[1]) | ||
1262 | 892 | else: | ||
1263 | 893 | self.assertEqual(None, fs_hash) | ||
1264 | 894 | new_entry = builder.new_inventory[file_id] | ||
1265 | 895 | if delta_against_basis: | ||
1266 | 896 | expected_delta = (name, new_name, file_id, new_entry) | ||
1267 | 897 | # The delta should be recorded | ||
1268 | 898 | self.assertEqual(expected_delta, | ||
1269 | 899 | builder.get_basis_delta()[-1]) | ||
1270 | 900 | else: | ||
1271 | 901 | expected_delta = None | ||
1272 | 902 | self.assertEqual(expected_delta, delta) | ||
1273 | 903 | builder.finish_inventory() | ||
1274 | 904 | except: | ||
1275 | 905 | builder.abort() | ||
1276 | 906 | raise | ||
1277 | 907 | else: | ||
1278 | 908 | rev2 = builder.commit('') | ||
1279 | 909 | except: | ||
1280 | 910 | tree.unlock() | ||
1281 | 911 | raise | ||
1282 | 912 | try: | ||
1283 | 913 | tree.set_parent_ids([rev2]) | ||
1284 | 914 | finally: | ||
1285 | 915 | tree.unlock() | ||
1286 | 916 | return rev2 | ||
1287 | 917 | |||
1288 | 918 | def mini_commit_record_iter_changes(self, tree, name, new_name, | 469 | def mini_commit_record_iter_changes(self, tree, name, new_name, |
1289 | 919 | records_version=True, delta_against_basis=True, expect_fs_hash=False): | 470 | records_version=True, delta_against_basis=True, expect_fs_hash=False): |
1290 | 920 | """Perform a miniature commit looking for record entry results. | 471 | """Perform a miniature commit looking for record entry results. |
1291 | @@ -934,7 +485,7 @@ | |||
1292 | 934 | tree.lock_write() | 485 | tree.lock_write() |
1293 | 935 | try: | 486 | try: |
1294 | 936 | # mini manual commit here so we can check the return of | 487 | # mini manual commit here so we can check the return of |
1296 | 937 | # record_entry_contents. | 488 | # record_iter_changes |
1297 | 938 | parent_ids = tree.get_parent_ids() | 489 | parent_ids = tree.get_parent_ids() |
1298 | 939 | builder = tree.branch.get_commit_builder(parent_ids) | 490 | builder = tree.branch.get_commit_builder(parent_ids) |
1299 | 940 | parent_tree = tree.basis_tree() | 491 | parent_tree = tree.basis_tree() |
1300 | @@ -958,14 +509,12 @@ | |||
1301 | 958 | self.assertEqualStat(result[2][1], tree_file_stat[1]) | 509 | self.assertEqualStat(result[2][1], tree_file_stat[1]) |
1302 | 959 | else: | 510 | else: |
1303 | 960 | self.assertEqual([], result) | 511 | self.assertEqual([], result) |
1304 | 961 | self.assertIs(None, builder.new_inventory) | ||
1305 | 962 | builder.finish_inventory() | 512 | builder.finish_inventory() |
1306 | 963 | if tree.branch.repository._format.supports_full_versioned_files: | 513 | if tree.branch.repository._format.supports_full_versioned_files: |
1307 | 964 | inv_key = (builder._new_revision_id,) | 514 | inv_key = (builder._new_revision_id,) |
1308 | 965 | inv_sha1 = tree.branch.repository.inventories.get_sha1s( | 515 | inv_sha1 = tree.branch.repository.inventories.get_sha1s( |
1309 | 966 | [inv_key])[inv_key] | 516 | [inv_key])[inv_key] |
1310 | 967 | self.assertEqual(inv_sha1, builder.inv_sha1) | 517 | self.assertEqual(inv_sha1, builder.inv_sha1) |
1311 | 968 | self.assertIs(None, builder.new_inventory) | ||
1312 | 969 | rev2 = builder.commit('') | 518 | rev2 = builder.commit('') |
1313 | 970 | delta = builder.get_basis_delta() | 519 | delta = builder.get_basis_delta() |
1314 | 971 | delta_dict = dict((change[2], change) for change in delta) | 520 | delta_dict = dict((change[2], change) for change in delta) |
1315 | @@ -1009,29 +558,10 @@ | |||
1316 | 1009 | def change_file(): | 558 | def change_file(): |
1317 | 1010 | tree.put_file_bytes_non_atomic('fileid', 'new content') | 559 | tree.put_file_bytes_non_atomic('fileid', 'new content') |
1318 | 1011 | self._add_commit_change_check_changed(tree, 'file', change_file, | 560 | self._add_commit_change_check_changed(tree, 'file', change_file, |
1319 | 1012 | expect_fs_hash=True) | ||
1320 | 1013 | |||
1321 | 1014 | def test_last_modified_revision_after_content_file_changes_ric(self): | ||
1322 | 1015 | # altering a file changes the last modified. | ||
1323 | 1016 | tree = self.make_branch_and_tree('.') | ||
1324 | 1017 | self.build_tree(['file']) | ||
1325 | 1018 | def change_file(): | ||
1326 | 1019 | tree.put_file_bytes_non_atomic('fileid', 'new content') | ||
1327 | 1020 | self._add_commit_change_check_changed(tree, 'file', change_file, | ||
1328 | 1021 | expect_fs_hash=True, | 561 | expect_fs_hash=True, |
1329 | 1022 | mini_commit=self.mini_commit_record_iter_changes) | 562 | mini_commit=self.mini_commit_record_iter_changes) |
1330 | 1023 | 563 | ||
1342 | 1024 | def test_last_modified_revision_after_content_link_changes(self): | 564 | def _test_last_mod_rev_after_content_link_changes( |
1332 | 1025 | # changing a link changes the last modified. | ||
1333 | 1026 | self.requireFeature(features.SymlinkFeature) | ||
1334 | 1027 | tree = self.make_branch_and_tree('.') | ||
1335 | 1028 | os.symlink('target', 'link') | ||
1336 | 1029 | def change_link(): | ||
1337 | 1030 | os.unlink('link') | ||
1338 | 1031 | os.symlink('newtarget', 'link') | ||
1339 | 1032 | self._add_commit_change_check_changed(tree, 'link', change_link) | ||
1340 | 1033 | |||
1341 | 1034 | def _test_last_mod_rev_after_content_link_changes_ric( | ||
1343 | 1035 | self, link, target, newtarget, file_id=None): | 565 | self, link, target, newtarget, file_id=None): |
1344 | 1036 | if file_id is None: | 566 | if file_id is None: |
1345 | 1037 | file_id = link | 567 | file_id = link |
1346 | @@ -1047,13 +577,13 @@ | |||
1347 | 1047 | mini_commit=self.mini_commit_record_iter_changes, | 577 | mini_commit=self.mini_commit_record_iter_changes, |
1348 | 1048 | file_id=file_id) | 578 | file_id=file_id) |
1349 | 1049 | 579 | ||
1352 | 1050 | def test_last_modified_rev_after_content_link_changes_ric(self): | 580 | def test_last_modified_rev_after_content_link_changes(self): |
1353 | 1051 | self._test_last_mod_rev_after_content_link_changes_ric( | 581 | self._test_last_mod_rev_after_content_link_changes( |
1354 | 1052 | 'link', 'target', 'newtarget') | 582 | 'link', 'target', 'newtarget') |
1355 | 1053 | 583 | ||
1357 | 1054 | def test_last_modified_rev_after_content_unicode_link_changes_ric(self): | 584 | def test_last_modified_rev_after_content_unicode_link_changes(self): |
1358 | 1055 | self.requireFeature(features.UnicodeFilenameFeature) | 585 | self.requireFeature(features.UnicodeFilenameFeature) |
1360 | 1056 | self._test_last_mod_rev_after_content_link_changes_ric( | 586 | self._test_last_mod_rev_after_content_link_changes( |
1361 | 1057 | u'li\u1234nk', u'targ\N{Euro Sign}t', u'n\N{Euro Sign}wtarget', | 587 | u'li\u1234nk', u'targ\N{Euro Sign}t', u'n\N{Euro Sign}wtarget', |
1362 | 1058 | 588 | ||
1363 | 1059 | file_id=u'li\u1234nk'.encode('UTF-8')) | 589 | file_id=u'li\u1234nk'.encode('UTF-8')) |
1364 | @@ -1075,8 +605,6 @@ | |||
1365 | 1075 | rev2 = self._rename_in_tree(tree1, name) | 605 | rev2 = self._rename_in_tree(tree1, name) |
1366 | 1076 | rev3 = self._rename_in_tree(tree2, name) | 606 | rev3 = self._rename_in_tree(tree2, name) |
1367 | 1077 | tree1.merge_from_branch(tree2.branch) | 607 | tree1.merge_from_branch(tree2.branch) |
1368 | 1078 | if mini_commit is None: | ||
1369 | 1079 | mini_commit = self.mini_commit | ||
1370 | 1080 | rev4 = mini_commit(tree1, 'new_' + name, 'new_' + name, | 608 | rev4 = mini_commit(tree1, 'new_' + name, 'new_' + name, |
1371 | 1081 | expect_fs_hash=expect_fs_hash) | 609 | expect_fs_hash=expect_fs_hash) |
1372 | 1082 | tree3, = self._get_revtrees(tree1, [rev4]) | 610 | tree3, = self._get_revtrees(tree1, [rev4]) |
1373 | @@ -1093,12 +621,6 @@ | |||
1374 | 1093 | # merge a dir changes the last modified. | 621 | # merge a dir changes the last modified. |
1375 | 1094 | tree1 = self.make_branch_and_tree('t1') | 622 | tree1 = self.make_branch_and_tree('t1') |
1376 | 1095 | self.build_tree(['t1/dir/']) | 623 | self.build_tree(['t1/dir/']) |
1377 | 1096 | self._commit_sprout_rename_merge(tree1, 'dir') | ||
1378 | 1097 | |||
1379 | 1098 | def test_last_modified_revision_after_merge_dir_changes_ric(self): | ||
1380 | 1099 | # merge a dir changes the last modified. | ||
1381 | 1100 | tree1 = self.make_branch_and_tree('t1') | ||
1382 | 1101 | self.build_tree(['t1/dir/']) | ||
1383 | 1102 | self._commit_sprout_rename_merge(tree1, 'dir', | 624 | self._commit_sprout_rename_merge(tree1, 'dir', |
1384 | 1103 | mini_commit=self.mini_commit_record_iter_changes) | 625 | mini_commit=self.mini_commit_record_iter_changes) |
1385 | 1104 | 626 | ||
1386 | @@ -1106,12 +628,6 @@ | |||
1387 | 1106 | # merge a file changes the last modified. | 628 | # merge a file changes the last modified. |
1388 | 1107 | tree1 = self.make_branch_and_tree('t1') | 629 | tree1 = self.make_branch_and_tree('t1') |
1389 | 1108 | self.build_tree(['t1/file']) | 630 | self.build_tree(['t1/file']) |
1390 | 1109 | self._commit_sprout_rename_merge(tree1, 'file', expect_fs_hash=True) | ||
1391 | 1110 | |||
1392 | 1111 | def test_last_modified_revision_after_merge_file_changes_ric(self): | ||
1393 | 1112 | # merge a file changes the last modified. | ||
1394 | 1113 | tree1 = self.make_branch_and_tree('t1') | ||
1395 | 1114 | self.build_tree(['t1/file']) | ||
1396 | 1115 | self._commit_sprout_rename_merge(tree1, 'file', expect_fs_hash=True, | 631 | self._commit_sprout_rename_merge(tree1, 'file', expect_fs_hash=True, |
1397 | 1116 | mini_commit=self.mini_commit_record_iter_changes) | 632 | mini_commit=self.mini_commit_record_iter_changes) |
1398 | 1117 | 633 | ||
1399 | @@ -1120,13 +636,6 @@ | |||
1400 | 1120 | self.requireFeature(features.SymlinkFeature) | 636 | self.requireFeature(features.SymlinkFeature) |
1401 | 1121 | tree1 = self.make_branch_and_tree('t1') | 637 | tree1 = self.make_branch_and_tree('t1') |
1402 | 1122 | os.symlink('target', 't1/link') | 638 | os.symlink('target', 't1/link') |
1403 | 1123 | self._commit_sprout_rename_merge(tree1, 'link') | ||
1404 | 1124 | |||
1405 | 1125 | def test_last_modified_revision_after_merge_link_changes_ric(self): | ||
1406 | 1126 | # merge a link changes the last modified. | ||
1407 | 1127 | self.requireFeature(features.SymlinkFeature) | ||
1408 | 1128 | tree1 = self.make_branch_and_tree('t1') | ||
1409 | 1129 | os.symlink('target', 't1/link') | ||
1410 | 1130 | self._commit_sprout_rename_merge(tree1, 'link', | 639 | self._commit_sprout_rename_merge(tree1, 'link', |
1411 | 1131 | mini_commit=self.mini_commit_record_iter_changes) | 640 | mini_commit=self.mini_commit_record_iter_changes) |
1412 | 1132 | 641 | ||
1413 | @@ -1140,8 +649,6 @@ | |||
1414 | 1140 | # change on the other side to merge back | 649 | # change on the other side to merge back |
1415 | 1141 | rev2 = self._rename_in_tree(tree2, name) | 650 | rev2 = self._rename_in_tree(tree2, name) |
1416 | 1142 | tree1.merge_from_branch(tree2.branch) | 651 | tree1.merge_from_branch(tree2.branch) |
1417 | 1143 | if mini_commit is None: | ||
1418 | 1144 | mini_commit = self.mini_commit | ||
1419 | 1145 | def _check_graph(in_tree, changed_in_tree): | 652 | def _check_graph(in_tree, changed_in_tree): |
1420 | 1146 | rev3 = mini_commit(in_tree, name, 'new_' + name, False, | 653 | rev3 = mini_commit(in_tree, name, 'new_' + name, False, |
1421 | 1147 | delta_against_basis=changed_in_tree) | 654 | delta_against_basis=changed_in_tree) |
1422 | @@ -1173,8 +680,6 @@ | |||
1423 | 1173 | tree2.add(['name'], [file_id]) | 680 | tree2.add(['name'], [file_id]) |
1424 | 1174 | rev2 = tree2.commit('') | 681 | rev2 = tree2.commit('') |
1425 | 1175 | tree1.merge_from_branch(tree2.branch) | 682 | tree1.merge_from_branch(tree2.branch) |
1426 | 1176 | if mini_commit is None: | ||
1427 | 1177 | mini_commit = self.mini_commit | ||
1428 | 1178 | rev3 = mini_commit(tree1, None, 'name', False) | 683 | rev3 = mini_commit(tree1, None, 'name', False) |
1429 | 1179 | tree3, = self._get_revtrees(tree1, [rev2]) | 684 | tree3, = self._get_revtrees(tree1, [rev2]) |
1430 | 1180 | # in rev2, name should be only changed in rev2 | 685 | # in rev2, name should be only changed in rev2 |
1431 | @@ -1187,12 +692,6 @@ | |||
1432 | 1187 | # merge a dir that changed preserves the last modified. | 692 | # merge a dir that changed preserves the last modified. |
1433 | 1188 | tree1 = self.make_branch_and_tree('t1') | 693 | tree1 = self.make_branch_and_tree('t1') |
1434 | 1189 | self.build_tree(['t1/dir/']) | 694 | self.build_tree(['t1/dir/']) |
1435 | 1190 | self._commit_sprout_rename_merge_converged(tree1, 'dir') | ||
1436 | 1191 | |||
1437 | 1192 | def test_last_modified_revision_after_converged_merge_dir_unchanged_ric(self): | ||
1438 | 1193 | # merge a dir that changed preserves the last modified. | ||
1439 | 1194 | tree1 = self.make_branch_and_tree('t1') | ||
1440 | 1195 | self.build_tree(['t1/dir/']) | ||
1441 | 1196 | self._commit_sprout_rename_merge_converged(tree1, 'dir', | 695 | self._commit_sprout_rename_merge_converged(tree1, 'dir', |
1442 | 1197 | mini_commit=self.mini_commit_record_iter_changes) | 696 | mini_commit=self.mini_commit_record_iter_changes) |
1443 | 1198 | 697 | ||
1444 | @@ -1200,12 +699,6 @@ | |||
1445 | 1200 | # merge a file that changed preserves the last modified. | 699 | # merge a file that changed preserves the last modified. |
1446 | 1201 | tree1 = self.make_branch_and_tree('t1') | 700 | tree1 = self.make_branch_and_tree('t1') |
1447 | 1202 | self.build_tree(['t1/file']) | 701 | self.build_tree(['t1/file']) |
1448 | 1203 | self._commit_sprout_rename_merge_converged(tree1, 'file') | ||
1449 | 1204 | |||
1450 | 1205 | def test_last_modified_revision_after_converged_merge_file_unchanged_ric(self): | ||
1451 | 1206 | # merge a file that changed preserves the last modified. | ||
1452 | 1207 | tree1 = self.make_branch_and_tree('t1') | ||
1453 | 1208 | self.build_tree(['t1/file']) | ||
1454 | 1209 | self._commit_sprout_rename_merge_converged(tree1, 'file', | 702 | self._commit_sprout_rename_merge_converged(tree1, 'file', |
1455 | 1210 | mini_commit=self.mini_commit_record_iter_changes) | 703 | mini_commit=self.mini_commit_record_iter_changes) |
1456 | 1211 | 704 | ||
1457 | @@ -1214,46 +707,24 @@ | |||
1458 | 1214 | self.requireFeature(features.SymlinkFeature) | 707 | self.requireFeature(features.SymlinkFeature) |
1459 | 1215 | tree1 = self.make_branch_and_tree('t1') | 708 | tree1 = self.make_branch_and_tree('t1') |
1460 | 1216 | os.symlink('target', 't1/link') | 709 | os.symlink('target', 't1/link') |
1461 | 1217 | self._commit_sprout_rename_merge_converged(tree1, 'link') | ||
1462 | 1218 | |||
1463 | 1219 | def test_last_modified_revision_after_converged_merge_link_unchanged_ric(self): | ||
1464 | 1220 | # merge a link that changed preserves the last modified. | ||
1465 | 1221 | self.requireFeature(features.SymlinkFeature) | ||
1466 | 1222 | tree1 = self.make_branch_and_tree('t1') | ||
1467 | 1223 | os.symlink('target', 't1/link') | ||
1468 | 1224 | self._commit_sprout_rename_merge_converged(tree1, 'link', | 710 | self._commit_sprout_rename_merge_converged(tree1, 'link', |
1469 | 1225 | mini_commit=self.mini_commit_record_iter_changes) | 711 | mini_commit=self.mini_commit_record_iter_changes) |
1470 | 1226 | 712 | ||
1471 | 1227 | def test_last_modified_revision_after_merge_new_dir_unchanged(self): | 713 | def test_last_modified_revision_after_merge_new_dir_unchanged(self): |
1472 | 1228 | # merge a new dir does not change the last modified. | 714 | # merge a new dir does not change the last modified. |
1473 | 1229 | tree1 = self.make_branch_and_tree('t1') | 715 | tree1 = self.make_branch_and_tree('t1') |
1474 | 1230 | self._commit_sprout_make_merge(tree1, self.make_dir) | ||
1475 | 1231 | |||
1476 | 1232 | def test_last_modified_revision_after_merge_new_dir_unchanged_ric(self): | ||
1477 | 1233 | # merge a new dir does not change the last modified. | ||
1478 | 1234 | tree1 = self.make_branch_and_tree('t1') | ||
1479 | 1235 | self._commit_sprout_make_merge(tree1, self.make_dir, | 716 | self._commit_sprout_make_merge(tree1, self.make_dir, |
1480 | 1236 | mini_commit=self.mini_commit_record_iter_changes) | 717 | mini_commit=self.mini_commit_record_iter_changes) |
1481 | 1237 | 718 | ||
1482 | 1238 | def test_last_modified_revision_after_merge_new_file_unchanged(self): | 719 | def test_last_modified_revision_after_merge_new_file_unchanged(self): |
1483 | 1239 | # merge a new file does not change the last modified. | 720 | # merge a new file does not change the last modified. |
1484 | 1240 | tree1 = self.make_branch_and_tree('t1') | 721 | tree1 = self.make_branch_and_tree('t1') |
1485 | 1241 | self._commit_sprout_make_merge(tree1, self.make_file) | ||
1486 | 1242 | |||
1487 | 1243 | def test_last_modified_revision_after_merge_new_file_unchanged_ric(self): | ||
1488 | 1244 | # merge a new file does not change the last modified. | ||
1489 | 1245 | tree1 = self.make_branch_and_tree('t1') | ||
1490 | 1246 | self._commit_sprout_make_merge(tree1, self.make_file, | 722 | self._commit_sprout_make_merge(tree1, self.make_file, |
1491 | 1247 | mini_commit=self.mini_commit_record_iter_changes) | 723 | mini_commit=self.mini_commit_record_iter_changes) |
1492 | 1248 | 724 | ||
1493 | 1249 | def test_last_modified_revision_after_merge_new_link_unchanged(self): | 725 | def test_last_modified_revision_after_merge_new_link_unchanged(self): |
1494 | 1250 | # merge a new link does not change the last modified. | 726 | # merge a new link does not change the last modified. |
1495 | 1251 | tree1 = self.make_branch_and_tree('t1') | 727 | tree1 = self.make_branch_and_tree('t1') |
1496 | 1252 | self._commit_sprout_make_merge(tree1, self.make_link) | ||
1497 | 1253 | |||
1498 | 1254 | def test_last_modified_revision_after_merge_new_link_unchanged_ric(self): | ||
1499 | 1255 | # merge a new link does not change the last modified. | ||
1500 | 1256 | tree1 = self.make_branch_and_tree('t1') | ||
1501 | 1257 | self._commit_sprout_make_merge(tree1, self.make_link, | 728 | self._commit_sprout_make_merge(tree1, self.make_link, |
1502 | 1258 | mini_commit=self.mini_commit_record_iter_changes) | 729 | mini_commit=self.mini_commit_record_iter_changes) |
1503 | 1259 | 730 | ||
1504 | @@ -1289,10 +760,6 @@ | |||
1505 | 1289 | expect_fs_hash=expect_fs_hash, mini_commit=mini_commit) | 760 | expect_fs_hash=expect_fs_hash, mini_commit=mini_commit) |
1506 | 1290 | 761 | ||
1507 | 1291 | def test_last_modified_dir_file(self): | 762 | def test_last_modified_dir_file(self): |
1508 | 1292 | self._check_kind_change(self.make_dir, self.make_file, | ||
1509 | 1293 | expect_fs_hash=True) | ||
1510 | 1294 | |||
1511 | 1295 | def test_last_modified_dir_file_ric(self): | ||
1512 | 1296 | try: | 763 | try: |
1513 | 1297 | self._check_kind_change(self.make_dir, self.make_file, | 764 | self._check_kind_change(self.make_dir, self.make_file, |
1514 | 1298 | expect_fs_hash=True, | 765 | expect_fs_hash=True, |
1515 | @@ -1303,9 +770,6 @@ | |||
1516 | 1303 | "directory to file") | 770 | "directory to file") |
1517 | 1304 | 771 | ||
1518 | 1305 | def test_last_modified_dir_link(self): | 772 | def test_last_modified_dir_link(self): |
1519 | 1306 | self._check_kind_change(self.make_dir, self.make_link) | ||
1520 | 1307 | |||
1521 | 1308 | def test_last_modified_dir_link_ric(self): | ||
1522 | 1309 | try: | 773 | try: |
1523 | 1310 | self._check_kind_change(self.make_dir, self.make_link, | 774 | self._check_kind_change(self.make_dir, self.make_link, |
1524 | 1311 | mini_commit=self.mini_commit_record_iter_changes) | 775 | mini_commit=self.mini_commit_record_iter_changes) |
1525 | @@ -1316,31 +780,18 @@ | |||
1526 | 1316 | 780 | ||
1527 | 1317 | def test_last_modified_link_file(self): | 781 | def test_last_modified_link_file(self): |
1528 | 1318 | self._check_kind_change(self.make_link, self.make_file, | 782 | self._check_kind_change(self.make_link, self.make_file, |
1529 | 1319 | expect_fs_hash=True) | ||
1530 | 1320 | |||
1531 | 1321 | def test_last_modified_link_file_ric(self): | ||
1532 | 1322 | self._check_kind_change(self.make_link, self.make_file, | ||
1533 | 1323 | expect_fs_hash=True, | 783 | expect_fs_hash=True, |
1534 | 1324 | mini_commit=self.mini_commit_record_iter_changes) | 784 | mini_commit=self.mini_commit_record_iter_changes) |
1535 | 1325 | 785 | ||
1536 | 1326 | def test_last_modified_link_dir(self): | 786 | def test_last_modified_link_dir(self): |
1537 | 1327 | self._check_kind_change(self.make_link, self.make_dir) | ||
1538 | 1328 | |||
1539 | 1329 | def test_last_modified_link_dir_ric(self): | ||
1540 | 1330 | self._check_kind_change(self.make_link, self.make_dir, | 787 | self._check_kind_change(self.make_link, self.make_dir, |
1541 | 1331 | mini_commit=self.mini_commit_record_iter_changes) | 788 | mini_commit=self.mini_commit_record_iter_changes) |
1542 | 1332 | 789 | ||
1543 | 1333 | def test_last_modified_file_dir(self): | 790 | def test_last_modified_file_dir(self): |
1544 | 1334 | self._check_kind_change(self.make_file, self.make_dir) | ||
1545 | 1335 | |||
1546 | 1336 | def test_last_modified_file_dir_ric(self): | ||
1547 | 1337 | self._check_kind_change(self.make_file, self.make_dir, | 791 | self._check_kind_change(self.make_file, self.make_dir, |
1548 | 1338 | mini_commit=self.mini_commit_record_iter_changes) | 792 | mini_commit=self.mini_commit_record_iter_changes) |
1549 | 1339 | 793 | ||
1550 | 1340 | def test_last_modified_file_link(self): | 794 | def test_last_modified_file_link(self): |
1551 | 1341 | self._check_kind_change(self.make_file, self.make_link) | ||
1552 | 1342 | |||
1553 | 1343 | def test_last_modified_file_link_ric(self): | ||
1554 | 1344 | self._check_kind_change(self.make_file, self.make_link, | 795 | self._check_kind_change(self.make_file, self.make_link, |
1555 | 1345 | mini_commit=self.mini_commit_record_iter_changes) | 796 | mini_commit=self.mini_commit_record_iter_changes) |
1556 | 1346 | 797 | ||
1557 | 1347 | 798 | ||
1558 | === modified file 'breezy/tests/per_workingtree/test_commit.py' | |||
1559 | --- breezy/tests/per_workingtree/test_commit.py 2017-06-10 00:17:06 +0000 | |||
1560 | +++ breezy/tests/per_workingtree/test_commit.py 2017-06-20 22:39:47 +0000 | |||
1561 | @@ -420,6 +420,7 @@ | |||
1562 | 420 | if not tree.supports_tree_reference(): | 420 | if not tree.supports_tree_reference(): |
1563 | 421 | # inapplicable test. | 421 | # inapplicable test. |
1564 | 422 | return | 422 | return |
1565 | 423 | self.knownFailure('nested trees don\'t work well with iter_changes') | ||
1566 | 423 | subtree = self.make_branch_and_tree('subtree') | 424 | subtree = self.make_branch_and_tree('subtree') |
1567 | 424 | tree.add(['subtree']) | 425 | tree.add(['subtree']) |
1568 | 425 | self.build_tree(['subtree/file']) | 426 | self.build_tree(['subtree/file']) |
1569 | 426 | 427 | ||
1570 | === modified file 'breezy/tests/test_foreign.py' | |||
1571 | --- breezy/tests/test_foreign.py 2017-06-10 16:40:42 +0000 | |||
1572 | +++ breezy/tests/test_foreign.py 2017-06-20 22:39:47 +0000 | |||
1573 | @@ -203,28 +203,24 @@ | |||
1574 | 203 | parent_revids = [] | 203 | parent_revids = [] |
1575 | 204 | else: | 204 | else: |
1576 | 205 | parent_revids = [parent_revid] | 205 | parent_revids = [parent_revid] |
1578 | 206 | builder = self.target.get_commit_builder(parent_revids, | 206 | builder = self.target.get_commit_builder(parent_revids, |
1579 | 207 | self.target.get_config_stack(), rev.timestamp, | 207 | self.target.get_config_stack(), rev.timestamp, |
1580 | 208 | rev.timezone, rev.committer, rev.properties, | 208 | rev.timezone, rev.committer, rev.properties, |
1581 | 209 | new_revid) | 209 | new_revid) |
1582 | 210 | try: | 210 | try: |
1583 | 211 | parent_tree = self.target.repository.revision_tree( | 211 | parent_tree = self.target.repository.revision_tree( |
1584 | 212 | parent_revid) | 212 | parent_revid) |
1592 | 213 | for path, ie in tree.iter_entries_by_dir(): | 213 | iter_changes = tree.iter_changes(parent_tree) |
1593 | 214 | new_ie = ie.copy() | 214 | list(builder.record_iter_changes( |
1594 | 215 | new_ie.revision = None | 215 | tree, parent_revid, iter_changes)) |
1588 | 216 | builder.record_entry_contents(new_ie, | ||
1589 | 217 | [parent_tree.root_inventory], | ||
1590 | 218 | path, tree, | ||
1591 | 219 | (ie.kind, ie.text_size, ie.executable, ie.text_sha1)) | ||
1595 | 220 | builder.finish_inventory() | 216 | builder.finish_inventory() |
1596 | 221 | except: | 217 | except: |
1597 | 222 | builder.abort() | 218 | builder.abort() |
1598 | 223 | raise | 219 | raise |
1599 | 224 | revidmap[revid] = builder.commit(rev.message) | 220 | revidmap[revid] = builder.commit(rev.message) |
1601 | 225 | self.target.set_last_revision_info(parent_revno+1, | 221 | self.target.set_last_revision_info(parent_revno+1, |
1602 | 226 | revidmap[revid]) | 222 | revidmap[revid]) |
1604 | 227 | trace.mutter('lossily pushed revision %s -> %s', | 223 | trace.mutter('lossily pushed revision %s -> %s', |
1605 | 228 | revid, revidmap[revid]) | 224 | revid, revidmap[revid]) |
1606 | 229 | finally: | 225 | finally: |
1607 | 230 | self.source.unlock() | 226 | self.source.unlock() |
1608 | 231 | 227 | ||
1609 | === modified file 'breezy/tests/test_merge.py' | |||
1610 | --- breezy/tests/test_merge.py 2017-06-10 16:40:42 +0000 | |||
1611 | +++ breezy/tests/test_merge.py 2017-06-20 22:39:47 +0000 | |||
1612 | @@ -226,6 +226,8 @@ | |||
1613 | 226 | tree_a.conflicts()) | 226 | tree_a.conflicts()) |
1614 | 227 | 227 | ||
1615 | 228 | def test_nested_merge(self): | 228 | def test_nested_merge(self): |
1616 | 229 | self.knownFailure( | ||
1617 | 230 | 'iter_changes doesn\'t work with changes in nested trees') | ||
1618 | 229 | tree = self.make_branch_and_tree('tree', | 231 | tree = self.make_branch_and_tree('tree', |
1619 | 230 | format='development-subtree') | 232 | format='development-subtree') |
1620 | 231 | sub_tree = self.make_branch_and_tree('tree/sub-tree', | 233 | sub_tree = self.make_branch_and_tree('tree/sub-tree', |
1621 | 232 | 234 | ||
1622 | === modified file 'doc/en/release-notes/brz-3.0.txt' | |||
1623 | --- doc/en/release-notes/brz-3.0.txt 2017-06-19 14:35:58 +0000 | |||
1624 | +++ doc/en/release-notes/brz-3.0.txt 2017-06-20 22:39:47 +0000 | |||
1625 | @@ -121,6 +121,9 @@ | |||
1626 | 121 | * All previously deprecated functionality has been removed. | 121 | * All previously deprecated functionality has been removed. |
1627 | 122 | (Jelmer Vernooij) | 122 | (Jelmer Vernooij) |
1628 | 123 | 123 | ||
1629 | 124 | * ``CommitBuilder.record_entry_contents`` has been removed. | ||
1630 | 125 | (Jelmer Vernooij, #731433, #604953) | ||
1631 | 126 | |||
1632 | 124 | * Renamed ``breezy.delta.report_delta`` parameter ``filter=`` to | 127 | * Renamed ``breezy.delta.report_delta`` parameter ``filter=`` to |
1633 | 125 | ``predicate=``. (Martin Packman) | 128 | ``predicate=``. (Martin Packman) |
1634 | 126 | 129 |
Changes here all look good to me.