Merge pull request #205 from AleoHQ/publish_command

Add publish an package to the package manager
This commit is contained in:
Sergey Isaev 2020-08-15 02:39:35 +03:00 committed by GitHub
commit ffd13b9897
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 129 additions and 11 deletions

View File

@ -54,7 +54,7 @@ impl LoginCommand {
impl CLI for LoginCommand {
// Format: token, username, password
type Options = (Option<String>, Option<String>, Option<String>);
type Output = ();
type Output = String;
const ABOUT: AboutType = "Login to the package manager (*)";
const ARGUMENTS: &'static [ArgumentType] = &[
@ -138,6 +138,6 @@ impl CLI for LoginCommand {
LoginCommand::write_token(token.as_str())?;
log::info!("Successfully logged in");
Ok(())
Ok(token)
}
}

View File

@ -1,21 +1,51 @@
use crate::{cli::*, cli_types::*, commands::BuildCommand, errors::CLIError};
use crate::{
cli::*,
cli_types::*,
commands::{BuildCommand, LoginCommand},
errors::{
commands::PublishError::{ConnectionUnavalaible, PackageNotPublished},
CLIError,
CLIError::PublishError,
},
};
use clap::ArgMatches;
use leo_package::{
outputs::OutputsDirectory,
root::{Manifest, ZipFile},
};
use clap::ArgMatches;
use reqwest::{
blocking::{multipart::Form, Client},
header::{HeaderMap, HeaderValue},
};
use serde::Deserialize;
use std::{convert::TryFrom, env::current_dir};
const PACKAGE_MANAGER_URL: &str = "https://apm-backend-dev.herokuapp.com/";
const PUBLISH_URL: &str = "api/package/publish";
#[derive(Deserialize)]
struct ResponseJson {
package_id: String,
_success: bool,
}
#[derive(Debug)]
pub struct PublishCommand;
impl CLI for PublishCommand {
type Options = ();
type Output = ();
type Output = Option<String>;
const ABOUT: AboutType = "Publish the current package to the package manager (*)";
const ARGUMENTS: &'static [ArgumentType] = &[];
const ARGUMENTS: &'static [ArgumentType] = &[
// (name, description, required, index)
(
"NAME",
"Sets the resulting package name, defaults to the directory name",
true,
1u64,
),
];
const FLAGS: &'static [FlagType] = &[];
const NAME: NameType = "publish";
const OPTIONS: &'static [OptionType] = &[];
@ -23,18 +53,23 @@ impl CLI for PublishCommand {
#[cfg_attr(tarpaulin, skip)]
fn parse(_arguments: &ArgMatches) -> Result<Self::Options, CLIError> {
// match arguments.value_of("NAME") {
// Some(name) => Ok((Some(name.to_string()),)),
// None => Ok((None,)),
// }
Ok(())
}
#[cfg_attr(tarpaulin, skip)]
fn output(options: Self::Options) -> Result<Self::Output, CLIError> {
fn output(_options: Self::Options) -> Result<Self::Output, CLIError> {
// Build all program files.
// It's okay if there's just a lib.leo file here
let _output = BuildCommand::output(options)?;
// let _output = BuildCommand::output(options)?;
// Get the package name
let path = current_dir()?;
let package_name = Manifest::try_from(&path)?.get_package_name();
let package_version = Manifest::try_from(&path)?.get_package_version();
// Create the output directory
OutputsDirectory::create(&path)?;
@ -47,6 +82,58 @@ impl CLI for PublishCommand {
zip_file.write(&path)?;
}
Ok(())
let form_data = Form::new()
.text("name", package_name)
.text("version", package_version)
.file("file", zip_file.get_file_path(&path))?;
// Client for make POST request
let client = Client::new();
// Get token to make an authorized request
let token = match LoginCommand::read_token() {
Ok(token) => token,
// If not logged then try to login using JWT
Err(_errorr) => {
log::warn!("You should be logged before publish the package");
log::info!("Trying to log in using JWT...");
let options = (None, None, None);
LoginCommand::output(options)?
}
};
// Headers for request to publish package
let mut headers = HeaderMap::new();
headers.insert(
"Authorization",
HeaderValue::from_str(&format!("{} {}", "Bearer", token)).unwrap(),
);
// Make a request to publish a package
let response = client
.post(format!("{}{}", PACKAGE_MANAGER_URL, PUBLISH_URL).as_str())
.headers(headers)
.multipart(form_data)
.send();
// Get a response result
let result = match response {
Ok(json_result) => match json_result.json::<ResponseJson>() {
Ok(json) => json,
Err(error) => {
log::warn!("{:?}", error);
return Err(PublishError(PackageNotPublished("Package not published".into())));
}
},
Err(error) => {
log::warn!("{:?}", error);
return Err(PublishError(ConnectionUnavalaible("Connection error".into())));
}
};
log::info!("Packge published successfully");
Ok(Some(result.package_id))
}
}

View File

@ -51,6 +51,9 @@ pub enum CLIError {
#[error("{}", _0)]
ProvingKeyFileError(ProvingKeyFileError),
#[error("{}", _0)]
PublishError(PublishError),
#[error("{}", _0)]
RunError(RunError),
@ -175,6 +178,13 @@ impl From<ProvingKeyFileError> for CLIError {
}
}
impl From<PublishError> for CLIError {
fn from(error: PublishError) -> Self {
log::error!("{}\n", error);
CLIError::PublishError(error)
}
}
impl From<RunError> for CLIError {
fn from(error: RunError) -> Self {
log::error!("{}\n", error);

View File

@ -10,6 +10,9 @@ pub use self::login::*;
pub mod new;
pub use self::new::*;
pub mod publish;
pub use self::publish::*;
pub mod run;
pub use self::run::*;

View File

@ -0,0 +1,10 @@
use std::ffi::OsString;
#[derive(Debug, Error)]
pub enum PublishError {
#[error("connection unavailable {:?}", _0)]
ConnectionUnavalaible(OsString),
#[error("package not published {:?}", _0)]
PackageNotPublished(OsString),
}

View File

@ -8,7 +8,7 @@ use std::{
path::PathBuf,
};
pub static MANIFEST_FILE_NAME: &str = "Leo.toml";
pub const MANIFEST_FILE_NAME: &str = "Leo.toml";
#[derive(Deserialize)]
pub struct Package {
@ -43,6 +43,10 @@ impl Manifest {
self.package.name.clone()
}
pub fn get_package_version(&self) -> String {
self.package.version.clone()
}
pub fn write_to(self, path: &PathBuf) -> Result<(), ManifestError> {
let mut path = path.to_owned();
if path.is_dir() {

View File

@ -41,6 +41,10 @@ impl ZipFile {
path.exists()
}
pub fn get_file_path(&self, current_dir: &PathBuf) -> PathBuf {
self.setup_file_path(current_dir)
}
// /// Reads the program bytes from the given file path if it exists.
// pub fn read_from(&self, path: &PathBuf) -> Result<Vec<u8>, ZipFileError> {
// let path = self.setup_file_path(path);