141 lines
4.3 KiB
Rust
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());
|
|
}
|
|
}
|