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
target: x86_64-apple-darwin
name: macos-x86_64
features: wgpu
features: default
- platform: macos-latest
target: aarch64-apple-darwin
name: macos-arm64
features: wgpu
features: default
fail-fast: false
runs-on: ${{ matrix.platform }}
steps:

7
Cargo.lock generated
View File

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

View File

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

View File

@ -17,7 +17,20 @@ use crate::{
pub struct BuildStatus {
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 {
@ -88,16 +101,24 @@ fn run_make(cwd: &Path, arg: &Path, config: &ObjDiffConfig) -> BuildStatus {
command.creation_flags(winapi::um::winbase::CREATE_NO_WINDOW);
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 stdout = from_utf8(&output.stdout).context("Failed to process stdout")?;
let stderr = from_utf8(&output.stderr).context("Failed to process stderr")?;
Ok(BuildStatus {
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,
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)
}
_ => BuildStatus { success: true, log: String::new() },
_ => BuildStatus::default(),
};
let second_status = match base_path_rel {
@ -164,7 +185,7 @@ fn run_build(
)?;
run_make(project_dir, base_path_rel, &config)
}
_ => BuildStatus { success: true, log: String::new() },
_ => BuildStatus::default(),
};
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::{
borrow::Cow,
@ -6,7 +6,7 @@ use std::{
path::{PathBuf, MAIN_SEPARATOR},
};
#[cfg(feature = "wsl")]
#[cfg(all(windows, feature = "wsl"))]
use anyhow::{Context, Result};
use const_format::formatcp;
use egui::{
@ -46,7 +46,7 @@ pub struct ConfigViewState {
pub object_search: String,
pub filter_diffable: bool,
pub filter_incomplete: bool,
#[cfg(feature = "wsl")]
#[cfg(all(windows, feature = "wsl"))]
pub available_wsl_distros: Option<Vec<String>>,
pub file_dialog_state: FileDialogState,
}
@ -134,7 +134,7 @@ pub const DEFAULT_WATCH_PATTERNS: &[&str] = &[
"*.inc", "*.py", "*.yml", "*.txt", "*.json",
];
#[cfg(feature = "wsl")]
#[cfg(all(windows, feature = "wsl"))]
fn process_utf16(bytes: &[u8]) -> Result<String, FromUtf16Error> {
let u16_bytes: Vec<u16> = bytes
.chunks_exact(2)
@ -143,7 +143,7 @@ fn process_utf16(bytes: &[u8]) -> Result<String, FromUtf16Error> {
String::from_utf16(&u16_bytes)
}
#[cfg(feature = "wsl")]
#[cfg(all(windows, feature = "wsl"))]
fn wsl_cmd(args: &[&str]) -> Result<String> {
use std::{os::windows::process::CommandExt, process::Command};
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")
}
#[cfg(feature = "wsl")]
#[cfg(all(windows, feature = "wsl"))]
fn fetch_wsl2_distros() -> Vec<String> {
wsl_cmd(&["-l", "-q"])
.map(|stdout| {
@ -176,7 +176,6 @@ pub fn config_ui(
) {
let mut config_guard = config.write().unwrap();
let AppConfig {
selected_wsl_distro,
target_obj_dir,
base_obj_dir,
selected_obj,
@ -227,27 +226,6 @@ pub fn config_ui(
}
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.heading("Project");
if ui.button(RichText::new("Settings")).clicked() {
@ -649,6 +627,24 @@ fn split_obj_config_ui(
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();
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) {
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.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
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);
});
});
}