mirror of
https://gitlab.com/gabmus/envision.git
synced 2025-08-04 15:18:58 +00:00
feat: runner status communicates exit code; build window shows color coded build status
This commit is contained in:
parent
47d7a7a629
commit
234f499d2f
4 changed files with 116 additions and 27 deletions
|
@ -30,7 +30,7 @@ pub struct Runner {
|
||||||
#[derive(PartialEq, Eq, Debug)]
|
#[derive(PartialEq, Eq, Debug)]
|
||||||
pub enum RunnerStatus {
|
pub enum RunnerStatus {
|
||||||
Running,
|
Running,
|
||||||
Stopped,
|
Stopped(Option<i32>),
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! logger_thread {
|
macro_rules! logger_thread {
|
||||||
|
@ -154,10 +154,10 @@ impl Runner {
|
||||||
|
|
||||||
pub fn status(&mut self) -> RunnerStatus {
|
pub fn status(&mut self) -> RunnerStatus {
|
||||||
match &mut self.process {
|
match &mut self.process {
|
||||||
None => RunnerStatus::Stopped,
|
None => RunnerStatus::Stopped(None),
|
||||||
Some(proc) => match proc.try_wait() {
|
Some(proc) => match proc.try_wait() {
|
||||||
Err(_) => RunnerStatus::Running,
|
Err(_) => RunnerStatus::Running,
|
||||||
Ok(Some(_)) => RunnerStatus::Stopped,
|
Ok(Some(code)) => RunnerStatus::Stopped(code.code()),
|
||||||
Ok(None) => RunnerStatus::Running,
|
Ok(None) => RunnerStatus::Running,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -217,7 +217,7 @@ mod tests {
|
||||||
runner.start();
|
runner.start();
|
||||||
sleep(time::Duration::from_millis(10));
|
sleep(time::Duration::from_millis(10));
|
||||||
runner.terminate();
|
runner.terminate();
|
||||||
assert_eq!(runner.status(), RunnerStatus::Stopped);
|
assert_eq!(runner.status(), RunnerStatus::Stopped(Some(0)));
|
||||||
let out = runner.consume_output();
|
let out = runner.consume_output();
|
||||||
assert_eq!(out, "REX2TEST: Lorem ipsum dolor\n");
|
assert_eq!(out, "REX2TEST: Lorem ipsum dolor\n");
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ use crate::runner::{Runner, RunnerStatus};
|
||||||
pub struct RunnerPipeline {
|
pub struct RunnerPipeline {
|
||||||
runners: Vec<RefCell<Runner>>,
|
runners: Vec<RefCell<Runner>>,
|
||||||
current_index: usize,
|
current_index: usize,
|
||||||
|
last_exit_status: Option<i32>,
|
||||||
has_started: bool,
|
has_started: bool,
|
||||||
pub log: Vec<String>,
|
pub log: Vec<String>,
|
||||||
}
|
}
|
||||||
|
@ -19,6 +20,7 @@ impl RunnerPipeline {
|
||||||
runners: c_runners,
|
runners: c_runners,
|
||||||
current_index: 0,
|
current_index: 0,
|
||||||
has_started: false,
|
has_started: false,
|
||||||
|
last_exit_status: None,
|
||||||
log: vec![],
|
log: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,12 +57,23 @@ impl RunnerPipeline {
|
||||||
self.log.extend(log);
|
self.log.extend(log);
|
||||||
match status {
|
match status {
|
||||||
RunnerStatus::Running => {},
|
RunnerStatus::Running => {},
|
||||||
RunnerStatus::Stopped => {
|
RunnerStatus::Stopped(ecode) => {
|
||||||
self.current_index += 1;
|
match ecode {
|
||||||
match self.get_current_runner() {
|
None => {} // should never get here
|
||||||
None => {},
|
Some(0) => {
|
||||||
Some(c_runner) => {
|
self.last_exit_status = Some(0);
|
||||||
c_runner.borrow_mut().start();
|
self.current_index += 1;
|
||||||
|
match self.get_current_runner() {
|
||||||
|
None => {},
|
||||||
|
Some(c_runner) => {
|
||||||
|
c_runner.borrow_mut().start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(nonzero) => {
|
||||||
|
self.last_exit_status = Some(nonzero);
|
||||||
|
// interrupting pipeline by going past last runner
|
||||||
|
self.current_index = self.runners.len();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,7 +86,10 @@ impl RunnerPipeline {
|
||||||
self.log.concat()
|
self.log.concat()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_running(&self) -> bool {
|
pub fn status(&self) -> RunnerStatus {
|
||||||
self.get_current_runner().is_some()
|
match self.get_current_runner() {
|
||||||
|
None => RunnerStatus::Stopped(self.last_exit_status),
|
||||||
|
Some(_) => RunnerStatus::Running
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use super::about_dialog::AboutDialog;
|
use super::about_dialog::AboutDialog;
|
||||||
use super::build_window::BuildWindow;
|
use super::build_window::{BuildStatus, BuildWindow};
|
||||||
use super::debug_view::{DebugView, DebugViewMsg};
|
use super::debug_view::{DebugView, DebugViewMsg};
|
||||||
use super::libsurvive_setup_window::LibsurviveSetupWindow;
|
use super::libsurvive_setup_window::LibsurviveSetupWindow;
|
||||||
use super::main_view::MainViewMsg;
|
use super::main_view::MainViewMsg;
|
||||||
|
@ -161,7 +161,7 @@ impl SimpleComponent for App {
|
||||||
}
|
}
|
||||||
match runner.status() {
|
match runner.status() {
|
||||||
RunnerStatus::Running => {}
|
RunnerStatus::Running => {}
|
||||||
RunnerStatus::Stopped => {
|
RunnerStatus::Stopped(_) => {
|
||||||
self.main_view
|
self.main_view
|
||||||
.sender()
|
.sender()
|
||||||
.emit(MainViewMsg::MonadoActiveChanged(false));
|
.emit(MainViewMsg::MonadoActiveChanged(false));
|
||||||
|
@ -176,12 +176,30 @@ impl SimpleComponent for App {
|
||||||
self.build_window
|
self.build_window
|
||||||
.sender()
|
.sender()
|
||||||
.emit(BuildWindowMsg::UpdateContent(pipeline.get_log()));
|
.emit(BuildWindowMsg::UpdateContent(pipeline.get_log()));
|
||||||
if !pipeline.is_running() {
|
match pipeline.status() {
|
||||||
self.setcap_confirm_dialog.present();
|
RunnerStatus::Running | RunnerStatus::Stopped(None) => {}
|
||||||
self.build_window
|
RunnerStatus::Stopped(Some(code)) => {
|
||||||
.sender()
|
self.build_window
|
||||||
.emit(BuildWindowMsg::UpdateCanClose(true));
|
.sender()
|
||||||
self.build_pipeline.take();
|
.emit(BuildWindowMsg::UpdateCanClose(true));
|
||||||
|
self.build_pipeline.take();
|
||||||
|
match code {
|
||||||
|
0 => {
|
||||||
|
self.build_window.sender().emit(
|
||||||
|
BuildWindowMsg::UpdateBuildStatus(BuildStatus::Done)
|
||||||
|
);
|
||||||
|
self.setcap_confirm_dialog.present();
|
||||||
|
self.build_window
|
||||||
|
.sender()
|
||||||
|
.emit(BuildWindowMsg::UpdateCanClose(true));
|
||||||
|
}
|
||||||
|
errcode => self.build_window.sender().emit(
|
||||||
|
BuildWindowMsg::UpdateBuildStatus(BuildStatus::Error(
|
||||||
|
format!("Exit status {}", errcode),
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -219,7 +237,7 @@ impl SimpleComponent for App {
|
||||||
.sender()
|
.sender()
|
||||||
.emit(MainViewMsg::MonadoActiveChanged(false));
|
.emit(MainViewMsg::MonadoActiveChanged(false));
|
||||||
}
|
}
|
||||||
RunnerStatus::Stopped => {
|
RunnerStatus::Stopped(_) => {
|
||||||
self.debug_view
|
self.debug_view
|
||||||
.sender()
|
.sender()
|
||||||
.emit(DebugViewMsg::LogUpdated(vec![]));
|
.emit(DebugViewMsg::LogUpdated(vec![]));
|
||||||
|
@ -301,7 +319,8 @@ impl SimpleComponent for App {
|
||||||
.sender()
|
.sender()
|
||||||
.send(LibsurviveSetupMsg::Present(
|
.send(LibsurviveSetupMsg::Present(
|
||||||
self.get_selected_profile().clone(),
|
self.get_selected_profile().clone(),
|
||||||
));
|
))
|
||||||
|
.expect_dialog("Failed to present Libsurvive Setup Window");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,27 @@
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
use relm4::prelude::*;
|
use relm4::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
|
pub enum BuildStatus {
|
||||||
|
Building,
|
||||||
|
Done,
|
||||||
|
Error(String),
|
||||||
|
}
|
||||||
|
|
||||||
#[tracker::track]
|
#[tracker::track]
|
||||||
pub struct BuildWindow {
|
pub struct BuildWindow {
|
||||||
title: String,
|
title: String,
|
||||||
content: String,
|
content: String,
|
||||||
can_close: bool,
|
can_close: bool,
|
||||||
|
build_status: BuildStatus,
|
||||||
|
|
||||||
#[tracker::do_not_track]
|
#[tracker::do_not_track]
|
||||||
pub textbuf: gtk::TextBuffer,
|
pub textbuf: gtk::TextBuffer,
|
||||||
#[tracker::do_not_track]
|
#[tracker::do_not_track]
|
||||||
pub win: Option<adw::Window>,
|
pub win: Option<adw::Window>,
|
||||||
#[tracker::do_not_track]
|
#[tracker::do_not_track]
|
||||||
|
build_status_label: Option<gtk::Label>,
|
||||||
|
#[tracker::do_not_track]
|
||||||
pub scrolled_win: Option<gtk::ScrolledWindow>,
|
pub scrolled_win: Option<gtk::ScrolledWindow>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,6 +29,7 @@ pub struct BuildWindow {
|
||||||
pub enum BuildWindowMsg {
|
pub enum BuildWindowMsg {
|
||||||
Present,
|
Present,
|
||||||
UpdateTitle(String),
|
UpdateTitle(String),
|
||||||
|
UpdateBuildStatus(BuildStatus),
|
||||||
UpdateContent(String),
|
UpdateContent(String),
|
||||||
UpdateCanClose(bool),
|
UpdateCanClose(bool),
|
||||||
}
|
}
|
||||||
|
@ -34,10 +45,12 @@ impl SimpleComponent for BuildWindow {
|
||||||
adw::Window {
|
adw::Window {
|
||||||
set_modal: true,
|
set_modal: true,
|
||||||
set_default_size: (520, 400),
|
set_default_size: (520, 400),
|
||||||
|
set_hide_on_close: true,
|
||||||
gtk::Box {
|
gtk::Box {
|
||||||
set_vexpand: true,
|
set_vexpand: true,
|
||||||
set_hexpand: true,
|
set_hexpand: true,
|
||||||
set_orientation: gtk::Orientation::Vertical,
|
set_orientation: gtk::Orientation::Vertical,
|
||||||
|
set_spacing: 12,
|
||||||
gtk::WindowHandle {
|
gtk::WindowHandle {
|
||||||
set_vexpand: false,
|
set_vexpand: false,
|
||||||
set_hexpand: true,
|
set_hexpand: true,
|
||||||
|
@ -48,11 +61,32 @@ impl SimpleComponent for BuildWindow {
|
||||||
#[wrap(Some)]
|
#[wrap(Some)]
|
||||||
set_title_widget: title_label = >k::Label {
|
set_title_widget: title_label = >k::Label {
|
||||||
#[track = "model.changed(BuildWindow::title())"]
|
#[track = "model.changed(BuildWindow::title())"]
|
||||||
set_label: &model.title,
|
set_markup: &model.title,
|
||||||
add_css_class: "title",
|
add_css_class: "title",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
gtk::Box {
|
||||||
|
set_orientation: gtk::Orientation::Horizontal,
|
||||||
|
set_hexpand: true,
|
||||||
|
set_halign: gtk::Align::Center,
|
||||||
|
set_spacing: 12,
|
||||||
|
#[name(build_status_label)]
|
||||||
|
gtk::Label {
|
||||||
|
#[track = "model.changed(BuildWindow::build_status())"]
|
||||||
|
set_markup: match &model.build_status {
|
||||||
|
BuildStatus::Building => "Build in progress...".to_string(),
|
||||||
|
BuildStatus::Done => "Build done, you can close this window".to_string(),
|
||||||
|
BuildStatus::Error(code) => {
|
||||||
|
format!("Build failed: \"{c}\"", c = code)
|
||||||
|
}
|
||||||
|
}.as_str(),
|
||||||
|
add_css_class: "title-2",
|
||||||
|
set_wrap: true,
|
||||||
|
set_wrap_mode: gtk::pango::WrapMode::Word,
|
||||||
|
set_justify: gtk::Justification::Center,
|
||||||
|
}
|
||||||
|
},
|
||||||
#[name(scrolled_win)]
|
#[name(scrolled_win)]
|
||||||
gtk::ScrolledWindow {
|
gtk::ScrolledWindow {
|
||||||
set_hexpand: true,
|
set_hexpand: true,
|
||||||
|
@ -65,6 +99,10 @@ impl SimpleComponent for BuildWindow {
|
||||||
set_vexpand: true,
|
set_vexpand: true,
|
||||||
set_editable: false,
|
set_editable: false,
|
||||||
set_monospace: true,
|
set_monospace: true,
|
||||||
|
set_left_margin: 6,
|
||||||
|
set_right_margin: 6,
|
||||||
|
set_top_margin: 6,
|
||||||
|
set_bottom_margin: 6,
|
||||||
set_buffer: Some(&model.textbuf),
|
set_buffer: Some(&model.textbuf),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -76,7 +114,8 @@ impl SimpleComponent for BuildWindow {
|
||||||
#[track = "model.changed(BuildWindow::can_close())"]
|
#[track = "model.changed(BuildWindow::can_close())"]
|
||||||
set_sensitive: model.can_close,
|
set_sensitive: model.can_close,
|
||||||
connect_clicked[win] => move |_| {
|
connect_clicked[win] => move |_| {
|
||||||
win.hide();
|
|
||||||
|
win.close();
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,10 +128,11 @@ impl SimpleComponent for BuildWindow {
|
||||||
match message {
|
match message {
|
||||||
BuildWindowMsg::Present => {
|
BuildWindowMsg::Present => {
|
||||||
self.win.as_ref().unwrap().present();
|
self.win.as_ref().unwrap().present();
|
||||||
},
|
sender.input(BuildWindowMsg::UpdateBuildStatus(BuildStatus::Building));
|
||||||
|
}
|
||||||
BuildWindowMsg::UpdateTitle(t) => {
|
BuildWindowMsg::UpdateTitle(t) => {
|
||||||
self.set_title(t);
|
self.set_title(t);
|
||||||
},
|
}
|
||||||
BuildWindowMsg::UpdateContent(c) => {
|
BuildWindowMsg::UpdateContent(c) => {
|
||||||
if self.content != c {
|
if self.content != c {
|
||||||
self.set_content(c);
|
self.set_content(c);
|
||||||
|
@ -103,7 +143,18 @@ impl SimpleComponent for BuildWindow {
|
||||||
adj.set_value(adj.upper());
|
adj.set_value(adj.upper());
|
||||||
sw.set_vadjustment(Some(&adj));
|
sw.set_vadjustment(Some(&adj));
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
BuildWindowMsg::UpdateBuildStatus(status) => {
|
||||||
|
let label = self.build_status_label.as_ref().unwrap();
|
||||||
|
label.remove_css_class("success");
|
||||||
|
label.remove_css_class("error");
|
||||||
|
match status {
|
||||||
|
BuildStatus::Done => label.add_css_class("success"),
|
||||||
|
BuildStatus::Error(_) => label.add_css_class("error"),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
self.set_build_status(status);
|
||||||
|
}
|
||||||
BuildWindowMsg::UpdateCanClose(val) => {
|
BuildWindowMsg::UpdateCanClose(val) => {
|
||||||
self.set_can_close(val);
|
self.set_can_close(val);
|
||||||
}
|
}
|
||||||
|
@ -121,12 +172,15 @@ impl SimpleComponent for BuildWindow {
|
||||||
content: "".into(),
|
content: "".into(),
|
||||||
can_close: false,
|
can_close: false,
|
||||||
textbuf: gtk::TextBuffer::builder().build(),
|
textbuf: gtk::TextBuffer::builder().build(),
|
||||||
|
build_status: BuildStatus::Building,
|
||||||
win: None,
|
win: None,
|
||||||
|
build_status_label: None,
|
||||||
scrolled_win: None,
|
scrolled_win: None,
|
||||||
};
|
};
|
||||||
let widgets = view_output!();
|
let widgets = view_output!();
|
||||||
model.scrolled_win = Some(widgets.scrolled_win.clone());
|
model.scrolled_win = Some(widgets.scrolled_win.clone());
|
||||||
model.win = Some(widgets.win.clone());
|
model.win = Some(widgets.win.clone());
|
||||||
|
model.build_status_label = Some(widgets.build_status_label.clone());
|
||||||
ComponentParts { model, widgets }
|
ComponentParts { model, widgets }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue