def initialize(self, a_bzrdir, revision_id=None, from_branch=None, accelerator_tree=None, hardlink=False): """See WorkingTreeFormat.initialize(). :param revision_id: if supplied, create a working tree at a different revision than the branch is at. :param accelerator_tree: A tree which can be used for retrieving file contents more quickly than the revision tree, i.e. a workingtree. The revision tree will be used for cases where accelerator_tree's content is different. :param hardlink: If true, hard-link files from accelerator_tree, where possible. """ if not isinstance(a_bzrdir.transport, LocalTransport): raise errors.NotLocalUrl(a_bzrdir.transport.base) transport = a_bzrdir.get_workingtree_transport(self) control_files = self._open_control_files(a_bzrdir) control_files.create_lock() control_files.lock_write() transport.put_bytes('format', self.as_string(), mode=a_bzrdir._get_file_mode()) if from_branch is not None: branch = from_branch else: branch = a_bzrdir.open_branch() if revision_id is None: revision_id = _mod_revision.ensure_null(branch.last_revision()) # WorkingTree3 can handle an inventory which has a unique root id. # as of bzr 0.12. However, bzr 0.11 and earlier fail to handle # those trees. And because there isn't a format bump inbetween, we # are maintaining compatibility with older clients. # inv = Inventory(root_id=gen_root_id()) inv = self._initial_inventory() wt = self._tree_class(a_bzrdir.root_transport.local_abspath('.'), branch, inv, _internal=True, _format=self, _bzrdir=a_bzrdir, _control_files=control_files) wt.lock_tree_write() try: basis_tree = branch.repository.revision_tree(revision_id) # only set an explicit root id if there is one to set. if basis_tree.get_root_id() is not None: wt.set_root_id(basis_tree.get_root_id()) if revision_id == _mod_revision.NULL_REVISION: wt.set_parent_trees([]) else: wt.set_parent_trees([(revision_id, basis_tree)]) transform.build_tree(basis_tree, wt) for hook in MutableTree.hooks['post_build_tree']: hook(wt) finally: # Unlock in this order so that the unlock-triggers-flush in # WorkingTree is given a chance to fire. control_files.unlock() wt.unlock() return wt
def revision_tree(self, revision_id): revision_id = revision.ensure_null(revision_id) if revision_id == revision.NULL_REVISION: inv = inventory.Inventory(root_id=None) inv.revision_id = revision_id return revisiontree.RevisionTree(self, inv, revision_id) return GitRevisionTree(self, self.get_mapping(), revision_id)
def _as_revision_id(self, context_branch): from bzrlib.branch import Branch other_branch = Branch.open(self.spec) last_revision = other_branch.last_revision() last_revision = revision.ensure_null(last_revision) context_branch.fetch(other_branch, last_revision) if last_revision == revision.NULL_REVISION: raise errors.NoCommits(other_branch) return last_revision
def make_read_requests(self, branch): """Do some read only requests.""" branch.lock_read() try: branch.repository.all_revision_ids() self.assertEqual(_mod_revision.NULL_REVISION, _mod_revision.ensure_null(branch.last_revision())) finally: branch.unlock()
def set_last_revision_info(self, revno, revision_id): if not revision_id or not isinstance(revision_id, basestring): raise errors.InvalidRevisionId(revision_id=revision_id, branch=self) revision_id = _mod_revision.ensure_null(revision_id) # this old format stores the full history, but this api doesn't # provide it, so we must generate, and might as well check it's # correct history = self._lefthand_history(revision_id) if len(history) != revno: raise AssertionError('%d != %d' % (len(history), revno)) self._set_revision_history(history)
def from_objects(klass, repository, revision_id, time, timezone, target_branch, patch_type='bundle', local_target_branch=None, public_branch=None, message=None): """Generate a merge directive from various objects :param repository: The repository containing the revision :param revision_id: The revision to merge :param time: The POSIX timestamp of the date the request was issued. :param timezone: The timezone of the request :param target_branch: The url of the branch to merge into :param patch_type: 'bundle', 'diff' or None, depending on the type of patch desired. :param local_target_branch: a local copy of the target branch :param public_branch: location of a public branch containing the target revision. :param message: Message to use when committing the merge :return: The merge directive The public branch is always used if supplied. If the patch_type is not 'bundle', the public branch must be supplied, and will be verified. If the message is not supplied, the message from revision_id will be used for the commit. """ t_revision_id = revision_id if revision_id == _mod_revision.NULL_REVISION: t_revision_id = None t = testament.StrictTestament3.from_revision(repository, t_revision_id) submit_branch = _mod_branch.Branch.open(target_branch) if submit_branch.get_public_branch() is not None: target_branch = submit_branch.get_public_branch() if patch_type is None: patch = None else: submit_revision_id = submit_branch.last_revision() submit_revision_id = _mod_revision.ensure_null(submit_revision_id) repository.fetch(submit_branch.repository, submit_revision_id) graph = repository.get_graph() ancestor_id = graph.find_unique_lca(revision_id, submit_revision_id) type_handler = {'bundle': klass._generate_bundle, 'diff': klass._generate_diff, None: lambda x, y, z: None } patch = type_handler[patch_type](repository, revision_id, ancestor_id) if public_branch is not None and patch_type != 'bundle': public_branch_obj = _mod_branch.Branch.open(public_branch) if not public_branch_obj.repository.has_revision(revision_id): raise errors.PublicBranchOutOfDate(public_branch, revision_id) return klass(revision_id, t.as_sha1(), time, timezone, target_branch, patch, patch_type, public_branch, message)
def assertConsistentParents(self, expected, tree): """Check that the parents found are as expected. This test helper also checks that they are consistent with the pre-get_parent_ids() api - which is now deprecated. """ self.assertEqual(expected, tree.get_parent_ids()) if expected == []: self.assertEqual(_mod_revision.NULL_REVISION, _mod_revision.ensure_null(tree.last_revision())) else: self.assertEqual(expected[0], tree.last_revision())
def _find_revision_id(branch, other_location): from bzrlib.branch import Branch branch.lock_read() try: revision_a = revision.ensure_null(branch.last_revision()) if revision_a == revision.NULL_REVISION: raise errors.NoCommits(branch) other_branch = Branch.open(other_location) other_branch.lock_read() try: revision_b = revision.ensure_null(other_branch.last_revision()) if revision_b == revision.NULL_REVISION: raise errors.NoCommits(other_branch) graph = branch.repository.get_graph(other_branch.repository) rev_id = graph.find_unique_lca(revision_a, revision_b) finally: other_branch.unlock() if rev_id == revision.NULL_REVISION: raise errors.NoCommonAncestor(revision_a, revision_b) return rev_id finally: branch.unlock()
def test_local_commit_does_not_push_to_master(self): # a --local commit does not require access to the master branch # at all, or even for it to exist. # we test that even when its available it does not push to it. master = self.make_branch('master') tree = self.make_branch_and_tree('tree') try: tree.branch.bind(master) except errors.UpgradeRequired: # older format. return tree.commit('foo', rev_id='foo', local=True) self.assertFalse(master.repository.has_revision('foo')) self.assertEqual(_mod_revision.NULL_REVISION, (_mod_revision.ensure_null(master.last_revision())))
def test_local_commit_does_not_push_to_master(self): # a --local commit does not require access to the master branch # at all, or even for it to exist. # we test that even when its available it does not push to it. master = self.make_branch('master') tree = self.make_branch_and_tree('tree') try: tree.branch.bind(master) except errors.UpgradeRequired: # older format. return tree.commit('foo', rev_id='foo', local=True) self.failIf(master.repository.has_revision('foo')) self.assertEqual(_mod_revision.NULL_REVISION, (_mod_revision.ensure_null(master.last_revision())))
def _any_local_commits(this_branch, possible_transports): """Does this branch have any commits not in the master branch?""" last_rev = revision.ensure_null(this_branch.last_revision()) if last_rev != revision.NULL_REVISION: other_branch = this_branch.get_master_branch(possible_transports) this_branch.lock_read() other_branch.lock_read() try: other_last_rev = other_branch.last_revision() graph = this_branch.repository.get_graph(other_branch.repository) if not graph.is_ancestor(last_rev, other_last_rev): return True finally: other_branch.unlock() this_branch.unlock() return False
def _any_local_commits(this_branch, possible_transports): """Does this branch have any commits not in the master branch?""" last_rev = revision.ensure_null(this_branch.last_revision()) if last_rev != revision.NULL_REVISION: other_branch = this_branch.get_master_branch(possible_transports) this_branch.lock_read() other_branch.lock_read() try: other_last_rev = other_branch.last_revision() graph = this_branch.repository.get_graph( other_branch.repository) if not graph.is_ancestor(last_rev, other_last_rev): return True finally: other_branch.unlock() this_branch.unlock() return False
def initialize(self, a_bzrdir, revision_id=None, from_branch=None, accelerator_tree=None, hardlink=False): """See WorkingTreeFormat.initialize().""" if not isinstance(a_bzrdir.transport, LocalTransport): raise errors.NotLocalUrl(a_bzrdir.transport.base) if from_branch is not None: branch = from_branch else: branch = a_bzrdir.open_branch() if revision_id is None: revision_id = _mod_revision.ensure_null(branch.last_revision()) branch.lock_write() try: branch.generate_revision_history(revision_id) finally: branch.unlock() inv = inventory.Inventory() wt = WorkingTree2(a_bzrdir.root_transport.local_abspath('.'), branch, inv, _internal=True, _format=self, _bzrdir=a_bzrdir, _control_files=branch.control_files) basis_tree = branch.repository.revision_tree(revision_id) if basis_tree.get_root_id() is not None: wt.set_root_id(basis_tree.get_root_id()) # set the parent list and cache the basis tree. if _mod_revision.is_null(revision_id): parent_trees = [] else: parent_trees = [(revision_id, basis_tree)] wt.set_parent_trees(parent_trees) transform.build_tree(basis_tree, wt) for hook in MutableTree.hooks['post_build_tree']: hook(wt) return wt
def test_sprout_bzrdir_repository(self): tree = self.make_branch_and_tree('commit_tree') self.build_tree(['foo'], transport=tree.bzrdir.transport.clone('..')) tree.add('foo') tree.commit('revision 1', rev_id='1') dir = self.make_bzrdir('source') repo = dir.create_repository() repo.fetch(tree.branch.repository) self.assertTrue(repo.has_revision('1')) try: self.assertTrue( _mod_revision.is_null(_mod_revision.ensure_null( dir.open_branch().last_revision()))) except errors.NotBranchError: pass target = dir.sprout(self.get_url('target')) self.assertNotEqual(dir.transport.base, target.transport.base) # testing inventory isn't reasonable for repositories self.assertDirectoriesEqual(dir.root_transport, target.root_transport, [ './.bzr/branch', './.bzr/checkout', './.bzr/inventory', './.bzr/parent', './.bzr/repository/inventory.knit', ]) try: local_inventory = dir.transport.local_abspath('inventory') except errors.NotLocalUrl: return try: # If we happen to have a tree, we'll guarantee everything # except for the tree root is the same. inventory_f = file(local_inventory, 'rb') self.addCleanup(inventory_f.close) self.assertContainsRe(inventory_f.read(), '<inventory format="5">\n</inventory>\n') except IOError, e: if e.errno != errno.ENOENT: raise
def test_update_unbound_works(self): b = self.make_branch('.') b.update() self.assertEqual(_mod_revision.NULL_REVISION, _mod_revision.ensure_null(b.last_revision()))
def from_objects(klass, repository, revision_id, time, timezone, target_branch, include_patch=True, include_bundle=True, local_target_branch=None, public_branch=None, message=None, base_revision_id=None): """Generate a merge directive from various objects :param repository: The repository containing the revision :param revision_id: The revision to merge :param time: The POSIX timestamp of the date the request was issued. :param timezone: The timezone of the request :param target_branch: The url of the branch to merge into :param include_patch: If true, include a preview patch :param include_bundle: If true, include a bundle :param local_target_branch: a local copy of the target branch :param public_branch: location of a public branch containing the target revision. :param message: Message to use when committing the merge :return: The merge directive The public branch is always used if supplied. If no bundle is included, the public branch must be supplied, and will be verified. If the message is not supplied, the message from revision_id will be used for the commit. """ locked = [] try: repository.lock_write() locked.append(repository) t_revision_id = revision_id if revision_id == 'null:': t_revision_id = None t = testament.StrictTestament3.from_revision(repository, t_revision_id) submit_branch = _mod_branch.Branch.open(target_branch) submit_branch.lock_read() locked.append(submit_branch) if submit_branch.get_public_branch() is not None: target_branch = submit_branch.get_public_branch() submit_revision_id = submit_branch.last_revision() submit_revision_id = _mod_revision.ensure_null(submit_revision_id) graph = repository.get_graph(submit_branch.repository) ancestor_id = graph.find_unique_lca(revision_id, submit_revision_id) if base_revision_id is None: base_revision_id = ancestor_id if (include_patch, include_bundle) != (False, False): repository.fetch(submit_branch.repository, submit_revision_id) if include_patch: patch = klass._generate_diff(repository, revision_id, base_revision_id) else: patch = None if include_bundle: bundle = klass._generate_bundle(repository, revision_id, ancestor_id).encode('base-64') else: bundle = None if public_branch is not None and not include_bundle: public_branch_obj = _mod_branch.Branch.open(public_branch) public_branch_obj.lock_read() locked.append(public_branch_obj) if not public_branch_obj.repository.has_revision( revision_id): raise errors.PublicBranchOutOfDate(public_branch, revision_id) finally: for entry in reversed(locked): entry.unlock() return klass(revision_id, t.as_sha1(), time, timezone, target_branch, patch, public_branch, message, bundle, base_revision_id)
def create_on_branch(branch): """Create a MemoryTree for branch, using the last-revision of branch.""" revision_id = _mod_revision.ensure_null(branch.last_revision()) return MemoryTree(branch, revision_id)
def from_objects(klass, repository, revision_id, time, timezone, target_branch, include_patch=True, include_bundle=True, local_target_branch=None, public_branch=None, message=None, base_revision_id=None): """Generate a merge directive from various objects :param repository: The repository containing the revision :param revision_id: The revision to merge :param time: The POSIX timestamp of the date the request was issued. :param timezone: The timezone of the request :param target_branch: The url of the branch to merge into :param include_patch: If true, include a preview patch :param include_bundle: If true, include a bundle :param local_target_branch: a local copy of the target branch :param public_branch: location of a public branch containing the target revision. :param message: Message to use when committing the merge :return: The merge directive The public branch is always used if supplied. If no bundle is included, the public branch must be supplied, and will be verified. If the message is not supplied, the message from revision_id will be used for the commit. """ locked = [] try: repository.lock_write() locked.append(repository) t_revision_id = revision_id if revision_id == 'null:': t_revision_id = None t = testament.StrictTestament3.from_revision( repository, t_revision_id) submit_branch = _mod_branch.Branch.open(target_branch) submit_branch.lock_read() locked.append(submit_branch) if submit_branch.get_public_branch() is not None: target_branch = submit_branch.get_public_branch() submit_revision_id = submit_branch.last_revision() submit_revision_id = _mod_revision.ensure_null(submit_revision_id) graph = repository.get_graph(submit_branch.repository) ancestor_id = graph.find_unique_lca(revision_id, submit_revision_id) if base_revision_id is None: base_revision_id = ancestor_id if (include_patch, include_bundle) != (False, False): repository.fetch(submit_branch.repository, submit_revision_id) if include_patch: patch = klass._generate_diff(repository, revision_id, base_revision_id) else: patch = None if include_bundle: bundle = klass._generate_bundle(repository, revision_id, ancestor_id).encode('base-64') else: bundle = None if public_branch is not None and not include_bundle: public_branch_obj = _mod_branch.Branch.open(public_branch) public_branch_obj.lock_read() locked.append(public_branch_obj) if not public_branch_obj.repository.has_revision(revision_id): raise errors.PublicBranchOutOfDate(public_branch, revision_id) finally: for entry in reversed(locked): entry.unlock() return klass(revision_id, t.as_sha1(), time, timezone, target_branch, patch, public_branch, message, bundle, base_revision_id)
def from_objects(klass, repository, revision_id, time, timezone, target_branch, patch_type='bundle', local_target_branch=None, public_branch=None, message=None): """Generate a merge directive from various objects :param repository: The repository containing the revision :param revision_id: The revision to merge :param time: The POSIX timestamp of the date the request was issued. :param timezone: The timezone of the request :param target_branch: The url of the branch to merge into :param patch_type: 'bundle', 'diff' or None, depending on the type of patch desired. :param local_target_branch: a local copy of the target branch :param public_branch: location of a public branch containing the target revision. :param message: Message to use when committing the merge :return: The merge directive The public branch is always used if supplied. If the patch_type is not 'bundle', the public branch must be supplied, and will be verified. If the message is not supplied, the message from revision_id will be used for the commit. """ t_revision_id = revision_id if revision_id == _mod_revision.NULL_REVISION: t_revision_id = None t = testament.StrictTestament3.from_revision(repository, t_revision_id) submit_branch = _mod_branch.Branch.open(target_branch) if submit_branch.get_public_branch() is not None: target_branch = submit_branch.get_public_branch() if patch_type is None: patch = None else: submit_revision_id = submit_branch.last_revision() submit_revision_id = _mod_revision.ensure_null(submit_revision_id) repository.fetch(submit_branch.repository, submit_revision_id) graph = repository.get_graph() ancestor_id = graph.find_unique_lca(revision_id, submit_revision_id) type_handler = { 'bundle': klass._generate_bundle, 'diff': klass._generate_diff, None: lambda x, y, z: None } patch = type_handler[patch_type](repository, revision_id, ancestor_id) if public_branch is not None and patch_type != 'bundle': public_branch_obj = _mod_branch.Branch.open(public_branch) if not public_branch_obj.repository.has_revision(revision_id): raise errors.PublicBranchOutOfDate(public_branch, revision_id) return klass(revision_id, t.as_sha1(), time, timezone, target_branch, patch, patch_type, public_branch, message)