1
0
Files
wfassoc/wfassoc-exec/src/runner.rs

194 lines
5.7 KiB
Rust
Raw Normal View History

2026-04-21 16:30:25 +08:00
use crate::cli;
use crate::manifest;
2026-05-09 20:07:08 +08:00
use comfy_table::Table;
use std::collections::{HashMap, HashSet};
2026-04-21 16:30:25 +08:00
use std::path::Path;
2026-01-04 14:05:34 +08:00
use thiserror::Error as TeError;
2026-05-09 20:07:08 +08:00
use toml;
2026-01-04 14:05:34 +08:00
2026-04-21 16:30:25 +08:00
// region: Error Handling
2026-01-04 14:05:34 +08:00
/// Error occurs in this module.
#[derive(Debug, TeError)]
pub enum Error {
2026-04-22 14:53:22 +08:00
/// Error when parsing Manifest TOML file.
2026-04-21 16:30:25 +08:00
#[error("{0}")]
ParseManifest(#[from] manifest::ParseManifestError),
2026-04-22 14:53:22 +08:00
/// Error when parsing Manifest into Schema.
2026-04-21 16:30:25 +08:00
#[error("{0}")]
ParseSchema(#[from] manifest::ParseSchemaError),
2026-04-22 14:53:22 +08:00
/// Error when parsing Schema into Program.
2026-04-21 16:30:25 +08:00
#[error("{0}")]
ParseProgram(#[from] wfassoc::highlevel::ParseProgramError),
2026-04-22 14:53:22 +08:00
/// Error when operating Program.
#[error("{0}")]
Program(#[from] wfassoc::highlevel::ProgramError),
2026-05-09 20:07:08 +08:00
/// Error when serializing TOML
#[error("{0}")]
SerializeToml(#[from] toml::ser::Error),
/// Find duplicated name when converting extension name to index
#[error("given extension name {0} has been specified more than one time")]
DupExtName(String),
/// Find invalid name when converting extension name to index
#[error("given extension name {0} is not presented in application")]
BadExtName(String),
/// Find star (*) extension name with other extension names when converting extension name to index
#[error("given extension name {0} is not presented in application")]
ExclusiveStarExtName(String),
2026-01-04 14:05:34 +08:00
}
/// Result type used in this module.
type Result<T> = std::result::Result<T, Error>;
2026-04-21 16:30:25 +08:00
// endregion
2026-01-04 14:05:34 +08:00
2026-05-09 20:07:08 +08:00
// region: Utilities
2026-04-21 16:30:25 +08:00
2026-05-08 14:14:55 +08:00
fn stringified_exts_to_indices(
program: &wfassoc::Program,
exts: Vec<String>,
) -> Result<Vec<usize>> {
2026-05-09 20:07:08 +08:00
// Check for duplicate extension names
let mut seen = HashSet::new();
for ext in &exts {
if !seen.insert(ext.as_str()) {
return Err(Error::DupExtName(ext.clone()));
}
}
// Check for star (*) with other extensions
let has_star = exts.iter().any(|ext| ext == "*");
if has_star && exts.len() > 1 {
return Err(Error::ExclusiveStarExtName("*".to_string()));
}
// If star is present alone, return fixed list from zero to the maximum ext index.
if has_star {
return Ok((0..program.get_ext_count()).collect());
}
// Convert each extension name to index using program.find_ext()
let indices = exts
.into_iter()
.map(|ext| program.find_ext(&ext).ok_or(Error::BadExtName(ext)))
.collect::<Result<Vec<_>>>()?;
Ok(indices)
2026-01-04 14:05:34 +08:00
}
2026-04-21 16:30:25 +08:00
// endregion
// region: Respective Runners
2026-04-22 14:53:22 +08:00
fn run_register(mut program: wfassoc::Program, scope: wfassoc::Scope) -> Result<()> {
2026-05-09 20:10:15 +08:00
program.register(scope)?;
println!("Application now is installed.");
Ok(())
2026-01-04 14:05:34 +08:00
}
2026-04-22 14:53:22 +08:00
fn run_unregister(mut program: wfassoc::Program, scope: wfassoc::Scope) -> Result<()> {
2026-05-09 20:10:15 +08:00
program.unregister(scope)?;
println!("Application now is uninstalled.");
Ok(())
2026-01-04 14:05:34 +08:00
}
2026-05-08 14:14:55 +08:00
fn run_status(program: wfassoc::Program, scope: wfassoc::Scope) -> Result<()> {
if program.is_registered(scope)? {
2026-04-22 14:53:22 +08:00
println!("Application is installed.");
} else {
println!("Application is not installed.");
}
2026-05-08 14:14:55 +08:00
2026-04-22 14:53:22 +08:00
Ok(())
2026-01-04 14:05:34 +08:00
}
2026-05-08 14:14:55 +08:00
fn run_ext_link(
mut program: wfassoc::Program,
scope: wfassoc::Scope,
exts: Vec<String>,
) -> Result<()> {
2026-04-21 16:30:25 +08:00
let exts = stringified_exts_to_indices(&program, exts)?;
2026-04-29 13:11:12 +08:00
for index in exts {
program.link_ext(scope, index)?;
}
2026-05-09 20:10:15 +08:00
println!("File extension now is linked.");
2026-04-29 13:11:12 +08:00
Ok(())
2026-01-04 14:05:34 +08:00
}
2026-04-21 16:30:25 +08:00
fn run_ext_unlink(
2026-05-08 14:14:55 +08:00
mut program: wfassoc::Program,
2026-04-21 16:30:25 +08:00
scope: wfassoc::Scope,
exts: Vec<String>,
) -> Result<()> {
let exts = stringified_exts_to_indices(&program, exts)?;
2026-04-29 13:11:12 +08:00
for index in exts {
program.link_ext(scope, index)?;
}
2026-05-09 20:10:15 +08:00
println!("File extension now is unlinked.");
2026-04-29 13:11:12 +08:00
Ok(())
2026-01-04 14:05:34 +08:00
}
2026-04-21 16:30:25 +08:00
fn run_ext_list(
program: wfassoc::Program,
view: wfassoc::View,
style: cli::ExtListStyle,
) -> Result<()> {
2026-05-09 20:07:08 +08:00
// Fetch info
let mut ext_list: HashMap<String, Option<String>> = HashMap::new();
for index in 0..program.get_ext_count() {
let ext = program.get_ext(index)?;
let status = program.query_ext(view, index)?;
ext_list.insert(ext.dotted_inner(), status.map(|s| s.get_name().to_string()));
}
// Output by styles
use cli::ExtListStyle;
match style {
ExtListStyle::Human => {
let mut table = Table::new();
table.set_header(["Extension", "Association"]);
for (k, v) in ext_list {
table.add_row([k, v.unwrap_or("".to_string())]);
}
println!("{table}");
}
ExtListStyle::Machine => {
let stoml = toml::to_string(&ext_list)?;
println!("{stoml}")
}
}
Ok(())
2026-04-21 16:30:25 +08:00
}
2026-01-04 14:05:34 +08:00
// endregion
2026-04-21 16:30:25 +08:00
pub fn run(c: cli::Cli) -> Result<()> {
// Read manifest file first
let mf = manifest::Manifest::from_file(Path::new(&c.manifest_file))?;
println!("{:?}", mf);
// Parse it into schema
let schema = mf.into_schema()?;
// Parse it into program
let program = schema.into_program()?;
match c.command {
cli::CliCommands::Register { target } => run_register(program, target.into()),
cli::CliCommands::Unregister { target } => run_unregister(program, target.into()),
cli::CliCommands::Status { target } => run_status(program, target.into()),
cli::CliCommands::Ext { command } => match command {
cli::CliExtCommands::Link { target, exts } => {
run_ext_link(program, target.into(), exts)
}
cli::CliExtCommands::Unlink { target, exts } => {
run_ext_unlink(program, target.into(), exts)
}
cli::CliExtCommands::List { target, style } => {
run_ext_list(program, target.into(), style)
}
},
}
2026-01-04 14:05:34 +08:00
}