def iter_lefthand_ancestry(self, start_key, stop_keys=None): """Iterate backwards through revision ids in the lefthand history :param start_key: The revision id to start with. All its lefthand ancestors will be traversed. """ if stop_keys is None: stop_keys = () if _mod_revision.is_null(start_key): return try: foreign_revid, mapping = self._revmeta_provider.lookup_bzr_revision_id(start_key) except _mod_errors.NoSuchRevision: for key in super(SubversionGraph, self).iter_lefthand_ancestry(start_key, stop_keys): yield key return (uuid, branch_path, revnum) = foreign_revid for revmeta, hidden, mapping in self._revmeta_provider._iter_reverse_revmeta_mapping_history( branch_path, revnum, to_revnum=0, mapping=mapping): if hidden: continue key = revmeta.get_revision_id(mapping) if key in stop_keys: return yield key
def _update_revisions(self, stop_revision=None, overwrite=False, graph=None, fetch_tags=None, fetch_non_mainline=None): "See InterBranch.update_revisions." "" with self.source.lock_read(): if stop_revision is None: stop_revision = self.source.last_revision() if is_null(stop_revision): # if there are no commits, we're done. return self.target.last_revision_info() # what's the current last revision, before we fetch [and # change it possibly] last_rev = self.target.last_revision() if fetch_non_mainline is None: fetch_non_mainline = True self.fetch(stop_revision=stop_revision, fetch_tags=fetch_tags, exclude_non_mainline=(not fetch_non_mainline)) # Check to see if one is an ancestor of the other if not overwrite: if graph is None: graph = self.target.repository.get_graph() with self.target.lock_read(): if self.target._check_if_descendant_or_diverged( stop_revision, last_rev, graph, self.source): # stop_revision is a descendant of last_rev, but we # aren't overwriting, so we're done. return self.target.last_revision_info() self.target._clear_cached_state() self.target.generate_revision_history(stop_revision) return self.target.last_revision_info()
def revision_id_to_revno(self, revision_id): """Given a revision id, return its revno""" if is_null(revision_id): return 0 revmeta_history = self._revision_meta_history() # FIXME: Maybe we can parse revision_id as a bzr-svn roundtripped # revision? for revmeta, hidden, mapping in revmeta_history: if hidden: continue if revmeta.get_revision_id(mapping) == revision_id: return revmeta.get_revno(mapping) raise NoSuchRevision(self, revision_id)
def compute_whole_history_data(branch): """Compute _rev_info and _rev_indices for a branch. See History.__doc__ for what these data structures mean. """ z = time.time() last_revid = branch.last_revision() log = logging.getLogger('loggerhead.%s' % (branch.get_config().get_nickname(), )) graph = branch.repository.get_graph() parent_map = dict((key, value) for key, value in graph.iter_ancestry([last_revid]) if value is not None) _revision_graph = _strip_NULL_ghosts(parent_map) _rev_info = [] _rev_indices = {} if is_null(last_revid): _merge_sort = [] else: _merge_sort = merge_sort(_revision_graph, last_revid, generate_revno=True) for info in _merge_sort: seq, revid, merge_depth, revno, end_of_merge = info revno_str = '.'.join(str(n) for n in revno) parents = _revision_graph[revid] _rev_indices[revid] = len(_rev_info) _rev_info.append([(seq, revid, merge_depth, revno_str, end_of_merge), (), parents]) for revid in _revision_graph.keys(): if _rev_info[_rev_indices[revid]][0][2] == 0: continue for parent in _revision_graph[revid]: c = _rev_info[_rev_indices[parent]] if revid not in c[1]: c[1] = c[1] + (revid, ) log.info('built revision graph cache: %.3f secs' % (time.time() - z, )) return (_rev_info, _rev_indices)
def get_threads(self, rev_id): """Return the threads from a loom revision. :param rev_id: A specific loom revision to retrieve. :return: a list of threads. e.g. [('threadname', 'last_revision')] """ if rev_id is None: symbol_versioning.warn( 'NULL_REVISION should be used for the null' ' revision instead of None, as of bzr 0.90.', DeprecationWarning, stacklevel=2) if is_null(rev_id): return [] content = self._loom_content(rev_id) return self._parse_loom(content)
def unlock(self): """Unlock the loom after a lock. If at the end of the lock, the current revision in the branch is not recorded correctly in the loom, an automatic record is attempted. """ if (self.control_files._lock_count == 1 and self.control_files._lock_mode == 'w'): # about to release the lock state = self.get_loom_state() threads = state.get_threads() if len(threads): # looms are enabled: lastrev = self.last_revision() if is_null(lastrev): lastrev = EMPTY_REVISION if dict(state.get_threads_dict())[self.nick][0] != lastrev: self.record_thread(self.nick, lastrev) super(LoomSupport, self).unlock()
def test_sprout_bzrdir_repository(self): tree = self.make_branch_and_tree('commit_tree') self.build_tree(['foo'], transport=tree.controldir.transport.clone('..')) tree.add('foo') tree.commit('revision 1', rev_id=b'1') dir = self.make_controldir('source') repo = dir.create_repository() repo.fetch(tree.branch.repository) self.assertTrue(repo.has_revision(b'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. with open(local_inventory, 'rb') as inventory_f: self.assertContainsRe( inventory_f.read(), b'<inventory format="5">\n</inventory>\n') except IOError as e: if e.errno != errno.ENOENT: raise
def record_thread(self, thread_name, revision_id): """Record an updated version of an existing thread. :param thread_name: the thread to record. :param revision_id: the revision it is now at. This should be a child of the next lower thread. """ with self.lock_write(): state = self.get_loom_state() threads = state.get_threads() assert thread_name in state.get_threads_dict() if is_null(revision_id): revision_id = EMPTY_REVISION for position, (name, rev, parents) in enumerate(threads): if name == thread_name: if revision_id == rev: raise UnchangedThreadRevision(self, thread_name) threads[position] = (name, revision_id, parents) state.set_threads(threads) self._set_last_loom(state)
def new_thread(self, thread_name, after_thread=None): """Add a new thread to this branch called 'thread_name'.""" state = self.get_loom_state() threads = state.get_threads() if thread_name in state.get_threads_dict(): raise DuplicateThreadName(self, thread_name) assert after_thread is None or after_thread in state.get_threads_dict() if after_thread is None: insertion_point = len(threads) else: insertion_point = state.thread_index(after_thread) + 1 if insertion_point == 0: revision_for_thread = self.last_revision() else: revision_for_thread = threads[insertion_point - 1][1] if is_null(revision_for_thread): revision_for_thread = EMPTY_REVISION threads.insert(insertion_point, (thread_name, revision_for_thread, [None] * len(state.get_parents()))) state.set_threads(threads) self._set_last_loom(state)
def refresh_view(self): """get the revisions wanted by the user, do the verifications and popular the tree widget with the results""" self.throbber.show() controldir = _mod_controldir.ControlDir.open_containing( self.location)[0] branch = controldir.open_branch() repo = branch.repository branch_config = branch.get_config_stack() gpg_strategy = gpg.GPGStrategy(branch_config) gpg_strategy.set_acceptable_keys(self.acceptable_keys) if branch.name is None: header = branch.user_url else: header = branch.name self.ui.treeWidget.setHeaderLabels([str(header)]) # get our list of revisions revisions = [] if self.revision is not None: if len(self.revision) == 1: revno, rev_id = self.revision[0].in_history(branch) revisions.append(rev_id) elif len(sel.revision) == 2: from_revno, from_revid = self.revision[0].in_history(branch) to_revno, to_revid = self.revision[1].in_history(branch) if to_revid is None: to_revno = branch.revno() if from_revno is None or to_revno is None: raise errors.BzrCommandError( 'Cannot verify a range of non-revision-history revisions' ) for revno in range(from_revno, to_revno + 1): revisions.append(branch.get_rev_id(revno)) else: # all revisions by default including merges graph = repo.get_graph() revisions = [] repo.lock_read() for rev_id, parents in graph.iter_ancestry( [branch.last_revision()]): if _mod_revision.is_null(rev_id): continue if parents is None: # Ignore ghosts continue revisions.append(rev_id) repo.unlock() count, result, all_verifiable = gpg.bulk_verify_signatures( repo, revisions, gpg_strategy, QApplication.processEvents) if all_verifiable: message = QTreeWidgetItem( [gettext("All commits signed with verifiable keys")]) self.ui.treeWidget.addTopLevelItem(message) for verbose_message in gpg.verbose_valid_message(result): QTreeWidgetItem(message, [verbose_message]) else: valid_commit_message = QTreeWidgetItem( [gpg.valid_commits_message(count)]) self.ui.treeWidget.addTopLevelItem(valid_commit_message) for verbose_message in gpg.verbose_valid_message(result): QTreeWidgetItem(valid_commit_message, [verbose_message]) expired_key_message = QTreeWidgetItem( [gpg.expired_commit_message(count)]) self.ui.treeWidget.addTopLevelItem(expired_key_message) for verbose_message in gpg.verbose_expired_key_message( result, repo): QTreeWidgetItem(expired_key_message, [verbose_message]) unknown_key_message = QTreeWidgetItem( [gpg.unknown_key_message(count)]) self.ui.treeWidget.addTopLevelItem(unknown_key_message) for verbose_message in gpg.verbose_missing_key_message(result): QTreeWidgetItem(unknown_key_message, [verbose_message]) commit_not_valid_message = QTreeWidgetItem( [gpg.commit_not_valid_message(count)]) self.ui.treeWidget.addTopLevelItem(commit_not_valid_message) for verbose_message in gpg.verbose_not_valid_message(result, repo): QTreeWidgetItem(commit_not_valid_message, [verbose_message]) commit_not_signed_message = QTreeWidgetItem( [gpg.commit_not_signed_message(count)]) self.ui.treeWidget.addTopLevelItem(commit_not_signed_message) for verbose_message in gpg.verbose_not_signed_message( result, repo): QTreeWidgetItem(commit_not_signed_message, [verbose_message]) self.throbber.hide()