Merge feature/capture-multi-app-registry: generalize bread-capture targets
This commit is contained in:
commit
1a3475bd23
1 changed files with 47 additions and 19 deletions
|
|
@ -2,10 +2,13 @@
|
||||||
//!
|
//!
|
||||||
//! Drives each target app's `--screenshot <view> --output <path>` mode (see
|
//! Drives each target app's `--screenshot <view> --output <path>` mode (see
|
||||||
//! `bread-screenshots` for what that mode does inside the app) and reports
|
//! `bread-screenshots` for what that mode does inside the app) and reports
|
||||||
//! pass/fail per view. Foundation-phase scope: one target (breadbar), a
|
//! pass/fail per view. One app per invocation, selected by `--app-name`
|
||||||
//! hardcoded view list, and a flat output directory — no versioned
|
//! (defaults to `--app-path`'s file stem, so `--app-path
|
||||||
//! `screenshots/vX.Y.Z/latest` structure or manifest file yet, since those
|
//! ./target/release/breadbox` needs no separate `--app-name`) — the view
|
||||||
//! only earn their complexity once more apps are wired up.
|
//! list for each app is looked up from [`TARGETS`] below. Flat output
|
||||||
|
//! directory for now — no versioned `screenshots/vX.Y.Z/latest` structure
|
||||||
|
//! or manifest file yet, since that's still not earning its complexity over
|
||||||
|
//! a handful of apps.
|
||||||
//!
|
//!
|
||||||
//! By default every capture runs inside a throwaway headless Sway instance
|
//! By default every capture runs inside a throwaway headless Sway instance
|
||||||
//! (see [`isolation`]) rather than the operator's live desktop, so another
|
//! (see [`isolation`]) rather than the operator's live desktop, so another
|
||||||
|
|
@ -16,25 +19,35 @@
|
||||||
|
|
||||||
mod isolation;
|
mod isolation;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::{bail, Result};
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use std::process::ExitCode;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
const CAPTURE_TIMEOUT: Duration = Duration::from_secs(10);
|
const CAPTURE_TIMEOUT: Duration = Duration::from_secs(10);
|
||||||
|
|
||||||
/// (view name, output filename)
|
/// Per-app (view name, output filename) lists. Keyed by the app's binary
|
||||||
const BREADBAR_TARGETS: &[(&str, &str)] = &[
|
/// name — see `--app-name`.
|
||||||
("bar", "breadbar-bar.png"),
|
const TARGETS: &[(&str, &[(&str, &str)])] = &[
|
||||||
("control-panel", "breadbar-control-panel.png"),
|
(
|
||||||
|
"breadbar",
|
||||||
|
&[("bar", "breadbar-bar.png"), ("control-panel", "breadbar-control-panel.png")],
|
||||||
|
),
|
||||||
|
("breadbox", &[("launcher", "breadbox-launcher.png")]),
|
||||||
];
|
];
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
struct Cli {
|
struct Cli {
|
||||||
/// Path to the breadbar binary (resolved via $PATH if not a path).
|
/// Path to the target app's binary (resolved via $PATH if not a path).
|
||||||
#[arg(long, default_value = "breadbar")]
|
#[arg(long)]
|
||||||
app_path: String,
|
app_path: String,
|
||||||
|
|
||||||
|
/// Which app's view list to use (see `TARGETS`). Defaults to
|
||||||
|
/// `--app-path`'s file stem, e.g. `./target/release/breadbox` -> `breadbox`.
|
||||||
|
#[arg(long)]
|
||||||
|
app_name: Option<String>,
|
||||||
|
|
||||||
/// Directory to write captured PNGs into.
|
/// Directory to write captured PNGs into.
|
||||||
#[arg(long, default_value = "./screenshots")]
|
#[arg(long, default_value = "./screenshots")]
|
||||||
out_dir: PathBuf,
|
out_dir: PathBuf,
|
||||||
|
|
@ -54,9 +67,27 @@ struct Cli {
|
||||||
isolate_height: u32,
|
isolate_height: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<ExitCode> {
|
||||||
let cli = Cli::parse();
|
let cli = Cli::parse();
|
||||||
|
|
||||||
|
let app_name = cli.app_name.clone().unwrap_or_else(|| {
|
||||||
|
PathBuf::from(&cli.app_path)
|
||||||
|
.file_stem()
|
||||||
|
.map(|s| s.to_string_lossy().into_owned())
|
||||||
|
.unwrap_or_else(|| cli.app_path.clone())
|
||||||
|
});
|
||||||
|
let Some((_, views)) = TARGETS.iter().find(|(name, _)| *name == app_name) else {
|
||||||
|
bail!(
|
||||||
|
"no known view list for app '{app_name}' (known: {})",
|
||||||
|
TARGETS.iter().map(|(n, _)| *n).collect::<Vec<_>>().join(", ")
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Bound, not dropped-and-discarded: `_isolation`'s teardown (kill the
|
||||||
|
// compositor, remove its socket/config) must run via Drop regardless of
|
||||||
|
// how this function returns below — returning an ExitCode rather than
|
||||||
|
// calling `std::process::exit` (which skips destructors entirely) is
|
||||||
|
// what makes that true on the failure path too.
|
||||||
let _isolation = if cli.no_isolate {
|
let _isolation = if cli.no_isolate {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -67,7 +98,7 @@ fn main() -> Result<()> {
|
||||||
let height_str = cli.isolate_height.to_string();
|
let height_str = cli.isolate_height.to_string();
|
||||||
|
|
||||||
let mut failed = false;
|
let mut failed = false;
|
||||||
for (view, filename) in BREADBAR_TARGETS {
|
for (view, filename) in *views {
|
||||||
let out_path = cli.out_dir.join(filename);
|
let out_path = cli.out_dir.join(filename);
|
||||||
let out_str = out_path.to_string_lossy();
|
let out_str = out_path.to_string_lossy();
|
||||||
let result = bread_utils::proc::run(
|
let result = bread_utils::proc::run(
|
||||||
|
|
@ -81,15 +112,12 @@ fn main() -> Result<()> {
|
||||||
CAPTURE_TIMEOUT,
|
CAPTURE_TIMEOUT,
|
||||||
);
|
);
|
||||||
if result.success {
|
if result.success {
|
||||||
println!("ok breadbar/{view} -> {}", out_path.display());
|
println!("ok {app_name}/{view} -> {}", out_path.display());
|
||||||
} else {
|
} else {
|
||||||
failed = true;
|
failed = true;
|
||||||
println!("FAIL breadbar/{view}: {}", result.stderr.trim());
|
println!("FAIL {app_name}/{view}: {}", result.stderr.trim());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if failed {
|
Ok(if failed { ExitCode::FAILURE } else { ExitCode::SUCCESS })
|
||||||
std::process::exit(1);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue