Re-enable wgpu and wsl features; rework WSL config

Improve build failure log view & add copy buttons
This commit is contained in:
Luke Street 2024-01-20 23:29:05 -07:00
parent b74a49ed0c
commit 4cdad8a519
6 changed files with 75 additions and 38 deletions

View File

@ -105,11 +105,11 @@ jobs:
- platform: macos-latest - platform: macos-latest
target: x86_64-apple-darwin target: x86_64-apple-darwin
name: macos-x86_64 name: macos-x86_64
features: wgpu features: default
- platform: macos-latest - platform: macos-latest
target: aarch64-apple-darwin target: aarch64-apple-darwin
name: macos-arm64 name: macos-arm64
features: wgpu features: default
fail-fast: false fail-fast: false
runs-on: ${{ matrix.platform }} runs-on: ${{ matrix.platform }}
steps: steps:

7
Cargo.lock generated
View File

@ -2867,6 +2867,7 @@ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
"serde_yaml", "serde_yaml",
"shell-escape",
"similar", "similar",
"tempfile", "tempfile",
"thiserror", "thiserror",
@ -3719,6 +3720,12 @@ dependencies = [
"lazy_static", "lazy_static",
] ]
[[package]]
name = "shell-escape"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f"
[[package]] [[package]]
name = "signal-hook-registry" name = "signal-hook-registry"
version = "1.4.1" version = "1.4.1"

View File

@ -1,6 +1,6 @@
[package] [package]
name = "objdiff" name = "objdiff"
version = "0.6.1" version = "0.7.0"
edition = "2021" edition = "2021"
rust-version = "1.70" rust-version = "1.70"
authors = ["Luke Street <luke@street.dev>"] authors = ["Luke Street <luke@street.dev>"]
@ -19,7 +19,7 @@ lto = "thin"
strip = "debuginfo" strip = "debuginfo"
[features] [features]
default = [] default = ["wgpu", "wsl"]
wgpu = ["eframe/wgpu"] wgpu = ["eframe/wgpu"]
wsl = [] wsl = []
@ -53,6 +53,7 @@ semver = "1.0.20"
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
serde_json = "1.0.108" serde_json = "1.0.108"
serde_yaml = "0.9.27" serde_yaml = "0.9.27"
shell-escape = "0.1.5"
similar = "2.3.0" similar = "2.3.0"
tempfile = "3.8.1" tempfile = "3.8.1"
thiserror = "1.0.50" thiserror = "1.0.50"

View File

@ -17,7 +17,20 @@ use crate::{
pub struct BuildStatus { pub struct BuildStatus {
pub success: bool, pub success: bool,
pub log: String, pub cmdline: String,
pub stdout: String,
pub stderr: String,
}
impl Default for BuildStatus {
fn default() -> Self {
BuildStatus {
success: true,
cmdline: String::new(),
stdout: String::new(),
stderr: String::new(),
}
}
} }
pub struct ObjDiffConfig { pub struct ObjDiffConfig {
@ -88,16 +101,24 @@ fn run_make(cwd: &Path, arg: &Path, config: &ObjDiffConfig) -> BuildStatus {
command.creation_flags(winapi::um::winbase::CREATE_NO_WINDOW); command.creation_flags(winapi::um::winbase::CREATE_NO_WINDOW);
command command
}; };
let mut cmdline =
shell_escape::escape(command.get_program().to_string_lossy()).into_owned();
for arg in command.get_args() {
cmdline.push(' ');
cmdline.push_str(shell_escape::escape(arg.to_string_lossy()).as_ref());
}
let output = command.output().context("Failed to execute build")?; let output = command.output().context("Failed to execute build")?;
let stdout = from_utf8(&output.stdout).context("Failed to process stdout")?; let stdout = from_utf8(&output.stdout).context("Failed to process stdout")?;
let stderr = from_utf8(&output.stderr).context("Failed to process stderr")?; let stderr = from_utf8(&output.stderr).context("Failed to process stderr")?;
Ok(BuildStatus { Ok(BuildStatus {
success: output.status.code().unwrap_or(-1) == 0, success: output.status.code().unwrap_or(-1) == 0,
log: format!("{stdout}\n{stderr}"), cmdline,
stdout: stdout.to_string(),
stderr: stderr.to_string(),
}) })
})() { })() {
Ok(status) => status, Ok(status) => status,
Err(e) => BuildStatus { success: false, log: e.to_string() }, Err(e) => BuildStatus { success: false, stderr: e.to_string(), ..Default::default() },
} }
} }
@ -150,7 +171,7 @@ fn run_build(
)?; )?;
run_make(project_dir, target_path_rel, &config) run_make(project_dir, target_path_rel, &config)
} }
_ => BuildStatus { success: true, log: String::new() }, _ => BuildStatus::default(),
}; };
let second_status = match base_path_rel { let second_status = match base_path_rel {
@ -164,7 +185,7 @@ fn run_build(
)?; )?;
run_make(project_dir, base_path_rel, &config) run_make(project_dir, base_path_rel, &config)
} }
_ => BuildStatus { success: true, log: String::new() }, _ => BuildStatus::default(),
}; };
let time = OffsetDateTime::now_utc(); let time = OffsetDateTime::now_utc();

View File

@ -1,4 +1,4 @@
#[cfg(feature = "wsl")] #[cfg(all(windows, feature = "wsl"))]
use std::string::FromUtf16Error; use std::string::FromUtf16Error;
use std::{ use std::{
borrow::Cow, borrow::Cow,
@ -6,7 +6,7 @@ use std::{
path::{PathBuf, MAIN_SEPARATOR}, path::{PathBuf, MAIN_SEPARATOR},
}; };
#[cfg(feature = "wsl")] #[cfg(all(windows, feature = "wsl"))]
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use const_format::formatcp; use const_format::formatcp;
use egui::{ use egui::{
@ -46,7 +46,7 @@ pub struct ConfigViewState {
pub object_search: String, pub object_search: String,
pub filter_diffable: bool, pub filter_diffable: bool,
pub filter_incomplete: bool, pub filter_incomplete: bool,
#[cfg(feature = "wsl")] #[cfg(all(windows, feature = "wsl"))]
pub available_wsl_distros: Option<Vec<String>>, pub available_wsl_distros: Option<Vec<String>>,
pub file_dialog_state: FileDialogState, pub file_dialog_state: FileDialogState,
} }
@ -134,7 +134,7 @@ pub const DEFAULT_WATCH_PATTERNS: &[&str] = &[
"*.inc", "*.py", "*.yml", "*.txt", "*.json", "*.inc", "*.py", "*.yml", "*.txt", "*.json",
]; ];
#[cfg(feature = "wsl")] #[cfg(all(windows, feature = "wsl"))]
fn process_utf16(bytes: &[u8]) -> Result<String, FromUtf16Error> { fn process_utf16(bytes: &[u8]) -> Result<String, FromUtf16Error> {
let u16_bytes: Vec<u16> = bytes let u16_bytes: Vec<u16> = bytes
.chunks_exact(2) .chunks_exact(2)
@ -143,7 +143,7 @@ fn process_utf16(bytes: &[u8]) -> Result<String, FromUtf16Error> {
String::from_utf16(&u16_bytes) String::from_utf16(&u16_bytes)
} }
#[cfg(feature = "wsl")] #[cfg(all(windows, feature = "wsl"))]
fn wsl_cmd(args: &[&str]) -> Result<String> { fn wsl_cmd(args: &[&str]) -> Result<String> {
use std::{os::windows::process::CommandExt, process::Command}; use std::{os::windows::process::CommandExt, process::Command};
let output = Command::new("wsl") let output = Command::new("wsl")
@ -154,7 +154,7 @@ fn wsl_cmd(args: &[&str]) -> Result<String> {
process_utf16(&output.stdout).context("Failed to process stdout") process_utf16(&output.stdout).context("Failed to process stdout")
} }
#[cfg(feature = "wsl")] #[cfg(all(windows, feature = "wsl"))]
fn fetch_wsl2_distros() -> Vec<String> { fn fetch_wsl2_distros() -> Vec<String> {
wsl_cmd(&["-l", "-q"]) wsl_cmd(&["-l", "-q"])
.map(|stdout| { .map(|stdout| {
@ -176,7 +176,6 @@ pub fn config_ui(
) { ) {
let mut config_guard = config.write().unwrap(); let mut config_guard = config.write().unwrap();
let AppConfig { let AppConfig {
selected_wsl_distro,
target_obj_dir, target_obj_dir,
base_obj_dir, base_obj_dir,
selected_obj, selected_obj,
@ -227,27 +226,6 @@ pub fn config_ui(
} }
ui.separator(); ui.separator();
#[cfg(feature = "wsl")]
{
ui.heading("Build");
if state.available_wsl_distros.is_none() {
state.available_wsl_distros = Some(fetch_wsl2_distros());
}
egui::ComboBox::from_label("Run in WSL2")
.selected_text(selected_wsl_distro.as_ref().unwrap_or(&"Disabled".to_string()))
.show_ui(ui, |ui| {
ui.selectable_value(selected_wsl_distro, None, "Disabled");
for distro in state.available_wsl_distros.as_ref().unwrap() {
ui.selectable_value(selected_wsl_distro, Some(distro.clone()), distro);
}
});
ui.separator();
}
#[cfg(not(feature = "wsl"))]
{
let _ = selected_wsl_distro;
}
ui.horizontal(|ui| { ui.horizontal(|ui| {
ui.heading("Project"); ui.heading("Project");
if ui.button(RichText::new("Settings")).clicked() { if ui.button(RichText::new("Settings")).clicked() {
@ -649,6 +627,24 @@ fn split_obj_config_ui(
config.custom_make = Some(custom_make_str); config.custom_make = Some(custom_make_str);
} }
} }
#[cfg(all(windows, feature = "wsl"))]
{
if state.available_wsl_distros.is_none() {
state.available_wsl_distros = Some(fetch_wsl2_distros());
}
egui::ComboBox::from_label("Run in WSL2")
.selected_text(config.selected_wsl_distro.as_ref().unwrap_or(&"Disabled".to_string()))
.show_ui(ui, |ui| {
ui.selectable_value(&mut config.selected_wsl_distro, None, "Disabled");
for distro in state.available_wsl_distros.as_ref().unwrap() {
ui.selectable_value(
&mut config.selected_wsl_distro,
Some(distro.clone()),
distro,
);
}
});
}
ui.separator(); ui.separator();
if let Some(project_dir) = config.project_dir.clone() { if let Some(project_dir) = config.project_dir.clone() {

View File

@ -262,11 +262,23 @@ fn symbol_list_ui(
fn build_log_ui(ui: &mut Ui, status: &BuildStatus, appearance: &Appearance) { fn build_log_ui(ui: &mut Ui, status: &BuildStatus, appearance: &Appearance) {
ScrollArea::both().auto_shrink([false, false]).show(ui, |ui| { ScrollArea::both().auto_shrink([false, false]).show(ui, |ui| {
ui.horizontal(|ui| {
if ui.button("Copy command").clicked() {
ui.output_mut(|output| output.copied_text = status.cmdline.clone());
}
if ui.button("Copy log").clicked() {
ui.output_mut(|output| {
output.copied_text = format!("{}\n{}", status.stdout, status.stderr)
});
}
});
ui.scope(|ui| { ui.scope(|ui| {
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace); ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
ui.style_mut().wrap = Some(false); ui.style_mut().wrap = Some(false);
ui.colored_label(appearance.replace_color, &status.log); ui.label(&status.cmdline);
ui.colored_label(appearance.replace_color, &status.stdout);
ui.colored_label(appearance.delete_color, &status.stderr);
}); });
}); });
} }