diff --git a/wfassoc-exec/src/cli.rs b/wfassoc-exec/src/cli.rs index 8765df7..2b54e95 100644 --- a/wfassoc-exec/src/cli.rs +++ b/wfassoc-exec/src/cli.rs @@ -3,53 +3,89 @@ use clap::{Parser, Subcommand, ValueEnum}; // region: Clap Declaration #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, ValueEnum)] -enum Target { +pub enum RegScope { #[value(name = "user")] User, #[value(name = "system")] System, } +impl From for wfassoc::Scope { + fn from(value: RegScope) -> Self { + match value { + RegScope::User => wfassoc::Scope::User, + RegScope::System => wfassoc::Scope::System, + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, ValueEnum)] +pub enum RegView { + #[value(name = "user")] + User, + #[value(name = "system")] + System, + #[value(name = "hybrid")] + Hybrid, +} + +impl From for wfassoc::View { + fn from(value: RegView) -> Self { + match value { + RegView::User => wfassoc::View::User, + RegView::System => wfassoc::View::System, + RegView::Hybrid => wfassoc::View::Hybrid, + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, ValueEnum)] +pub enum ExtListStyle { + #[value(name = "human")] + Human, + #[value(name = "machine")] + Machine, +} + /// Simple program to manage Windows file associations #[derive(Parser)] #[command(name = "Windows File Association Operator", version, about)] -struct Cli { +pub struct Cli { /// The TOML manifest file representing the complete program #[arg( short = 'm', long = "manifest", - value_name = "PROG_MANIFEST", + value_name = "MANIFEST_TOML", required = true )] - manifest_file: String, + pub manifest_file: String, #[command(subcommand)] - command: CliCommands, + pub command: CliCommands, } #[derive(Subcommand)] -enum CliCommands { - /// Register the program +pub enum CliCommands { #[command(name = "register")] #[command(about = "Register application with given manifest and scope.")] Register { - /// The scope where wfassoc operate - #[arg(short = 't', long = "target", value_name = "TARGET", required = true, value_enum, default_value_t = Target::User)] - target: Target, + /// The scope where wfassoc operate. + #[arg(short = 't', long = "target", value_name = "TARGET", required = true, value_enum, default_value_t = RegScope::User)] + target: RegScope, }, - /// Unregister the program #[command(name = "unregister")] #[command(about = "Unregister application with given manifest and scope.")] Unregister { - /// The scope where wfassoc operate - #[arg(short = 't', long = "target", value_name = "TARGET", required = true, value_enum, default_value_t = Target::User)] - target: Target, + /// The scope where wfassoc operate. + #[arg(short = 't', long = "target", value_name = "TARGET", required = true, value_enum, default_value_t = RegScope::User)] + target: RegScope, }, - /// Fetch current registration status #[command(name = "status")] - #[command( - about = "Fetch the status of registration for given manifest represented application." - )] - Status, + #[command(about = "Fetch the status of registration with given manifest and scope.")] + Status { + /// The scope where fetch info. + #[arg(short = 't', long = "target", value_name = "TARGET", required = true, value_enum, default_value_t = RegScope::User)] + target: RegScope, + }, #[command(name = "ext")] #[command(about = "File extension related operations according to given program manifest.")] Ext { @@ -59,10 +95,13 @@ enum CliCommands { } #[derive(Subcommand)] -enum CliExtCommands { +pub enum CliExtCommands { #[command(name = "link")] #[command(about = "Link user given file extension to the program declared in manifest file.")] Link { + /// The scope where link file extension. + #[arg(short = 't', long = "target", value_name = "TARGET", required = true, value_enum, default_value_t = RegScope::User)] + target: RegScope, // The file extensions used for this operation. Specify * for all file extension. #[arg(required = true, value_name = "EXTS", num_args = 1..)] exts: Vec, @@ -72,6 +111,9 @@ enum CliExtCommands { about = "Unlink user given file extension from the program declared in manifest file." )] Unlink { + /// The scope where unlink file extension. + #[arg(short = 't', long = "target", value_name = "TARGET", required = true, value_enum, default_value_t = RegScope::User)] + target: RegScope, // The file extensions used for this operation. Specify * for all file extension. #[arg(required = true, value_name = "EXTS", num_args = 1..)] exts: Vec, @@ -80,37 +122,24 @@ enum CliExtCommands { #[command( about = "List the association status for all extensions declared in given program manifest." )] - List, -} - -// endregion - -// region: Exposed Type - -#[derive(Debug)] -pub struct Request { - -} - -#[derive(Debug)] -pub struct RequestCommand { - -} - -#[derive(Debug)] -pub struct RequestExtCommand { - + List { + /// The view where list file extension. + #[arg(short = 't', long = "target", value_name = "TARGET", required = true, value_enum, default_value_t = RegView::User)] + target: RegView, + /// The style when listing file extensions. + #[arg(short = 's', long = "style", value_name = "STYLE", required = true, value_enum, default_value_t = ExtListStyle::Human)] + style: ExtListStyle, + }, } // endregion +/// Parse current commandline argument. /// -/// /// Please note that if there is "help" or "version" command matched, /// or any command line parse error occurs, /// this function will order program exit immediately. -/// This is the mechanism of clap crate. -pub fn parse() -> Request { - let cli = Cli::parse(); - todo!() +/// This is the mechanism of `clap` crate. +pub fn parse() -> Cli { + Cli::parse() } diff --git a/wfassoc-exec/src/main.rs b/wfassoc-exec/src/main.rs index 7d92901..00ba679 100644 --- a/wfassoc-exec/src/main.rs +++ b/wfassoc-exec/src/main.rs @@ -1,37 +1,11 @@ -pub(crate) mod manifest; pub(crate) mod cli; +pub(crate) mod manifest; pub(crate) mod runner; -use std::path::Path; -use std::process; -use thiserror::Error as TeError; - -/// All errors occurs in this executable. -#[derive(TeError, Debug)] -enum Error { - /// Error when parsing manifest TOML file. - #[error("{0}")] - ParseManifest(#[from] manifest::ParseManifestError), - /// Error when parsing manifest into schema. - #[error("{0}")] - ParseSchema(#[from] manifest::ParseSchemaError), -} - -/// Result type used in this executable. -type Result = std::result::Result; - -fn runner() -> Result<()> { - let mf = manifest::Manifest::from_file(Path::new(r#"D:\Repo\wfassoc\example\manifest\ppic.toml"#))?; - //let mf = raw_mf.to_checked()?; - println!("{:?}", mf); - Ok(()) -} - fn main() { - //let cli = cli::parse(); - - runner().unwrap_or_else(|e| { + let cli = cli::parse(); + runner::run(cli).unwrap_or_else(|e| { eprintln!("Runtime error: {}.", e); - process::exit(1) + std::process::exit(1) }); } diff --git a/wfassoc-exec/src/manifest.rs b/wfassoc-exec/src/manifest.rs index 28f0496..476c3aa 100644 --- a/wfassoc-exec/src/manifest.rs +++ b/wfassoc-exec/src/manifest.rs @@ -96,4 +96,10 @@ impl TryFrom for wfassoc::Schema { } } +impl Manifest { + pub fn into_schema(self) -> Result { + wfassoc::Schema::try_from(self) + } +} + // endregion diff --git a/wfassoc-exec/src/runner.rs b/wfassoc-exec/src/runner.rs index 1c2f70c..6272506 100644 --- a/wfassoc-exec/src/runner.rs +++ b/wfassoc-exec/src/runner.rs @@ -1,45 +1,98 @@ -use crate::cli::Request; +use crate::cli; +use crate::manifest; +use std::path::Path; use thiserror::Error as TeError; +// region: Error Handling + /// Error occurs in this module. #[derive(Debug, TeError)] -#[error("{0}")] pub enum Error { - + /// Error when parsing manifest TOML file. + #[error("{0}")] + ParseManifest(#[from] manifest::ParseManifestError), + /// Error when parsing manifest into schema. + #[error("{0}")] + ParseSchema(#[from] manifest::ParseSchemaError), + /// Error when parsing schema into program. + #[error("{0}")] + ParseProgram(#[from] wfassoc::highlevel::ParseProgramError), } /// Result type used in this module. type Result = std::result::Result; -// region: Respective Runners +// endregion -fn run_register() -> Result<()> { +// region: Utilities Functions + +fn stringified_exts_to_indices(program: &wfassoc::Program, exts: Vec) -> Result> { todo!() } -fn run_unregister() -> Result<()> { - todo!() -} - -fn run_status() -> Result<()> { - todo!() -} - -fn run_ext_link() -> Result<()> { - todo!() -} - -fn run_ext_unlink() -> Result<()> { - todo!() -} - -fn run_ext_list() -> Result<()> { - todo!() -} - - // endregion -pub fn run(request: Request) -> Result<()> { +// region: Respective Runners + +fn run_register(program: wfassoc::Program, scope: wfassoc::Scope) -> Result<()> { todo!() } + +fn run_unregister(program: wfassoc::Program, scope: wfassoc::Scope) -> Result<()> { + todo!() +} + +fn run_status(program: wfassoc::Program, scope: wfassoc::Scope) -> Result<()> { + todo!() +} + +fn run_ext_link(program: wfassoc::Program, scope: wfassoc::Scope, exts: Vec) -> Result<()> { + let exts = stringified_exts_to_indices(&program, exts)?; + todo!() +} + +fn run_ext_unlink( + program: wfassoc::Program, + scope: wfassoc::Scope, + exts: Vec, +) -> Result<()> { + let exts = stringified_exts_to_indices(&program, exts)?; + todo!() +} + +fn run_ext_list( + program: wfassoc::Program, + view: wfassoc::View, + style: cli::ExtListStyle, +) -> Result<()> { + todo!() +} + +// endregion + +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) + } + }, + } +}