Exemplo n.º 1
0
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)
Exemplo n.º 2
0
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)
Exemplo n.º 3
0
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)
Exemplo n.º 4
0
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)
Exemplo n.º 5
0
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)