diff --git a/gui/mozregression-gui.py b/gui/mozregression-gui.py index 3323550f..5b3bde65 100644 --- a/gui/mozregression-gui.py +++ b/gui/mozregression-gui.py @@ -9,6 +9,7 @@ from mozlog.structured.structuredlog import StructuredLogger from mozregui.ui.mainwindow import Ui_MainWindow from mozregui.wizard import BisectionWizard from mozregui.bisection import BisectRunner +from mozregui.report import ReportModel class MainWindow(QMainWindow): @@ -18,6 +19,12 @@ class MainWindow(QMainWindow): self.ui.setupUi(self) self.bisect_runner = BisectRunner(self) + self.report_model = ReportModel() + self.ui.report_view.setModel(self.report_model) + + self.bisect_runner.bisector_created.connect( + self.report_model.attach_bisector) + @Slot() def start_bisection_wizard(self): wizard = BisectionWizard(self) diff --git a/gui/mozregui/bisection.py b/gui/mozregui/bisection.py index a5ebd255..c54df2f0 100644 --- a/gui/mozregui/bisection.py +++ b/gui/mozregui/bisection.py @@ -66,7 +66,11 @@ class GuiTestRunner(QObject, TestRunner): class GuiBisector(QObject, Bisector): - finished = Signal(int) + started = Signal(object) + finished = Signal(object, int) + step_started = Signal(object, int) + step_build_found = Signal(object, int, object) + step_finished = Signal(object, int, str) def __init__(self, fetch_config, persist=None): QObject.__init__(self) @@ -75,6 +79,7 @@ class GuiBisector(QObject, Bisector): self.bisection = None self.mid = None self.build_infos = None + self._step_num = 0 self.download_manager.download_finished.connect(self._build_dl_finished) self.test_runner.evaluate_finished.connect(self._evaluate_finished) @@ -85,19 +90,25 @@ class GuiBisector(QObject, Bisector): self.test_runner, self.fetch_config, dl_in_background=False) + self._step_num = 0 + self.started.emit(self.bisection) self._bisect_next() @Slot() def _bisect_next(self): + self._step_num += 1 + self.step_started.emit(self.bisection, self._step_num) # todo: make this non blocking self.mid = mid = self.bisection.search_mid_point() result = self.bisection.init_handler(mid) if result != Bisection.RUNNING: - self.finished.emit(result) + 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._step_num, + self.build_infos) @Slot(object) def _build_dl_finished(self, dl): @@ -111,14 +122,18 @@ class GuiBisector(QObject, Bisector): @Slot() def _evaluate_finished(self): self.bisection.update_build_info(self.mid, self.test_runner.app_info) + self.step_finished.emit(self.bisection, self._step_num, + self.test_runner.verdict) result = self.bisection.handle_verdict(self.mid, self.test_runner.verdict) if result != Bisection.RUNNING: - self.finished.emit(result) + self.finished.emit(self.bisection, result) else: self._bisect_next() class BisectRunner(QObject): + bisector_created = Signal(object) + def __init__(self, mainwindow): QObject.__init__(self) self.mainwindow = mainwindow @@ -129,6 +144,7 @@ class BisectRunner(QObject): fetch_config = create_config(options['application'], mozinfo.os, mozinfo.bits) self.bisector = GuiBisector(fetch_config) + self.bisector.started.connect(self.on_bisection_started) self.bisector.download_manager.download_progress.connect( self.show_dl_progress) self.bisector.test_runner.evaluate_started.connect( @@ -166,8 +182,8 @@ class BisectRunner(QObject): verdict = "b" self.bisector.test_runner.finish(verdict) - @Slot(int) - def bisection_finished(self, resultcode): + @Slot(object, int) + def bisection_finished(self, bisection, resultcode): if resultcode == Bisection.NO_DATA: msg = "Unable to find enough data to bisect." dialog = QMessageBox.warning @@ -175,3 +191,7 @@ class BisectRunner(QObject): msg = "The bisection is done." dialog = QMessageBox.information dialog(self.mainwindow, "End of the bisection", msg) + + @Slot() + def on_bisection_started(self): + self.bisector_created.emit(self.bisector) diff --git a/gui/mozregui/report.py b/gui/mozregui/report.py new file mode 100644 index 00000000..c1dd5366 --- /dev/null +++ b/gui/mozregui/report.py @@ -0,0 +1,72 @@ +from PySide.QtCore import QAbstractTableModel, QModelIndex, Qt, \ + Slot + +class StepReport(object): + def __init__(self): + self.build_infos = None + self.verdict = None + + def status_text(self): + if self.build_infos is None: + return "Looking for build data..." + if self.build_infos['build_type'] == 'nightly': + msg = "Found nightly build: %s" % self.build_infos['build_date'] + else: + msg = "Found inbound build: %s" % self.build_infos['changeset'] + if self.verdict is not None: + msg += ' (verdict: %s)' % self.verdict + return msg + +class ReportModel(QAbstractTableModel): + def __init__(self): + QAbstractTableModel.__init__(self) + self.step_reports = [] + + @Slot(object) + def attach_bisector(self, bisector): + bisector.step_started.connect(self.step_started) + bisector.step_build_found.connect(self.step_build_found) + bisector.step_finished.connect(self.step_finished) + bisector.finished.connect(self.finished) + + def rowCount(self, parent=QModelIndex()): + return len(self.step_reports) + + def columnCount(self, parent=QModelIndex()): + return 1 + + def data(self, index, role=Qt.DisplayRole): + if role == Qt.DisplayRole: + step_report = self.step_reports[index.row()] + return step_report.status_text() + return None + + def update_step_report(self, step_report): + index = self.createIndex(self.step_reports.index(step_report), 0) + self.dataChanged.emit(index, index) + + @Slot(object, int) + def step_started(self, bisection, step_num): + self.beginInsertRows(QModelIndex(), step_num-1, step_num-1) + self.step_reports.append(StepReport()) + self.endInsertRows() + + @Slot(object, int, object) + def step_build_found(self, bisection, step_num, build_infos): + step_report = self.step_reports[step_num-1] + step_report.build_infos = build_infos + self.update_step_report(step_report) + + @Slot(object, int, str) + def step_finished(self, bisection, step_num, verdict): + step_report = self.step_reports[step_num-1] + step_report.verdict = verdict + self.update_step_report(step_report) + + @Slot(object, int) + def finished(self, bisection, result): + # remove the last insterted step + index = len(self.step_reports) -1 + self.beginRemoveRows(QModelIndex(), index, index) + self.step_reports.pop(index) + self.endRemoveRows() diff --git a/gui/mozregui/ui/mainwindow.ui b/gui/mozregui/ui/mainwindow.ui index 41bcc366..4136dd89 100644 --- a/gui/mozregui/ui/mainwindow.ui +++ b/gui/mozregui/ui/mainwindow.ui @@ -13,7 +13,23 @@ Mozregression-gui - + + + + + + false + + + true + + + false + + + + +