# This tracks path->file-id for things we're creating this commit.
# If the same path is created multiple times, we need to warn the
# user and add it just once.
+ # If a path is added then renamed or copied, we need to handle that.
self._new_file_ids = {}
+ # This tracks path->file-id for things we're modifying this commit.
+ # If a path is modified then renamed or copied, we need the make
+ # sure we grab the new content.
+ self._modified_file_ids = {}
# This tracks the paths for things we're deleting this commit.
# If the same path is added or the destination of a rename say,
# then a fresh file-id is required.
kind, path)
def _rename_item(self, old_path, new_path, inv):
- existing = self._new_file_ids.get(old_path)
+ existing = self._new_file_ids.get(old_path) or \
+ self._modified_file_ids.get(old_path)
if existing:
- # We've only just added this path earlier in this commit.
- # Change the add of old_path to an add of new_path
- self._rename_pending_add(old_path, new_path, existing)
+ # We've only just added/modified this path earlier in this commit.
+ # Change the add/modify of old_path to an add of new_path
+ self._rename_pending_change(old_path, new_path, existing)
return
file_id = inv.path2id(old_path)
def record_changed(self, path, ie, parent_id=None):
self._add_entry((path, path, ie.file_id, ie))
+ self._modified_file_ids[path] = ie.file_id
def record_delete(self, path, ie):
self._add_entry((path, None, ie.file_id, None))
new_ie.revision = self.revision_id
self._add_entry((old_path, new_path, file_id, new_ie))
- def _rename_pending_add(self, old_path, new_path, file_id):
- """Instead of adding old-path, add new-path instead."""
+ def _rename_pending_change(self, old_path, new_path, file_id):
+ """Instead of adding/modifying old-path, add new-path instead."""
# note: delta entries look like (old, new, file-id, ie)
old_ie = self._delta_entries_by_fileid[file_id][3]
# deletion of newly created parents that could now become empty.
self.record_delete(old_path, old_ie)
- # Update the dictionary used for tracking new file-ids
- del self._new_file_ids[old_path]
+ # Update the dictionaries used for tracking new file-ids
+ if old_path in self._new_file_ids:
+ del self._new_file_ids[old_path]
+ else:
+ del self._modified_file_ids[old_path]
self._new_file_ids[new_path] = file_id
# Create the new InventoryEntry
self.assertSymlinkTarget(branch, revtree2, new_path, "aaa")
+class TestImportToPackRenameModified(TestCaseForGenericProcessor):
+ """Test rename of a path previously modified in this commit."""
+
+ def get_command_iter(self, old_path, new_path, kind='file'):
+ # Revno 1: create a file or symlink
+ # Revno 2: modify then rename it
+ def command_list():
+ author = ['', 'bugs@a.com', time.time(), time.timezone]
+ committer = ['', 'elmer@a.com', time.time(), time.timezone]
+ def files_one():
+ yield commands.FileModifyCommand(old_path, kind, False,
+ None, "aaa")
+ yield commands.CommitCommand('head', '1', author,
+ committer, "commit 1", None, [], files_one)
+ def files_two():
+ yield commands.FileModifyCommand(old_path, kind, False,
+ None, "bbb")
+ yield commands.FileRenameCommand(old_path, new_path)
+ yield commands.CommitCommand('head', '2', author,
+ committer, "commit 2", ":1", [], files_two)
+ return command_list
+
+ def test_rename_of_modified_file_in_root(self):
+ handler, branch = self.get_handler()
+ old_path = 'a'
+ new_path = 'b'
+ handler.process(self.get_command_iter(old_path, new_path))
+ revtree0, revtree1 = self.assertChanges(branch, 1,
+ expected_added=[(old_path,)])
+ # Note: the delta doesn't show the modification?
+ # The actual new content is validated in the assertions following.
+ revtree1, revtree2 = self.assertChanges(branch, 2,
+ expected_renamed=[(old_path, new_path)])
+ self.assertContent(branch, revtree1, old_path, "aaa")
+ self.assertContent(branch, revtree2, new_path, "bbb")
+ self.assertRevisionRoot(revtree1, old_path)
+ self.assertRevisionRoot(revtree2, new_path)
+
+ def test_rename_of_modified_symlink_in_root(self):
+ handler, branch = self.get_handler()
+ old_path = 'a'
+ new_path = 'b'
+ handler.process(self.get_command_iter(old_path, new_path, 'symlink'))
+ revtree0, revtree1 = self.assertChanges(branch, 1,
+ expected_added=[(old_path,)])
+ # Note: the delta doesn't show the modification?
+ # The actual new content is validated in the assertions following.
+ revtree1, revtree2 = self.assertChanges(branch, 2,
+ expected_renamed=[(old_path, new_path)])
+ self.assertSymlinkTarget(branch, revtree1, old_path, "aaa")
+ self.assertSymlinkTarget(branch, revtree2, new_path, "bbb")
+ self.assertRevisionRoot(revtree1, old_path)
+ self.assertRevisionRoot(revtree2, new_path)
+
+ def test_rename_of_modified_file_in_subdir(self):
+ handler, branch = self.get_handler()
+ old_path = 'd/a'
+ new_path = 'd/b'
+ handler.process(self.get_command_iter(old_path, new_path))
+ revtree0, revtree1 = self.assertChanges(branch, 1,
+ expected_added=[('d',), (old_path,)])
+ # Note: the delta doesn't show the modification?
+ # The actual new content is validated in the assertions following.
+ revtree1, revtree2 = self.assertChanges(branch, 2,
+ expected_renamed=[(old_path, new_path)])
+ self.assertContent(branch, revtree1, old_path, "aaa")
+ self.assertContent(branch, revtree2, new_path, "bbb")
+
+ def test_rename_of_modified_symlink_in_subdir(self):
+ handler, branch = self.get_handler()
+ old_path = 'd/a'
+ new_path = 'd/b'
+ handler.process(self.get_command_iter(old_path, new_path, 'symlink'))
+ revtree0, revtree1 = self.assertChanges(branch, 1,
+ expected_added=[('d',), (old_path,)])
+ # Note: the delta doesn't show the modification?
+ # The actual new content is validated in the assertions following.
+ revtree1, revtree2 = self.assertChanges(branch, 2,
+ expected_renamed=[(old_path, new_path)])
+ self.assertSymlinkTarget(branch, revtree1, old_path, "aaa")
+ self.assertSymlinkTarget(branch, revtree2, new_path, "bbb")
+
+ def test_rename_of_modified_file_to_new_dir(self):
+ handler, branch = self.get_handler()
+ old_path = 'd1/a'
+ new_path = 'd2/b'
+ handler.process(self.get_command_iter(old_path, new_path))
+ revtree0, revtree1 = self.assertChanges(branch, 1,
+ expected_added=[('d1',), (old_path,)])
+ # Note: the delta doesn't show the modification?
+ # The actual new content is validated in the assertions following.
+ revtree1, revtree2 = self.assertChanges(branch, 2,
+ expected_renamed=[(old_path, new_path)],
+ expected_added=[('d2',)],
+ expected_removed=[('d1',)])
+ self.assertContent(branch, revtree1, old_path, "aaa")
+ self.assertContent(branch, revtree2, new_path, "bbb")
+
+ def test_rename_of_modified_symlink_to_new_dir(self):
+ handler, branch = self.get_handler()
+ old_path = 'd1/a'
+ new_path = 'd2/b'
+ handler.process(self.get_command_iter(old_path, new_path, 'symlink'))
+ revtree0, revtree1 = self.assertChanges(branch, 1,
+ expected_added=[('d1',), (old_path,)])
+ # Note: the delta doesn't show the modification?
+ # The actual new content is validated in the assertions following.
+ revtree1, revtree2 = self.assertChanges(branch, 2,
+ expected_renamed=[(old_path, new_path)],
+ expected_added=[('d2',)],
+ expected_removed=[('d1',)])
+ self.assertSymlinkTarget(branch, revtree1, old_path, "aaa")
+ self.assertSymlinkTarget(branch, revtree2, new_path, "bbb")
+
+
class TestImportToPackRenameTricky(TestCaseForGenericProcessor):
def file_command_iter(self, path1, old_path2, new_path2, kind='file'):
class TestImportToRichRootRenameToDeleted(TestImportToPackRenameToDeleted):
branch_format = "1.9-rich-root"
+class TestImportToRichRootRenameModified(TestImportToPackRenameModified):
+ branch_format = "1.9-rich-root"
+
class TestImportToRichRootRenameTricky(TestImportToPackRenameTricky):
branch_format = "1.9-rich-root"
class TestImportToChkRenameToDeleted(TestImportToPackRenameToDeleted):
branch_format = "2a"
+ class TestImportToChkRenameModified(TestImportToPackRenameModified):
+ branch_format = "2a"
+
class TestImportToChkRenameTricky(TestImportToPackRenameTricky):
branch_format = "2a"