def _bisect(self, handler, build_data): self.bisection = Bisection(handler, build_data, self.download_manager, self.test_runner, self.fetch_config, dl_in_background=False) self._bisect_next()
def _bisect(self, handler, build_range): self.bisection = Bisection(handler, build_range, self.download_manager, self.test_runner, dl_in_background=False, approx_chooser=self.approx_chooser) self._bisect_next()
class GuiBisector(QObject, Bisector): started = Signal() finished = Signal(object, int) step_started = Signal(object) step_build_found = Signal(object, object) step_testing = Signal(object, object) step_finished = Signal(object, str) def __init__(self, fetch_config, persist=None): QObject.__init__(self) Bisector.__init__(self, fetch_config, GuiTestRunner(), persist=persist) self.download_manager = GuiBuildDownloadManager(self.download_dir) self.bisection = None self.mid = None self.build_infos = None self._bisect_args = None self.error = None self.download_manager.download_finished.connect( self._build_dl_finished) self.test_runner.evaluate_finished.connect(self._evaluate_finished) def _finish_on_exception(self, bisection): self.error = sys.exc_info() self.finished.emit(bisection, Bisection.EXCEPTION) @Slot() def bisect(self): # this is a slot so it will be called in the thread self.started.emit() try: Bisector.bisect(self, *self._bisect_args) except MozRegressionError: self._finish_on_exception(None) @Slot() def nightlies_to_inbound(self): """ Call this when going from nightlies to inbound. """ assert self.bisection self.started.emit() try: # first we need to find the changesets first, last = self.bisection.handler.find_inbound_changesets() # create the inbound handler, and go with that handler = InboundHandler(find_fix=self.bisection.handler.find_fix) Bisector.bisect(self, handler, first, last) except MozRegressionError: self._finish_on_exception(None) def _bisect(self, handler, build_data): self.bisection = Bisection(handler, build_data, self.download_manager, self.test_runner, self.fetch_config, dl_in_background=False) self._bisect_next() @Slot() def _bisect_next(self): # this is executed in the working thread self.step_started.emit(self.bisection) try: self.mid = mid = self.bisection.search_mid_point() except MozRegressionError: self._finish_on_exception(self.bisection) return result = self.bisection.init_handler(mid) if result != Bisection.RUNNING: self.finished.emit(self.bisection, result) else: self.build_infos = \ self.bisection.handler.build_infos(mid, self.fetch_config) self.download_manager.focus_download(self.build_infos) self.step_build_found.emit(self.bisection, self.build_infos) @Slot() def _evaluate(self): # this is called in the working thread, so installation does not # block the ui. self.bisection.evaluate(self.build_infos) @Slot(object, str) def _build_dl_finished(self, dl, dest): # here we are not in the working thread, since the connection was # done in the constructor if not dest == self.build_infos['build_path']: return if dl is not None and (dl.is_canceled() or dl.error()): # todo handle this return self.step_testing.emit(self.bisection, self.build_infos) # call this in the thread QTimer.singleShot(0, self._evaluate) @Slot() def _evaluate_finished(self): # here we are not in the working thread, since the connection was # done in the constructor self.bisection.update_build_info(self.mid, self.test_runner.app_info) self.step_finished.emit(self.bisection, self.test_runner.verdict) result = self.bisection.handle_verdict(self.mid, self.test_runner.verdict) if result != Bisection.RUNNING: self.finished.emit(self.bisection, result) else: # call this in the thread QTimer.singleShot(0, self._bisect_next)
class GuiBisector(QObject, Bisector): started = Signal() finished = Signal(object, int) choose_next_build = Signal() step_started = Signal(object) step_build_found = Signal(object, object) step_testing = Signal(object, object) step_finished = Signal(object, str) handle_merge = Signal(object, str, str, str) def __init__(self, fetch_config, test_runner, download_manager, download_in_background=True): QObject.__init__(self) Bisector.__init__(self, fetch_config, test_runner, download_manager) self.bisection = None self.mid = None self.build_infos = None self._bisect_args = None self.error = None self._next_build_index = None self.download_in_background = download_in_background self.index_promise = None self._persist_files = () self.should_stop = threading.Event() self.download_manager.download_finished.connect(self._build_dl_finished) self.test_runner.evaluate_finished.connect(self._evaluate_finished) def _finish_on_exception(self, bisection): self.error = sys.exc_info() self.finished.emit(bisection, Bisection.EXCEPTION) @Slot() def bisect(self): # this is a slot so it will be called in the thread self.started.emit() try: Bisector.bisect(self, *self._bisect_args) except MozRegressionError: self._finish_on_exception(None) @Slot() def bisect_further(self): assert self.bisection self.started.emit() handler = self.bisection.handler try: nhandler = IntegrationHandler(find_fix=self.bisection.handler.find_fix) Bisector.bisect( self, nhandler, handler.good_revision, handler.bad_revision, expand=DEFAULT_EXPAND, interrupt=self.should_stop.is_set, ) except MozRegressionError: self._finish_on_exception(None) except StopIteration: self.finished.emit(None, Bisection.USER_EXIT) @Slot() def check_merge(self): handler = self.bisection.handler try: result = handler.handle_merge() except MozRegressionError: self._finish_on_exception(None) return if result is None: self.bisection.no_more_merge = True self.finished.emit(self.bisection, Bisection.FINISHED) else: self.handle_merge.emit(self.bisection, *result) def _bisect(self, handler, build_range): self.bisection = Bisection( handler, build_range, self.download_manager, self.test_runner, dl_in_background=False, approx_chooser=self.approx_chooser, ) self._bisect_next() @Slot() def _bisect_next(self): # this is executed in the working thread if self.test_runner.verdict != "r": try: self.mid = self.bisection.search_mid_point(interrupt=self.should_stop.is_set) except MozRegressionError: self._finish_on_exception(self.bisection) return except StopIteration: return # if our last answer was skip, and that the next build # to use is not chosen yet, ask to choose it. if ( self._next_build_index is None and self.test_runner.verdict == "s" and len(self.bisection.build_range) > 3 ): self.choose_next_build.emit() return if self._next_build_index is not None: # here user asked for specific build (eg from choose_next_build) self.mid = self._next_build_index # this will download build infos if required if self.bisection.build_range[self.mid] is False: # in case no build info is found, ask to choose again self.choose_next_build.emit() return self._next_build_index = None self.step_started.emit(self.bisection) result = self.bisection.init_handler(self.mid) if result != Bisection.RUNNING: self.finished.emit(self.bisection, result) else: self.build_infos = self.bisection.handler.build_range[self.mid] ( found, self.mid, self.build_infos, self._persist_files, ) = self.bisection._find_approx_build(self.mid, self.build_infos) if not found: self.download_manager.focus_download(self.build_infos) self.step_build_found.emit(self.bisection, self.build_infos) if found: # to continue the bisection, act as if it was downloaded self._build_dl_finished(None, self.build_infos.build_file) @Slot() def _evaluate(self): # this is called in the working thread, so installation does not # block the ui. # download in background, if desired and that last verdict was not # a skip. if self.download_in_background and self.test_runner.verdict != "s": self.index_promise = IndexPromise( self.mid, self.bisection._download_next_builds, args=(self._persist_files,), ) # run the build evaluation self.bisection.evaluate(self.build_infos) # wait for the next index in the thread if any if self.index_promise: self.index_promise() # if there was an error, stop the possible downloads if self.test_runner.run_error: self.download_manager.cancel() self.download_manager.wait(raise_if_error=False) if not self.test_runner.run_error: self.step_testing.emit(self.bisection, self.build_infos) @Slot(object, str) def _build_dl_finished(self, dl, dest): # here we are not in the working thread, since the connection was # done in the constructor if not dest == self.build_infos.build_file: return if dl is not None and (dl.is_canceled() or dl.error()): # todo handle this return # call this in the thread QTimer.singleShot(0, self._evaluate) @Slot() def _evaluate_finished(self): # here we are not in the working thread, since the connection was # done in the constructor if self.index_promise: self.mid = self.index_promise() self.index_promise = None self.step_finished.emit(self.bisection, self.test_runner.verdict) result = self.bisection.handle_verdict(self.mid, self.test_runner.verdict) if result != Bisection.RUNNING: self.finished.emit(self.bisection, result) else: # call this in the thread QTimer.singleShot(0, self._bisect_next)
class GuiBisector(QObject, Bisector): started = Signal() finished = Signal(object, int) choose_next_build = Signal() step_started = Signal(object) step_build_found = Signal(object, object) step_testing = Signal(object, object) step_finished = Signal(object, str) def __init__(self, fetch_config, download_dir, persist_limit): QObject.__init__(self) Bisector.__init__(self, fetch_config, GuiTestRunner(), GuiBuildDownloadManager(download_dir, persist_limit)) self.bisection = None self.mid = None self.build_infos = None self._bisect_args = None self.error = None self._next_build_index = None self.download_manager.download_finished.connect( self._build_dl_finished) self.test_runner.evaluate_finished.connect(self._evaluate_finished) def _finish_on_exception(self, bisection): self.error = sys.exc_info() self.finished.emit(bisection, Bisection.EXCEPTION) @Slot() def bisect(self): # this is a slot so it will be called in the thread self.started.emit() try: Bisector.bisect(self, *self._bisect_args) except MozRegressionError: self._finish_on_exception(None) @Slot() def nightlies_to_inbound(self): """ Call this when going from nightlies to inbound. """ assert self.bisection self.started.emit() try: # first we need to find the changesets first, last = self.bisection.handler.find_inbound_changesets() # create the inbound handler, and go with that handler = InboundHandler(find_fix=self.bisection.handler.find_fix) Bisector.bisect(self, handler, first, last) except MozRegressionError: self._finish_on_exception(None) def _bisect(self, handler, build_range): self.bisection = Bisection(handler, build_range, self.download_manager, self.test_runner, dl_in_background=False) self._bisect_next() @Slot() def _bisect_next(self): # this is executed in the working thread try: self.mid = mid = self.bisection.search_mid_point() except MozRegressionError: self._finish_on_exception(self.bisection) return # if our last answer was skip, and that the next build # to use is not chosen yet, ask to choose it. if (self._next_build_index is None and self.test_runner.verdict == 's' and len(self.bisection.build_range) > 3): self.choose_next_build.emit() return if self._next_build_index is not None: # here user asked for specific build (eg from choose_next_build) self.mid = mid = self._next_build_index # this will download build infos if required if self.bisection.build_range[mid] is False: # in case no build info is found, ask to choose again self.choose_next_build.emit() return self._next_build_index = None self.step_started.emit(self.bisection) result = self.bisection.init_handler(mid) if result != Bisection.RUNNING: self.finished.emit(self.bisection, result) else: self.build_infos = self.bisection.handler.build_range[mid] self.download_manager.focus_download(self.build_infos) self.step_build_found.emit(self.bisection, self.build_infos) @Slot() def _evaluate(self): # this is called in the working thread, so installation does not # block the ui. self.bisection.evaluate(self.build_infos) @Slot(object, str) def _build_dl_finished(self, dl, dest): # here we are not in the working thread, since the connection was # done in the constructor if not dest == self.build_infos.build_file: return if dl is not None and (dl.is_canceled() or dl.error()): # todo handle this return self.step_testing.emit(self.bisection, self.build_infos) # call this in the thread QTimer.singleShot(0, self._evaluate) @Slot() def _evaluate_finished(self): # here we are not in the working thread, since the connection was # done in the constructor self.step_finished.emit(self.bisection, self.test_runner.verdict) result = self.bisection.handle_verdict(self.mid, self.test_runner.verdict) if result != Bisection.RUNNING: self.finished.emit(self.bisection, result) else: # call this in the thread QTimer.singleShot(0, self._bisect_next)
class GuiBisector(QObject, Bisector): started = Signal() finished = Signal(object, int) choose_next_build = Signal() step_started = Signal(object) step_build_found = Signal(object, object) step_testing = Signal(object, object) step_finished = Signal(object, str) handle_merge = Signal(object, str, str, str) def __init__(self, fetch_config, test_runner, download_manager, download_in_background=True): QObject.__init__(self) Bisector.__init__(self, fetch_config, test_runner, download_manager) self.bisection = None self.mid = None self.build_infos = None self._bisect_args = None self.error = None self._next_build_index = None self.download_in_background = download_in_background self.index_promise = None self._persist_files = () self.should_stop = threading.Event() self.download_manager.download_finished.connect( self._build_dl_finished) self.test_runner.evaluate_finished.connect(self._evaluate_finished) def _finish_on_exception(self, bisection): self.error = sys.exc_info() self.finished.emit(bisection, Bisection.EXCEPTION) @Slot() def bisect(self): # this is a slot so it will be called in the thread self.started.emit() try: Bisector.bisect(self, *self._bisect_args) except MozRegressionError: self._finish_on_exception(None) @Slot() def bisect_further(self): assert self.bisection self.started.emit() handler = self.bisection.handler try: nhandler = InboundHandler(find_fix=self.bisection.handler.find_fix) Bisector.bisect(self, nhandler, handler.good_revision, handler.bad_revision) except MozRegressionError: self._finish_on_exception(None) @Slot() def check_merge(self): handler = self.bisection.handler try: result = handler.handle_merge() except MozRegressionError: self._finish_on_exception(None) return if result is None: self.bisection.no_more_merge = True else: self.handle_merge.emit(self.bisection, *result) def _bisect(self, handler, build_range): self.bisection = Bisection(handler, build_range, self.download_manager, self.test_runner, dl_in_background=False, approx_chooser=self.approx_chooser) self._bisect_next() @Slot() def _bisect_next(self): # this is executed in the working thread try: self.mid = mid = self.bisection.search_mid_point( interrupt=self.should_stop.is_set) except MozRegressionError: self._finish_on_exception(self.bisection) return except StopIteration: return # if our last answer was skip, and that the next build # to use is not chosen yet, ask to choose it. if (self._next_build_index is None and self.test_runner.verdict == 's' and len(self.bisection.build_range) > 3): self.choose_next_build.emit() return if self._next_build_index is not None: # here user asked for specific build (eg from choose_next_build) self.mid = mid = self._next_build_index # this will download build infos if required if self.bisection.build_range[mid] is False: # in case no build info is found, ask to choose again self.choose_next_build.emit() return self._next_build_index = None self.step_started.emit(self.bisection) result = self.bisection.init_handler(mid) if result != Bisection.RUNNING: self.finished.emit(self.bisection, result) else: self.build_infos = self.bisection.handler.build_range[mid] found, self.mid, self.build_infos, self._persist_files = \ self.bisection._find_approx_build(self.mid, self.build_infos) if not found: self.download_manager.focus_download(self.build_infos) self.step_build_found.emit(self.bisection, self.build_infos) if found: # to continue the bisection, act as if it was downloaded self._build_dl_finished(None, self.build_infos.build_file) @Slot() def _evaluate(self): # this is called in the working thread, so installation does not # block the ui. # download in background, if desired and that last verdict was not # a skip. if self.download_in_background and self.test_runner.verdict != 's': self.index_promise = IndexPromise( self.mid, self.bisection._download_next_builds, args=(self._persist_files,) ) # run the build evaluation self.bisection.evaluate(self.build_infos) # wait for the next index in the thread if any if self.index_promise: self.index_promise() # if there was an error, stop the possible downloads if self.test_runner.run_error: self.download_manager.cancel() self.download_manager.wait(raise_if_error=False) if not self.test_runner.run_error: self.step_testing.emit(self.bisection, self.build_infos) @Slot(object, str) def _build_dl_finished(self, dl, dest): # here we are not in the working thread, since the connection was # done in the constructor if not dest == self.build_infos.build_file: return if dl is not None and (dl.is_canceled() or dl.error()): # todo handle this return # call this in the thread QTimer.singleShot(0, self._evaluate) @Slot() def _evaluate_finished(self): # here we are not in the working thread, since the connection was # done in the constructor if self.index_promise: self.mid = self.index_promise() self.index_promise = None self.step_finished.emit(self.bisection, self.test_runner.verdict) result = self.bisection.handle_verdict(self.mid, self.test_runner.verdict) if result != Bisection.RUNNING: self.finished.emit(self.bisection, result) else: # call this in the thread QTimer.singleShot(0, self._bisect_next)