Add version subcommand to determine remote server API version

This commit is contained in:
timvisee 2019-02-26 15:28:13 +01:00
parent 7c1429e112
commit f53f11a9f1
No known key found for this signature in database
GPG key ID: B8DB720BC383E172
9 changed files with 143 additions and 4 deletions

View file

@ -8,3 +8,4 @@ pub mod info;
pub mod params;
pub mod password;
pub mod upload;
pub mod version;

62
src/action/version.rs Normal file
View file

@ -0,0 +1,62 @@
use clap::ArgMatches;
use ffsend_api::action::version::{Error as VersionError, Version as ApiVersion};
use ffsend_api::file::remote_file::{FileParseError, RemoteFile};
use crate::client::create_client;
use crate::cmd::matcher::main::MainMatcher;
use crate::cmd::matcher::{version::VersionMatcher, Matcher};
use crate::error::ActionError;
#[cfg(feature = "history")]
use crate::history_tool;
/// A file version action.
pub struct Version<'a> {
cmd_matches: &'a ArgMatches<'a>,
}
impl<'a> Version<'a> {
/// Construct a new version action.
pub fn new(cmd_matches: &'a ArgMatches<'a>) -> Self {
Self { cmd_matches }
}
/// Invoke the version action.
// TODO: create a trait for this method
pub fn invoke(&self) -> Result<(), ActionError> {
// Create the command matchers
let matcher_version = VersionMatcher::with(self.cmd_matches).unwrap();
let matcher_main = MainMatcher::with(self.cmd_matches).unwrap();
// Get the host
let host = matcher_version.host();
// Create a reqwest client
let client = create_client(&matcher_main);
// Make sure the file version
let response = ApiVersion::new(host).invoke(&client);
// Print the result
match response {
Ok(v) => println!("API version: {}", v),
Err(VersionError::Unknown) => println!("Version: unknown"),
Err(VersionError::Unsupported(v)) => println!("Version: {} (unsupported)", v),
Err(e) => return Err(e.into()),
}
Ok(())
}
}
#[derive(Debug, Fail)]
pub enum Error {
/// An error occurred while attempting to determine the Send server version.
#[fail(display = "failed to check the server version")]
Version(#[cause] VersionError),
}
impl From<VersionError> for Error {
fn from(err: VersionError) -> Error {
Error::Version(err)
}
}

View file

@ -6,12 +6,13 @@ use clap::{App, AppSettings, Arg, ArgMatches};
use super::matcher::HistoryMatcher;
use super::matcher::{
DebugMatcher, DeleteMatcher, DownloadMatcher, ExistsMatcher, InfoMatcher, Matcher,
ParamsMatcher, PasswordMatcher, UploadMatcher,
ParamsMatcher, PasswordMatcher, UploadMatcher, VersionMatcher,
};
#[cfg(feature = "history")]
use super::subcmd::CmdHistory;
use super::subcmd::{
CmdDebug, CmdDelete, CmdDownload, CmdExists, CmdInfo, CmdParams, CmdPassword, CmdUpload,
CmdVersion,
};
use crate::config::{CLIENT_TIMEOUT, CLIENT_TRANSFER_TIMEOUT};
#[cfg(feature = "history")]
@ -145,7 +146,8 @@ impl<'a: 'b, 'b> Handler<'a> {
.subcommand(CmdInfo::build())
.subcommand(CmdParams::build())
.subcommand(CmdPassword::build())
.subcommand(CmdUpload::build().display_order(1));
.subcommand(CmdUpload::build().display_order(1))
.subcommand(CmdVersion::build());
// With history support, a flag for the history file and incognito mode
#[cfg(feature = "history")]
@ -239,4 +241,9 @@ impl<'a: 'b, 'b> Handler<'a> {
pub fn upload(&'a self) -> Option<UploadMatcher> {
UploadMatcher::with(&self.matches)
}
/// Get the version sub command, if matched.
pub fn version(&'a self) -> Option<VersionMatcher> {
VersionMatcher::with(&self.matches)
}
}

View file

@ -9,8 +9,9 @@ pub mod main;
pub mod params;
pub mod password;
pub mod upload;
pub mod version;
// Reexport to matcher module
// Re-export to matcher module
pub use self::debug::DebugMatcher;
pub use self::delete::DeleteMatcher;
pub use self::download::DownloadMatcher;
@ -22,6 +23,7 @@ pub use self::main::MainMatcher;
pub use self::params::ParamsMatcher;
pub use self::password::PasswordMatcher;
pub use self::upload::UploadMatcher;
pub use self::version::VersionMatcher;
use clap::ArgMatches;

View file

@ -0,0 +1,30 @@
use ffsend_api::url::Url;
use clap::ArgMatches;
use super::Matcher;
use crate::cmd::arg::{ArgHost, CmdArgOption};
/// The version command matcher.
pub struct VersionMatcher<'a> {
matches: &'a ArgMatches<'a>,
}
impl<'a: 'b, 'b> VersionMatcher<'a> {
/// Get the host to probe.
///
/// This method parses the host into an `Url`.
/// If the given host is invalid,
/// the program will quit with an error message.
pub fn host(&'a self) -> Url {
ArgHost::value(self.matches)
}
}
impl<'a> Matcher<'a> for VersionMatcher<'a> {
fn with(matches: &'a ArgMatches) -> Option<Self> {
matches
.subcommand_matches("version")
.map(|matches| VersionMatcher { matches })
}
}

View file

@ -8,8 +8,9 @@ pub mod info;
pub mod params;
pub mod password;
pub mod upload;
pub mod version;
// Reexport to cmd module
// Re-export to cmd module
pub use self::debug::CmdDebug;
pub use self::delete::CmdDelete;
pub use self::download::CmdDownload;
@ -20,3 +21,4 @@ pub use self::info::CmdInfo;
pub use self::params::CmdParams;
pub use self::password::CmdPassword;
pub use self::upload::CmdUpload;
pub use self::version::CmdVersion;

16
src/cmd/subcmd/version.rs Normal file
View file

@ -0,0 +1,16 @@
use clap::{App, SubCommand};
use crate::cmd::arg::{ArgHost, CmdArg};
/// The version command definition.
pub struct CmdVersion;
impl CmdVersion {
pub fn build<'a, 'b>() -> App<'a, 'b> {
SubCommand::with_name("version")
.about("Determine the Send server version")
.alias("ver")
.visible_alias("v")
.arg(ArgHost::build())
}
}

View file

@ -2,6 +2,7 @@ use ffsend_api::action::delete::Error as DeleteError;
use ffsend_api::action::exists::Error as ExistsError;
use ffsend_api::action::params::Error as ParamsError;
use ffsend_api::action::password::Error as PasswordError;
use ffsend_api::action::version::Error as VersionError;
use ffsend_api::file::remote_file::FileParseError;
use crate::action::download::Error as CliDownloadError;
@ -72,6 +73,10 @@ pub enum ActionError {
#[fail(display = "failed to change the password")]
Password(#[cause] PasswordError),
/// An error occurred while invoking the version action.
#[fail(display = "failed to determine server version")]
Version(#[cause] VersionError),
/// An error occurred while invoking the upload action.
#[fail(display = "failed to upload the specified file")]
Upload(#[cause] CliUploadError),
@ -113,6 +118,12 @@ impl From<PasswordError> for ActionError {
}
}
impl From<VersionError> for ActionError {
fn from(err: VersionError) -> ActionError {
ActionError::Version(err)
}
}
impl From<FileParseError> for ActionError {
fn from(err: FileParseError) -> ActionError {
ActionError::InvalidUrl(err)

View file

@ -43,6 +43,7 @@ use crate::action::info::Info;
use crate::action::params::Params;
use crate::action::password::Password;
use crate::action::upload::Upload;
use crate::action::version::Version;
use crate::cmd::{
matcher::{MainMatcher, Matcher},
Handler,
@ -135,6 +136,13 @@ fn invoke_action(handler: &Handler) -> Result<(), Error> {
.map_err(|err| err.into());
}
// Match the version command
if handler.version().is_some() {
return Version::new(handler.matches())
.invoke()
.map_err(|err| err.into());
}
// Get the main matcher
let matcher_main = MainMatcher::with(handler.matches()).unwrap();