Add publish an package to the package manager

This commit is contained in:
Sergey Isaev 2020-08-12 02:33:32 +03:00
parent 3980ff8e1e
commit cde9c0ef40
6 changed files with 129 additions and 9 deletions

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::{ use leo_package::{
outputs::OutputsDirectory, outputs::OutputsDirectory,
root::{Manifest, ZipFile}, root::{Manifest, ZipFile},
}; };
use reqwest::{
use clap::ArgMatches; blocking::{multipart::Form, Client},
header::{HeaderMap, HeaderValue},
};
use serde::Deserialize;
use std::{convert::TryFrom, env::current_dir}; 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)] #[derive(Debug)]
pub struct PublishCommand; pub struct PublishCommand;
impl CLI for PublishCommand { impl CLI for PublishCommand {
type Options = (); type Options = ();
type Output = (); type Output = Option<String>;
const ABOUT: AboutType = "Publish the current package to the package manager (*)"; 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 FLAGS: &'static [FlagType] = &[];
const NAME: NameType = "publish"; const NAME: NameType = "publish";
const OPTIONS: &'static [OptionType] = &[]; const OPTIONS: &'static [OptionType] = &[];
@ -23,18 +53,23 @@ impl CLI for PublishCommand {
#[cfg_attr(tarpaulin, skip)] #[cfg_attr(tarpaulin, skip)]
fn parse(_arguments: &ArgMatches) -> Result<Self::Options, CLIError> { fn parse(_arguments: &ArgMatches) -> Result<Self::Options, CLIError> {
// match arguments.value_of("NAME") {
// Some(name) => Ok((Some(name.to_string()),)),
// None => Ok((None,)),
// }
Ok(()) Ok(())
} }
#[cfg_attr(tarpaulin, skip)] #[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. // Build all program files.
// It's okay if there's just a lib.leo file here // 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 // Get the package name
let path = current_dir()?; let path = current_dir()?;
let package_name = Manifest::try_from(&path)?.get_package_name(); let package_name = Manifest::try_from(&path)?.get_package_name();
let package_version = Manifest::try_from(&path)?.get_package_version();
// Create the output directory // Create the output directory
OutputsDirectory::create(&path)?; OutputsDirectory::create(&path)?;
@ -47,6 +82,60 @@ impl CLI for PublishCommand {
zip_file.write(&path)?; zip_file.write(&path)?;
} }
Ok(()) let is_public = "false";
let form_data = Form::new()
.text("name", package_name)
.text("version", package_version)
.file("file", zip_file.get_file_path(&path))?
.text("public", is_public);
// 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)] #[error("{}", _0)]
ProvingKeyFileError(ProvingKeyFileError), ProvingKeyFileError(ProvingKeyFileError),
#[error("{}", _0)]
PublishError(PublishError),
#[error("{}", _0)] #[error("{}", _0)]
RunError(RunError), 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 { impl From<RunError> for CLIError {
fn from(error: RunError) -> Self { fn from(error: RunError) -> Self {
log::error!("{}\n", error); log::error!("{}\n", error);

View File

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

View File

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