def test_add_revision_inventory_sha1(self): inv = inventory.Inventory(revision_id='A') inv.root.revision = 'A' inv.root.file_id = 'fixed-root' # Insert the inventory on its own to an identical repository, to get # its sha1. reference_repo = self.make_repository('reference_repo') reference_repo.lock_write() reference_repo.start_write_group() inv_sha1 = reference_repo.add_inventory('A', inv, []) reference_repo.abort_write_group() reference_repo.unlock() # Now insert a revision with this inventory, and it should get the same # sha1. repo = self.make_repository('repo') repo.lock_write() repo.start_write_group() root_id = inv.root.file_id repo.texts.add_lines(('fixed-root', 'A'), [], []) repo.add_revision('A', _mod_revision.Revision( 'A', committer='B', timestamp=0, timezone=0, message='C'), inv=inv) repo.commit_write_group() repo.unlock() repo.lock_read() self.assertEqual(inv_sha1, repo.get_revision('A').inventory_sha1) repo.unlock()
def create_branch_with_ghost_text(self): builder = self.make_branch_builder('ghost') builder.build_snapshot( 'A-id', None, [('add', ('', 'root-id', 'directory', None)), ('add', ('a', 'a-file-id', 'file', 'some content\n'))]) b = builder.get_branch() old_rt = b.repository.revision_tree('A-id') new_inv = inventory.mutable_inventory_from_tree(old_rt) new_inv.revision_id = 'B-id' new_inv['a-file-id'].revision = 'ghost-id' new_rev = _mod_revision.Revision( 'B-id', timestamp=time.time(), timezone=0, message='Committing against a ghost', committer='Joe Foo <*****@*****.**>', properties={}, parent_ids=('A-id', 'ghost-id'), ) b.lock_write() self.addCleanup(b.unlock) b.repository.start_write_group() b.repository.add_revision('B-id', new_rev, new_inv) self.disable_commit_write_group_paranoia(b.repository) b.repository.commit_write_group() return b
def read_revision_from_string(self, text): # TODO: consider writing a Revision decoder, rather than using the # generic bencode decoder # However, to decode all 25k revisions of bzr takes approx 1.3s # If we remove all extra validation that goes down to about 1.2s. # Of that time, probably 0.6s is spend in bencode.bdecode(). # Regardless 'time bzr log' of everything is 7+s, so 1.3s to # extract revision texts isn't a majority of time. ret = bencode.bdecode(text) if not isinstance(ret, list): raise ValueError("invalid revision text") schema = self._schema # timezone is allowed to be missing, but should be set bits = {'timezone': None} for key, value in ret: # Will raise KeyError if not a valid part of the schema, or an # entry is given 2 times. var_name, expected_type, validator = schema[key] if value.__class__ is not expected_type: raise ValueError('key %s did not conform to the expected type' ' %s, but was %s' % (key, expected_type, type(value))) if validator is not None: value = validator(value) bits[var_name] = value if len(bits) != len(schema): missing = [key for key, (var_name, _, _) in schema.iteritems() if var_name not in bits] raise ValueError('Revision text was missing expected keys %s.' ' text %r' % (missing, text)) del bits[None] # Get rid of 'format' since it doesn't get mapped rev = _mod_revision.Revision(**bits) return rev
def add_revision(self, repo, revision_id, inv, parent_ids): inv.revision_id = revision_id inv.root.revision = revision_id repo.add_inventory(revision_id, inv, parent_ids) revision = _mod_revision.Revision(revision_id, committer='*****@*****.**', timestamp=0, inventory_sha1='', timezone=0, message='foo', parent_ids=parent_ids) repo.add_revision(revision_id,revision, inv)
def test_get_apparent_authors(self): r = revision.Revision('1') r.committer = 'A' self.assertEqual(['A'], r.get_apparent_authors()) r.properties['author'] = 'B' self.assertEqual(['B'], r.get_apparent_authors()) r.properties['authors'] = 'C\nD' self.assertEqual(['C', 'D'], r.get_apparent_authors())
def test_get_summary(self): r = revision.Revision('1') r.message = 'a' self.assertEqual('a', r.get_summary()) r.message = 'a\nb' self.assertEqual('a', r.get_summary()) r.message = '\na\nb' self.assertEqual('a', r.get_summary())
def setUp(self): super(TestCaseWithCorruptRepository, self).setUp() # a inventory with no parents and the revision has parents.. # i.e. a ghost. repo = self.make_repository('inventory_with_unnecessary_ghost') repo.lock_write() repo.start_write_group() inv = inventory.Inventory(revision_id = 'ghost') inv.root.revision = 'ghost' if repo.supports_rich_root(): root_id = inv.root.file_id repo.texts.add_lines((root_id, 'ghost'), [], []) sha1 = repo.add_inventory('ghost', inv, []) rev = _mod_revision.Revision( timestamp=0, timezone=None, committer="Foo Bar <*****@*****.**>", message="Message", inventory_sha1=sha1, revision_id='ghost') rev.parent_ids = ['the_ghost'] try: repo.add_revision('ghost', rev) except (errors.NoSuchRevision, errors.RevisionNotPresent): raise tests.TestNotApplicable( "Cannot test with ghosts for this format.") inv = inventory.Inventory(revision_id = 'the_ghost') inv.root.revision = 'the_ghost' if repo.supports_rich_root(): root_id = inv.root.file_id repo.texts.add_lines((root_id, 'the_ghost'), [], []) sha1 = repo.add_inventory('the_ghost', inv, []) rev = _mod_revision.Revision( timestamp=0, timezone=None, committer="Foo Bar <*****@*****.**>", message="Message", inventory_sha1=sha1, revision_id='the_ghost') rev.parent_ids = [] repo.add_revision('the_ghost', rev) # check its setup usefully inv_weave = repo.inventories possible_parents = (None, (('ghost',),)) self.assertSubset(inv_weave.get_parent_map([('ghost',)])[('ghost',)], possible_parents) repo.commit_write_group() repo.unlock()
def test_some_bugs(self): r = revision.Revision('1', properties={ 'bugs': bugtracker.encode_fixes_bug_urls([ 'http://example.com/bugs/1', 'http://launchpad.net/bugs/1234' ]) }) self.assertEqual( [('http://example.com/bugs/1', bugtracker.FIXED), ('http://launchpad.net/bugs/1234', bugtracker.FIXED)], list(r.iter_bugs()))
def make_broken_repository(self): # XXX: This function is borrowed from Aaron's "Reconcile can fix bad # parent references" branch which is due to land in bzr.dev soon. Once # it does, this duplication should be removed. repo = self.make_repository('broken-repo') cleanups = [] try: repo.lock_write() cleanups.append(repo.unlock) repo.start_write_group() cleanups.append(repo.commit_write_group) # make rev1a: A well-formed revision, containing 'file1' inv = inventory.Inventory(revision_id='rev1a') inv.root.revision = 'rev1a' self.add_file(repo, inv, 'file1', 'rev1a', []) repo.add_inventory('rev1a', inv, []) revision = _mod_revision.Revision('rev1a', committer='*****@*****.**', timestamp=0, inventory_sha1='', timezone=0, message='foo', parent_ids=[]) repo.add_revision('rev1a',revision, inv) # make rev1b, which has no Revision, but has an Inventory, and # file1 inv = inventory.Inventory(revision_id='rev1b') inv.root.revision = 'rev1b' self.add_file(repo, inv, 'file1', 'rev1b', []) repo.add_inventory('rev1b', inv, []) # make rev2, with file1 and file2 # file2 is sane # file1 has 'rev1b' as an ancestor, even though this is not # mentioned by 'rev1a', making it an unreferenced ancestor inv = inventory.Inventory() self.add_file(repo, inv, 'file1', 'rev2', ['rev1a', 'rev1b']) self.add_file(repo, inv, 'file2', 'rev2', []) self.add_revision(repo, 'rev2', inv, ['rev1a']) # make ghost revision rev1c inv = inventory.Inventory() self.add_file(repo, inv, 'file2', 'rev1c', []) # make rev3 with file2 # file2 refers to 'rev1c', which is a ghost in this repository, so # file2 cannot have rev1c as its ancestor. inv = inventory.Inventory() self.add_file(repo, inv, 'file2', 'rev3', ['rev1c']) self.add_revision(repo, 'rev3', inv, ['rev1c']) return repo finally: for cleanup in reversed(cleanups): cleanup()
def make_repo_with_extra_ghost_index(self): """Make a corrupt repository. It will contain one revision, 'revision-id'. The knit index will claim that it has one parent, 'incorrect-parent', but the revision text will claim it has no parents. Note: only the *cache* of the knit index is corrupted. Thus the corruption will only last while the repository is locked. For this reason, the returned repo is locked. """ if not isinstance(self.repository_format, RepositoryFormatKnit): # XXX: Broken revision graphs can happen to weaves too, but they're # pretty deprecated. Ideally these tests should apply to any repo # where repo.revision_graph_can_have_wrong_parents() is True, but # at the moment we only know how to corrupt knit repos. raise TestNotApplicable( "%s isn't a knit format" % self.repository_format) repo = self.make_repository('broken') repo.lock_write() repo.start_write_group() try: inv = inventory.Inventory(revision_id='revision-id') inv.root.revision = 'revision-id' inv_sha1 = repo.add_inventory('revision-id', inv, []) if repo.supports_rich_root(): root_id = inv.root.file_id repo.texts.add_lines((root_id, 'revision-id'), [], []) revision = _mod_revision.Revision('revision-id', committer='*****@*****.**', timestamp=0, inventory_sha1=inv_sha1, timezone=0, message='message', parent_ids=[]) # Manually add the revision text using the RevisionStore API, with # bad parents. rev_text = repo._serializer.write_revision_to_string(revision) repo.revisions.add_lines((revision.revision_id,), [('incorrect-parent',)], osutils.split_lines(rev_text)) except: repo.abort_write_group() repo.unlock() raise else: repo.commit_write_group() repo.unlock() repo.lock_write() self.addCleanup(repo.unlock) return repo
def add_commit(repo, revision_id, parent_ids): repo.lock_write() repo.start_write_group() inv = inventory.Inventory(revision_id=revision_id) inv.root.revision = revision_id root_id = inv.root.file_id sha1 = repo.add_inventory(revision_id, inv, []) repo.texts.add_lines((root_id, revision_id), [], []) rev = _mod_revision.Revision(timestamp=0, timezone=None, committer="Foo Bar <*****@*****.**>", message="Message", inventory_sha1=sha1, revision_id=revision_id) rev.parent_ids = parent_ids repo.add_revision(revision_id, rev) repo.commit_write_group() repo.unlock()
def test_invalid_status(self): r = revision.Revision( '1', properties={'bugs': 'http://example.com/bugs/1 faxed'}) self.assertRaises(InvalidBugStatus, list, r.iter_bugs())
def test_too_much_information(self): r = revision.Revision( '1', properties={'bugs': 'http://example.com/bugs/1 fixed bar'}) self.assertRaises(InvalidLineInBugsProperty, list, r.iter_bugs())
def test_no_status(self): r = revision.Revision('1', properties={'bugs': 'http://example.com/bugs/1'}) self.assertRaises(InvalidLineInBugsProperty, list, r.iter_bugs())
def test_get_apparent_authors_no_committer(self): r = revision.Revision('1') self.assertEqual([], r.get_apparent_authors())
def test_get_apparent_author(self): r = revision.Revision('1') r.committer = 'A' self.assertEqual('A', r.get_apparent_author()) r.properties['author'] = 'B' self.assertEqual('B', r.get_apparent_author())
def test_no_bugs(self): r = revision.Revision('1') self.assertEqual([], list(r.iter_bugs()))