def test_make_entry(self): self.assertIsInstance(inventory.make_entry("file", "name", ROOT_ID), inventory.InventoryFile) self.assertIsInstance(inventory.make_entry("symlink", "name", ROOT_ID), inventory.InventoryLink) self.assertIsInstance(inventory.make_entry("directory", "name", ROOT_ID), inventory.InventoryDirectory)
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] # Delete the old path. Note that this might trigger implicit # deletion of newly created parents that could now become empty. self.record_delete(old_path, old_ie) # 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 kind = old_ie.kind basename, parent_id = self._ensure_directory(new_path, self.basis_inventory) ie = inventory.make_entry(kind, basename, parent_id, file_id) ie.revision = self.revision_id if kind == 'file': ie.executable = old_ie.executable ie.text_sha1 = old_ie.text_sha1 ie.text_size = old_ie.text_size elif kind == 'symlink': ie.symlink_target = old_ie.symlink_target # Record it self.record_new(new_path, ie)
def test_commit_unchanged_root(self): tree = self.make_branch_and_tree(".") old_revision_id = tree.commit('') tree.lock_write() parent_tree = tree.basis_tree() parent_tree.lock_read() self.addCleanup(parent_tree.unlock) builder = tree.branch.get_commit_builder([parent_tree.inventory]) try: ie = inventory.make_entry('directory', '', None, tree.get_root_id()) delta, version_recorded = builder.record_entry_contents( ie, [parent_tree.inventory], '', tree, tree.path_content_summary('')) self.assertFalse(version_recorded) # if the repository format recorded a new root revision, that # should be in the delta got_new_revision = ie.revision != old_revision_id if got_new_revision: self.assertEqual( ('', '', ie.file_id, ie), delta) else: self.assertEqual(None, delta) builder.abort() except: builder.abort() tree.unlock() raise else: tree.unlock()
def test_commit_unchanged_root(self): tree = self.make_branch_and_tree(".") old_revision_id = tree.commit('') tree.lock_write() parent_tree = tree.basis_tree() parent_tree.lock_read() self.addCleanup(parent_tree.unlock) builder = tree.branch.get_commit_builder([parent_tree.inventory]) try: ie = inventory.make_entry('directory', '', None, tree.get_root_id()) delta, version_recorded = builder.record_entry_contents( ie, [parent_tree.inventory], '', tree, tree.path_content_summary('')) self.assertFalse(version_recorded) # if the repository format recorded a new root revision, that # should be in the delta got_new_revision = ie.revision != old_revision_id if got_new_revision: self.assertEqual(('', '', ie.file_id, ie), delta) else: self.assertEqual(None, delta) builder.abort() except: builder.abort() tree.unlock() raise else: tree.unlock()
def test_file_executable(self): file_entry = inventory.make_entry('file', 'a file', None, 'file-id') file_entry.executable = True file_entry.text_sha1 = 'foo' file_entry.text_size = 10 self.assertEqual('file\x0010\x00Y\x00foo', inventory_delta._file_content(file_entry))
def commit_id(file_id): old_ie = tree.inventory[file_id] path = tree.id2path(file_id) ie = inventory.make_entry(tree.kind(file_id), old_ie.name, old_ie.parent_id, file_id) return builder.record_entry_contents(ie, parent_invs, path, tree, tree.path_content_summary(path))
def test_to_inventory_root_id_not_versioned(self): delta = [(None, '', 'an-id', inventory.make_entry( 'directory', '', None, 'an-id'))] serializer = inventory_delta.InventoryDeltaSerializer( versioned_root=True, tree_references=True) self.assertRaises( InventoryDeltaError, serializer.delta_to_lines, 'old-version', 'new-version', delta)
def test_parse_versioned_root_only(self): deserializer = inventory_delta.InventoryDeltaDeserializer() parse_result = deserializer.parse_text_bytes(root_only_lines) expected_entry = inventory.make_entry('directory', u'', None, 'an-id') expected_entry.revision = 'a@e\xc3\xa5ample.com--2004' self.assertEqual(('null:', 'entry-version', True, True, [ (None, '', 'an-id', expected_entry) ]), parse_result)
def commit_id(file_id): old_ie = tree.inventory[file_id] path = tree.id2path(file_id) ie = inventory.make_entry(tree.kind(file_id), old_ie.name, old_ie.parent_id, file_id) return builder.record_entry_contents( ie, parent_invs, path, tree, tree.path_content_summary(path))
def test_to_inventory_root_id_versioned_not_permitted(self): root_entry = inventory.make_entry('directory', '', None, 'TREE_ROOT') root_entry.revision = 'some-version' delta = [(None, '', 'TREE_ROOT', root_entry)] serializer = inventory_delta.InventoryDeltaSerializer( versioned_root=False, tree_references=True) self.assertRaises( InventoryDeltaError, serializer.delta_to_lines, 'old-version', 'new-version', delta)
def test_parse_unversioned_root_versioning_enabled(self): deserializer = inventory_delta.InventoryDeltaDeserializer() parse_result = deserializer.parse_text_bytes(root_only_unversioned) expected_entry = inventory.make_entry('directory', u'', None, 'TREE_ROOT') expected_entry.revision = 'entry-version' self.assertEqual(('null:', 'entry-version', False, False, [ (None, u'', 'TREE_ROOT', expected_entry) ]), parse_result)
def test_parse_unversioned_root_versioning_enabled(self): deserializer = inventory_delta.InventoryDeltaDeserializer() parse_result = deserializer.parse_text_bytes(root_only_unversioned) expected_entry = inventory.make_entry( 'directory', u'', None, 'TREE_ROOT') expected_entry.revision = 'entry-version' self.assertEqual( ('null:', 'entry-version', False, False, [(None, u'', 'TREE_ROOT', expected_entry)]), parse_result)
def test_parse_versioned_root_only(self): deserializer = inventory_delta.InventoryDeltaDeserializer() parse_result = deserializer.parse_text_bytes(root_only_lines) expected_entry = inventory.make_entry( 'directory', u'', None, 'an-id') expected_entry.revision = 'a@e\xc3\xa5ample.com--2004' self.assertEqual( ('null:', 'entry-version', True, True, [(None, '', 'an-id', expected_entry)]), parse_result)
def _modify_item(self, path, kind, is_executable, data, inv): """Add to or change an item in the inventory.""" # If we've already added this, warn the user that we're ignoring it. # In the future, it might be nice to double check that the new data # is the same as the old but, frankly, exporters should be fixed # not to produce bad data streams in the first place ... existing = self._new_file_ids.get(path) if existing: # We don't warn about directories because it's fine for them # to be created already by a previous rename if kind != 'directory': self.warning("%s already added in this commit - ignoring" % (path,)) return # Create the new InventoryEntry basename, parent_id = self._ensure_directory(path, inv) file_id = self.bzr_file_id(path) ie = inventory.make_entry(kind, basename, parent_id, file_id) ie.revision = self.revision_id if kind == 'file': ie.executable = is_executable # lines = osutils.split_lines(data) ie.text_sha1 = osutils.sha_string(data) ie.text_size = len(data) self.data_for_commit[file_id] = data elif kind == 'directory': self.directory_entries[path] = ie # There are no lines stored for a directory so # make sure the cache used by get_lines knows that self.data_for_commit[file_id] = '' elif kind == 'symlink': ie.symlink_target = self._decode_path(data) # There are no lines stored for a symlink so # make sure the cache used by get_lines knows that self.data_for_commit[file_id] = '' else: self.warning("Cannot import items of kind '%s' yet - ignoring '%s'" % (kind, path)) return # Record it if inv.has_id(file_id): old_ie = inv[file_id] if old_ie.kind == 'directory': self.record_delete(path, old_ie) self.record_changed(path, ie, parent_id) else: try: self.record_new(path, ie) except: print "failed to add path '%s' with entry '%s' in command %s" \ % (path, ie, self.command.id) print "parent's children are:\n%r\n" % (ie.parent_id.children,) raise
def test_fetch_inconsistent_last_changed_entries(self): """If an inventory has odd data we should still get what it references. This test tests that we do fetch a file text created in a revision not being fetched, but referenced from the revision we are fetching when the adjacent revisions to the one being fetched do not reference that text. """ tree = self.make_branch_and_tree('source') revid = tree.commit('old') to_repo = self.make_to_repository('to_repo') to_repo.fetch(tree.branch.repository, revid) # Make a broken revision and fetch it. source = tree.branch.repository source.lock_write() self.addCleanup(source.unlock) source.start_write_group() try: # We need two revisions: OLD and NEW. NEW will claim to need a file # 'FOO' changed in 'OLD'. OLD will not have that file at all. source.texts.insert_record_stream([ versionedfile.FulltextContentFactory(('foo', revid), (), None, 'contents') ]) basis = source.revision_tree(revid) parent_id = basis.path2id('') entry = inventory.make_entry('file', 'foo-path', parent_id, 'foo') entry.revision = revid entry.text_size = len('contents') entry.text_sha1 = osutils.sha_string('contents') inv_sha1, _ = source.add_inventory_by_delta( revid, [(None, 'foo-path', 'foo', entry)], 'new', [revid]) rev = Revision(timestamp=0, timezone=None, committer="Foo Bar <*****@*****.**>", message="Message", inventory_sha1=inv_sha1, revision_id='new', parent_ids=[revid]) source.add_revision(rev.revision_id, rev) except: source.abort_write_group() raise else: source.commit_write_group() to_repo.fetch(source, 'new') to_repo.lock_read() self.addCleanup(to_repo.unlock) self.assertEqual( 'contents', to_repo.texts.get_record_stream( [('foo', revid)], 'unordered', True).next().get_bytes_as('fulltext'))
def test_make_entry_non_normalized(self): orig_normalized_filename = osutils.normalized_filename try: osutils.normalized_filename = osutils._accessible_normalized_filename entry = inventory.make_entry("file", u'a\u030a', ROOT_ID) self.assertEqual(u'\xe5', entry.name) self.assertIsInstance(entry, inventory.InventoryFile) osutils.normalized_filename = osutils._inaccessible_normalized_filename self.assertRaises(errors.InvalidNormalization, inventory.make_entry, 'file', u'a\u030a', ROOT_ID) finally: osutils.normalized_filename = orig_normalized_filename
def test_fetch_inconsistent_last_changed_entries(self): """If an inventory has odd data we should still get what it references. This test tests that we do fetch a file text created in a revision not being fetched, but referenced from the revision we are fetching when the adjacent revisions to the one being fetched do not reference that text. """ tree = self.make_branch_and_tree('source') revid = tree.commit('old') to_repo = self.make_to_repository('to_repo') to_repo.fetch(tree.branch.repository, revid) # Make a broken revision and fetch it. source = tree.branch.repository source.lock_write() self.addCleanup(source.unlock) source.start_write_group() try: # We need two revisions: OLD and NEW. NEW will claim to need a file # 'FOO' changed in 'OLD'. OLD will not have that file at all. source.texts.insert_record_stream([ versionedfile.FulltextContentFactory(('foo', revid), (), None, 'contents')]) basis = source.revision_tree(revid) parent_id = basis.path2id('') entry = inventory.make_entry('file', 'foo-path', parent_id, 'foo') entry.revision = revid entry.text_size = len('contents') entry.text_sha1 = osutils.sha_string('contents') inv_sha1, _ = source.add_inventory_by_delta(revid, [ (None, 'foo-path', 'foo', entry)], 'new', [revid]) rev = Revision(timestamp=0, timezone=None, committer="Foo Bar <*****@*****.**>", message="Message", inventory_sha1=inv_sha1, revision_id='new', parent_ids=[revid]) source.add_revision(rev.revision_id, rev) except: source.abort_write_group() raise else: source.commit_write_group() to_repo.fetch(source, 'new') to_repo.lock_read() self.addCleanup(to_repo.unlock) self.assertEqual('contents', to_repo.texts.get_record_stream([('foo', revid)], 'unordered', True).next().get_bytes_as('fulltext'))
def test_parse_new_file(self): """a new file is parsed correctly""" lines = root_only_lines fake_sha = "deadbeef" * 5 lines += ( "None\x00/new\x00file-id\x00an-id\x00version\x00file\x00123\x00" + "\x00" + fake_sha + "\n") deserializer = inventory_delta.InventoryDeltaDeserializer() parse_result = deserializer.parse_text_bytes(lines) expected_entry = inventory.make_entry('file', u'new', 'an-id', 'file-id') expected_entry.revision = 'version' expected_entry.text_size = 123 expected_entry.text_sha1 = fake_sha delta = parse_result[4] self.assertEqual((None, u'new', 'file-id', expected_entry), delta[-1])
def test_parse_new_file(self): """a new file is parsed correctly""" lines = root_only_lines fake_sha = "deadbeef" * 5 lines += ( "None\x00/new\x00file-id\x00an-id\x00version\x00file\x00123\x00" + "\x00" + fake_sha + "\n") deserializer = inventory_delta.InventoryDeltaDeserializer() parse_result = deserializer.parse_text_bytes(lines) expected_entry = inventory.make_entry( 'file', u'new', 'an-id', 'file-id') expected_entry.revision = 'version' expected_entry.text_size = 123 expected_entry.text_sha1 = fake_sha delta = parse_result[4] self.assertEqual( (None, u'new', 'file-id', expected_entry), delta[-1])
def _record_entry(self, path, file_id, specific_files, kind, name, parent_id, definitely_changed, existing_ie, report_changes, content_summary): "Record the new inventory entry for a path if any." # mutter('check %s {%s}', path, file_id) # mutter('%s selected for commit', path) if definitely_changed or existing_ie is None: ie = make_entry(kind, name, parent_id, file_id) else: ie = existing_ie.copy() ie.revision = None delta, version_recorded = self.builder.record_entry_contents(ie, self.parent_invs, path, self.work_tree, content_summary) if delta: self._basis_delta.append(delta) if version_recorded: self.any_entries_changed = True if report_changes: self._report_change(ie, path) return ie
def _record_entry(self, path, file_id, specific_files, kind, name, parent_id, definitely_changed, existing_ie, report_changes, content_summary): "Record the new inventory entry for a path if any." # mutter('check %s {%s}', path, file_id) # mutter('%s selected for commit', path) if definitely_changed or existing_ie is None: ie = make_entry(kind, name, parent_id, file_id) else: ie = existing_ie.copy() ie.revision = None # For carried over entries we don't care about the fs hash - the repo # isn't generating a sha, so we're not saving computation time. _, _, fs_hash = self.builder.record_entry_contents( ie, self.parent_invs, path, self.work_tree, content_summary) if report_changes: self._report_change(ie, path) if fs_hash: self.work_tree._observed_sha1(ie.file_id, path, fs_hash) return ie
def test_dir(self): entry = inventory.make_entry('directory', 'a dir', None) self.assertEqual('dir', inventory_delta._directory_content(entry))
def mini_commit(self, tree, name, new_name, records_version=True, delta_against_basis=True): """Perform a miniature commit looking for record entry results. :param tree: The tree to commit. :param name: The path in the basis tree of the tree being committed. :param new_name: The path in the tree being committed. :param records_version: True if the commit of new_name is expected to record a new version. :param delta_against_basis: True of the commit of new_name is expected to have a delta against the basis. """ tree.lock_write() try: # mini manual commit here so we can check the return of # record_entry_contents. parent_ids = tree.get_parent_ids() builder = tree.branch.get_commit_builder(parent_ids) parent_tree = tree.basis_tree() parent_tree.lock_read() self.addCleanup(parent_tree.unlock) parent_invs = [parent_tree.inventory] for parent_id in parent_ids[1:]: parent_invs.append(tree.branch.repository.revision_tree( parent_id).inventory) # root builder.record_entry_contents( inventory.make_entry('directory', '', None, tree.get_root_id()), parent_invs, '', tree, tree.path_content_summary('')) def commit_id(file_id): old_ie = tree.inventory[file_id] path = tree.id2path(file_id) ie = inventory.make_entry(tree.kind(file_id), old_ie.name, old_ie.parent_id, file_id) return builder.record_entry_contents(ie, parent_invs, path, tree, tree.path_content_summary(path)) file_id = tree.path2id(new_name) parent_id = tree.inventory[file_id].parent_id if parent_id != tree.get_root_id(): commit_id(parent_id) # because a change of some sort is meant to have occurred, # recording the entry must return True. delta, version_recorded = commit_id(file_id) if records_version: self.assertTrue(version_recorded) else: self.assertFalse(version_recorded) new_entry = builder.new_inventory[file_id] if delta_against_basis: expected_delta = (name, new_name, file_id, new_entry) else: expected_delta = None if expected_delta != delta: import pdb;pdb.set_trace() self.assertEqual(expected_delta, delta) builder.finish_inventory() rev2 = builder.commit('') tree.set_parent_ids([rev2]) except: builder.abort() tree.unlock() raise else: tree.unlock() return rev2
def test_reference_revision(self): entry = inventory.make_entry('tree-reference', 'a tree', None) entry.reference_revision = 'foo@\xc3\xa5b-lah' self.assertEqual('tree\x00foo@\xc3\xa5b-lah', inventory_delta._reference_content(entry))
def test_reference_null(self): entry = inventory.make_entry('tree-reference', 'a tree', None) entry.reference_revision = NULL_REVISION self.assertEqual('tree\x00null:', inventory_delta._reference_content(entry))
def test_link_no_target(self): entry = inventory.make_entry('symlink', 'a link', None) self.assertRaises(InventoryDeltaError, inventory_delta._link_content, entry)
def test_link_space_target(self): entry = inventory.make_entry('symlink', 'a link', None) entry.symlink_target = ' ' self.assertEqual('link\x00 ', inventory_delta._link_content(entry))
def test_link_unicode_target(self): entry = inventory.make_entry('symlink', 'a link', None) entry.symlink_target = ' \xc3\xa5'.decode('utf8') self.assertEqual('link\x00 \xc3\xa5', inventory_delta._link_content(entry))
def test_reference_no_reference(self): entry = inventory.make_entry('tree-reference', 'a tree', None) self.assertRaises(InventoryDeltaError, inventory_delta._reference_content, entry)
def mini_commit(self, tree, name, new_name, records_version=True, delta_against_basis=True): """Perform a miniature commit looking for record entry results. :param tree: The tree to commit. :param name: The path in the basis tree of the tree being committed. :param new_name: The path in the tree being committed. :param records_version: True if the commit of new_name is expected to record a new version. :param delta_against_basis: True of the commit of new_name is expected to have a delta against the basis. """ tree.lock_write() try: # mini manual commit here so we can check the return of # record_entry_contents. parent_ids = tree.get_parent_ids() builder = tree.branch.get_commit_builder(parent_ids) parent_tree = tree.basis_tree() parent_tree.lock_read() self.addCleanup(parent_tree.unlock) parent_invs = [parent_tree.inventory] for parent_id in parent_ids[1:]: parent_invs.append( tree.branch.repository.revision_tree(parent_id).inventory) # root builder.record_entry_contents( inventory.make_entry('directory', '', None, tree.get_root_id()), parent_invs, '', tree, tree.path_content_summary('')) def commit_id(file_id): old_ie = tree.inventory[file_id] path = tree.id2path(file_id) ie = inventory.make_entry(tree.kind(file_id), old_ie.name, old_ie.parent_id, file_id) return builder.record_entry_contents( ie, parent_invs, path, tree, tree.path_content_summary(path)) file_id = tree.path2id(new_name) parent_id = tree.inventory[file_id].parent_id if parent_id != tree.get_root_id(): commit_id(parent_id) # because a change of some sort is meant to have occurred, # recording the entry must return True. delta, version_recorded = commit_id(file_id) if records_version: self.assertTrue(version_recorded) else: self.assertFalse(version_recorded) new_entry = builder.new_inventory[file_id] if delta_against_basis: expected_delta = (name, new_name, file_id, new_entry) else: expected_delta = None if expected_delta != delta: import pdb pdb.set_trace() self.assertEqual(expected_delta, delta) builder.finish_inventory() rev2 = builder.commit('') tree.set_parent_ids([rev2]) except: builder.abort() tree.unlock() raise else: tree.unlock() return rev2
def make_entry(kind, name, parent_id, file_id, **attrs): entry = inventory.make_entry(kind, name, parent_id, file_id) for name, value in attrs.items(): setattr(entry, name, value) return entry
def test_file_without_sha1(self): file_entry = inventory.make_entry('file', 'a file', None, 'file-id') file_entry.text_size = 10 self.assertRaises(InventoryDeltaError, inventory_delta._file_content, file_entry)
def test_file_0_short_sha(self): file_entry = inventory.make_entry('file', 'a file', None, 'file-id') file_entry.text_sha1 = '' file_entry.text_size = 0 self.assertEqual('file\x000\x00\x00', inventory_delta._file_content(file_entry))