diff --git a/leo/commands/add.rs b/leo/commands/add.rs new file mode 100644 index 0000000000..1851a37607 --- /dev/null +++ b/leo/commands/add.rs @@ -0,0 +1,105 @@ +// +// Usage: +// +// leo add -a author -p package_name -v version +// leo add -a author -p package_name +// + +use crate::{ + cli::CLI, + cli_types::*, + credentials::*, + errors::{AddError::*, CLIError::AddError}, +}; + +use std::{collections::HashMap, env::current_dir, fs::File, io::Write}; + +pub const ADD_URL: &str = "api/package/fetch"; + +#[derive(Debug)] +pub struct AddCommand; + +impl CLI for AddCommand { + // Format: author, package_name, version + type Options = (Option, Option, Option); + type Output = (); + + const ABOUT: AboutType = "Install a package from the package manager"; + const ARGUMENTS: &'static [ArgumentType] = &[]; + const FLAGS: &'static [FlagType] = &[]; + const NAME: NameType = "add"; + const OPTIONS: &'static [OptionType] = &[ + // (argument, conflicts, possible_values, requires) + ("[author] -a --author= 'Specify a package author'", &[], &[], &[ + "package_name", + ]), + ( + "[package_name] -p --package_name= 'Specify a package name'", + &[], + &[], + &["author"], + ), + ( + "[version] -v --version=[version] 'Specify a package version'", + &[], + &[], + &["author", "package_name"], + ), + ]; + const SUBCOMMANDS: &'static [SubCommandType] = &[]; + + fn parse(arguments: &clap::ArgMatches) -> Result { + if arguments.is_present("author") && arguments.is_present("package_name") { + return Ok(( + arguments.value_of("author").map(|s| s.to_string()), + arguments.value_of("package_name").map(|s| s.to_string()), + arguments.value_of("version").map(|s| s.to_string()), + )); + } else { + return Err(AddError(MissingAuthorOrPackageName)); + } + } + + fn output(options: Self::Options) -> Result { + let token = read_token()?; + + let (mut result, package_name) = match options { + (Some(author), Some(package_name), version) => { + let client = reqwest::blocking::Client::new(); + let url = format!("{}{}", PACKAGE_MANAGER_URL, ADD_URL); + + let mut json = HashMap::new(); + json.insert("author", author); + json.insert("package_name", package_name.clone()); + + if let Some(version) = version { + json.insert("version", version); + } + + match client.post(&url).bearer_auth(token).json(&json).send() { + Ok(result) => (result, package_name), + //Cannot connect to the server + Err(_error) => { + return Err(AddError(ConnectionUnavailable( + "Could not connect to the package manager".into(), + ))); + } + } + } + _ => return Err(AddError(MissingAuthorOrPackageName)), + }; + + let mut path = current_dir()?; + path.push(format!("{}.zip", package_name)); + + // TODO (raychu86) Display download progress + let mut buffer: Vec = vec![]; + result.copy_to(&mut buffer).unwrap(); + + let mut file = File::create(path)?; + file.write_all(&buffer)?; + + log::info!("Successfully added package"); + Ok(()) + } +} diff --git a/leo/commands/login.rs b/leo/commands/login.rs index a0b7204377..aa97a6a1ff 100644 --- a/leo/commands/login.rs +++ b/leo/commands/login.rs @@ -12,7 +12,7 @@ use crate::{ credentials::*, errors::{ CLIError::LoginError, - LoginError::{CannotGetToken, ConnectionUnavalaible, WrongLoginOrPassword}, + LoginError::{CannotGetToken, ConnectionUnavailable, WrongLoginOrPassword}, }, }; @@ -84,7 +84,7 @@ impl CLI for LoginCommand { }, //Cannot connect to the server Err(_error) => { - return Err(LoginError(ConnectionUnavalaible( + return Err(LoginError(ConnectionUnavailable( "Could not connect to the package manager".into(), ))); } diff --git a/leo/commands/mod.rs b/leo/commands/mod.rs index 4fac06e973..2e9053ecb6 100644 --- a/leo/commands/mod.rs +++ b/leo/commands/mod.rs @@ -1,3 +1,6 @@ +pub mod add; +pub use self::add::*; + pub mod build; pub use self::build::*; diff --git a/leo/errors/cli.rs b/leo/errors/cli.rs index c9f28f281f..553bcc39e2 100644 --- a/leo/errors/cli.rs +++ b/leo/errors/cli.rs @@ -3,6 +3,9 @@ use leo_package::errors::*; #[derive(Debug, Error)] pub enum CLIError { + #[error("{}", _0)] + AddError(AddError), + #[error("{}", _0)] BuildError(BuildError), @@ -84,6 +87,13 @@ impl From for CLIError { } } +impl From for CLIError { + fn from(error: AddError) -> Self { + log::error!("{}\n", error); + CLIError::AddError(error) + } +} + impl From for CLIError { fn from(error: ChecksumFileError) -> Self { log::error!("{}\n", error); diff --git a/leo/errors/commands/add.rs b/leo/errors/commands/add.rs new file mode 100644 index 0000000000..bbf6b533ed --- /dev/null +++ b/leo/errors/commands/add.rs @@ -0,0 +1,10 @@ +use std::ffi::OsString; + +#[derive(Debug, Error)] +pub enum AddError { + #[error("connection unavailable {:?}", _0)] + ConnectionUnavailable(OsString), + + #[error("missing author or package name")] + MissingAuthorOrPackageName, +} diff --git a/leo/errors/commands/login.rs b/leo/errors/commands/login.rs index f05729a947..9402c9d557 100644 --- a/leo/errors/commands/login.rs +++ b/leo/errors/commands/login.rs @@ -5,8 +5,8 @@ pub enum LoginError { #[error("{:?}", _0)] CannotGetToken(OsString), - #[error("connectin unavalaible {:?}", _0)] - ConnectionUnavalaible(OsString), + #[error("connection unavailable {:?}", _0)] + ConnectionUnavailable(OsString), #[error("wrong login or password {:?}", _0)] WrongLoginOrPassword(OsString), diff --git a/leo/errors/commands/mod.rs b/leo/errors/commands/mod.rs index e283cfaa63..8fbb3cfe75 100644 --- a/leo/errors/commands/mod.rs +++ b/leo/errors/commands/mod.rs @@ -1,3 +1,6 @@ +pub mod add; +pub use self::add::*; + pub mod build; pub use self::build::*; diff --git a/leo/main.rs b/leo/main.rs index 06578f29ca..5c800b3ee6 100644 --- a/leo/main.rs +++ b/leo/main.rs @@ -35,6 +35,7 @@ fn main() -> Result<(), CLIError> { DeployCommand::new().display_order(12), CleanCommand::new().display_order(13), WatchCommand::new().display_order(14), + AddCommand::new().display_order(15), // TODO update add command order ]) .set_term_width(0) .get_matches(); @@ -55,6 +56,7 @@ fn main() -> Result<(), CLIError> { ("deploy", Some(arguments)) => DeployCommand::process(arguments), ("clean", Some(arguments)) => CleanCommand::process(arguments), ("watch", Some(arguments)) => WatchCommand::process(arguments), + ("add", Some(arguments)) => AddCommand::process(arguments), _ => unreachable!(), } }