diff --git a/cli/src/action/history.rs b/cli/src/action/history.rs new file mode 100644 index 0000000..90451fe --- /dev/null +++ b/cli/src/action/history.rs @@ -0,0 +1,62 @@ +use clap::ArgMatches; + +use cmd::matcher::{ + Matcher, + history::HistoryMatcher, + main::MainMatcher, +}; +use error::ActionError; +use history::{ + History as HistoryManager, + LoadError as HistoryLoadError, +}; + +/// A history action. +pub struct History<'a> { + cmd_matches: &'a ArgMatches<'a>, +} + +impl<'a> History<'a> { + /// Construct a new history action. + pub fn new(cmd_matches: &'a ArgMatches<'a>) -> Self { + Self { + cmd_matches, + } + } + + /// Invoke the history action. + // TODO: create a trait for this method + pub fn invoke(&self) -> Result<(), ActionError> { + // Create the command matchers + let matcher_main = MainMatcher::with(self.cmd_matches).unwrap(); + let _matcher_history = HistoryMatcher::with(self.cmd_matches).unwrap(); + + // Get the history path, make sure it exists + let history_path = matcher_main.history(); + if !history_path.is_file() { + return Ok(()); + } + + // History + let history = HistoryManager::load(history_path)?; + + for file in history.files() { + println!("- File ID: {}", file.id()); + } + + Ok(()) + } +} + +#[derive(Debug, Fail)] +pub enum Error { + /// Failed to load the history. + #[fail(display = "Failed to load file history")] + Load(#[cause] HistoryLoadError), +} + +impl From for ActionError { + fn from(err: HistoryLoadError) -> ActionError { + ActionError::History(Error::Load(err)) + } +} diff --git a/cli/src/action/mod.rs b/cli/src/action/mod.rs index c6bf01e..0d32b89 100644 --- a/cli/src/action/mod.rs +++ b/cli/src/action/mod.rs @@ -1,6 +1,7 @@ pub mod delete; pub mod download; pub mod exists; +pub mod history; pub mod info; pub mod params; pub mod password; diff --git a/cli/src/cmd/cmd/history.rs b/cli/src/cmd/cmd/history.rs new file mode 100644 index 0000000..f51071f --- /dev/null +++ b/cli/src/cmd/cmd/history.rs @@ -0,0 +1,15 @@ +use clap::{App, SubCommand}; + +/// The history command definition. +pub struct CmdHistory; + +impl CmdHistory { + pub fn build<'a, 'b>() -> App<'a, 'b> { + SubCommand::with_name("history") + .about("View file history") + .visible_alias("h") + .alias("his") + .alias("list") + .alias("ls") + } +} diff --git a/cli/src/cmd/cmd/mod.rs b/cli/src/cmd/cmd/mod.rs index 0e6cc0a..951a8d6 100644 --- a/cli/src/cmd/cmd/mod.rs +++ b/cli/src/cmd/cmd/mod.rs @@ -1,6 +1,7 @@ pub mod delete; pub mod download; pub mod exists; +pub mod history; pub mod info; pub mod params; pub mod password; @@ -10,6 +11,7 @@ pub mod upload; pub use self::delete::CmdDelete; pub use self::download::CmdDownload; pub use self::exists::CmdExists; +pub use self::history::CmdHistory; pub use self::info::CmdInfo; pub use self::params::CmdParams; pub use self::password::CmdPassword; diff --git a/cli/src/cmd/handler.rs b/cli/src/cmd/handler.rs index fd4a3b6..ad29b50 100644 --- a/cli/src/cmd/handler.rs +++ b/cli/src/cmd/handler.rs @@ -7,6 +7,7 @@ use super::matcher::{ DeleteMatcher, DownloadMatcher, ExistsMatcher, + HistoryMatcher, InfoMatcher, Matcher, ParamsMatcher, @@ -17,6 +18,7 @@ use super::cmd::{ CmdDelete, CmdDownload, CmdExists, + CmdHistory, CmdInfo, CmdParams, CmdPassword, @@ -92,6 +94,7 @@ impl<'a: 'b, 'b> Handler<'a> { .subcommand(CmdDelete::build()) .subcommand(CmdDownload::build().display_order(2)) .subcommand(CmdExists::build()) + .subcommand(CmdHistory::build()) .subcommand(CmdInfo::build()) .subcommand(CmdParams::build()) .subcommand(CmdPassword::build()) @@ -132,6 +135,11 @@ impl<'a: 'b, 'b> Handler<'a> { ExistsMatcher::with(&self.matches) } + /// Get the history sub command, if matched. + pub fn history(&'a self) -> Option { + HistoryMatcher::with(&self.matches) + } + /// Get the info matcher, if that subcommand is entered. pub fn info(&'a self) -> Option { InfoMatcher::with(&self.matches) diff --git a/cli/src/cmd/matcher/history.rs b/cli/src/cmd/matcher/history.rs new file mode 100644 index 0000000..adfb772 --- /dev/null +++ b/cli/src/cmd/matcher/history.rs @@ -0,0 +1,20 @@ +use clap::ArgMatches; + +use super::Matcher; + +/// The history command matcher. +pub struct HistoryMatcher<'a> { + #[allow(unused)] + matches: &'a ArgMatches<'a>, +} + +impl<'a> Matcher<'a> for HistoryMatcher<'a> { + fn with(matches: &'a ArgMatches) -> Option { + matches.subcommand_matches("history") + .map(|matches| + HistoryMatcher { + matches, + } + ) + } +} diff --git a/cli/src/cmd/matcher/mod.rs b/cli/src/cmd/matcher/mod.rs index 342274d..dbbbdcb 100644 --- a/cli/src/cmd/matcher/mod.rs +++ b/cli/src/cmd/matcher/mod.rs @@ -1,6 +1,7 @@ pub mod delete; pub mod download; pub mod exists; +pub mod history; pub mod info; pub mod main; pub mod params; @@ -11,6 +12,7 @@ pub mod upload; pub use self::delete::DeleteMatcher; pub use self::download::DownloadMatcher; pub use self::exists::ExistsMatcher; +pub use self::history::HistoryMatcher; pub use self::info::InfoMatcher; pub use self::main::MainMatcher; pub use self::params::ParamsMatcher; diff --git a/cli/src/error.rs b/cli/src/error.rs index a3560d2..e8d0fb4 100644 --- a/cli/src/error.rs +++ b/cli/src/error.rs @@ -6,6 +6,7 @@ use ffsend_api::action::upload::Error as UploadError; use ffsend_api::file::remote_file::FileParseError; use action::download::Error as CliDownloadError; +use action::history::Error as CliHistoryError; use action::info::Error as CliInfoError; #[derive(Fail, Debug)] @@ -47,6 +48,10 @@ pub enum ActionError { #[fail(display = "Failed to check whether the file exists")] Exists(#[cause] ExistsError), + /// An error occurred while processing the file history. + #[fail(display = "Failed to process the history")] + History(#[cause] CliHistoryError), + /// An error occurred while invoking the info action. #[fail(display = "Failed to fetch file info")] Info(#[cause] CliInfoError), @@ -82,6 +87,12 @@ impl From for ActionError { } } +impl From for ActionError { + fn from(err: CliHistoryError) -> ActionError { + ActionError::History(err) + } +} + impl From for ActionError { fn from(err: ParamsError) -> ActionError { ActionError::Params(err) diff --git a/cli/src/main.rs b/cli/src/main.rs index c506b3e..8ce1d11 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -26,6 +26,7 @@ mod util; use action::delete::Delete; use action::download::Download; use action::exists::Exists; +use action::history::History; use action::info::Info; use action::params::Params; use action::password::Password; @@ -68,6 +69,12 @@ fn invoke_action(handler: &Handler) -> Result<(), Error> { .map_err(|err| err.into()); } + // Match the history command + if handler.history().is_some() { + return History::new(handler.matches()).invoke() + .map_err(|err| err.into()); + } + // Match the info command if handler.info().is_some() { return Info::new(handler.matches()).invoke() diff --git a/cli/src/util.rs b/cli/src/util.rs index 3e5805b..19afcca 100644 --- a/cli/src/util.rs +++ b/cli/src/util.rs @@ -26,7 +26,7 @@ use cmd::matcher::MainMatcher; /// Print a success message. pub fn print_success(msg: &str) { - println!("{}", msg.green()); + eprintln!("{}", msg.green()); } /// Print the given error in a proper format for the user,