Refactor command-line handling into modules per subcommands

This commit is contained in:
Dustin J. Mitchell 2020-11-23 19:33:04 -05:00
parent e0b69a62b1
commit fe4183c3ca
12 changed files with 560 additions and 59 deletions

69
cli/src/cmd/mod.rs Normal file
View file

@ -0,0 +1,69 @@
use clap::{App, ArgMatches};
use failure::{Error, Fallible};
use std::path::Path;
use taskchampion::{taskstorage, Replica};
#[macro_use]
mod macros;
mod add;
mod gc;
mod list;
mod pending;
/// Get a list of all subcommands in this crate
pub(crate) fn subcommands() -> Vec<Box<dyn SubCommand>> {
vec![add::cmd(), gc::cmd(), list::cmd(), pending::cmd()]
}
/// The result of a [`crate::cmd::SubCommand::arg_match`] call
pub(crate) enum ArgMatchResult {
/// No match
None,
/// A good match
Ok(Box<dyn SubCommandInvocation>),
/// A match, but an issue with the command line
Err(Error),
}
/// A subcommand represents a defined subcommand, and is typically a singleton.
pub(crate) trait SubCommand {
/// Decorate the given [`clap::App`] appropriately for this subcommand
fn decorate_app<'a>(&self, app: App<'a, 'a>) -> App<'a, 'a>;
/// If this ArgMatches is for this command, return an appropriate invocation.
fn arg_match<'a>(&self, matches: &ArgMatches<'a>) -> ArgMatchResult;
}
/// A subcommand invocation is specialized to a subcommand
pub(crate) trait SubCommandInvocation: std::fmt::Debug {
fn run(&self, command: &CommandInvocation) -> Fallible<()>;
// tests use downcasting, which requires a function to cast to Any
#[cfg(test)]
fn as_any(&self) -> &dyn std::any::Any;
}
/// A command invocation contains all of the necessary regarding a single invocation of the CLI.
#[derive(Debug)]
pub struct CommandInvocation {
pub(crate) subcommand: Box<dyn SubCommandInvocation>,
}
impl CommandInvocation {
pub(crate) fn new(subcommand: Box<dyn SubCommandInvocation>) -> Self {
Self { subcommand }
}
pub fn run(self) -> Fallible<()> {
self.subcommand.run(&self)
}
fn get_replica(&self) -> Replica {
Replica::new(Box::new(
taskstorage::KVStorage::new(Path::new("/tmp/tasks")).unwrap(),
))
}
}