Files
fds-os/rust/fds-workstation/src/main.rs
T

141 lines
4.3 KiB
Rust

use clap::{Parser, Subcommand};
use fds_common::Result;
use std::{path::PathBuf, process::ExitCode};
#[derive(Parser)]
#[command(
name = "fds-cartridge",
version = env!("FDS_BUILD_VERSION"),
about = "Build Void source packages and ready-to-run cartridge images on Linux"
)]
struct Cli {
/// Optional wrapper that accepts TOOL followed by its arguments.
#[arg(long, global = true)]
image_tool_runner: Option<PathBuf>,
#[command(flatten)]
build: fds_workstation::software::BuildOptions,
#[command(subcommand)]
command: Action,
}
#[derive(Subcommand)]
enum Action {
/// Check EROFS tools, the inspection sandbox and legacy xz reader.
Doctor,
/// Build or package software on the workstation, never on the Pi.
Software {
#[command(subcommand)]
command: Software,
},
/// Construct and verify a complete 1+m GPT cartridge image before burning.
Create { recipe: PathBuf, output: PathBuf },
/// Verify GPT, every filesystem, catalogue and installed program tree.
Inspect { image: PathBuf },
/// Verify a prepared image and save an image/target-bound write preview.
Preview {
image: PathBuf,
target: PathBuf,
output: PathBuf,
/// Use an existing disposable regular file instead of a physical USB drive.
#[arg(long)]
file_target: bool,
},
/// Write the entire prepared image only after exact preview confirmation.
Write {
preview: PathBuf,
#[arg(long)]
confirm: String,
},
}
#[derive(Subcommand)]
enum Software {
/// Build a Void source template and install its complete runtime package tree.
Build { recipe: PathBuf, output: PathBuf },
/// Check installed package metadata and every program/dependency file.
Inspect { directory: PathBuf },
}
fn run() -> Result<()> {
let cli = Cli::parse();
let result = match cli.command {
Action::Doctor => Ok(fds_workstation::doctor::cartridge(
cli.image_tool_runner.as_deref(),
)?),
Action::Preview {
image,
target,
output,
file_target,
} => serde_json::to_value(fds_workstation::writing::preview(
&image,
&target,
&output,
file_target,
cli.image_tool_runner.as_deref(),
)?),
Action::Write { preview, confirm } => {
fds_workstation::writing::write(&preview, &confirm)?;
return Ok(());
}
Action::Software { command } => serde_json::to_value(match command {
Software::Build { recipe, output } => {
fds_workstation::software::build(&recipe, &output, &cli.build)?
}
Software::Inspect { directory } => fds_workstation::software::load(&directory)?,
}),
Action::Create { recipe, output } => {
serde_json::to_value(fds_workstation::cartridge::create(
&recipe,
&output,
cli.image_tool_runner.as_deref(),
&cli.build,
)?)
}
Action::Inspect { image } => serde_json::to_value(fds_workstation::cartridge::inspect(
&image,
cli.image_tool_runner.as_deref(),
)?),
}
.map_err(|e| fds_common::Error(e.to_string()))?;
println!("{}", serde_json::to_string_pretty(&result).unwrap());
Ok(())
}
fn main() -> ExitCode {
match run() {
Ok(()) => ExitCode::SUCCESS,
Err(e) => {
eprintln!("fds-cartridge: {e}");
ExitCode::from(2)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use clap::CommandFactory;
#[test]
fn typed_grammar() {
Cli::command().debug_assert();
assert!(
Cli::try_parse_from([
"fds-cartridge",
"software",
"build",
"recipe.toml",
"bundle"
])
.is_ok()
);
assert!(
Cli::try_parse_from([
"fds-cartridge",
"create",
"recipe.toml",
"card.img",
"--force"
])
.is_err()
);
assert!(Cli::try_parse_from(["fds-cartridge", "create", "recipe.toml"]).is_err());
}
}