mirror of
https://github.com/AleoHQ/leo.git
synced 2024-12-27 03:21:49 +03:00
Merge pull request #632 from AleoHQ/adds-structopt-to-leo
[CLI] Leo CLI is now on StructOpt and Anyhow (reopened)
This commit is contained in:
commit
59fa8fd62b
1
.github/workflows/leo-login-logout.yml
vendored
1
.github/workflows/leo-login-logout.yml
vendored
@ -43,6 +43,5 @@ jobs:
|
|||||||
leo login -u "$USER" -p "$PASS"
|
leo login -u "$USER" -p "$PASS"
|
||||||
leo add argus4130/xnor
|
leo add argus4130/xnor
|
||||||
leo remove xnor
|
leo remove xnor
|
||||||
leo clean
|
|
||||||
leo logout
|
leo logout
|
||||||
|
|
||||||
|
42
Cargo.lock
generated
42
Cargo.lock
generated
@ -1010,6 +1010,15 @@ version = "0.9.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
|
checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heck"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-segmentation",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
version = "0.1.17"
|
version = "0.1.17"
|
||||||
@ -1388,6 +1397,7 @@ dependencies = [
|
|||||||
name = "leo-lang"
|
name = "leo-lang"
|
||||||
version = "1.2.2"
|
version = "1.2.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
"clap",
|
"clap",
|
||||||
"colored",
|
"colored",
|
||||||
"console",
|
"console",
|
||||||
@ -1416,6 +1426,7 @@ dependencies = [
|
|||||||
"snarkvm-gadgets",
|
"snarkvm-gadgets",
|
||||||
"snarkvm-models",
|
"snarkvm-models",
|
||||||
"snarkvm-utilities",
|
"snarkvm-utilities",
|
||||||
|
"structopt",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"toml",
|
"toml",
|
||||||
"tracing",
|
"tracing",
|
||||||
@ -2052,6 +2063,7 @@ dependencies = [
|
|||||||
"proc-macro-error-attr",
|
"proc-macro-error-attr",
|
||||||
"proc-macro2 1.0.24",
|
"proc-macro2 1.0.24",
|
||||||
"quote 1.0.7",
|
"quote 1.0.7",
|
||||||
|
"syn 1.0.60",
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -2809,6 +2821,30 @@ version = "0.8.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "structopt"
|
||||||
|
version = "0.3.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5277acd7ee46e63e5168a80734c9f6ee81b1367a7d8772a2d765df2a3705d28c"
|
||||||
|
dependencies = [
|
||||||
|
"clap",
|
||||||
|
"lazy_static",
|
||||||
|
"structopt-derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "structopt-derive"
|
||||||
|
version = "0.4.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5ba9cdfda491b814720b6b06e0cac513d922fc407582032e8706e9f137976f90"
|
||||||
|
dependencies = [
|
||||||
|
"heck",
|
||||||
|
"proc-macro-error",
|
||||||
|
"proc-macro2 1.0.24",
|
||||||
|
"quote 1.0.7",
|
||||||
|
"syn 1.0.60",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "subtle"
|
name = "subtle"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
@ -3152,6 +3188,12 @@ dependencies = [
|
|||||||
"tinyvec",
|
"tinyvec",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-segmentation"
|
||||||
|
version = "1.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-width"
|
name = "unicode-width"
|
||||||
version = "0.1.8"
|
version = "0.1.8"
|
||||||
|
@ -89,6 +89,12 @@ default-features = false
|
|||||||
[dependencies.snarkvm-utilities]
|
[dependencies.snarkvm-utilities]
|
||||||
version = "0.0.3"
|
version = "0.0.3"
|
||||||
|
|
||||||
|
[dependencies.anyhow]
|
||||||
|
version = "1.0"
|
||||||
|
|
||||||
|
[dependencies.structopt]
|
||||||
|
version = "0.3"
|
||||||
|
|
||||||
[dependencies.clap]
|
[dependencies.clap]
|
||||||
version = "2.33.3"
|
version = "2.33.3"
|
||||||
|
|
||||||
|
202
leo/api.rs
Normal file
202
leo/api.rs
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||||
|
// This file is part of the Leo library.
|
||||||
|
|
||||||
|
// The Leo library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// The Leo library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use anyhow::{anyhow, Error, Result};
|
||||||
|
use reqwest::{
|
||||||
|
blocking::{Client, Response},
|
||||||
|
Method,
|
||||||
|
StatusCode,
|
||||||
|
};
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
|
/// Trait describes API Routes and Request bodies, struct which implements
|
||||||
|
/// Route MUST also support Serialize to be usable in Api::run_route(r: Route)
|
||||||
|
pub trait Route {
|
||||||
|
/// Whether to use bearer auth or not. Some routes may have additional
|
||||||
|
/// features for logged-in users, so authorization token should be sent
|
||||||
|
/// if it is created of course
|
||||||
|
const AUTH: bool;
|
||||||
|
|
||||||
|
/// HTTP method to use when requesting
|
||||||
|
const METHOD: Method;
|
||||||
|
|
||||||
|
/// URL path without first forward slash (e.g. v1/package/fetch)
|
||||||
|
const PATH: &'static str;
|
||||||
|
|
||||||
|
/// Output type for this route. For login it is simple - String
|
||||||
|
/// But for other routes may be more complex.
|
||||||
|
type Output;
|
||||||
|
|
||||||
|
/// Process reqwest Response and turn it into Output
|
||||||
|
fn process(&self, res: Response) -> Result<Self::Output>;
|
||||||
|
|
||||||
|
/// Transform specific status codes into correct errors for this route.
|
||||||
|
/// For example 404 on package fetch should mean that 'Package is not found'
|
||||||
|
fn status_to_err(&self, _status: StatusCode) -> Error {
|
||||||
|
anyhow!("Unidentified API error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// REST API handler with reqwest::blocking inside
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Api {
|
||||||
|
host: String,
|
||||||
|
client: Client,
|
||||||
|
/// Authorization token for API requests
|
||||||
|
auth_token: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Api {
|
||||||
|
/// Create new instance of API, set host and Client is going to be
|
||||||
|
/// created and set automatically
|
||||||
|
pub fn new(host: String, auth_token: Option<String>) -> Api {
|
||||||
|
Api {
|
||||||
|
client: Client::new(),
|
||||||
|
auth_token,
|
||||||
|
host,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get token for bearer auth, should be passed into Api through Context
|
||||||
|
pub fn auth_token(&self) -> Option<String> {
|
||||||
|
self.auth_token.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set authorization token for future requests
|
||||||
|
pub fn set_auth_token(&mut self, token: String) {
|
||||||
|
self.auth_token = Some(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run specific route struct. Turn struct into request body
|
||||||
|
/// and use type constants and Route implementation to get request params
|
||||||
|
pub fn run_route<T>(&self, route: T) -> Result<T::Output>
|
||||||
|
where
|
||||||
|
T: Route,
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
let mut res = self.client.request(T::METHOD, &format!("{}{}", self.host, T::PATH));
|
||||||
|
|
||||||
|
// add body for POST and PUT requests
|
||||||
|
if T::METHOD == Method::POST || T::METHOD == Method::PUT {
|
||||||
|
res = res.json(&route);
|
||||||
|
};
|
||||||
|
|
||||||
|
// if Route::Auth is true and token is present - pass it
|
||||||
|
if T::AUTH && self.auth_token().is_some() {
|
||||||
|
res = res.bearer_auth(&self.auth_token().unwrap());
|
||||||
|
};
|
||||||
|
|
||||||
|
// only one error is possible here
|
||||||
|
let res = res.send().map_err(|_| anyhow!("Unable to connect to Aleo PM"))?;
|
||||||
|
|
||||||
|
// where magic begins
|
||||||
|
route.process(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------
|
||||||
|
// | Defining routes |
|
||||||
|
// --------------------------------------------------
|
||||||
|
|
||||||
|
/// Handler for 'fetch' route - fetch packages from Aleo PM
|
||||||
|
/// Route: POST /v1/package/fetch
|
||||||
|
#[derive(Serialize, Debug)]
|
||||||
|
pub struct Fetch {
|
||||||
|
pub author: String,
|
||||||
|
pub package_name: String,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub version: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Route for Fetch {
|
||||||
|
type Output = Response;
|
||||||
|
|
||||||
|
const AUTH: bool = true;
|
||||||
|
const METHOD: Method = Method::POST;
|
||||||
|
const PATH: &'static str = "api/package/fetch";
|
||||||
|
|
||||||
|
fn process(&self, res: Response) -> Result<Self::Output> {
|
||||||
|
// check status code first
|
||||||
|
if res.status() != 200 {
|
||||||
|
return Err(self.status_to_err(res.status()));
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn status_to_err(&self, status: StatusCode) -> Error {
|
||||||
|
match status {
|
||||||
|
StatusCode::BAD_REQUEST => anyhow!("Package is not found - check author and/or package name"),
|
||||||
|
// TODO: we should return 404 on not found author/package
|
||||||
|
// and return BAD_REQUEST if data format is incorrect or some of the arguments
|
||||||
|
// were not passed
|
||||||
|
StatusCode::NOT_FOUND => anyhow!("Package is hidden"),
|
||||||
|
_ => anyhow!("Unknown API error: {}", status),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handler for 'login' route - send username and password and receive JWT
|
||||||
|
/// Route: POST /v1/account/authenticate
|
||||||
|
#[derive(Serialize)]
|
||||||
|
pub struct Login {
|
||||||
|
pub email_username: String,
|
||||||
|
pub password: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Route for Login {
|
||||||
|
type Output = Response;
|
||||||
|
|
||||||
|
const AUTH: bool = false;
|
||||||
|
const METHOD: Method = Method::POST;
|
||||||
|
const PATH: &'static str = "api/account/authenticate";
|
||||||
|
|
||||||
|
fn process(&self, res: Response) -> Result<Self::Output> {
|
||||||
|
if res.status() != 200 {
|
||||||
|
return Err(self.status_to_err(res.status()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn status_to_err(&self, status: StatusCode) -> Error {
|
||||||
|
match status {
|
||||||
|
StatusCode::BAD_REQUEST => anyhow!("This username is not yet registered or the password is incorrect"),
|
||||||
|
// TODO: NOT_FOUND here should be replaced, this error code has no relation to what this route is doing
|
||||||
|
StatusCode::NOT_FOUND => anyhow!("Incorrect password"),
|
||||||
|
_ => anyhow!("Unknown API error: {}", status),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handler for 'my_profile' route. Meant to be used to get profile details but
|
||||||
|
/// in current application is used to check if user is logged in. Any non-200 response
|
||||||
|
/// is treated as Unauthorized
|
||||||
|
#[derive(Serialize)]
|
||||||
|
pub struct Profile {}
|
||||||
|
|
||||||
|
impl Route for Profile {
|
||||||
|
type Output = bool;
|
||||||
|
|
||||||
|
const AUTH: bool = true;
|
||||||
|
const METHOD: Method = Method::GET;
|
||||||
|
const PATH: &'static str = "api/account/my_profile";
|
||||||
|
|
||||||
|
fn process(&self, res: Response) -> Result<Self::Output> {
|
||||||
|
// this may be extended for more precise error handling
|
||||||
|
Ok(res.status() == 200)
|
||||||
|
}
|
||||||
|
}
|
127
leo/cli.rs
127
leo/cli.rs
@ -1,127 +0,0 @@
|
|||||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
|
||||||
// This file is part of the Leo library.
|
|
||||||
|
|
||||||
// The Leo library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// The Leo library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
use crate::{cli_types::*, errors::CLIError, logger, updater::Updater};
|
|
||||||
|
|
||||||
use clap::{App, AppSettings, Arg, ArgMatches, SubCommand};
|
|
||||||
|
|
||||||
pub trait CLI {
|
|
||||||
type Options;
|
|
||||||
type Output;
|
|
||||||
|
|
||||||
const ABOUT: AboutType;
|
|
||||||
const ARGUMENTS: &'static [ArgumentType];
|
|
||||||
const FLAGS: &'static [FlagType];
|
|
||||||
const NAME: NameType;
|
|
||||||
const OPTIONS: &'static [OptionType];
|
|
||||||
const SUBCOMMANDS: &'static [SubCommandType];
|
|
||||||
|
|
||||||
#[allow(clippy::new_ret_no_self)]
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
|
||||||
fn new<'a, 'b>() -> App<'a, 'b> {
|
|
||||||
let arguments = &Self::ARGUMENTS
|
|
||||||
.iter()
|
|
||||||
.map(|a| {
|
|
||||||
let mut args = Arg::with_name(a.0).help(a.1).required(a.3).index(a.4);
|
|
||||||
if !a.2.is_empty() {
|
|
||||||
args = args.possible_values(a.2);
|
|
||||||
}
|
|
||||||
args
|
|
||||||
})
|
|
||||||
.collect::<Vec<Arg<'static, 'static>>>();
|
|
||||||
let flags = &Self::FLAGS
|
|
||||||
.iter()
|
|
||||||
.map(|a| Arg::from_usage(a))
|
|
||||||
.collect::<Vec<Arg<'static, 'static>>>();
|
|
||||||
let options = &Self::OPTIONS
|
|
||||||
.iter()
|
|
||||||
.map(|a| match !a.2.is_empty() {
|
|
||||||
true => Arg::from_usage(a.0)
|
|
||||||
.conflicts_with_all(a.1)
|
|
||||||
.possible_values(a.2)
|
|
||||||
.requires_all(a.3),
|
|
||||||
false => Arg::from_usage(a.0).conflicts_with_all(a.1).requires_all(a.3),
|
|
||||||
})
|
|
||||||
.collect::<Vec<Arg<'static, 'static>>>();
|
|
||||||
let subcommands = Self::SUBCOMMANDS.iter().map(|s| {
|
|
||||||
SubCommand::with_name(s.0)
|
|
||||||
.about(s.1)
|
|
||||||
.args(
|
|
||||||
&s.2.iter()
|
|
||||||
.map(|a| {
|
|
||||||
let mut args = Arg::with_name(a.0).help(a.1).required(a.3).index(a.4);
|
|
||||||
if !a.2.is_empty() {
|
|
||||||
args = args.possible_values(a.2);
|
|
||||||
}
|
|
||||||
args
|
|
||||||
})
|
|
||||||
.collect::<Vec<Arg<'static, 'static>>>(),
|
|
||||||
)
|
|
||||||
.args(
|
|
||||||
&s.3.iter()
|
|
||||||
.map(|a| Arg::from_usage(a))
|
|
||||||
.collect::<Vec<Arg<'static, 'static>>>(),
|
|
||||||
)
|
|
||||||
.args(
|
|
||||||
&s.4.iter()
|
|
||||||
.map(|a| match !a.2.is_empty() {
|
|
||||||
true => Arg::from_usage(a.0)
|
|
||||||
.conflicts_with_all(a.1)
|
|
||||||
.possible_values(a.2)
|
|
||||||
.requires_all(a.3),
|
|
||||||
false => Arg::from_usage(a.0).conflicts_with_all(a.1).requires_all(a.3),
|
|
||||||
})
|
|
||||||
.collect::<Vec<Arg<'static, 'static>>>(),
|
|
||||||
)
|
|
||||||
.settings(s.5)
|
|
||||||
});
|
|
||||||
|
|
||||||
SubCommand::with_name(Self::NAME)
|
|
||||||
.about(Self::ABOUT)
|
|
||||||
.settings(&[
|
|
||||||
AppSettings::ColoredHelp,
|
|
||||||
AppSettings::DisableHelpSubcommand,
|
|
||||||
AppSettings::DisableVersion,
|
|
||||||
])
|
|
||||||
.args(arguments)
|
|
||||||
.args(flags)
|
|
||||||
.args(options)
|
|
||||||
.subcommands(subcommands)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
|
||||||
fn process(arguments: &ArgMatches) -> Result<(), CLIError> {
|
|
||||||
// Set logging environment
|
|
||||||
match arguments.is_present("debug") {
|
|
||||||
true => logger::init_logger("leo", 2),
|
|
||||||
false => logger::init_logger("leo", 1),
|
|
||||||
}
|
|
||||||
|
|
||||||
if arguments.subcommand().0 != "update" {
|
|
||||||
Updater::print_cli();
|
|
||||||
}
|
|
||||||
|
|
||||||
let options = Self::parse(arguments)?;
|
|
||||||
let _output = Self::output(options)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
|
||||||
fn parse(arguments: &ArgMatches) -> Result<Self::Options, CLIError>;
|
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
|
||||||
fn output(options: Self::Options) -> Result<Self::Output, CLIError>;
|
|
||||||
}
|
|
@ -1,53 +0,0 @@
|
|||||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
|
||||||
// This file is part of the Leo library.
|
|
||||||
|
|
||||||
// The Leo library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// The Leo library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
use clap::AppSettings;
|
|
||||||
|
|
||||||
pub type NameType = &'static str;
|
|
||||||
|
|
||||||
pub type AboutType = &'static str;
|
|
||||||
|
|
||||||
pub type DescriptionType = &'static str;
|
|
||||||
|
|
||||||
pub type RequiredType = bool;
|
|
||||||
|
|
||||||
pub type PossibleValuesType = &'static [&'static str];
|
|
||||||
|
|
||||||
pub type IndexType = u64;
|
|
||||||
|
|
||||||
pub type ArgumentType = (NameType, DescriptionType, PossibleValuesType, RequiredType, IndexType);
|
|
||||||
|
|
||||||
// Format
|
|
||||||
// "[flag] -f --flag 'Add flag description here'"
|
|
||||||
pub type FlagType = &'static str;
|
|
||||||
|
|
||||||
// Format
|
|
||||||
// (argument, conflicts, possible_values, requires)
|
|
||||||
pub type OptionType = (
|
|
||||||
&'static str,
|
|
||||||
&'static [&'static str],
|
|
||||||
&'static [&'static str],
|
|
||||||
&'static [&'static str],
|
|
||||||
);
|
|
||||||
|
|
||||||
pub type SubCommandType = (
|
|
||||||
NameType,
|
|
||||||
AboutType,
|
|
||||||
&'static [ArgumentType],
|
|
||||||
&'static [FlagType],
|
|
||||||
&'static [OptionType],
|
|
||||||
&'static [AppSettings],
|
|
||||||
);
|
|
@ -1,198 +0,0 @@
|
|||||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
|
||||||
// This file is part of the Leo library.
|
|
||||||
|
|
||||||
// The Leo library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// The Leo library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
//
|
|
||||||
// Usage:
|
|
||||||
//
|
|
||||||
// leo add -a author -p package_name -v version
|
|
||||||
// leo add -a author -p package_name
|
|
||||||
//
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
cli::CLI,
|
|
||||||
cli_types::*,
|
|
||||||
config::*,
|
|
||||||
errors::{AddError::*, CLIError},
|
|
||||||
};
|
|
||||||
|
|
||||||
use leo_package::{
|
|
||||||
imports::{ImportsDirectory, IMPORTS_DIRECTORY_NAME},
|
|
||||||
root::Manifest,
|
|
||||||
};
|
|
||||||
|
|
||||||
use std::{
|
|
||||||
collections::HashMap,
|
|
||||||
convert::TryFrom,
|
|
||||||
env::current_dir,
|
|
||||||
fs::{create_dir_all, File},
|
|
||||||
io::{Read, Write},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const ADD_URL: &str = "v1/package/fetch";
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct AddCommand;
|
|
||||||
|
|
||||||
impl CLI for AddCommand {
|
|
||||||
// Format: author, package_name, version
|
|
||||||
type Options = (Option<String>, Option<String>, Option<String>);
|
|
||||||
type Output = ();
|
|
||||||
|
|
||||||
const ABOUT: AboutType = "Install a package from the Aleo Package Manager";
|
|
||||||
const ARGUMENTS: &'static [ArgumentType] = &[
|
|
||||||
// (name, description, possible_values, required, index)
|
|
||||||
(
|
|
||||||
"REMOTE",
|
|
||||||
"Install a package from the Aleo Package Manager with the given remote",
|
|
||||||
&[],
|
|
||||||
false,
|
|
||||||
1u64,
|
|
||||||
),
|
|
||||||
];
|
|
||||||
const FLAGS: &'static [FlagType] = &[];
|
|
||||||
const NAME: NameType = "add";
|
|
||||||
const OPTIONS: &'static [OptionType] = &[
|
|
||||||
// (argument, conflicts, possible_values, requires)
|
|
||||||
("[author] -a --author=<author> 'Specify a package author'", &[], &[], &[
|
|
||||||
"package",
|
|
||||||
]),
|
|
||||||
(
|
|
||||||
"[package] -p --package=<package> 'Specify a package name'",
|
|
||||||
&[],
|
|
||||||
&[],
|
|
||||||
&["author"],
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"[version] -v --version=[version] 'Specify a package version'",
|
|
||||||
&[],
|
|
||||||
&[],
|
|
||||||
&["author", "package"],
|
|
||||||
),
|
|
||||||
];
|
|
||||||
const SUBCOMMANDS: &'static [SubCommandType] = &[];
|
|
||||||
|
|
||||||
fn parse(arguments: &clap::ArgMatches) -> Result<Self::Options, crate::errors::CLIError> {
|
|
||||||
// TODO update to new package manager API without an author field
|
|
||||||
if arguments.is_present("author") && arguments.is_present("package") {
|
|
||||||
return Ok((
|
|
||||||
arguments.value_of("author").map(|s| s.to_string()),
|
|
||||||
arguments.value_of("package").map(|s| s.to_string()),
|
|
||||||
arguments.value_of("version").map(|s| s.to_string()),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
match arguments.value_of("REMOTE") {
|
|
||||||
Some(remote) => {
|
|
||||||
let values: Vec<&str> = remote.split('/').collect();
|
|
||||||
|
|
||||||
if values.len() != 2 {
|
|
||||||
return Err(InvalidRemote.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
let author = values[0].to_string();
|
|
||||||
let package = values[1].to_string();
|
|
||||||
|
|
||||||
Ok((Some(author), Some(package), None))
|
|
||||||
}
|
|
||||||
None => Ok((None, None, None)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output(options: Self::Options) -> Result<Self::Output, CLIError> {
|
|
||||||
// Begin "Adding" context for console logging
|
|
||||||
let span = tracing::span!(tracing::Level::INFO, "Adding");
|
|
||||||
let _enter = span.enter();
|
|
||||||
let path = current_dir()?;
|
|
||||||
|
|
||||||
// Enforce that the current directory is a leo package
|
|
||||||
Manifest::try_from(path.as_path())?;
|
|
||||||
|
|
||||||
let (response, 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
let result = match read_token() {
|
|
||||||
Ok(token) => {
|
|
||||||
tracing::info!("Logged in, using token to authorize");
|
|
||||||
client.post(&url).bearer_auth(token)
|
|
||||||
}
|
|
||||||
Err(_) => client.post(&url),
|
|
||||||
}
|
|
||||||
.json(&json)
|
|
||||||
.send();
|
|
||||||
|
|
||||||
match result {
|
|
||||||
Ok(response) => (response, package_name),
|
|
||||||
//Cannot connect to the server
|
|
||||||
Err(_error) => {
|
|
||||||
return Err(
|
|
||||||
ConnectionUnavailable("Could not connect to the Aleo Package Manager".into()).into(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => return Err(MissingAuthorOrPackageName.into()),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut path = current_dir()?;
|
|
||||||
ImportsDirectory::create(&path)?;
|
|
||||||
path.push(IMPORTS_DIRECTORY_NAME);
|
|
||||||
path.push(package_name);
|
|
||||||
create_dir_all(&path)?;
|
|
||||||
|
|
||||||
let bytes = response.bytes()?;
|
|
||||||
let reader = std::io::Cursor::new(bytes);
|
|
||||||
|
|
||||||
let mut zip_arhive = match zip::ZipArchive::new(reader) {
|
|
||||||
Ok(zip) => zip,
|
|
||||||
Err(error) => return Err(ZipError(error.to_string().into()).into()),
|
|
||||||
};
|
|
||||||
|
|
||||||
for i in 0..zip_arhive.len() {
|
|
||||||
let file = match zip_arhive.by_index(i) {
|
|
||||||
Ok(file) => file,
|
|
||||||
Err(error) => return Err(ZipError(error.to_string().into()).into()),
|
|
||||||
};
|
|
||||||
|
|
||||||
let file_name = file.name();
|
|
||||||
|
|
||||||
let mut file_path = path.clone();
|
|
||||||
file_path.push(file_name);
|
|
||||||
|
|
||||||
if file_name.ends_with('/') {
|
|
||||||
create_dir_all(file_path)?;
|
|
||||||
} else {
|
|
||||||
if let Some(parent_directory) = path.parent() {
|
|
||||||
create_dir_all(parent_directory)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
File::create(file_path)?.write_all(&file.bytes().map(|e| e.unwrap()).collect::<Vec<u8>>())?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tracing::info!("Successfully added a package\n");
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
@ -15,55 +15,50 @@
|
|||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
cli::*,
|
commands::Command,
|
||||||
cli_types::*,
|
context::Context,
|
||||||
errors::CLIError,
|
|
||||||
synthesizer::{CircuitSynthesizer, SerializedCircuit},
|
synthesizer::{CircuitSynthesizer, SerializedCircuit},
|
||||||
};
|
};
|
||||||
use leo_compiler::{compiler::Compiler, group::targets::edwards_bls12::EdwardsGroupType};
|
use leo_compiler::{compiler::Compiler, group::targets::edwards_bls12::EdwardsGroupType};
|
||||||
use leo_package::{
|
use leo_package::{
|
||||||
inputs::*,
|
inputs::*,
|
||||||
outputs::{ChecksumFile, CircuitFile, OutputsDirectory, OUTPUTS_DIRECTORY_NAME},
|
outputs::{ChecksumFile, CircuitFile, OutputsDirectory, OUTPUTS_DIRECTORY_NAME},
|
||||||
root::Manifest,
|
|
||||||
source::{LibraryFile, MainFile, LIBRARY_FILENAME, MAIN_FILENAME, SOURCE_DIRECTORY_NAME},
|
source::{LibraryFile, MainFile, LIBRARY_FILENAME, MAIN_FILENAME, SOURCE_DIRECTORY_NAME},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
use snarkvm_curves::{bls12_377::Bls12_377, edwards_bls12::Fq};
|
use snarkvm_curves::{bls12_377::Bls12_377, edwards_bls12::Fq};
|
||||||
use snarkvm_models::gadgets::r1cs::ConstraintSystem;
|
use snarkvm_models::gadgets::r1cs::ConstraintSystem;
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
use structopt::StructOpt;
|
||||||
|
use tracing::span::Span;
|
||||||
|
|
||||||
use clap::ArgMatches;
|
/// Compile and build program command
|
||||||
use std::{convert::TryFrom, env::current_dir, time::Instant};
|
#[derive(StructOpt, Debug, Default)]
|
||||||
|
#[structopt(setting = structopt::clap::AppSettings::ColoredHelp)]
|
||||||
|
pub struct Build {}
|
||||||
|
|
||||||
#[derive(Debug)]
|
impl Build {
|
||||||
pub struct BuildCommand;
|
pub fn new() -> Build {
|
||||||
|
Build {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl CLI for BuildCommand {
|
impl Command for Build {
|
||||||
type Options = ();
|
type Input = ();
|
||||||
type Output = Option<(Compiler<Fq, EdwardsGroupType>, bool)>;
|
type Output = Option<(Compiler<Fq, EdwardsGroupType>, bool)>;
|
||||||
|
|
||||||
const ABOUT: AboutType = "Compile the current package as a program";
|
fn log_span(&self) -> Span {
|
||||||
const ARGUMENTS: &'static [ArgumentType] = &[];
|
tracing::span!(tracing::Level::INFO, "Build")
|
||||||
const FLAGS: &'static [FlagType] = &[];
|
}
|
||||||
const NAME: NameType = "build";
|
|
||||||
const OPTIONS: &'static [OptionType] = &[];
|
|
||||||
const SUBCOMMANDS: &'static [SubCommandType] = &[];
|
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
fn prelude(&self) -> Result<Self::Input> {
|
||||||
fn parse(_arguments: &ArgMatches) -> Result<Self::Options, CLIError> {
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
fn apply(self, ctx: Context, _: Self::Input) -> Result<Self::Output> {
|
||||||
fn output(_options: Self::Options) -> Result<Self::Output, CLIError> {
|
let path = ctx.dir()?;
|
||||||
// Begin "Compiling" context for console logging
|
let package_name = ctx.manifest()?.get_package_name();
|
||||||
let span = tracing::span!(tracing::Level::INFO, "Compiling");
|
|
||||||
let enter = span.enter();
|
|
||||||
|
|
||||||
let path = current_dir()?;
|
|
||||||
|
|
||||||
// Get the package name
|
|
||||||
let manifest = Manifest::try_from(path.as_path())?;
|
|
||||||
let package_name = manifest.get_package_name();
|
|
||||||
|
|
||||||
// Sanitize the package path to the root directory
|
// Sanitize the package path to the root directory
|
||||||
let mut package_path = path.clone();
|
let mut package_path = path.clone();
|
||||||
@ -77,9 +72,6 @@ impl CLI for BuildCommand {
|
|||||||
|
|
||||||
tracing::info!("Starting...");
|
tracing::info!("Starting...");
|
||||||
|
|
||||||
// Start the timer
|
|
||||||
let start = Instant::now();
|
|
||||||
|
|
||||||
// Compile the package starting with the lib.leo file
|
// Compile the package starting with the lib.leo file
|
||||||
if LibraryFile::exists_at(&package_path) {
|
if LibraryFile::exists_at(&package_path) {
|
||||||
// Construct the path to the library file in the source directory
|
// Construct the path to the library file in the source directory
|
||||||
@ -185,21 +177,9 @@ impl CLI for BuildCommand {
|
|||||||
|
|
||||||
tracing::info!("Complete");
|
tracing::info!("Complete");
|
||||||
|
|
||||||
// Drop "Compiling" context for console logging
|
|
||||||
drop(enter);
|
|
||||||
|
|
||||||
// Begin "Done" context for console logging todo: @collin figure a way to get this output with tracing without dropping span
|
|
||||||
tracing::span!(tracing::Level::INFO, "Done").in_scope(|| {
|
|
||||||
tracing::info!("Finished in {} milliseconds\n", start.elapsed().as_millis());
|
|
||||||
});
|
|
||||||
|
|
||||||
return Ok(Some((program, checksum_differs)));
|
return Ok(Some((program, checksum_differs)));
|
||||||
}
|
}
|
||||||
|
|
||||||
drop(enter);
|
|
||||||
|
|
||||||
// Return None when compiling a package for publishing
|
|
||||||
// The published package does not need to have a main.leo
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,45 +14,40 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::{cli::*, cli_types::*, errors::CLIError};
|
use crate::{commands::Command, context::Context};
|
||||||
use leo_package::{
|
|
||||||
outputs::{ChecksumFile, ProofFile, ProvingKeyFile, VerificationKeyFile},
|
|
||||||
root::Manifest,
|
|
||||||
};
|
|
||||||
|
|
||||||
use clap::ArgMatches;
|
|
||||||
use leo_compiler::OutputFile;
|
use leo_compiler::OutputFile;
|
||||||
use leo_package::outputs::CircuitFile;
|
use leo_package::outputs::{ChecksumFile, CircuitFile, ProofFile, ProvingKeyFile, VerificationKeyFile};
|
||||||
use std::{convert::TryFrom, env::current_dir};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
use anyhow::Result;
|
||||||
pub struct CleanCommand;
|
use structopt::StructOpt;
|
||||||
|
use tracing::span::Span;
|
||||||
|
|
||||||
impl CLI for CleanCommand {
|
/// Clean outputs folder command
|
||||||
type Options = ();
|
#[derive(StructOpt, Debug, Default)]
|
||||||
|
#[structopt(setting = structopt::clap::AppSettings::ColoredHelp)]
|
||||||
|
pub struct Clean {}
|
||||||
|
|
||||||
|
impl Clean {
|
||||||
|
pub fn new() -> Clean {
|
||||||
|
Clean {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Command for Clean {
|
||||||
|
type Input = ();
|
||||||
type Output = ();
|
type Output = ();
|
||||||
|
|
||||||
const ABOUT: AboutType = "Clean the output directory";
|
fn log_span(&self) -> Span {
|
||||||
const ARGUMENTS: &'static [ArgumentType] = &[];
|
tracing::span!(tracing::Level::INFO, "Cleaning")
|
||||||
const FLAGS: &'static [FlagType] = &[];
|
}
|
||||||
const NAME: NameType = "clean";
|
|
||||||
const OPTIONS: &'static [OptionType] = &[];
|
|
||||||
const SUBCOMMANDS: &'static [SubCommandType] = &[];
|
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
fn prelude(&self) -> Result<Self::Input> {
|
||||||
fn parse(_arguments: &ArgMatches) -> Result<Self::Options, CLIError> {
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
fn apply(self, ctx: Context, _: Self::Input) -> Result<Self::Output> {
|
||||||
fn output(_options: Self::Options) -> Result<Self::Output, CLIError> {
|
let path = ctx.dir()?;
|
||||||
// Begin "Clean" context for console logging
|
let package_name = ctx.manifest()?.get_package_name();
|
||||||
let span = tracing::span!(tracing::Level::INFO, "Cleaning");
|
|
||||||
let enter = span.enter();
|
|
||||||
|
|
||||||
// Get the package name
|
|
||||||
let path = current_dir()?;
|
|
||||||
let package_name = Manifest::try_from(path.as_path())?.get_package_name();
|
|
||||||
|
|
||||||
// Remove the checksum from the output directory
|
// Remove the checksum from the output directory
|
||||||
ChecksumFile::new(&package_name).remove(&path)?;
|
ChecksumFile::new(&package_name).remove(&path)?;
|
||||||
@ -72,14 +67,6 @@ impl CLI for CleanCommand {
|
|||||||
// Remove the proof from the output directory
|
// Remove the proof from the output directory
|
||||||
ProofFile::new(&package_name).remove(&path)?;
|
ProofFile::new(&package_name).remove(&path)?;
|
||||||
|
|
||||||
// Drop "Compiling" context for console logging
|
|
||||||
drop(enter);
|
|
||||||
|
|
||||||
// Begin "Done" context for console logging
|
|
||||||
tracing::span!(tracing::Level::INFO, "Done").in_scope(|| {
|
|
||||||
tracing::info!("Program workspace cleaned\n");
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,65 +14,36 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::{
|
use crate::{commands::Command, context::Context};
|
||||||
cli::*,
|
|
||||||
cli_types::*,
|
|
||||||
commands::BuildCommand,
|
|
||||||
errors::{CLIError, RunError},
|
|
||||||
};
|
|
||||||
use leo_package::{
|
|
||||||
root::Manifest,
|
|
||||||
source::{MAIN_FILENAME, SOURCE_DIRECTORY_NAME},
|
|
||||||
};
|
|
||||||
|
|
||||||
use clap::ArgMatches;
|
use anyhow::Result;
|
||||||
use std::{convert::TryFrom, env::current_dir};
|
use structopt::StructOpt;
|
||||||
|
use tracing::span::Span;
|
||||||
|
|
||||||
#[derive(Debug)]
|
/// Deploy Leo program to the network
|
||||||
pub struct DeployCommand;
|
#[derive(StructOpt, Debug, Default)]
|
||||||
|
#[structopt(setting = structopt::clap::AppSettings::ColoredHelp)]
|
||||||
|
pub struct Deploy {}
|
||||||
|
|
||||||
impl CLI for DeployCommand {
|
impl Deploy {
|
||||||
type Options = ();
|
pub fn new() -> Deploy {
|
||||||
|
Deploy {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Command for Deploy {
|
||||||
|
type Input = ();
|
||||||
type Output = ();
|
type Output = ();
|
||||||
|
|
||||||
const ABOUT: AboutType = "Deploy the current package as a program to the network (*)";
|
fn log_span(&self) -> Span {
|
||||||
const ARGUMENTS: &'static [ArgumentType] = &[];
|
tracing::span!(tracing::Level::INFO, "Deploy")
|
||||||
const FLAGS: &'static [FlagType] = &[];
|
}
|
||||||
const NAME: NameType = "deploy";
|
|
||||||
const OPTIONS: &'static [OptionType] = &[];
|
|
||||||
const SUBCOMMANDS: &'static [SubCommandType] = &[];
|
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
fn prelude(&self) -> Result<Self::Input> {
|
||||||
fn parse(_arguments: &ArgMatches) -> Result<Self::Options, CLIError> {
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
fn apply(self, _: Context, _: Self::Input) -> Result<Self::Output> {
|
||||||
fn output(options: Self::Options) -> Result<Self::Output, CLIError> {
|
unimplemented!("Deploy command has not been implemented yet");
|
||||||
// Begin "Deploy" context for console logging
|
|
||||||
let span = tracing::span!(tracing::Level::INFO, "Deploying");
|
|
||||||
let _enter = span.enter();
|
|
||||||
|
|
||||||
let path = current_dir()?;
|
|
||||||
|
|
||||||
match BuildCommand::output(options)? {
|
|
||||||
Some((_program, _checksum_differs)) => {
|
|
||||||
// Get the package name
|
|
||||||
let _package_name = Manifest::try_from(path.as_path())?.get_package_name();
|
|
||||||
|
|
||||||
tracing::error!("Unimplemented - `leo deploy`");
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
let mut main_file_path = path;
|
|
||||||
main_file_path.push(SOURCE_DIRECTORY_NAME);
|
|
||||||
main_file_path.push(MAIN_FILENAME);
|
|
||||||
|
|
||||||
Err(CLIError::RunError(RunError::MainFileDoesNotExist(
|
|
||||||
main_file_path.into_os_string(),
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,58 +14,50 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::{
|
use crate::{commands::Command, context::Context};
|
||||||
cli::*,
|
|
||||||
cli_types::*,
|
|
||||||
errors::{CLIError, InitError},
|
|
||||||
};
|
|
||||||
use leo_package::LeoPackage;
|
use leo_package::LeoPackage;
|
||||||
|
|
||||||
use clap::ArgMatches;
|
use anyhow::{anyhow, Result};
|
||||||
use std::env::current_dir;
|
use std::env::current_dir;
|
||||||
|
use structopt::StructOpt;
|
||||||
|
use tracing::span::Span;
|
||||||
|
|
||||||
#[derive(Debug)]
|
/// Init Leo project command within current directory
|
||||||
pub struct InitCommand;
|
#[derive(StructOpt, Debug, Default)]
|
||||||
|
#[structopt(setting = structopt::clap::AppSettings::ColoredHelp)]
|
||||||
|
pub struct Init {}
|
||||||
|
|
||||||
impl CLI for InitCommand {
|
impl Init {
|
||||||
type Options = bool;
|
pub fn new() -> Init {
|
||||||
type Output = ();
|
Init {}
|
||||||
|
}
|
||||||
const ABOUT: AboutType = "Create a new Leo package in an existing directory";
|
|
||||||
const ARGUMENTS: &'static [ArgumentType] = &[];
|
|
||||||
const FLAGS: &'static [FlagType] = &[("--lib"), ("--bin")];
|
|
||||||
const NAME: NameType = "init";
|
|
||||||
const OPTIONS: &'static [OptionType] = &[];
|
|
||||||
const SUBCOMMANDS: &'static [SubCommandType] = &[];
|
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
|
||||||
fn parse(arguments: &ArgMatches) -> Result<Self::Options, CLIError> {
|
|
||||||
Ok(arguments.is_present("lib"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
impl Command for Init {
|
||||||
fn output(options: Self::Options) -> Result<Self::Output, CLIError> {
|
type Input = ();
|
||||||
// Begin "Initializing" context for console logging
|
type Output = ();
|
||||||
let span = tracing::span!(tracing::Level::INFO, "Initializing");
|
|
||||||
let _enter = span.enter();
|
|
||||||
|
|
||||||
|
fn log_span(&self) -> Span {
|
||||||
|
tracing::span!(tracing::Level::INFO, "Initializing")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prelude(&self) -> Result<Self::Input> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply(self, _: Context, _: Self::Input) -> Result<Self::Output> {
|
||||||
let path = current_dir()?;
|
let path = current_dir()?;
|
||||||
|
|
||||||
// Derive the package name
|
|
||||||
let package_name = path
|
let package_name = path
|
||||||
.file_stem()
|
.file_stem()
|
||||||
.ok_or_else(|| InitError::ProjectNameInvalid(path.as_os_str().to_owned()))?
|
.ok_or_else(|| anyhow!("Project name invalid"))?
|
||||||
.to_string_lossy()
|
.to_string_lossy()
|
||||||
.to_string();
|
.to_string();
|
||||||
|
|
||||||
// Verify the directory does not exist
|
|
||||||
if !path.exists() {
|
if !path.exists() {
|
||||||
return Err(InitError::DirectoryDoesNotExist(path.as_os_str().to_owned()).into());
|
return Err(anyhow!("Directory does not exist"));
|
||||||
}
|
}
|
||||||
|
|
||||||
LeoPackage::initialize(&package_name, options, &path)?;
|
LeoPackage::initialize(&package_name, false, &path)?;
|
||||||
|
|
||||||
tracing::info!("Successfully initialized package \"{}\"\n", package_name);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -14,65 +14,36 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::{
|
use crate::{commands::Command, context::Context};
|
||||||
cli::*,
|
|
||||||
cli_types::*,
|
|
||||||
commands::BuildCommand,
|
|
||||||
errors::{CLIError, RunError},
|
|
||||||
};
|
|
||||||
use leo_package::{
|
|
||||||
root::Manifest,
|
|
||||||
source::{MAIN_FILENAME, SOURCE_DIRECTORY_NAME},
|
|
||||||
};
|
|
||||||
|
|
||||||
use clap::ArgMatches;
|
use anyhow::Result;
|
||||||
use std::{convert::TryFrom, env::current_dir};
|
use structopt::StructOpt;
|
||||||
|
use tracing::span::Span;
|
||||||
|
|
||||||
#[derive(Debug)]
|
/// Lint Leo code command
|
||||||
pub struct LintCommand;
|
#[derive(StructOpt, Debug, Default)]
|
||||||
|
#[structopt(setting = structopt::clap::AppSettings::ColoredHelp)]
|
||||||
|
pub struct Lint {}
|
||||||
|
|
||||||
impl CLI for LintCommand {
|
impl Lint {
|
||||||
type Options = ();
|
pub fn new() -> Lint {
|
||||||
|
Lint {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Command for Lint {
|
||||||
|
type Input = ();
|
||||||
type Output = ();
|
type Output = ();
|
||||||
|
|
||||||
const ABOUT: AboutType = "Lints the Leo files in the package (*)";
|
fn log_span(&self) -> Span {
|
||||||
const ARGUMENTS: &'static [ArgumentType] = &[];
|
tracing::span!(tracing::Level::INFO, "Linting")
|
||||||
const FLAGS: &'static [FlagType] = &[];
|
}
|
||||||
const NAME: NameType = "lint";
|
|
||||||
const OPTIONS: &'static [OptionType] = &[];
|
|
||||||
const SUBCOMMANDS: &'static [SubCommandType] = &[];
|
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
fn prelude(&self) -> Result<Self::Input> {
|
||||||
fn parse(_arguments: &ArgMatches) -> Result<Self::Options, CLIError> {
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
fn apply(self, _: Context, _: Self::Input) -> Result<Self::Output> {
|
||||||
fn output(options: Self::Options) -> Result<Self::Output, CLIError> {
|
unimplemented!("Lint command has not been implemented yet");
|
||||||
// Begin "Linting" context for console logging
|
|
||||||
let span = tracing::span!(tracing::Level::INFO, "Linting");
|
|
||||||
let _enter = span.enter();
|
|
||||||
|
|
||||||
let path = current_dir()?;
|
|
||||||
|
|
||||||
match BuildCommand::output(options)? {
|
|
||||||
Some((_program, _checksum_differs)) => {
|
|
||||||
// Get the package name
|
|
||||||
let _package_name = Manifest::try_from(path.as_path())?.get_package_name();
|
|
||||||
|
|
||||||
tracing::error!("Unimplemented - `leo lint`");
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
let mut main_file_path = path;
|
|
||||||
main_file_path.push(SOURCE_DIRECTORY_NAME);
|
|
||||||
main_file_path.push(MAIN_FILENAME);
|
|
||||||
|
|
||||||
Err(CLIError::RunError(RunError::MainFileDoesNotExist(
|
|
||||||
main_file_path.into_os_string(),
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,142 +0,0 @@
|
|||||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
|
||||||
// This file is part of the Leo library.
|
|
||||||
|
|
||||||
// The Leo library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// The Leo library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
//
|
|
||||||
// Usage:
|
|
||||||
//
|
|
||||||
// leo login <token>
|
|
||||||
// leo login -u username -p password
|
|
||||||
//
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
cli::CLI,
|
|
||||||
cli_types::*,
|
|
||||||
config::*,
|
|
||||||
errors::{CLIError, LoginError::*},
|
|
||||||
};
|
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
pub const LOGIN_URL: &str = "v1/account/authenticate";
|
|
||||||
pub const PROFILE_URL: &str = "v1/account/my_profile";
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct LoginCommand;
|
|
||||||
|
|
||||||
impl CLI for LoginCommand {
|
|
||||||
// Format: token, username, password
|
|
||||||
type Options = (Option<String>, Option<String>, Option<String>);
|
|
||||||
type Output = String;
|
|
||||||
|
|
||||||
const ABOUT: AboutType = "Login to the Aleo Package Manager";
|
|
||||||
const ARGUMENTS: &'static [ArgumentType] = &[
|
|
||||||
// (name, description, possible_values, required, index)
|
|
||||||
(
|
|
||||||
"NAME",
|
|
||||||
"Sets the authentication token for login to the package manager",
|
|
||||||
&[],
|
|
||||||
false,
|
|
||||||
1u64,
|
|
||||||
),
|
|
||||||
];
|
|
||||||
const FLAGS: &'static [FlagType] = &[];
|
|
||||||
const NAME: NameType = "login";
|
|
||||||
const OPTIONS: &'static [OptionType] = &[
|
|
||||||
// (argument, conflicts, possible_values, requires)
|
|
||||||
("[username] -u --user=[username] 'Sets a username'", &[], &[], &[]),
|
|
||||||
("[password] -p --password=[password] 'Sets a password'", &[], &[], &[]),
|
|
||||||
];
|
|
||||||
const SUBCOMMANDS: &'static [SubCommandType] = &[];
|
|
||||||
|
|
||||||
fn parse(arguments: &clap::ArgMatches) -> Result<Self::Options, crate::errors::CLIError> {
|
|
||||||
if arguments.is_present("username") && arguments.is_present("password") {
|
|
||||||
return Ok((
|
|
||||||
None,
|
|
||||||
Some(arguments.value_of("username").unwrap().to_string()),
|
|
||||||
Some(arguments.value_of("password").unwrap().to_string()),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
match arguments.value_of("NAME") {
|
|
||||||
Some(name) => Ok((Some(name.to_string()), None, None)),
|
|
||||||
None => Ok((None, None, None)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output(options: Self::Options) -> Result<Self::Output, CLIError> {
|
|
||||||
// Begin "Login" context for console logging
|
|
||||||
let span = tracing::span!(tracing::Level::INFO, "Login");
|
|
||||||
let _enter = span.enter();
|
|
||||||
|
|
||||||
let token = match options {
|
|
||||||
// Login using existing token
|
|
||||||
(Some(token), _, _) => Some(token),
|
|
||||||
|
|
||||||
// Login using username and password
|
|
||||||
(None, Some(username), Some(password)) => {
|
|
||||||
// prepare JSON data to be sent
|
|
||||||
let mut json = HashMap::new();
|
|
||||||
json.insert("email_username", username);
|
|
||||||
json.insert("password", password);
|
|
||||||
|
|
||||||
let client = reqwest::blocking::Client::new();
|
|
||||||
let url = format!("{}{}", PACKAGE_MANAGER_URL, LOGIN_URL);
|
|
||||||
let response: HashMap<String, String> = match client.post(&url).json(&json).send() {
|
|
||||||
Ok(result) => match result.json() {
|
|
||||||
Ok(json) => json,
|
|
||||||
Err(_error) => {
|
|
||||||
return Err(WrongLoginOrPassword.into());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
//Cannot connect to the server
|
|
||||||
Err(_error) => {
|
|
||||||
return Err(NoConnectionFound.into());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
match response.get("token") {
|
|
||||||
Some(token) => Some(token.clone()),
|
|
||||||
None => {
|
|
||||||
return Err(CannotGetToken.into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Login using stored JWT credentials.
|
|
||||||
// TODO (raychu86) Package manager re-authentication from token
|
|
||||||
(_, _, _) => {
|
|
||||||
let token = read_token().map_err(|_| -> CLIError { NoCredentialsProvided.into() })?;
|
|
||||||
|
|
||||||
Some(token)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
match token {
|
|
||||||
Some(token) => {
|
|
||||||
write_token(token.as_str())?;
|
|
||||||
|
|
||||||
tracing::info!("success");
|
|
||||||
|
|
||||||
Ok(token)
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
tracing::error!("Failed to login. Please run `leo login -h` for help.");
|
|
||||||
|
|
||||||
Err(NoCredentialsProvided.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -14,53 +14,125 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
pub mod add;
|
use crate::context::{get_context, Context};
|
||||||
pub use self::add::*;
|
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use std::time::Instant;
|
||||||
|
use tracing::span::Span;
|
||||||
|
|
||||||
|
// local program commands
|
||||||
pub mod build;
|
pub mod build;
|
||||||
pub use self::build::*;
|
pub use build::Build;
|
||||||
|
|
||||||
pub mod clean;
|
pub mod clean;
|
||||||
pub use self::clean::*;
|
pub use clean::Clean;
|
||||||
|
|
||||||
pub mod deploy;
|
pub mod deploy;
|
||||||
pub use self::deploy::*;
|
pub use deploy::Deploy;
|
||||||
|
|
||||||
pub mod init;
|
pub mod init;
|
||||||
pub use self::init::*;
|
pub use init::Init;
|
||||||
|
|
||||||
pub mod lint;
|
pub mod lint;
|
||||||
pub use self::lint::*;
|
pub use lint::Lint;
|
||||||
|
|
||||||
pub mod login;
|
|
||||||
pub use self::login::*;
|
|
||||||
|
|
||||||
pub mod logout;
|
|
||||||
pub use self::logout::*;
|
|
||||||
|
|
||||||
pub mod new;
|
pub mod new;
|
||||||
pub use self::new::*;
|
pub use new::New;
|
||||||
|
|
||||||
pub mod prove;
|
pub mod prove;
|
||||||
pub use self::prove::*;
|
pub use prove::Prove;
|
||||||
|
|
||||||
pub mod publish;
|
|
||||||
pub use self::publish::*;
|
|
||||||
|
|
||||||
pub mod run;
|
pub mod run;
|
||||||
pub use self::run::*;
|
pub use run::Run;
|
||||||
|
|
||||||
pub mod setup;
|
pub mod setup;
|
||||||
pub use self::setup::*;
|
pub use setup::Setup;
|
||||||
|
|
||||||
pub mod test;
|
pub mod test;
|
||||||
pub use self::test::*;
|
pub use test::Test;
|
||||||
|
|
||||||
pub mod remove;
|
|
||||||
pub use self::remove::*;
|
|
||||||
|
|
||||||
pub mod update;
|
pub mod update;
|
||||||
pub use self::update::*;
|
pub use update::{Sub as UpdateAutomatic, Update};
|
||||||
|
|
||||||
pub mod watch;
|
pub mod watch;
|
||||||
pub use self::watch::*;
|
pub use watch::Watch;
|
||||||
|
|
||||||
|
// Aleo PM related commands
|
||||||
|
pub mod package;
|
||||||
|
|
||||||
|
/// Base trait for Leo CLI, see methods and their documentation for details
|
||||||
|
pub trait Command {
|
||||||
|
/// If current command requires running another command before
|
||||||
|
/// and needs its output results, this is the place to set.
|
||||||
|
/// Example: type Input: <CommandA as Command>::Out
|
||||||
|
type Input;
|
||||||
|
|
||||||
|
/// Define output of the command to be reused as an Input for another
|
||||||
|
/// command. If this command is not used as a prelude for another, keep empty
|
||||||
|
type Output;
|
||||||
|
|
||||||
|
/// Returns project context, currently keeping it simple but it is possible
|
||||||
|
/// that in the future leo will not depend on current directory, and we're keeping
|
||||||
|
/// option for extending current core
|
||||||
|
fn context(&self) -> Result<Context> {
|
||||||
|
get_context()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add span to the logger tracing::span.
|
||||||
|
/// Due to specifics of macro implementation it is impossible to set
|
||||||
|
/// span name with non-literal i.e. dynamic variable even if this
|
||||||
|
/// variable is &'static str
|
||||||
|
fn log_span(&self) -> Span {
|
||||||
|
tracing::span!(tracing::Level::INFO, "Leo")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run prelude and get Input for current command. As simple as that.
|
||||||
|
/// But due to inability to pass default implementation of a type, this
|
||||||
|
/// method must be present in every trait implementation.
|
||||||
|
fn prelude(&self) -> Result<Self::Input>
|
||||||
|
where
|
||||||
|
Self: std::marker::Sized;
|
||||||
|
|
||||||
|
/// Core of the execution - do what is necessary. This function is run within
|
||||||
|
/// context of 'execute' function, which sets logging and timers
|
||||||
|
fn apply(self, ctx: Context, input: Self::Input) -> Result<Self::Output>
|
||||||
|
where
|
||||||
|
Self: std::marker::Sized;
|
||||||
|
|
||||||
|
/// Wrapper around apply function, sets up tracing, time tracking and context
|
||||||
|
fn execute(self) -> Result<Self::Output>
|
||||||
|
where
|
||||||
|
Self: std::marker::Sized,
|
||||||
|
{
|
||||||
|
let input = self.prelude()?;
|
||||||
|
|
||||||
|
// create span for this command
|
||||||
|
let span = self.log_span();
|
||||||
|
let span = span.enter();
|
||||||
|
|
||||||
|
// calculate execution time for each run
|
||||||
|
let timer = Instant::now();
|
||||||
|
|
||||||
|
let context = self.context()?;
|
||||||
|
let out = self.apply(context, input);
|
||||||
|
|
||||||
|
drop(span);
|
||||||
|
|
||||||
|
// use done context to print time
|
||||||
|
tracing::span!(tracing::Level::INFO, "Done").in_scope(|| {
|
||||||
|
tracing::info!("Finished in {} milliseconds \n", timer.elapsed().as_millis());
|
||||||
|
});
|
||||||
|
|
||||||
|
out
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Execute command but empty the result. Comes in handy where there's a
|
||||||
|
/// need to make match arms compatible while keeping implementation-specific
|
||||||
|
/// output possible. Errors however are all of the type Error
|
||||||
|
fn try_execute(self) -> Result<()>
|
||||||
|
where
|
||||||
|
Self: std::marker::Sized,
|
||||||
|
{
|
||||||
|
self.execute().map(|_| Ok(()))?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -14,81 +14,56 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::{
|
use crate::{commands::Command, context::Context};
|
||||||
cli::*,
|
|
||||||
cli_types::*,
|
|
||||||
errors::{CLIError, NewError},
|
|
||||||
};
|
|
||||||
use leo_package::LeoPackage;
|
use leo_package::LeoPackage;
|
||||||
|
|
||||||
use clap::ArgMatches;
|
use anyhow::{anyhow, Result};
|
||||||
use std::{env::current_dir, fs};
|
use std::{env::current_dir, fs};
|
||||||
|
use structopt::StructOpt;
|
||||||
|
use tracing::span::Span;
|
||||||
|
|
||||||
#[derive(Debug)]
|
/// Create new Leo project
|
||||||
pub struct NewCommand;
|
#[derive(StructOpt, Debug)]
|
||||||
|
#[structopt(setting = structopt::clap::AppSettings::ColoredHelp)]
|
||||||
|
pub struct New {
|
||||||
|
#[structopt(name = "NAME", help = "Set package name")]
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
impl CLI for NewCommand {
|
impl New {
|
||||||
type Options = (Option<String>, bool);
|
pub fn new(name: String) -> New {
|
||||||
|
New { name }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Command for New {
|
||||||
|
type Input = ();
|
||||||
type Output = ();
|
type Output = ();
|
||||||
|
|
||||||
const ABOUT: AboutType = "Create a new Leo package in a new directory";
|
fn log_span(&self) -> Span {
|
||||||
const ARGUMENTS: &'static [ArgumentType] = &[
|
tracing::span!(tracing::Level::INFO, "New")
|
||||||
// (name, description, possible_values, required, index)
|
|
||||||
(
|
|
||||||
"NAME",
|
|
||||||
"Sets the resulting package name, defaults to the directory name",
|
|
||||||
&[],
|
|
||||||
true,
|
|
||||||
1u64,
|
|
||||||
),
|
|
||||||
];
|
|
||||||
const FLAGS: &'static [FlagType] = &[("--lib"), ("--bin")];
|
|
||||||
const NAME: NameType = "new";
|
|
||||||
const OPTIONS: &'static [OptionType] = &[];
|
|
||||||
const SUBCOMMANDS: &'static [SubCommandType] = &[];
|
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
|
||||||
fn parse(arguments: &ArgMatches) -> Result<Self::Options, CLIError> {
|
|
||||||
let is_lib = arguments.is_present("lib");
|
|
||||||
match arguments.value_of("NAME") {
|
|
||||||
Some(name) => Ok((Some(name.to_string()), is_lib)),
|
|
||||||
None => Ok((None, is_lib)),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
fn prelude(&self) -> Result<Self::Input> {
|
||||||
fn output(options: Self::Options) -> Result<Self::Output, CLIError> {
|
Ok(())
|
||||||
// Begin "Initializing" context for console logging
|
}
|
||||||
let span = tracing::span!(tracing::Level::INFO, "Initializing");
|
|
||||||
let _enter = span.enter();
|
|
||||||
|
|
||||||
|
fn apply(self, _: Context, _: Self::Input) -> Result<Self::Output> {
|
||||||
let mut path = current_dir()?;
|
let mut path = current_dir()?;
|
||||||
|
let package_name = self.name;
|
||||||
// Derive the package name
|
|
||||||
let package_name = match options.0 {
|
|
||||||
Some(name) => name,
|
|
||||||
None => path
|
|
||||||
.file_stem()
|
|
||||||
.ok_or_else(|| NewError::ProjectNameInvalid(path.as_os_str().to_owned()))?
|
|
||||||
.to_string_lossy()
|
|
||||||
.to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Derive the package directory path
|
// Derive the package directory path
|
||||||
path.push(&package_name);
|
path.push(&package_name);
|
||||||
|
|
||||||
// Verify the package directory path does not exist yet
|
// Verify the package directory path does not exist yet
|
||||||
if path.exists() {
|
if path.exists() {
|
||||||
return Err(NewError::DirectoryAlreadyExists(path.as_os_str().to_owned()).into());
|
return Err(anyhow!("Directory already exists {:?}", path));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the package directory
|
// Create the package directory
|
||||||
fs::create_dir_all(&path)
|
fs::create_dir_all(&path).map_err(|err| anyhow!("Could not create directory {}", err))?;
|
||||||
.map_err(|error| NewError::CreatingRootDirectory(path.as_os_str().to_owned(), error))?;
|
|
||||||
|
|
||||||
LeoPackage::initialize(&package_name, options.1, &path)?;
|
LeoPackage::initialize(&package_name, false, &path)?;
|
||||||
|
|
||||||
tracing::info!("Successfully initialized package \"{}\"\n", package_name);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
156
leo/commands/package/add.rs
Normal file
156
leo/commands/package/add.rs
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||||
|
// This file is part of the Leo library.
|
||||||
|
|
||||||
|
// The Leo library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// The Leo library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use crate::{api::Fetch, commands::Command, context::Context};
|
||||||
|
use leo_package::imports::{ImportsDirectory, IMPORTS_DIRECTORY_NAME};
|
||||||
|
|
||||||
|
use anyhow::{anyhow, Result};
|
||||||
|
use std::{
|
||||||
|
fs::{create_dir_all, File},
|
||||||
|
io::{Read, Write},
|
||||||
|
};
|
||||||
|
use structopt::StructOpt;
|
||||||
|
use tracing::Span;
|
||||||
|
|
||||||
|
/// Add package from Aleo Package Manager
|
||||||
|
#[derive(StructOpt, Debug)]
|
||||||
|
#[structopt(setting = structopt::clap::AppSettings::ColoredHelp)]
|
||||||
|
pub struct Add {
|
||||||
|
#[structopt(name = "REMOTE")]
|
||||||
|
remote: Option<String>,
|
||||||
|
|
||||||
|
#[structopt(name = "author", help = "Specify a package author", long = "author", short = "a")]
|
||||||
|
author: Option<String>,
|
||||||
|
|
||||||
|
#[structopt(name = "package", help = "Specify a package name", long = "package", short = "p")]
|
||||||
|
package: Option<String>,
|
||||||
|
|
||||||
|
#[structopt(name = "version", help = "Specify a package version", long = "version", short = "v")]
|
||||||
|
version: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add {
|
||||||
|
pub fn new(
|
||||||
|
remote: Option<String>,
|
||||||
|
author: Option<String>,
|
||||||
|
package: Option<String>,
|
||||||
|
version: Option<String>,
|
||||||
|
) -> Add {
|
||||||
|
Add {
|
||||||
|
remote,
|
||||||
|
author,
|
||||||
|
package,
|
||||||
|
version,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Try to parse author/package string from self.remote
|
||||||
|
pub fn try_read_arguments(&self) -> Result<(String, String)> {
|
||||||
|
if let Some(val) = &self.remote {
|
||||||
|
let v: Vec<&str> = val.split('/').collect();
|
||||||
|
if v.len() == 2 {
|
||||||
|
Ok((v[0].to_string(), v[1].to_string()))
|
||||||
|
} else {
|
||||||
|
Err(anyhow!(
|
||||||
|
"Incorrect argument, please use --help for information on command use"
|
||||||
|
))
|
||||||
|
}
|
||||||
|
} else if let (Some(author), Some(package)) = (&self.author, &self.package) {
|
||||||
|
Ok((author.clone(), package.clone()))
|
||||||
|
} else {
|
||||||
|
Err(anyhow!(
|
||||||
|
"Incorrect argument, please use --help for information on command use"
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Command for Add {
|
||||||
|
type Input = ();
|
||||||
|
type Output = ();
|
||||||
|
|
||||||
|
fn log_span(&self) -> Span {
|
||||||
|
tracing::span!(tracing::Level::INFO, "Adding")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prelude(&self) -> Result<Self::Input> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply(self, ctx: Context, _: Self::Input) -> Result<Self::Output> {
|
||||||
|
// checking that manifest exists...
|
||||||
|
if ctx.manifest().is_err() {
|
||||||
|
return Err(anyhow!("Package Manifest not found, try running leo init or leo new"));
|
||||||
|
};
|
||||||
|
|
||||||
|
let (author, package_name) = match self.try_read_arguments() {
|
||||||
|
Ok((author, package)) => (author, package),
|
||||||
|
Err(err) => return Err(err),
|
||||||
|
};
|
||||||
|
let version = self.version;
|
||||||
|
|
||||||
|
// build request body (Options are skipped when sealizing)
|
||||||
|
let fetch = Fetch {
|
||||||
|
author,
|
||||||
|
package_name: package_name.clone(),
|
||||||
|
version,
|
||||||
|
};
|
||||||
|
|
||||||
|
let bytes = ctx.api.run_route(fetch)?.bytes()?;
|
||||||
|
let mut path = ctx.dir()?;
|
||||||
|
|
||||||
|
{
|
||||||
|
// setup directory structure since request was success
|
||||||
|
ImportsDirectory::create(&path)?;
|
||||||
|
path.push(IMPORTS_DIRECTORY_NAME);
|
||||||
|
path.push(package_name);
|
||||||
|
create_dir_all(&path)?;
|
||||||
|
};
|
||||||
|
|
||||||
|
let reader = std::io::Cursor::new(bytes);
|
||||||
|
|
||||||
|
let mut zip_archive = match zip::ZipArchive::new(reader) {
|
||||||
|
Ok(zip) => zip,
|
||||||
|
Err(error) => return Err(anyhow!(error)),
|
||||||
|
};
|
||||||
|
|
||||||
|
for i in 0..zip_archive.len() {
|
||||||
|
let file = match zip_archive.by_index(i) {
|
||||||
|
Ok(file) => file,
|
||||||
|
Err(error) => return Err(anyhow!(error)),
|
||||||
|
};
|
||||||
|
|
||||||
|
let file_name = file.name();
|
||||||
|
|
||||||
|
let mut file_path = path.clone();
|
||||||
|
file_path.push(file_name);
|
||||||
|
|
||||||
|
if file_name.ends_with('/') {
|
||||||
|
create_dir_all(file_path)?;
|
||||||
|
} else {
|
||||||
|
if let Some(parent_directory) = path.parent() {
|
||||||
|
create_dir_all(parent_directory)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
File::create(file_path)?.write_all(&file.bytes().map(|e| e.unwrap()).collect::<Vec<u8>>())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tracing::info!("Successfully added a package");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
115
leo/commands/package/login.rs
Normal file
115
leo/commands/package/login.rs
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||||
|
// This file is part of the Leo library.
|
||||||
|
|
||||||
|
// The Leo library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// The Leo library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
api::{Login as LoginRoute, Profile as ProfileRoute},
|
||||||
|
commands::Command,
|
||||||
|
config::*,
|
||||||
|
context::Context,
|
||||||
|
};
|
||||||
|
|
||||||
|
use anyhow::{anyhow, Result};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use structopt::StructOpt;
|
||||||
|
use tracing::Span;
|
||||||
|
|
||||||
|
/// Login to Aleo PM and store credentials locally
|
||||||
|
#[derive(StructOpt, Debug)]
|
||||||
|
#[structopt(setting = structopt::clap::AppSettings::ColoredHelp)]
|
||||||
|
pub struct Login {
|
||||||
|
#[structopt(name = "AUTH_TOKEN", about = "Pass authorization token")]
|
||||||
|
token: Option<String>,
|
||||||
|
|
||||||
|
#[structopt(short = "u", long = "user", about = "Username for Aleo PM")]
|
||||||
|
user: Option<String>,
|
||||||
|
|
||||||
|
#[structopt(short = "p", long = "password", about = "Password for Aleo PM")]
|
||||||
|
pass: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Login {
|
||||||
|
pub fn new(token: Option<String>, user: Option<String>, pass: Option<String>) -> Login {
|
||||||
|
Login { token, user, pass }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Command for Login {
|
||||||
|
type Input = ();
|
||||||
|
type Output = String;
|
||||||
|
|
||||||
|
fn log_span(&self) -> Span {
|
||||||
|
tracing::span!(tracing::Level::INFO, "Login")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prelude(&self) -> Result<Self::Input> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply(self, ctx: Context, _: Self::Input) -> Result<Self::Output> {
|
||||||
|
// quick hack to check if user is already logged in. ;)
|
||||||
|
if ctx.api.auth_token().is_some() {
|
||||||
|
tracing::info!("You are already logged in");
|
||||||
|
return Ok(ctx.api.auth_token().unwrap());
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut api = ctx.api;
|
||||||
|
|
||||||
|
// ...or trying to use arguments to either get token or user-pass
|
||||||
|
let token = match (self.token, self.user, self.pass) {
|
||||||
|
// Login using existing token, use get_profile route for that
|
||||||
|
(Some(token), _, _) => {
|
||||||
|
tracing::info!("Token passed, checking...");
|
||||||
|
|
||||||
|
api.set_auth_token(token.clone());
|
||||||
|
|
||||||
|
let is_ok = api.run_route(ProfileRoute {})?;
|
||||||
|
if !is_ok {
|
||||||
|
return Err(anyhow!("Supplied token is incorrect"));
|
||||||
|
};
|
||||||
|
|
||||||
|
token
|
||||||
|
}
|
||||||
|
|
||||||
|
// Login using username and password
|
||||||
|
(None, Some(email_username), Some(password)) => {
|
||||||
|
let login = LoginRoute {
|
||||||
|
email_username,
|
||||||
|
password,
|
||||||
|
};
|
||||||
|
|
||||||
|
let res = api.run_route(login)?;
|
||||||
|
let mut res: HashMap<String, String> = res.json()?;
|
||||||
|
|
||||||
|
let tok_opt = res.remove("token");
|
||||||
|
if tok_opt.is_none() {
|
||||||
|
return Err(anyhow!("Unable to get token"));
|
||||||
|
};
|
||||||
|
|
||||||
|
tok_opt.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
// In case token or login/pass were not passed as arguments
|
||||||
|
(_, _, _) => return Err(anyhow!("No credentials provided")),
|
||||||
|
};
|
||||||
|
|
||||||
|
// write token either after logging or if it was passed
|
||||||
|
write_token(token.as_str())?;
|
||||||
|
|
||||||
|
tracing::info!("Success! You are now logged in!");
|
||||||
|
|
||||||
|
Ok(token)
|
||||||
|
}
|
||||||
|
}
|
@ -14,40 +14,37 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
//
|
use crate::{commands::Command, config::remove_token, context::Context};
|
||||||
// Usage:
|
|
||||||
//
|
|
||||||
// leo logout
|
|
||||||
//
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
use anyhow::Result;
|
||||||
pub struct LogoutCommand;
|
|
||||||
|
|
||||||
use crate::{cli::CLI, cli_types::*, config::remove_token, errors::CLIError};
|
|
||||||
use std::io::ErrorKind;
|
use std::io::ErrorKind;
|
||||||
|
use structopt::StructOpt;
|
||||||
|
use tracing::Span;
|
||||||
|
|
||||||
impl CLI for LogoutCommand {
|
/// Remove credentials for Aleo PM from .leo directory
|
||||||
type Options = ();
|
#[derive(StructOpt, Debug, Default)]
|
||||||
|
#[structopt(setting = structopt::clap::AppSettings::ColoredHelp)]
|
||||||
|
pub struct Logout {}
|
||||||
|
|
||||||
|
impl Logout {
|
||||||
|
pub fn new() -> Logout {
|
||||||
|
Logout {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Command for Logout {
|
||||||
|
type Input = ();
|
||||||
type Output = ();
|
type Output = ();
|
||||||
|
|
||||||
const ABOUT: AboutType = "Logout from Aleo Package Manager";
|
fn log_span(&self) -> Span {
|
||||||
const ARGUMENTS: &'static [ArgumentType] = &[];
|
tracing::span!(tracing::Level::INFO, "Logout")
|
||||||
const FLAGS: &'static [FlagType] = &[];
|
}
|
||||||
const NAME: NameType = "logout";
|
|
||||||
const OPTIONS: &'static [OptionType] = &[];
|
|
||||||
const SUBCOMMANDS: &'static [SubCommandType] = &[];
|
|
||||||
|
|
||||||
/// no options and no arguments for this buddy
|
fn prelude(&self) -> Result<Self::Input> {
|
||||||
fn parse(_: &clap::ArgMatches) -> Result<Self::Options, CLIError> {
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// as simple as it could be - remove credentials file
|
fn apply(self, _ctx: Context, _: Self::Input) -> Result<Self::Output> {
|
||||||
fn output(_: Self::Options) -> Result<Self::Output, CLIError> {
|
|
||||||
// we gotta do something about this span issue :confused:
|
|
||||||
let span = tracing::span!(tracing::Level::INFO, "Logout");
|
|
||||||
let _ent = span.enter();
|
|
||||||
|
|
||||||
// the only error we're interested here is NotFound
|
// the only error we're interested here is NotFound
|
||||||
// however err in this case can also be of kind PermissionDenied or other
|
// however err in this case can also be of kind PermissionDenied or other
|
||||||
if let Err(err) = remove_token() {
|
if let Err(err) = remove_token() {
|
@ -14,11 +14,19 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
pub mod cli;
|
pub mod add;
|
||||||
pub use self::cli::*;
|
pub use add::Add;
|
||||||
|
|
||||||
pub mod commands;
|
pub mod login;
|
||||||
pub use self::commands::*;
|
pub use login::Login;
|
||||||
|
|
||||||
pub mod updater;
|
pub mod logout;
|
||||||
pub use self::updater::*;
|
pub use logout::Logout;
|
||||||
|
|
||||||
|
pub mod publish;
|
||||||
|
pub use publish::Publish;
|
||||||
|
|
||||||
|
pub mod remove;
|
||||||
|
pub use remove::Remove;
|
||||||
|
|
||||||
|
pub use super::*;
|
@ -14,29 +14,20 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use super::build::Build;
|
||||||
use crate::{
|
use crate::{
|
||||||
cli::*,
|
commands::Command,
|
||||||
cli_types::*,
|
context::{Context, PACKAGE_MANAGER_URL},
|
||||||
commands::{BuildCommand, LoginCommand},
|
|
||||||
config::{read_token, PACKAGE_MANAGER_URL},
|
|
||||||
errors::{
|
|
||||||
commands::PublishError::{ConnectionUnavalaible, PackageNotPublished},
|
|
||||||
CLIError,
|
|
||||||
PublishError::{MissingPackageDescription, MissingPackageLicense, MissingPackageRemote},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
use leo_package::{
|
|
||||||
outputs::OutputsDirectory,
|
|
||||||
root::{Manifest, ZipFile},
|
|
||||||
};
|
};
|
||||||
|
use leo_package::{outputs::OutputsDirectory, root::ZipFile};
|
||||||
|
|
||||||
use clap::ArgMatches;
|
use anyhow::{anyhow, Result};
|
||||||
use reqwest::{
|
use reqwest::{
|
||||||
blocking::{multipart::Form, Client},
|
blocking::{multipart::Form, Client},
|
||||||
header::{HeaderMap, HeaderValue},
|
header::{HeaderMap, HeaderValue},
|
||||||
};
|
};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::{convert::TryFrom, env::current_dir};
|
use structopt::StructOpt;
|
||||||
|
|
||||||
pub const PUBLISH_URL: &str = "v1/package/publish";
|
pub const PUBLISH_URL: &str = "v1/package/publish";
|
||||||
|
|
||||||
@ -45,54 +36,47 @@ struct ResponseJson {
|
|||||||
package_id: String,
|
package_id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
/// Publish package to Aleo Package Manager
|
||||||
pub struct PublishCommand;
|
#[derive(StructOpt, Debug, Default)]
|
||||||
|
#[structopt(setting = structopt::clap::AppSettings::ColoredHelp)]
|
||||||
|
pub struct Publish {}
|
||||||
|
|
||||||
impl CLI for PublishCommand {
|
impl Publish {
|
||||||
type Options = ();
|
pub fn new() -> Publish {
|
||||||
|
Publish {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Command for Publish {
|
||||||
|
type Input = <Build as Command>::Output;
|
||||||
type Output = Option<String>;
|
type Output = Option<String>;
|
||||||
|
|
||||||
const ABOUT: AboutType = "Publish the current package to the Aleo Package Manager";
|
/// Build program before publishing
|
||||||
const ARGUMENTS: &'static [ArgumentType] = &[];
|
fn prelude(&self) -> Result<Self::Input> {
|
||||||
const FLAGS: &'static [FlagType] = &[];
|
Build::new().execute()
|
||||||
const NAME: NameType = "publish";
|
|
||||||
const OPTIONS: &'static [OptionType] = &[];
|
|
||||||
const SUBCOMMANDS: &'static [SubCommandType] = &[];
|
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
|
||||||
fn parse(_arguments: &ArgMatches) -> Result<Self::Options, CLIError> {
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
fn apply(self, ctx: Context, _input: Self::Input) -> Result<Self::Output> {
|
||||||
fn output(_options: Self::Options) -> Result<Self::Output, CLIError> {
|
|
||||||
// Build all program files.
|
|
||||||
let _output = BuildCommand::output(())?;
|
|
||||||
|
|
||||||
// Begin "Publishing" context for console logging
|
|
||||||
let span = tracing::span!(tracing::Level::INFO, "Publishing");
|
|
||||||
let _enter = span.enter();
|
|
||||||
|
|
||||||
// Get the package manifest
|
// Get the package manifest
|
||||||
let path = current_dir()?;
|
let path = ctx.dir()?;
|
||||||
let package_manifest = Manifest::try_from(path.as_path())?;
|
let manifest = ctx.manifest()?;
|
||||||
|
|
||||||
let package_name = package_manifest.get_package_name();
|
let package_name = manifest.get_package_name();
|
||||||
let package_version = package_manifest.get_package_version();
|
let package_version = manifest.get_package_version();
|
||||||
|
|
||||||
if package_manifest.get_package_description().is_none() {
|
match (
|
||||||
return Err(MissingPackageDescription.into());
|
manifest.get_package_description(),
|
||||||
}
|
manifest.get_package_license(),
|
||||||
|
manifest.get_package_remote(),
|
||||||
if package_manifest.get_package_license().is_none() {
|
) {
|
||||||
return Err(MissingPackageLicense.into());
|
(None, _, _) => return Err(anyhow!("No package description")),
|
||||||
}
|
(_, None, _) => return Err(anyhow!("Missing package license")),
|
||||||
|
(_, _, None) => return Err(anyhow!("Missing package remote")),
|
||||||
let package_remote = match package_manifest.get_package_remote() {
|
(_, _, _) => (),
|
||||||
Some(remote) => remote,
|
|
||||||
None => return Err(MissingPackageRemote.into()),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let package_remote = manifest.get_package_remote().unwrap();
|
||||||
|
|
||||||
// Create the output directory
|
// Create the output directory
|
||||||
OutputsDirectory::create(&path)?;
|
OutputsDirectory::create(&path)?;
|
||||||
|
|
||||||
@ -115,18 +99,9 @@ impl CLI for PublishCommand {
|
|||||||
// Client for make POST request
|
// Client for make POST request
|
||||||
let client = Client::new();
|
let client = Client::new();
|
||||||
|
|
||||||
// Get token to make an authorized request
|
let token = match ctx.api.auth_token() {
|
||||||
let token = match read_token() {
|
Some(token) => token,
|
||||||
Ok(token) => token,
|
None => return Err(anyhow!("Login before publishing package: try leo login --help")),
|
||||||
|
|
||||||
// If not logged in, then try logging in using JWT.
|
|
||||||
Err(_error) => {
|
|
||||||
tracing::warn!("You should be logged in before attempting to publish a package");
|
|
||||||
tracing::info!("Trying to log in using JWT...");
|
|
||||||
let options = (None, None, None);
|
|
||||||
|
|
||||||
LoginCommand::output(options)?
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Headers for request to publish package
|
// Headers for request to publish package
|
||||||
@ -149,12 +124,12 @@ impl CLI for PublishCommand {
|
|||||||
Ok(json) => json,
|
Ok(json) => json,
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
tracing::warn!("{:?}", error);
|
tracing::warn!("{:?}", error);
|
||||||
return Err(PackageNotPublished("Package not published".into()).into());
|
return Err(anyhow!("Package not published"));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
tracing::warn!("{:?}", error);
|
tracing::warn!("{:?}", error);
|
||||||
return Err(ConnectionUnavalaible("Connection error".into()).into());
|
return Err(anyhow!("Connection unavailable"));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
59
leo/commands/package/remove.rs
Normal file
59
leo/commands/package/remove.rs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||||
|
// This file is part of the Leo library.
|
||||||
|
|
||||||
|
// The Leo library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// The Leo library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use crate::{commands::Command, context::Context};
|
||||||
|
use leo_package::LeoPackage;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use structopt::StructOpt;
|
||||||
|
use tracing::span::Span;
|
||||||
|
|
||||||
|
/// Remove imported package
|
||||||
|
#[derive(StructOpt, Debug, Default)]
|
||||||
|
#[structopt(setting = structopt::clap::AppSettings::ColoredHelp)]
|
||||||
|
pub struct Remove {
|
||||||
|
#[structopt(name = "PACKAGE")]
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Remove {
|
||||||
|
pub fn new(name: String) -> Remove {
|
||||||
|
Remove { name }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Command for Remove {
|
||||||
|
type Input = ();
|
||||||
|
type Output = ();
|
||||||
|
|
||||||
|
fn log_span(&self) -> Span {
|
||||||
|
tracing::span!(tracing::Level::INFO, "Removing")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prelude(&self) -> Result<Self::Input> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply(self, ctx: Context, _: Self::Input) -> Result<Self::Output> {
|
||||||
|
let path = ctx.dir()?;
|
||||||
|
let package_name = self.name;
|
||||||
|
|
||||||
|
LeoPackage::remove_imported_package(&package_name, &path)?;
|
||||||
|
tracing::info!("Successfully removed package \"{}\"\n", package_name);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
@ -14,73 +14,62 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::{cli::*, cli_types::*, commands::SetupCommand, errors::CLIError};
|
use super::setup::Setup;
|
||||||
use leo_package::{outputs::ProofFile, root::Manifest};
|
use crate::{commands::Command, context::Context};
|
||||||
|
use leo_package::outputs::ProofFile;
|
||||||
use snarkvm_algorithms::snark::groth16::{Groth16, PreparedVerifyingKey, Proof};
|
use snarkvm_algorithms::snark::groth16::{Groth16, PreparedVerifyingKey, Proof};
|
||||||
use snarkvm_curves::bls12_377::{Bls12_377, Fr};
|
use snarkvm_curves::bls12_377::{Bls12_377, Fr};
|
||||||
use snarkvm_models::algorithms::SNARK;
|
use snarkvm_models::algorithms::SNARK;
|
||||||
use snarkvm_utilities::bytes::ToBytes;
|
use snarkvm_utilities::bytes::ToBytes;
|
||||||
|
|
||||||
use clap::ArgMatches;
|
use anyhow::Result;
|
||||||
use rand::thread_rng;
|
use rand::thread_rng;
|
||||||
use std::{convert::TryFrom, env::current_dir, time::Instant};
|
use structopt::StructOpt;
|
||||||
|
use tracing::span::Span;
|
||||||
|
|
||||||
#[derive(Debug)]
|
/// Run the program and produce a proof
|
||||||
pub struct ProveCommand;
|
#[derive(StructOpt, Debug, Default)]
|
||||||
|
#[structopt(setting = structopt::clap::AppSettings::ColoredHelp)]
|
||||||
impl CLI for ProveCommand {
|
pub struct Prove {
|
||||||
type Options = bool;
|
#[structopt(long = "skip-key-check", help = "Skip key verification on Setup stage")]
|
||||||
type Output = (Proof<Bls12_377>, PreparedVerifyingKey<Bls12_377>);
|
skip_key_check: bool,
|
||||||
|
|
||||||
const ABOUT: AboutType = "Run the program and produce a proof";
|
|
||||||
const ARGUMENTS: &'static [ArgumentType] = &[];
|
|
||||||
const FLAGS: &'static [FlagType] = &[("--skip-key-check")];
|
|
||||||
const NAME: NameType = "prove";
|
|
||||||
const OPTIONS: &'static [OptionType] = &[];
|
|
||||||
const SUBCOMMANDS: &'static [SubCommandType] = &[];
|
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
|
||||||
fn parse(arguments: &ArgMatches) -> Result<Self::Options, CLIError> {
|
|
||||||
Ok(!arguments.is_present("skip-key-check"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
impl Prove {
|
||||||
fn output(do_setup_check: Self::Options) -> Result<Self::Output, CLIError> {
|
pub fn new(skip_key_check: bool) -> Prove {
|
||||||
let (program, parameters, prepared_verifying_key) = SetupCommand::output(do_setup_check)?;
|
Prove { skip_key_check }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Begin "Proving" context for console logging
|
impl Command for Prove {
|
||||||
let span = tracing::span!(tracing::Level::INFO, "Proving");
|
type Input = <Setup as Command>::Output;
|
||||||
let enter = span.enter();
|
type Output = (Proof<Bls12_377>, PreparedVerifyingKey<Bls12_377>);
|
||||||
|
|
||||||
|
fn log_span(&self) -> Span {
|
||||||
|
tracing::span!(tracing::Level::INFO, "Proving")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prelude(&self) -> Result<Self::Input> {
|
||||||
|
Setup::new(self.skip_key_check).execute()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply(self, ctx: Context, input: Self::Input) -> Result<Self::Output> {
|
||||||
|
let (program, parameters, prepared_verifying_key) = input;
|
||||||
|
|
||||||
// Get the package name
|
// Get the package name
|
||||||
let path = current_dir()?;
|
let path = ctx.dir()?;
|
||||||
let package_name = Manifest::try_from(path.as_path())?.get_package_name();
|
let package_name = ctx.manifest()?.get_package_name();
|
||||||
|
|
||||||
tracing::info!("Starting...");
|
tracing::info!("Starting...");
|
||||||
|
|
||||||
// Start the timer
|
|
||||||
let start = Instant::now();
|
|
||||||
|
|
||||||
let rng = &mut thread_rng();
|
let rng = &mut thread_rng();
|
||||||
let program_proof = Groth16::<Bls12_377, _, Vec<Fr>>::prove(¶meters, &program, rng)?;
|
let program_proof = Groth16::<Bls12_377, _, Vec<Fr>>::prove(¶meters, &program, rng)?;
|
||||||
|
|
||||||
// Finish the timer
|
|
||||||
let end = start.elapsed().as_millis();
|
|
||||||
|
|
||||||
// Write the proof file to the output directory
|
// Write the proof file to the output directory
|
||||||
let mut proof = vec![];
|
let mut proof = vec![];
|
||||||
program_proof.write(&mut proof)?;
|
program_proof.write(&mut proof)?;
|
||||||
ProofFile::new(&package_name).write_to(&path, &proof)?;
|
ProofFile::new(&package_name).write_to(&path, &proof)?;
|
||||||
|
|
||||||
// Drop "Proving" context for console logging
|
|
||||||
drop(enter);
|
|
||||||
|
|
||||||
// Begin "Done" context for console logging
|
|
||||||
tracing::span!(tracing::Level::INFO, "Done").in_scope(|| {
|
|
||||||
tracing::info!("Finished in {:?} milliseconds\n", end);
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok((program_proof, prepared_verifying_key))
|
Ok((program_proof, prepared_verifying_key))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,69 +0,0 @@
|
|||||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
|
||||||
// This file is part of the Leo library.
|
|
||||||
|
|
||||||
// The Leo library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// The Leo library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
use crate::{cli::*, cli_types::*, errors::CLIError};
|
|
||||||
use leo_package::LeoPackage;
|
|
||||||
|
|
||||||
use clap::ArgMatches;
|
|
||||||
use std::env::current_dir;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct RemoveCommand;
|
|
||||||
|
|
||||||
impl CLI for RemoveCommand {
|
|
||||||
type Options = Option<String>;
|
|
||||||
type Output = ();
|
|
||||||
|
|
||||||
const ABOUT: AboutType = "Uninstall a package from the current package";
|
|
||||||
const ARGUMENTS: &'static [ArgumentType] = &[
|
|
||||||
// (name, description, possible_values, required, index)
|
|
||||||
(
|
|
||||||
"NAME",
|
|
||||||
"Removes the package from the current directory",
|
|
||||||
&[],
|
|
||||||
true,
|
|
||||||
1u64,
|
|
||||||
),
|
|
||||||
];
|
|
||||||
const FLAGS: &'static [FlagType] = &[];
|
|
||||||
const NAME: NameType = "remove";
|
|
||||||
const OPTIONS: &'static [OptionType] = &[];
|
|
||||||
const SUBCOMMANDS: &'static [SubCommandType] = &[];
|
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
|
||||||
fn parse(arguments: &ArgMatches) -> Result<Self::Options, CLIError> {
|
|
||||||
Ok(match arguments.value_of("NAME") {
|
|
||||||
Some(name) => Some(name.to_string()),
|
|
||||||
None => unreachable!(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
|
||||||
fn output(options: Self::Options) -> Result<Self::Output, CLIError> {
|
|
||||||
// Begin "Removing" context for console logging
|
|
||||||
let span = tracing::span!(tracing::Level::INFO, "Removing");
|
|
||||||
let _enter = span.enter();
|
|
||||||
|
|
||||||
let path = current_dir()?;
|
|
||||||
|
|
||||||
if let Some(package_name) = options {
|
|
||||||
LeoPackage::remove_imported_package(&package_name, &path)?;
|
|
||||||
tracing::info!("Successfully removed package \"{}\"\n", package_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
@ -14,48 +14,48 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::{cli::*, cli_types::*, commands::ProveCommand, errors::CLIError};
|
use super::prove::Prove;
|
||||||
|
use crate::{commands::Command, context::Context};
|
||||||
use leo_compiler::{compiler::Compiler, group::targets::edwards_bls12::EdwardsGroupType};
|
use leo_compiler::{compiler::Compiler, group::targets::edwards_bls12::EdwardsGroupType};
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
use snarkvm_algorithms::snark::groth16::Groth16;
|
use snarkvm_algorithms::snark::groth16::Groth16;
|
||||||
use snarkvm_curves::bls12_377::{Bls12_377, Fr};
|
use snarkvm_curves::bls12_377::{Bls12_377, Fr};
|
||||||
use snarkvm_models::algorithms::SNARK;
|
use snarkvm_models::algorithms::SNARK;
|
||||||
|
use structopt::StructOpt;
|
||||||
|
use tracing::span::Span;
|
||||||
|
|
||||||
use clap::ArgMatches;
|
/// Build, Prove and Run Leo program with inputs
|
||||||
use std::time::Instant;
|
#[derive(StructOpt, Debug, Default)]
|
||||||
|
#[structopt(setting = structopt::clap::AppSettings::ColoredHelp)]
|
||||||
#[derive(Debug)]
|
pub struct Run {
|
||||||
pub struct RunCommand;
|
#[structopt(long = "skip-key-check", help = "Skip key verification on Setup stage")]
|
||||||
|
skip_key_check: bool,
|
||||||
impl CLI for RunCommand {
|
|
||||||
type Options = bool;
|
|
||||||
type Output = ();
|
|
||||||
|
|
||||||
const ABOUT: AboutType = "Run a program with input variables";
|
|
||||||
const ARGUMENTS: &'static [ArgumentType] = &[];
|
|
||||||
const FLAGS: &'static [FlagType] = &[("--skip-key-check")];
|
|
||||||
const NAME: NameType = "run";
|
|
||||||
const OPTIONS: &'static [OptionType] = &[];
|
|
||||||
const SUBCOMMANDS: &'static [SubCommandType] = &[];
|
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
|
||||||
fn parse(arguments: &ArgMatches) -> Result<Self::Options, CLIError> {
|
|
||||||
Ok(!arguments.is_present("skip-key-check"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
impl Run {
|
||||||
fn output(do_setup_check: Self::Options) -> Result<(), CLIError> {
|
pub fn new(skip_key_check: bool) -> Run {
|
||||||
let (proof, prepared_verifying_key) = ProveCommand::output(do_setup_check)?;
|
Run { skip_key_check }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Begin "Verifying" context for console logging
|
impl Command for Run {
|
||||||
let span = tracing::span!(tracing::Level::INFO, "Verifying");
|
type Input = <Prove as Command>::Output;
|
||||||
let enter = span.enter();
|
type Output = ();
|
||||||
|
|
||||||
|
fn log_span(&self) -> Span {
|
||||||
|
tracing::span!(tracing::Level::INFO, "Verifying")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prelude(&self) -> Result<Self::Input> {
|
||||||
|
Prove::new(self.skip_key_check).execute()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply(self, _ctx: Context, input: Self::Input) -> Result<Self::Output> {
|
||||||
|
let (proof, prepared_verifying_key) = input;
|
||||||
|
|
||||||
tracing::info!("Starting...");
|
tracing::info!("Starting...");
|
||||||
|
|
||||||
// Start the timer
|
|
||||||
let start = Instant::now();
|
|
||||||
|
|
||||||
// Run the verifier
|
// Run the verifier
|
||||||
let is_success = Groth16::<Bls12_377, Compiler<Fr, EdwardsGroupType>, Vec<Fr>>::verify(
|
let is_success = Groth16::<Bls12_377, Compiler<Fr, EdwardsGroupType>, Vec<Fr>>::verify(
|
||||||
&prepared_verifying_key,
|
&prepared_verifying_key,
|
||||||
@ -63,23 +63,12 @@ impl CLI for RunCommand {
|
|||||||
&proof,
|
&proof,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// End the timer
|
|
||||||
let end = start.elapsed().as_millis();
|
|
||||||
|
|
||||||
// Log the verifier output
|
// Log the verifier output
|
||||||
match is_success {
|
match is_success {
|
||||||
true => tracing::info!("Proof is valid"),
|
true => tracing::info!("Proof is valid"),
|
||||||
false => tracing::error!("Proof is invalid"),
|
false => tracing::error!("Proof is invalid"),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Drop "Verifying" context for console logging
|
|
||||||
drop(enter);
|
|
||||||
|
|
||||||
// Begin "Done" context for console logging
|
|
||||||
tracing::span!(tracing::Level::INFO, "Done").in_scope(|| {
|
|
||||||
tracing::info!("Finished in {:?} milliseconds\n", end);
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,81 +14,71 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::{
|
use super::build::Build;
|
||||||
cli::*,
|
use crate::{commands::Command, context::Context};
|
||||||
cli_types::*,
|
|
||||||
commands::BuildCommand,
|
|
||||||
errors::{CLIError, RunError},
|
|
||||||
};
|
|
||||||
use leo_compiler::{compiler::Compiler, group::targets::edwards_bls12::EdwardsGroupType};
|
use leo_compiler::{compiler::Compiler, group::targets::edwards_bls12::EdwardsGroupType};
|
||||||
use leo_package::{
|
use leo_package::{
|
||||||
outputs::{ProvingKeyFile, VerificationKeyFile},
|
outputs::{ProvingKeyFile, VerificationKeyFile},
|
||||||
root::Manifest,
|
|
||||||
source::{MAIN_FILENAME, SOURCE_DIRECTORY_NAME},
|
source::{MAIN_FILENAME, SOURCE_DIRECTORY_NAME},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use anyhow::{anyhow, Result};
|
||||||
|
use rand::thread_rng;
|
||||||
use snarkvm_algorithms::snark::groth16::{Groth16, Parameters, PreparedVerifyingKey, VerifyingKey};
|
use snarkvm_algorithms::snark::groth16::{Groth16, Parameters, PreparedVerifyingKey, VerifyingKey};
|
||||||
use snarkvm_curves::bls12_377::{Bls12_377, Fr};
|
use snarkvm_curves::bls12_377::{Bls12_377, Fr};
|
||||||
use snarkvm_models::algorithms::snark::SNARK;
|
use snarkvm_models::algorithms::snark::SNARK;
|
||||||
|
use structopt::StructOpt;
|
||||||
|
use tracing::span::Span;
|
||||||
|
|
||||||
use clap::ArgMatches;
|
/// Executes the setup command for a Leo program
|
||||||
use rand::thread_rng;
|
#[derive(StructOpt, Debug, Default)]
|
||||||
use std::{convert::TryFrom, env::current_dir, time::Instant};
|
#[structopt(setting = structopt::clap::AppSettings::ColoredHelp)]
|
||||||
|
pub struct Setup {
|
||||||
|
#[structopt(long = "skip-key-check", help = "Skip key verification")]
|
||||||
|
skip_key_check: bool,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
impl Setup {
|
||||||
pub struct SetupCommand;
|
pub fn new(skip_key_check: bool) -> Setup {
|
||||||
|
Setup { skip_key_check }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl CLI for SetupCommand {
|
impl Command for Setup {
|
||||||
type Options = bool;
|
type Input = <Build as Command>::Output;
|
||||||
type Output = (
|
type Output = (
|
||||||
Compiler<Fr, EdwardsGroupType>,
|
Compiler<Fr, EdwardsGroupType>,
|
||||||
Parameters<Bls12_377>,
|
Parameters<Bls12_377>,
|
||||||
PreparedVerifyingKey<Bls12_377>,
|
PreparedVerifyingKey<Bls12_377>,
|
||||||
);
|
);
|
||||||
|
|
||||||
const ABOUT: AboutType = "Run a program setup";
|
fn log_span(&self) -> Span {
|
||||||
const ARGUMENTS: &'static [ArgumentType] = &[];
|
tracing::span!(tracing::Level::INFO, "Setup")
|
||||||
const FLAGS: &'static [FlagType] = &[("--skip-key-check")];
|
|
||||||
const NAME: NameType = "setup";
|
|
||||||
const OPTIONS: &'static [OptionType] = &[];
|
|
||||||
const SUBCOMMANDS: &'static [SubCommandType] = &[];
|
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
|
||||||
fn parse(arguments: &ArgMatches) -> Result<Self::Options, CLIError> {
|
|
||||||
Ok(!arguments.is_present("skip-key-check"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
fn prelude(&self) -> Result<Self::Input> {
|
||||||
fn output(do_check: Self::Options) -> Result<Self::Output, CLIError> {
|
Build::new().execute()
|
||||||
// Get the package name
|
}
|
||||||
let path = current_dir()?;
|
|
||||||
let package_name = Manifest::try_from(path.as_path())?.get_package_name();
|
|
||||||
|
|
||||||
match BuildCommand::output(())? {
|
fn apply(self, ctx: Context, input: Self::Input) -> Result<Self::Output> {
|
||||||
|
let path = ctx.dir()?;
|
||||||
|
let package_name = ctx.manifest()?.get_package_name();
|
||||||
|
|
||||||
|
match input {
|
||||||
Some((program, checksum_differs)) => {
|
Some((program, checksum_differs)) => {
|
||||||
// Begin "Setup" context for console logging
|
|
||||||
let span = tracing::span!(tracing::Level::INFO, "Setup");
|
|
||||||
let enter = span.enter();
|
|
||||||
|
|
||||||
// Check if a proving key and verification key already exists
|
// Check if a proving key and verification key already exists
|
||||||
let keys_exist = ProvingKeyFile::new(&package_name).exists_at(&path)
|
let keys_exist = ProvingKeyFile::new(&package_name).exists_at(&path)
|
||||||
&& VerificationKeyFile::new(&package_name).exists_at(&path);
|
&& VerificationKeyFile::new(&package_name).exists_at(&path);
|
||||||
|
|
||||||
// If keys do not exist or the checksum differs, run the program setup
|
// If keys do not exist or the checksum differs, run the program setup
|
||||||
// If keys do not exist or the checksum differs, run the program setup
|
// If keys do not exist or the checksum differs, run the program setup
|
||||||
let (end, proving_key, prepared_verifying_key) = if !keys_exist || checksum_differs {
|
let (proving_key, prepared_verifying_key) = if !keys_exist || checksum_differs {
|
||||||
tracing::info!("Starting...");
|
tracing::info!("Starting...");
|
||||||
|
|
||||||
// Start the timer for setup
|
|
||||||
let setup_start = Instant::now();
|
|
||||||
|
|
||||||
// Run the program setup operation
|
// Run the program setup operation
|
||||||
let rng = &mut thread_rng();
|
let rng = &mut thread_rng();
|
||||||
let (proving_key, prepared_verifying_key) =
|
let (proving_key, prepared_verifying_key) =
|
||||||
Groth16::<Bls12_377, Compiler<Fr, _>, Vec<Fr>>::setup(&program, rng).unwrap();
|
Groth16::<Bls12_377, Compiler<Fr, _>, Vec<Fr>>::setup(&program, rng)?;
|
||||||
|
|
||||||
// End the timer
|
|
||||||
let end = setup_start.elapsed().as_millis();
|
|
||||||
|
|
||||||
// TODO (howardwu): Convert parameters to a 'proving key' struct for serialization.
|
// TODO (howardwu): Convert parameters to a 'proving key' struct for serialization.
|
||||||
// Write the proving key file to the output directory
|
// Write the proving key file to the output directory
|
||||||
@ -107,20 +97,19 @@ impl CLI for SetupCommand {
|
|||||||
let _ = verification_key_file.write_to(&path, &verification_key)?;
|
let _ = verification_key_file.write_to(&path, &verification_key)?;
|
||||||
tracing::info!("Complete");
|
tracing::info!("Complete");
|
||||||
|
|
||||||
(end, proving_key, prepared_verifying_key)
|
(proving_key, prepared_verifying_key)
|
||||||
} else {
|
} else {
|
||||||
tracing::info!("Detected saved setup");
|
tracing::info!("Detected saved setup");
|
||||||
|
|
||||||
// Start the timer for setup
|
|
||||||
let setup_start = Instant::now();
|
|
||||||
|
|
||||||
// Read the proving key file from the output directory
|
// Read the proving key file from the output directory
|
||||||
tracing::info!("Loading proving key...");
|
tracing::info!("Loading proving key...");
|
||||||
if !do_check {
|
|
||||||
|
if self.skip_key_check {
|
||||||
tracing::info!("Skipping curve check");
|
tracing::info!("Skipping curve check");
|
||||||
}
|
}
|
||||||
let proving_key_bytes = ProvingKeyFile::new(&package_name).read_from(&path)?;
|
let proving_key_bytes = ProvingKeyFile::new(&package_name).read_from(&path)?;
|
||||||
let proving_key = Parameters::<Bls12_377>::read(proving_key_bytes.as_slice(), do_check)?;
|
let proving_key =
|
||||||
|
Parameters::<Bls12_377>::read(proving_key_bytes.as_slice(), !self.skip_key_check)?;
|
||||||
tracing::info!("Complete");
|
tracing::info!("Complete");
|
||||||
|
|
||||||
// Read the verification key file from the output directory
|
// Read the verification key file from the output directory
|
||||||
@ -132,20 +121,9 @@ impl CLI for SetupCommand {
|
|||||||
let prepared_verifying_key = PreparedVerifyingKey::<Bls12_377>::from(verifying_key);
|
let prepared_verifying_key = PreparedVerifyingKey::<Bls12_377>::from(verifying_key);
|
||||||
tracing::info!("Complete");
|
tracing::info!("Complete");
|
||||||
|
|
||||||
// End the timer
|
(proving_key, prepared_verifying_key)
|
||||||
let end = setup_start.elapsed().as_millis();
|
|
||||||
|
|
||||||
(end, proving_key, prepared_verifying_key)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Drop "Setup" context for console logging
|
|
||||||
drop(enter);
|
|
||||||
|
|
||||||
// Begin "Done" context for console logging
|
|
||||||
tracing::span!(tracing::Level::INFO, "Done").in_scope(|| {
|
|
||||||
tracing::info!("Finished in {:?} milliseconds\n", end);
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok((program, proving_key, prepared_verifying_key))
|
Ok((program, proving_key, prepared_verifying_key))
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
@ -153,9 +131,7 @@ impl CLI for SetupCommand {
|
|||||||
main_file_path.push(SOURCE_DIRECTORY_NAME);
|
main_file_path.push(SOURCE_DIRECTORY_NAME);
|
||||||
main_file_path.push(MAIN_FILENAME);
|
main_file_path.push(MAIN_FILENAME);
|
||||||
|
|
||||||
Err(CLIError::RunError(RunError::MainFileDoesNotExist(
|
Err(anyhow!("Unable to build, check that main file exists"))
|
||||||
main_file_path.into_os_string(),
|
|
||||||
)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,67 +14,75 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::{
|
use crate::{commands::Command, context::Context};
|
||||||
cli::*,
|
|
||||||
cli_types::*,
|
|
||||||
errors::{CLIError, TestError::ProgramFileDoesNotExist},
|
|
||||||
};
|
|
||||||
use leo_compiler::{compiler::Compiler, group::targets::edwards_bls12::EdwardsGroupType};
|
use leo_compiler::{compiler::Compiler, group::targets::edwards_bls12::EdwardsGroupType};
|
||||||
use leo_package::{
|
use leo_package::{
|
||||||
inputs::*,
|
inputs::*,
|
||||||
outputs::{OutputsDirectory, OUTPUTS_DIRECTORY_NAME},
|
outputs::{OutputsDirectory, OUTPUTS_DIRECTORY_NAME},
|
||||||
root::Manifest,
|
source::{MainFile, MAIN_FILENAME, SOURCE_DIRECTORY_NAME},
|
||||||
source::{LibraryFile, MainFile, LIBRARY_FILENAME, MAIN_FILENAME, SOURCE_DIRECTORY_NAME},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use anyhow::{anyhow, Result};
|
||||||
use snarkvm_curves::edwards_bls12::Fq;
|
use snarkvm_curves::edwards_bls12::Fq;
|
||||||
|
use std::{convert::TryFrom, path::PathBuf, time::Instant};
|
||||||
|
use structopt::StructOpt;
|
||||||
|
use tracing::span::Span;
|
||||||
|
|
||||||
use clap::ArgMatches;
|
/// Build program and run tests command
|
||||||
use std::{convert::TryFrom, env::current_dir, time::Instant};
|
#[derive(StructOpt, Debug, Default)]
|
||||||
|
#[structopt(setting = structopt::clap::AppSettings::ColoredHelp)]
|
||||||
|
pub struct Test {
|
||||||
|
#[structopt(short = "f", long = "file", name = "file")]
|
||||||
|
files: Vec<PathBuf>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
impl Test {
|
||||||
pub struct TestCommand;
|
pub fn new(files: Vec<PathBuf>) -> Test {
|
||||||
|
Test { files }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl CLI for TestCommand {
|
impl Command for Test {
|
||||||
type Options = ();
|
type Input = ();
|
||||||
type Output = ();
|
type Output = ();
|
||||||
|
|
||||||
const ABOUT: AboutType = "Compile and run all tests in the current package";
|
fn log_span(&self) -> Span {
|
||||||
const ARGUMENTS: &'static [ArgumentType] = &[];
|
tracing::span!(tracing::Level::INFO, "Test")
|
||||||
const FLAGS: &'static [FlagType] = &[];
|
}
|
||||||
const NAME: NameType = "test";
|
|
||||||
const OPTIONS: &'static [OptionType] = &[];
|
|
||||||
const SUBCOMMANDS: &'static [SubCommandType] = &[];
|
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
fn prelude(&self) -> Result<Self::Input> {
|
||||||
fn parse(_arguments: &ArgMatches) -> Result<Self::Options, CLIError> {
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
fn apply(self, ctx: Context, _: Self::Input) -> Result<Self::Output> {
|
||||||
fn output(_options: Self::Options) -> Result<Self::Output, CLIError> {
|
|
||||||
let path = current_dir()?;
|
|
||||||
|
|
||||||
// Get the package name
|
// Get the package name
|
||||||
let manifest = Manifest::try_from(path.as_path())?;
|
let package_name = ctx.manifest()?.get_package_name();
|
||||||
let package_name = manifest.get_package_name();
|
|
||||||
|
|
||||||
// Sanitize the package path to the root directory
|
// Sanitize the package path to the root directory
|
||||||
let mut package_path = path;
|
let mut package_path = ctx.dir()?;
|
||||||
if package_path.is_file() {
|
if package_path.is_file() {
|
||||||
package_path.pop();
|
package_path.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut to_test: Vec<PathBuf> = Vec::new();
|
||||||
|
|
||||||
|
// if -f flag was used, then we'll test only this files
|
||||||
|
if !self.files.is_empty() {
|
||||||
|
to_test.extend(self.files.iter().cloned());
|
||||||
|
|
||||||
|
// if args were not passed - try main file
|
||||||
|
} else if MainFile::exists_at(&package_path) {
|
||||||
let mut file_path = package_path.clone();
|
let mut file_path = package_path.clone();
|
||||||
file_path.push(SOURCE_DIRECTORY_NAME);
|
file_path.push(SOURCE_DIRECTORY_NAME);
|
||||||
|
|
||||||
// Verify a main or library file exists
|
|
||||||
if MainFile::exists_at(&package_path) {
|
|
||||||
file_path.push(MAIN_FILENAME);
|
file_path.push(MAIN_FILENAME);
|
||||||
} else if LibraryFile::exists_at(&package_path) {
|
to_test.push(file_path);
|
||||||
file_path.push(LIBRARY_FILENAME);
|
|
||||||
|
// when no main file and no files marked - error
|
||||||
} else {
|
} else {
|
||||||
return Err(ProgramFileDoesNotExist(package_path.into()).into());
|
return Err(anyhow!(
|
||||||
|
"Program file does not exist {}",
|
||||||
|
package_path.to_string_lossy()
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct the path to the output directory;
|
// Construct the path to the output directory;
|
||||||
@ -84,49 +92,45 @@ impl CLI for TestCommand {
|
|||||||
// Create the output directory
|
// Create the output directory
|
||||||
OutputsDirectory::create(&package_path)?;
|
OutputsDirectory::create(&package_path)?;
|
||||||
|
|
||||||
// Begin "Test" context for console logging
|
// Finally test every passed file
|
||||||
let span = tracing::span!(tracing::Level::INFO, "Test");
|
for file_path in to_test {
|
||||||
let enter = span.enter();
|
tracing::info!("Running tests in file {:?}", file_path);
|
||||||
|
|
||||||
// Start the timer
|
let input_pairs = match InputPairs::try_from(package_path.as_path()) {
|
||||||
let start = Instant::now();
|
Ok(pairs) => pairs,
|
||||||
|
Err(_) => {
|
||||||
|
tracing::warn!("Unable to find inputs, ignore this message or put them into /inputs folder");
|
||||||
|
InputPairs::new()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Parse the current main program file
|
let timer = Instant::now();
|
||||||
let program =
|
let program = Compiler::<Fq, EdwardsGroupType>::parse_program_without_input(
|
||||||
Compiler::<Fq, EdwardsGroupType>::parse_program_without_input(package_name, file_path, output_directory)?;
|
package_name.clone(),
|
||||||
|
file_path,
|
||||||
|
output_directory.clone(),
|
||||||
|
)?;
|
||||||
|
|
||||||
// Parse all inputs as input pairs
|
|
||||||
let pairs = InputPairs::try_from(package_path.as_path())?;
|
|
||||||
|
|
||||||
// Run tests
|
|
||||||
let temporary_program = program;
|
let temporary_program = program;
|
||||||
let (passed, failed) = temporary_program.compile_test_constraints(pairs)?;
|
let (passed, failed) = temporary_program.compile_test_constraints(input_pairs)?;
|
||||||
|
let time_taken = timer.elapsed().as_millis();
|
||||||
|
|
||||||
// Drop "Test" context for console logging
|
|
||||||
drop(enter);
|
|
||||||
|
|
||||||
// Set the result of the test command to passed if no tests failed.
|
|
||||||
if failed == 0 {
|
if failed == 0 {
|
||||||
// Begin "Done" context for console logging
|
|
||||||
tracing::span!(tracing::Level::INFO, "Done").in_scope(|| {
|
|
||||||
tracing::info!(
|
tracing::info!(
|
||||||
"Tests passed in {} milliseconds. {} passed; {} failed;\n",
|
"Tests passed in {} milliseconds. {} passed; {} failed;\n",
|
||||||
start.elapsed().as_millis(),
|
time_taken,
|
||||||
passed,
|
passed,
|
||||||
failed
|
failed
|
||||||
);
|
);
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
// Begin "Done" context for console logging
|
|
||||||
tracing::span!(tracing::Level::ERROR, "Done").in_scope(|| {
|
|
||||||
tracing::error!(
|
tracing::error!(
|
||||||
"Tests failed in {} milliseconds. {} passed; {} failed;\n",
|
"Tests failed in {} milliseconds. {} passed; {} failed;\n",
|
||||||
start.elapsed().as_millis(),
|
time_taken,
|
||||||
passed,
|
passed,
|
||||||
failed
|
failed
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -14,179 +14,97 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::{cli::CLI, cli_types::*, config::Config, updater::Updater};
|
use crate::{commands::Command, config::Config, context::Context, updater::Updater};
|
||||||
|
|
||||||
use clap::AppSettings;
|
use anyhow::{anyhow, Result};
|
||||||
|
use structopt::StructOpt;
|
||||||
|
use tracing::span::Span;
|
||||||
|
|
||||||
#[derive(Debug)]
|
/// Setting for automatic updates of Leo
|
||||||
pub struct UpdateCommand;
|
#[derive(Debug, StructOpt, PartialEq)]
|
||||||
|
pub enum Sub {
|
||||||
|
Automatic {
|
||||||
|
#[structopt(name = "bool", help = "Boolean value: true or false", parse(try_from_str))]
|
||||||
|
value: bool,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
impl CLI for UpdateCommand {
|
/// Update Leo to the latest version
|
||||||
// (show_all_versions, quiet)
|
#[derive(StructOpt, Debug, Default)]
|
||||||
type Options = Option<(bool, bool, bool)>;
|
#[structopt(setting = structopt::clap::AppSettings::ColoredHelp)]
|
||||||
|
pub struct Update {
|
||||||
|
/// List all available versions of Leo
|
||||||
|
#[structopt(short, long)]
|
||||||
|
list: bool,
|
||||||
|
|
||||||
|
/// For Aleo Studio only
|
||||||
|
#[structopt(short, long)]
|
||||||
|
studio: bool,
|
||||||
|
|
||||||
|
/// Setting for automatic updates of Leo
|
||||||
|
#[structopt(subcommand)]
|
||||||
|
automatic: Option<Sub>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Update {
|
||||||
|
pub fn new(list: bool, studio: bool, automatic: Option<Sub>) -> Update {
|
||||||
|
Update {
|
||||||
|
list,
|
||||||
|
studio,
|
||||||
|
automatic,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Command for Update {
|
||||||
|
type Input = ();
|
||||||
type Output = ();
|
type Output = ();
|
||||||
|
|
||||||
const ABOUT: AboutType = "Update Leo to the latest version";
|
fn log_span(&self) -> Span {
|
||||||
const ARGUMENTS: &'static [ArgumentType] = &[];
|
tracing::span!(tracing::Level::INFO, "Updating")
|
||||||
const FLAGS: &'static [FlagType] = &[
|
|
||||||
"[list] -l --list 'List all available versions of Leo'",
|
|
||||||
"[quiet] -q --quiet 'Suppress outputs to terminal'",
|
|
||||||
"[studio] -s --studio 'For Aleo Studio only'",
|
|
||||||
];
|
|
||||||
const NAME: NameType = "update";
|
|
||||||
const OPTIONS: &'static [OptionType] = &[];
|
|
||||||
const SUBCOMMANDS: &'static [SubCommandType] = &[
|
|
||||||
// (name, description, options, settings)
|
|
||||||
(
|
|
||||||
UpdateAutomatic::NAME,
|
|
||||||
UpdateAutomatic::ABOUT,
|
|
||||||
UpdateAutomatic::ARGUMENTS,
|
|
||||||
UpdateAutomatic::FLAGS,
|
|
||||||
&UpdateAutomatic::OPTIONS,
|
|
||||||
&[
|
|
||||||
AppSettings::ColoredHelp,
|
|
||||||
AppSettings::DisableHelpSubcommand,
|
|
||||||
AppSettings::DisableVersion,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
];
|
|
||||||
|
|
||||||
fn parse(arguments: &clap::ArgMatches) -> Result<Self::Options, crate::errors::CLIError> {
|
|
||||||
if let ("automatic", Some(arguments)) = arguments.subcommand() {
|
|
||||||
// Run the `automatic` subcommand
|
|
||||||
let options = UpdateAutomatic::parse(arguments)?;
|
|
||||||
let _output = UpdateAutomatic::output(options)?;
|
|
||||||
return Ok(None);
|
|
||||||
};
|
|
||||||
|
|
||||||
let show_all_versions = arguments.is_present("list");
|
|
||||||
let quiet = arguments.is_present("quiet");
|
|
||||||
let studio = arguments.is_present("studio");
|
|
||||||
|
|
||||||
Ok(Some((show_all_versions, quiet, studio)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn output(options: Self::Options) -> Result<Self::Output, crate::errors::CLIError> {
|
fn prelude(&self) -> Result<Self::Input> {
|
||||||
// Begin "Updating" context for console logging
|
Ok(())
|
||||||
let span = tracing::span!(tracing::Level::INFO, "Updating");
|
|
||||||
let _enter = span.enter();
|
|
||||||
|
|
||||||
let (show_all_versions, quiet, studio) = match options {
|
|
||||||
Some(options) => options,
|
|
||||||
None => return Ok(()),
|
|
||||||
};
|
|
||||||
|
|
||||||
match show_all_versions {
|
|
||||||
true => match Updater::show_available_releases() {
|
|
||||||
Ok(_) => return Ok(()),
|
|
||||||
Err(e) => {
|
|
||||||
tracing::error!("Could not fetch that latest version of Leo");
|
|
||||||
tracing::error!("{}", e);
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
fn apply(self, _: Context, _: Self::Input) -> Result<Self::Output> {
|
||||||
|
// if --list is passed - simply list everything and exit
|
||||||
|
if self.list {
|
||||||
|
return Updater::show_available_releases().map_err(|e| anyhow!("Could not fetch versions: {}", e));
|
||||||
|
}
|
||||||
|
|
||||||
|
// in case automatic subcommand was called
|
||||||
|
if let Some(Sub::Automatic { value }) = self.automatic {
|
||||||
|
Config::set_update_automatic(value)?;
|
||||||
|
|
||||||
|
match value {
|
||||||
|
true => tracing::info!("Automatic updates are enabled. Leo will update as new versions are released"),
|
||||||
false => {
|
false => {
|
||||||
|
tracing::info!("Automatic updates are disabled. Leo will not update as new versions are released")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let config = Config::read_config()?;
|
let config = Config::read_config()?;
|
||||||
|
|
||||||
// If update is run with studio and the automatic update is off, finish quietly
|
// If update is run with studio and the automatic update is off, finish quietly
|
||||||
if studio && !config.update.automatic {
|
if self.studio && !config.update.automatic {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
match Updater::update_to_latest_release(!quiet) {
|
match Updater::update_to_latest_release(true) {
|
||||||
Ok(status) => {
|
Ok(status) => match (status.uptodate(), status.updated()) {
|
||||||
if !quiet {
|
(true, _) => tracing::info!("Leo is already on the latest version"),
|
||||||
if status.uptodate() {
|
(_, true) => tracing::info!("Leo has successfully updated to version {}", status.version()),
|
||||||
tracing::info!("Leo is already on the latest version");
|
(_, _) => (),
|
||||||
} else if status.updated() {
|
},
|
||||||
tracing::info!("Leo has successfully updated to version {}", status.version());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
if !quiet {
|
|
||||||
tracing::error!("Could not update Leo to the latest version");
|
tracing::error!("Could not update Leo to the latest version");
|
||||||
tracing::error!("{}", e);
|
tracing::error!("{}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO (raychu86) Move this to dedicated file/module
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct UpdateAutomatic;
|
|
||||||
|
|
||||||
impl CLI for UpdateAutomatic {
|
|
||||||
// (is_automatic, quiet)
|
|
||||||
type Options = (Option<bool>, bool);
|
|
||||||
type Output = ();
|
|
||||||
|
|
||||||
const ABOUT: AboutType = "Setting for automatic updates of Leo";
|
|
||||||
const ARGUMENTS: &'static [ArgumentType] = &[
|
|
||||||
// (name, description, possible_values, required, index)
|
|
||||||
(
|
|
||||||
"automatic",
|
|
||||||
"Enable or disable automatic updates",
|
|
||||||
&["true", "false"],
|
|
||||||
false,
|
|
||||||
1u64,
|
|
||||||
),
|
|
||||||
];
|
|
||||||
const FLAGS: &'static [FlagType] = &["[quiet] -q --quiet 'Suppress outputs to terminal'"];
|
|
||||||
const NAME: NameType = "automatic";
|
|
||||||
const OPTIONS: &'static [OptionType] = &[];
|
|
||||||
const SUBCOMMANDS: &'static [SubCommandType] = &[];
|
|
||||||
|
|
||||||
fn parse(arguments: &clap::ArgMatches) -> Result<Self::Options, crate::errors::CLIError> {
|
|
||||||
let quiet = arguments.is_present("quiet");
|
|
||||||
|
|
||||||
match arguments.value_of("automatic") {
|
|
||||||
Some(automatic) => {
|
|
||||||
// TODO enforce that the possible values is true or false
|
|
||||||
let automatic = match automatic {
|
|
||||||
"true" => Some(true),
|
|
||||||
"false" => Some(false),
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok((automatic, quiet))
|
|
||||||
}
|
|
||||||
None => Ok((None, quiet)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output(options: Self::Options) -> Result<Self::Output, crate::errors::CLIError> {
|
|
||||||
// Begin "Settings" context for console logging
|
|
||||||
let span = tracing::span!(tracing::Level::INFO, "Settings");
|
|
||||||
let enter = span.enter();
|
|
||||||
|
|
||||||
// If a boolean value is provided, update the saved
|
|
||||||
// `automatic` configuration value to this boolean value.
|
|
||||||
if let Some(automatic) = options.0 {
|
|
||||||
Config::set_update_automatic(automatic)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If --quiet is not enabled, log the output.
|
|
||||||
if !options.1 {
|
|
||||||
// Read the `automatic` value now.
|
|
||||||
let automatic = Config::read_config()?.update.automatic;
|
|
||||||
|
|
||||||
// Log the output.
|
|
||||||
tracing::debug!("automatic = {}", automatic);
|
|
||||||
match automatic {
|
|
||||||
true => tracing::info!("Automatic updates are enabled. Leo will update as new versions are released."),
|
|
||||||
false => {
|
|
||||||
tracing::info!("Automatic updates are disabled. Leo will not update as new versions are released.")
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Drop "Settings" context for console logging.
|
|
||||||
drop(enter);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -14,42 +14,55 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::{cli::CLI, cli_types::*, commands::BuildCommand, errors::CLIError};
|
use super::build::Build;
|
||||||
use clap::ArgMatches;
|
use crate::{commands::Command, context::Context};
|
||||||
use notify::{watcher, DebouncedEvent, RecursiveMode, Watcher};
|
|
||||||
use std::{sync::mpsc::channel, time::Duration};
|
use std::{sync::mpsc::channel, time::Duration};
|
||||||
|
|
||||||
|
use anyhow::{anyhow, Result};
|
||||||
|
use notify::{watcher, DebouncedEvent, RecursiveMode, Watcher};
|
||||||
|
use structopt::StructOpt;
|
||||||
|
use tracing::span::Span;
|
||||||
|
|
||||||
const LEO_SOURCE_DIR: &str = "src/";
|
const LEO_SOURCE_DIR: &str = "src/";
|
||||||
|
|
||||||
// Time interval for watching files, in seconds
|
/// Watch file changes in src/ directory and run Build Command
|
||||||
const INTERVAL: u64 = 3;
|
#[derive(StructOpt, Debug, Default)]
|
||||||
|
#[structopt(setting = structopt::clap::AppSettings::ColoredHelp)]
|
||||||
|
pub struct Watch {
|
||||||
|
/// Set up watch interval
|
||||||
|
#[structopt(short, long, default_value = "3")]
|
||||||
|
interval: u64,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct WatchCommand;
|
impl Watch {
|
||||||
|
pub fn new(interval: u64) -> Watch {
|
||||||
|
Watch { interval }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl CLI for WatchCommand {
|
impl Command for Watch {
|
||||||
type Options = ();
|
type Input = ();
|
||||||
type Output = ();
|
type Output = ();
|
||||||
|
|
||||||
const ABOUT: AboutType = "Watch for changes of Leo source files";
|
fn log_span(&self) -> Span {
|
||||||
const ARGUMENTS: &'static [ArgumentType] = &[];
|
tracing::span!(tracing::Level::INFO, "Watching")
|
||||||
const FLAGS: &'static [FlagType] = &[];
|
}
|
||||||
const NAME: NameType = "watch";
|
|
||||||
const OPTIONS: &'static [OptionType] = &[];
|
|
||||||
const SUBCOMMANDS: &'static [SubCommandType] = &[];
|
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
fn prelude(&self) -> Result<Self::Input> {
|
||||||
fn parse(_arguments: &ArgMatches) -> Result<Self::Options, CLIError> {
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn output(_options: Self::Options) -> Result<Self::Output, CLIError> {
|
fn apply(self, _ctx: Context, _: Self::Input) -> Result<Self::Output> {
|
||||||
// Begin "Watching" context for console logging
|
|
||||||
let span = tracing::span!(tracing::Level::INFO, "Watching");
|
|
||||||
let _enter = span.enter();
|
|
||||||
|
|
||||||
let (tx, rx) = channel();
|
let (tx, rx) = channel();
|
||||||
let mut watcher = watcher(tx, Duration::from_secs(INTERVAL)).unwrap();
|
let mut watcher = watcher(tx, Duration::from_secs(self.interval)).unwrap();
|
||||||
watcher.watch(LEO_SOURCE_DIR, RecursiveMode::Recursive).unwrap();
|
|
||||||
|
watcher.watch(LEO_SOURCE_DIR, RecursiveMode::Recursive).map_err(|e| {
|
||||||
|
anyhow!(
|
||||||
|
"Unable to watch, check that directory contains Leo.toml file. Error: {}",
|
||||||
|
e
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
tracing::info!("Watching Leo source code");
|
tracing::info!("Watching Leo source code");
|
||||||
|
|
||||||
@ -57,7 +70,7 @@ impl CLI for WatchCommand {
|
|||||||
match rx.recv() {
|
match rx.recv() {
|
||||||
// See changes on the write event
|
// See changes on the write event
|
||||||
Ok(DebouncedEvent::Write(_write)) => {
|
Ok(DebouncedEvent::Write(_write)) => {
|
||||||
match BuildCommand::output(()) {
|
match Build::new().execute() {
|
||||||
Ok(_output) => {
|
Ok(_output) => {
|
||||||
tracing::info!("Built successfully");
|
tracing::info!("Built successfully");
|
||||||
}
|
}
|
||||||
|
@ -14,11 +14,6 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::errors::CLIError;
|
|
||||||
|
|
||||||
use dirs::home_dir;
|
|
||||||
use lazy_static::lazy_static;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use std::{
|
use std::{
|
||||||
fs::{self, create_dir_all, File},
|
fs::{self, create_dir_all, File},
|
||||||
io,
|
io,
|
||||||
@ -26,7 +21,10 @@ use std::{
|
|||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const PACKAGE_MANAGER_URL: &str = "https://api.aleo.pm/";
|
use anyhow::Error;
|
||||||
|
use dirs::home_dir;
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
pub const LEO_CREDENTIALS_FILE: &str = "credentials";
|
pub const LEO_CREDENTIALS_FILE: &str = "credentials";
|
||||||
pub const LEO_CONFIG_FILE: &str = "config.toml";
|
pub const LEO_CONFIG_FILE: &str = "config.toml";
|
||||||
@ -75,7 +73,7 @@ impl Default for Config {
|
|||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
/// Read the config from the `config.toml` file
|
/// Read the config from the `config.toml` file
|
||||||
pub fn read_config() -> Result<Self, CLIError> {
|
pub fn read_config() -> Result<Self, Error> {
|
||||||
let config_dir = LEO_CONFIG_DIRECTORY.clone();
|
let config_dir = LEO_CONFIG_DIRECTORY.clone();
|
||||||
let config_path = LEO_CONFIG_PATH.clone();
|
let config_path = LEO_CONFIG_PATH.clone();
|
||||||
|
|
||||||
@ -112,7 +110,7 @@ impl Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Update the `automatic` configuration in the `config.toml` file.
|
/// Update the `automatic` configuration in the `config.toml` file.
|
||||||
pub fn set_update_automatic(automatic: bool) -> Result<(), CLIError> {
|
pub fn set_update_automatic(automatic: bool) -> Result<(), Error> {
|
||||||
let mut config = Self::read_config()?;
|
let mut config = Self::read_config()?;
|
||||||
|
|
||||||
if config.update.automatic != automatic {
|
if config.update.automatic != automatic {
|
||||||
|
72
leo/context.rs
Normal file
72
leo/context.rs
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||||
|
// This file is part of the Leo library.
|
||||||
|
|
||||||
|
// The Leo library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// The Leo library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use crate::{api::Api, config};
|
||||||
|
use leo_package::root::Manifest;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use std::{convert::TryFrom, env::current_dir, path::PathBuf};
|
||||||
|
|
||||||
|
pub const PACKAGE_MANAGER_URL: &str = "https://api.aleo.pm/";
|
||||||
|
|
||||||
|
/// Project context, manifest, current directory etc
|
||||||
|
/// All the info that is relevant in most of the commands
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Context {
|
||||||
|
/// Api client for Aleo PM
|
||||||
|
pub api: Api,
|
||||||
|
|
||||||
|
/// Path at which the command is called, None when default
|
||||||
|
pub path: Option<PathBuf>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Context {
|
||||||
|
pub fn dir(&self) -> Result<PathBuf> {
|
||||||
|
match &self.path {
|
||||||
|
Some(path) => Ok(path.clone()),
|
||||||
|
None => Ok(current_dir()?),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get package manifest for current context
|
||||||
|
pub fn manifest(&self) -> Result<Manifest> {
|
||||||
|
Ok(Manifest::try_from(self.dir()?.as_path())?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new context for the current directory.
|
||||||
|
pub fn create_context(path: PathBuf) -> Result<Context> {
|
||||||
|
let token = match config::read_token() {
|
||||||
|
Ok(token) => Some(token),
|
||||||
|
Err(_) => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let api = Api::new(PACKAGE_MANAGER_URL.to_string(), token);
|
||||||
|
|
||||||
|
Ok(Context { api, path: Some(path) })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns project context.
|
||||||
|
pub fn get_context() -> Result<Context> {
|
||||||
|
let token = match config::read_token() {
|
||||||
|
Ok(token) => Some(token),
|
||||||
|
Err(_) => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let api = Api::new(PACKAGE_MANAGER_URL.to_string(), token);
|
||||||
|
|
||||||
|
Ok(Context { api, path: None })
|
||||||
|
}
|
@ -1,213 +0,0 @@
|
|||||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
|
||||||
// This file is part of the Leo library.
|
|
||||||
|
|
||||||
// The Leo library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// The Leo library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
use crate::errors::*;
|
|
||||||
use leo_compiler::errors::OutputFileError;
|
|
||||||
use leo_package::errors::*;
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
|
||||||
pub enum CLIError {
|
|
||||||
#[error("{}", _0)]
|
|
||||||
AddError(AddError),
|
|
||||||
|
|
||||||
#[error("{}", _0)]
|
|
||||||
BuildError(BuildError),
|
|
||||||
|
|
||||||
#[error("{}", _0)]
|
|
||||||
ZipFileError(ZipFileError),
|
|
||||||
|
|
||||||
#[error("{}", _0)]
|
|
||||||
ChecksumFileError(ChecksumFileError),
|
|
||||||
|
|
||||||
#[error("{}", _0)]
|
|
||||||
CircuitFileError(CircuitFileError),
|
|
||||||
|
|
||||||
#[error("{}: {}", _0, _1)]
|
|
||||||
Crate(&'static str, String),
|
|
||||||
|
|
||||||
#[error("{}", _0)]
|
|
||||||
GitignoreError(GitignoreError),
|
|
||||||
|
|
||||||
#[error("{}", _0)]
|
|
||||||
InitError(InitError),
|
|
||||||
|
|
||||||
#[error("{}", _0)]
|
|
||||||
ImportsDirectoryError(ImportsDirectoryError),
|
|
||||||
|
|
||||||
#[error("{}", _0)]
|
|
||||||
InputsDirectoryError(InputsDirectoryError),
|
|
||||||
|
|
||||||
#[error("{}", _0)]
|
|
||||||
InputFileError(InputFileError),
|
|
||||||
|
|
||||||
#[error("{}", _0)]
|
|
||||||
LibraryFileError(LibraryFileError),
|
|
||||||
|
|
||||||
#[error("{}", _0)]
|
|
||||||
LoginError(LoginError),
|
|
||||||
|
|
||||||
#[error("{}", _0)]
|
|
||||||
MainFileError(MainFileError),
|
|
||||||
|
|
||||||
#[error("{}", _0)]
|
|
||||||
ManifestError(ManifestError),
|
|
||||||
|
|
||||||
#[error("{}", _0)]
|
|
||||||
NewError(NewError),
|
|
||||||
|
|
||||||
#[error("{}", _0)]
|
|
||||||
OutputFileError(OutputFileError),
|
|
||||||
|
|
||||||
#[error("{}", _0)]
|
|
||||||
OutputsDirectoryError(OutputsDirectoryError),
|
|
||||||
|
|
||||||
#[error("{}", _0)]
|
|
||||||
PackageError(PackageError),
|
|
||||||
|
|
||||||
#[error("{}", _0)]
|
|
||||||
ProofFileError(ProofFileError),
|
|
||||||
|
|
||||||
#[error("{}", _0)]
|
|
||||||
ProvingKeyFileError(ProvingKeyFileError),
|
|
||||||
|
|
||||||
#[error("{}", _0)]
|
|
||||||
PublishError(PublishError),
|
|
||||||
|
|
||||||
#[error("{}", _0)]
|
|
||||||
READMEError(READMEError),
|
|
||||||
|
|
||||||
#[error("{}", _0)]
|
|
||||||
RunError(RunError),
|
|
||||||
|
|
||||||
#[error("{}", _0)]
|
|
||||||
SNARKError(snarkvm_errors::algorithms::snark::SNARKError),
|
|
||||||
|
|
||||||
#[error("{}", _0)]
|
|
||||||
SourceDirectoryError(SourceDirectoryError),
|
|
||||||
|
|
||||||
#[error("{}", _0)]
|
|
||||||
StateFileError(StateFileError),
|
|
||||||
|
|
||||||
#[error("{}", _0)]
|
|
||||||
TestError(TestError),
|
|
||||||
|
|
||||||
#[error("TomlSerError: {0}")]
|
|
||||||
TomlSerError(#[from] toml::ser::Error),
|
|
||||||
|
|
||||||
#[error("TomlDeError: {0}")]
|
|
||||||
TomlDeError(#[from] toml::de::Error),
|
|
||||||
|
|
||||||
#[error("{}", _0)]
|
|
||||||
VerificationKeyFileError(VerificationKeyFileError),
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_cli_error {
|
|
||||||
($($t:tt), +) => {
|
|
||||||
$(impl From<$t> for CLIError {
|
|
||||||
fn from(error: $t) -> Self {
|
|
||||||
tracing::error!("{}\n", error);
|
|
||||||
|
|
||||||
CLIError::$t(error)
|
|
||||||
}
|
|
||||||
})*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_cli_error!(
|
|
||||||
AddError,
|
|
||||||
BuildError,
|
|
||||||
CircuitFileError,
|
|
||||||
ChecksumFileError,
|
|
||||||
GitignoreError,
|
|
||||||
ImportsDirectoryError,
|
|
||||||
InitError,
|
|
||||||
InputsDirectoryError,
|
|
||||||
InputFileError,
|
|
||||||
LibraryFileError,
|
|
||||||
LoginError,
|
|
||||||
MainFileError,
|
|
||||||
ManifestError,
|
|
||||||
NewError,
|
|
||||||
OutputFileError,
|
|
||||||
OutputsDirectoryError,
|
|
||||||
PackageError,
|
|
||||||
ProofFileError,
|
|
||||||
ProvingKeyFileError,
|
|
||||||
PublishError,
|
|
||||||
READMEError,
|
|
||||||
RunError,
|
|
||||||
SourceDirectoryError,
|
|
||||||
StateFileError,
|
|
||||||
TestError,
|
|
||||||
VerificationKeyFileError,
|
|
||||||
ZipFileError
|
|
||||||
);
|
|
||||||
|
|
||||||
impl From<clap::Error> for CLIError {
|
|
||||||
fn from(error: clap::Error) -> Self {
|
|
||||||
tracing::error!("{}\n", error);
|
|
||||||
CLIError::Crate("clap", error.to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<leo_compiler::errors::CompilerError> for CLIError {
|
|
||||||
fn from(error: leo_compiler::errors::CompilerError) -> Self {
|
|
||||||
tracing::error!("{}\n", error);
|
|
||||||
CLIError::Crate("leo-compiler", "Program failed due to previous error".into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<leo_input::errors::InputParserError> for CLIError {
|
|
||||||
fn from(error: leo_input::errors::InputParserError) -> Self {
|
|
||||||
tracing::error!("{}\n", error);
|
|
||||||
CLIError::Crate("leo-input", "Program failed due to previous error".into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<reqwest::Error> for CLIError {
|
|
||||||
fn from(error: reqwest::Error) -> Self {
|
|
||||||
tracing::error!("{}\n", error);
|
|
||||||
CLIError::Crate("rewquest", error.to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<snarkvm_errors::algorithms::snark::SNARKError> for CLIError {
|
|
||||||
fn from(error: snarkvm_errors::algorithms::snark::SNARKError) -> Self {
|
|
||||||
tracing::error!("{}\n", error);
|
|
||||||
CLIError::Crate("snarkvm_errors", error.to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<snarkvm_errors::gadgets::SynthesisError> for CLIError {
|
|
||||||
fn from(error: snarkvm_errors::gadgets::SynthesisError) -> Self {
|
|
||||||
tracing::error!("{}\n", error);
|
|
||||||
CLIError::Crate("snarkvm_errors", error.to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<serde_json::error::Error> for CLIError {
|
|
||||||
fn from(error: serde_json::error::Error) -> Self {
|
|
||||||
tracing::error!("{}\n", error);
|
|
||||||
CLIError::Crate("serde_json", error.to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<std::io::Error> for CLIError {
|
|
||||||
fn from(error: std::io::Error) -> Self {
|
|
||||||
tracing::error!("{}\n", error);
|
|
||||||
CLIError::Crate("std::io", error.to_string())
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
|
||||||
// This file is part of the Leo library.
|
|
||||||
|
|
||||||
// The Leo library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// The Leo library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
use std::ffi::OsString;
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
|
||||||
pub enum AddError {
|
|
||||||
#[error("Connection unavailable {:?}", _0)]
|
|
||||||
ConnectionUnavailable(OsString),
|
|
||||||
|
|
||||||
#[error("Missing author or package name: leo add author/package")]
|
|
||||||
MissingAuthorOrPackageName,
|
|
||||||
|
|
||||||
#[error("Invalid remote")]
|
|
||||||
InvalidRemote,
|
|
||||||
|
|
||||||
#[error("Not authorized in package manager. Use leo login to sign in")]
|
|
||||||
NotAuthorized,
|
|
||||||
|
|
||||||
#[error("{:?}", _0)]
|
|
||||||
ZipError(OsString),
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
|
||||||
// This file is part of the Leo library.
|
|
||||||
|
|
||||||
// The Leo library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// The Leo library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
use leo_package::errors::ManifestError;
|
|
||||||
|
|
||||||
use std::ffi::OsString;
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
|
||||||
pub enum BuildError {
|
|
||||||
#[error("main file {:?} does not exist", _0)]
|
|
||||||
MainFileDoesNotExist(OsString),
|
|
||||||
|
|
||||||
#[error("{}", _0)]
|
|
||||||
ManifestError(#[from] ManifestError),
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
|
||||||
// This file is part of the Leo library.
|
|
||||||
|
|
||||||
// The Leo library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// The Leo library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
use leo_package::errors::ManifestError;
|
|
||||||
|
|
||||||
use std::{ffi::OsString, io};
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
|
||||||
pub enum InitError {
|
|
||||||
#[error("root directory {:?} creating: {}", _0, _1)]
|
|
||||||
CreatingRootDirectory(OsString, io::Error),
|
|
||||||
|
|
||||||
#[error("directory {:?} does not exist", _0)]
|
|
||||||
DirectoryDoesNotExist(OsString),
|
|
||||||
|
|
||||||
#[error("{}", _0)]
|
|
||||||
ManifestError(#[from] ManifestError),
|
|
||||||
|
|
||||||
#[error("package name is missing - {:?}", _0)]
|
|
||||||
ProjectNameInvalid(OsString),
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
|
||||||
// This file is part of the Leo library.
|
|
||||||
|
|
||||||
// The Leo library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// The Leo library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
|
||||||
pub enum LoginError {
|
|
||||||
#[error("No token was provided in the response")]
|
|
||||||
CannotGetToken,
|
|
||||||
|
|
||||||
#[error("Could not connect to the package manager")]
|
|
||||||
NoConnectionFound,
|
|
||||||
|
|
||||||
#[error("No login credentials were provided")]
|
|
||||||
NoCredentialsProvided,
|
|
||||||
|
|
||||||
#[error("Wrong login or password")]
|
|
||||||
WrongLoginOrPassword,
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
|
||||||
// This file is part of the Leo library.
|
|
||||||
|
|
||||||
// The Leo library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// The Leo library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
pub mod add;
|
|
||||||
pub use self::add::*;
|
|
||||||
|
|
||||||
pub mod build;
|
|
||||||
pub use self::build::*;
|
|
||||||
|
|
||||||
pub mod init;
|
|
||||||
pub use self::init::*;
|
|
||||||
|
|
||||||
pub mod login;
|
|
||||||
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::*;
|
|
||||||
|
|
||||||
pub mod test;
|
|
||||||
pub use self::test::*;
|
|
@ -1,34 +0,0 @@
|
|||||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
|
||||||
// This file is part of the Leo library.
|
|
||||||
|
|
||||||
// The Leo library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// The Leo library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
use leo_package::errors::ManifestError;
|
|
||||||
|
|
||||||
use std::{ffi::OsString, io};
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
|
||||||
pub enum NewError {
|
|
||||||
#[error("root directory {:?} creating: {}", _0, _1)]
|
|
||||||
CreatingRootDirectory(OsString, io::Error),
|
|
||||||
|
|
||||||
#[error("directory {:?} already exists", _0)]
|
|
||||||
DirectoryAlreadyExists(OsString),
|
|
||||||
|
|
||||||
#[error("{}", _0)]
|
|
||||||
ManifestError(#[from] ManifestError),
|
|
||||||
|
|
||||||
#[error("package name is missing - {:?}", _0)]
|
|
||||||
ProjectNameInvalid(OsString),
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
|
||||||
// This file is part of the Leo library.
|
|
||||||
|
|
||||||
// The Leo library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// The Leo library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
use std::ffi::OsString;
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
|
||||||
pub enum PublishError {
|
|
||||||
#[error("connection unavailable {:?}", _0)]
|
|
||||||
ConnectionUnavalaible(OsString),
|
|
||||||
|
|
||||||
#[error("package toml file is missing a description")]
|
|
||||||
MissingPackageDescription,
|
|
||||||
|
|
||||||
#[error("package toml file is missing a license")]
|
|
||||||
MissingPackageLicense,
|
|
||||||
|
|
||||||
#[error("package toml file is missing a remote")]
|
|
||||||
MissingPackageRemote,
|
|
||||||
|
|
||||||
#[error("package not published {:?}", _0)]
|
|
||||||
PackageNotPublished(OsString),
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
|
||||||
// This file is part of the Leo library.
|
|
||||||
|
|
||||||
// The Leo library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// The Leo library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
use leo_package::errors::ManifestError;
|
|
||||||
|
|
||||||
use std::ffi::OsString;
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
|
||||||
pub enum RunError {
|
|
||||||
#[error("main file {:?} does not exist", _0)]
|
|
||||||
MainFileDoesNotExist(OsString),
|
|
||||||
|
|
||||||
#[error("{}", _0)]
|
|
||||||
ManifestError(#[from] ManifestError),
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
|
||||||
// This file is part of the Leo library.
|
|
||||||
|
|
||||||
// The Leo library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// The Leo library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
use std::ffi::OsString;
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
|
||||||
pub enum TestError {
|
|
||||||
#[error("could not find main or library file in {:?}", _0)]
|
|
||||||
ProgramFileDoesNotExist(OsString),
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
|
||||||
// This file is part of the Leo library.
|
|
||||||
|
|
||||||
// The Leo library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// The Leo library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
|
||||||
pub enum UpdaterError {
|
|
||||||
#[error("{}: {}", _0, _1)]
|
|
||||||
Crate(&'static str, String),
|
|
||||||
|
|
||||||
#[error("The current version {} is more recent than the release version {}", _0, _1)]
|
|
||||||
OldReleaseVersion(String, String),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<self_update::errors::Error> for UpdaterError {
|
|
||||||
fn from(error: self_update::errors::Error) -> Self {
|
|
||||||
tracing::error!("{}\n", error);
|
|
||||||
UpdaterError::Crate("self_update", error.to_string())
|
|
||||||
}
|
|
||||||
}
|
|
12
leo/lib.rs
12
leo/lib.rs
@ -14,15 +14,13 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#[macro_use]
|
pub mod api;
|
||||||
extern crate thiserror;
|
|
||||||
|
|
||||||
pub mod cli;
|
|
||||||
pub mod cli_types;
|
|
||||||
pub mod commands;
|
pub mod commands;
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod errors;
|
pub mod context;
|
||||||
pub mod logger;
|
pub mod logger;
|
||||||
pub mod synthesizer;
|
pub mod synthesizer;
|
||||||
pub mod updater;
|
pub mod updater;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests;
|
||||||
|
@ -14,8 +14,9 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use colored::Colorize;
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
use colored::Colorize;
|
||||||
use tracing::{event::Event, subscriber::Subscriber};
|
use tracing::{event::Event, subscriber::Subscriber};
|
||||||
use tracing_subscriber::{
|
use tracing_subscriber::{
|
||||||
fmt::{format::*, time::*, FmtContext, FormattedFields},
|
fmt::{format::*, time::*, FmtContext, FormattedFields},
|
||||||
|
251
leo/main.rs
251
leo/main.rs
@ -14,80 +14,197 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use leo_lang::{cli::*, commands::*, errors::CLIError, logger, updater::Updater};
|
pub mod api;
|
||||||
|
pub mod commands;
|
||||||
|
pub mod config;
|
||||||
|
pub mod context;
|
||||||
|
pub mod logger;
|
||||||
|
pub mod synthesizer;
|
||||||
|
pub mod updater;
|
||||||
|
|
||||||
use clap::{App, AppSettings, Arg};
|
use commands::{
|
||||||
|
package::{Add, Login, Logout, Publish, Remove},
|
||||||
|
Build,
|
||||||
|
Clean,
|
||||||
|
Command,
|
||||||
|
Deploy,
|
||||||
|
Init,
|
||||||
|
Lint,
|
||||||
|
New,
|
||||||
|
Prove,
|
||||||
|
Run,
|
||||||
|
Setup,
|
||||||
|
Test,
|
||||||
|
Update,
|
||||||
|
Watch,
|
||||||
|
};
|
||||||
|
|
||||||
#[cfg_attr(tarpaulin, skip)]
|
use anyhow::Error;
|
||||||
fn main() -> Result<(), CLIError> {
|
use std::process::exit;
|
||||||
let app = App::new("leo")
|
use structopt::{clap::AppSettings, StructOpt};
|
||||||
.version(env!("CARGO_PKG_VERSION"))
|
|
||||||
.about("Leo compiler and package manager")
|
|
||||||
.author("The Aleo Team <hello@aleo.org>")
|
|
||||||
.settings(&[
|
|
||||||
AppSettings::ColoredHelp,
|
|
||||||
AppSettings::DisableHelpSubcommand,
|
|
||||||
AppSettings::DisableVersion,
|
|
||||||
])
|
|
||||||
.args(&[Arg::with_name("debug")
|
|
||||||
.short("d")
|
|
||||||
.long("debug")
|
|
||||||
.help("Enables debugging mode")
|
|
||||||
.global(true)])
|
|
||||||
.subcommands(vec![
|
|
||||||
NewCommand::new().display_order(0),
|
|
||||||
InitCommand::new().display_order(1),
|
|
||||||
BuildCommand::new().display_order(2),
|
|
||||||
WatchCommand::new().display_order(3),
|
|
||||||
TestCommand::new().display_order(4),
|
|
||||||
SetupCommand::new().display_order(5),
|
|
||||||
ProveCommand::new().display_order(6),
|
|
||||||
RunCommand::new().display_order(7),
|
|
||||||
LoginCommand::new().display_order(8),
|
|
||||||
AddCommand::new().display_order(9),
|
|
||||||
RemoveCommand::new().display_order(10),
|
|
||||||
PublishCommand::new().display_order(11),
|
|
||||||
DeployCommand::new().display_order(12),
|
|
||||||
CleanCommand::new().display_order(13),
|
|
||||||
LintCommand::new().display_order(14),
|
|
||||||
UpdateCommand::new().display_order(15),
|
|
||||||
LogoutCommand::new().display_order(16),
|
|
||||||
])
|
|
||||||
.set_term_width(0);
|
|
||||||
|
|
||||||
let mut help = app.clone();
|
/// CLI Arguments entry point - includes global parameters and subcommands
|
||||||
let arguments = app.get_matches();
|
#[derive(StructOpt, Debug)]
|
||||||
|
#[structopt(name = "leo", author = "The Aleo Team <hello@aleo.org>", setting = AppSettings::ColoredHelp)]
|
||||||
|
struct Opt {
|
||||||
|
#[structopt(short, long, help = "Print additional information for debugging")]
|
||||||
|
debug: bool,
|
||||||
|
|
||||||
match arguments.subcommand() {
|
#[structopt(short, long, help = "Suppress CLI output")]
|
||||||
("new", Some(arguments)) => NewCommand::process(arguments),
|
quiet: bool,
|
||||||
("init", Some(arguments)) => InitCommand::process(arguments),
|
|
||||||
("build", Some(arguments)) => BuildCommand::process(arguments),
|
#[structopt(subcommand)]
|
||||||
("watch", Some(arguments)) => WatchCommand::process(arguments),
|
command: CommandOpts,
|
||||||
("test", Some(arguments)) => TestCommand::process(arguments),
|
|
||||||
("setup", Some(arguments)) => SetupCommand::process(arguments),
|
|
||||||
("prove", Some(arguments)) => ProveCommand::process(arguments),
|
|
||||||
("run", Some(arguments)) => RunCommand::process(arguments),
|
|
||||||
("login", Some(arguments)) => LoginCommand::process(arguments),
|
|
||||||
("add", Some(arguments)) => AddCommand::process(arguments),
|
|
||||||
("remove", Some(arguments)) => RemoveCommand::process(arguments),
|
|
||||||
("publish", Some(arguments)) => PublishCommand::process(arguments),
|
|
||||||
("deploy", Some(arguments)) => DeployCommand::process(arguments),
|
|
||||||
("clean", Some(arguments)) => CleanCommand::process(arguments),
|
|
||||||
("lint", Some(arguments)) => LintCommand::process(arguments),
|
|
||||||
("update", Some(arguments)) => UpdateCommand::process(arguments),
|
|
||||||
("logout", Some(arguments)) => LogoutCommand::process(arguments),
|
|
||||||
_ => {
|
|
||||||
// Set logging environment
|
|
||||||
match arguments.is_present("debug") {
|
|
||||||
true => logger::init_logger("leo", 2),
|
|
||||||
false => logger::init_logger("leo", 1),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Updater::print_cli();
|
///Leo compiler and package manager
|
||||||
|
#[derive(StructOpt, Debug)]
|
||||||
|
#[structopt(setting = AppSettings::ColoredHelp)]
|
||||||
|
enum CommandOpts {
|
||||||
|
#[structopt(about = "Create a new Leo package in an existing directory")]
|
||||||
|
Init {
|
||||||
|
#[structopt(flatten)]
|
||||||
|
command: Init,
|
||||||
|
},
|
||||||
|
|
||||||
help.print_help()?;
|
#[structopt(about = "Create a new Leo package in a new directory")]
|
||||||
println!();
|
New {
|
||||||
Ok(())
|
#[structopt(flatten)]
|
||||||
|
command: New,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[structopt(about = "Compile the current package as a program")]
|
||||||
|
Build {
|
||||||
|
#[structopt(flatten)]
|
||||||
|
command: Build,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[structopt(about = "Run a program setup")]
|
||||||
|
Setup {
|
||||||
|
#[structopt(flatten)]
|
||||||
|
command: Setup,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[structopt(about = "Run the program and produce a proof")]
|
||||||
|
Prove {
|
||||||
|
#[structopt(flatten)]
|
||||||
|
command: Prove,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[structopt(about = "Run a program with input variables")]
|
||||||
|
Run {
|
||||||
|
#[structopt(flatten)]
|
||||||
|
command: Run,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[structopt(about = "Clean the output directory")]
|
||||||
|
Clean {
|
||||||
|
#[structopt(flatten)]
|
||||||
|
command: Clean,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[structopt(about = "Watch for changes of Leo source files")]
|
||||||
|
Watch {
|
||||||
|
#[structopt(flatten)]
|
||||||
|
command: Watch,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[structopt(about = "Update Leo to the latest version")]
|
||||||
|
Update {
|
||||||
|
#[structopt(flatten)]
|
||||||
|
command: Update,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[structopt(about = "Compile and run all tests in the current package")]
|
||||||
|
Test {
|
||||||
|
#[structopt(flatten)]
|
||||||
|
command: Test,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[structopt(about = "Install a package from the Aleo Package Manager")]
|
||||||
|
Add {
|
||||||
|
#[structopt(flatten)]
|
||||||
|
command: Add,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[structopt(about = "Login to the Aleo Package Manager")]
|
||||||
|
Login {
|
||||||
|
#[structopt(flatten)]
|
||||||
|
command: Login,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[structopt(about = "Logout of the Aleo Package Manager")]
|
||||||
|
Logout {
|
||||||
|
#[structopt(flatten)]
|
||||||
|
command: Logout,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[structopt(about = "Publish the current package to the Aleo Package Manager")]
|
||||||
|
Publish {
|
||||||
|
#[structopt(flatten)]
|
||||||
|
command: Publish,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[structopt(about = "Uninstall a package from the current package")]
|
||||||
|
Remove {
|
||||||
|
#[structopt(flatten)]
|
||||||
|
command: Remove,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[structopt(about = "Lints the Leo files in the package (*)")]
|
||||||
|
Lint {
|
||||||
|
#[structopt(flatten)]
|
||||||
|
command: Lint,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[structopt(about = "Deploy the current package as a program to the network (*)")]
|
||||||
|
Deploy {
|
||||||
|
#[structopt(flatten)]
|
||||||
|
command: Deploy,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// read command line arguments
|
||||||
|
let opt = Opt::from_args();
|
||||||
|
|
||||||
|
if !opt.quiet {
|
||||||
|
// init logger with optional debug flag
|
||||||
|
logger::init_logger("leo", match opt.debug {
|
||||||
|
false => 1,
|
||||||
|
true => 2,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_error(match opt.command {
|
||||||
|
CommandOpts::Init { command } => command.try_execute(),
|
||||||
|
CommandOpts::New { command } => command.try_execute(),
|
||||||
|
CommandOpts::Build { command } => command.try_execute(),
|
||||||
|
CommandOpts::Setup { command } => command.try_execute(),
|
||||||
|
CommandOpts::Prove { command } => command.try_execute(),
|
||||||
|
CommandOpts::Test { command } => command.try_execute(),
|
||||||
|
CommandOpts::Run { command } => command.try_execute(),
|
||||||
|
CommandOpts::Clean { command } => command.try_execute(),
|
||||||
|
CommandOpts::Watch { command } => command.try_execute(),
|
||||||
|
CommandOpts::Update { command } => command.try_execute(),
|
||||||
|
|
||||||
|
CommandOpts::Add { command } => command.try_execute(),
|
||||||
|
CommandOpts::Login { command } => command.try_execute(),
|
||||||
|
CommandOpts::Logout { command } => command.try_execute(),
|
||||||
|
CommandOpts::Publish { command } => command.try_execute(),
|
||||||
|
CommandOpts::Remove { command } => command.try_execute(),
|
||||||
|
|
||||||
|
CommandOpts::Lint { command } => command.try_execute(),
|
||||||
|
CommandOpts::Deploy { command } => command.try_execute(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_error<T>(res: Result<T, Error>) -> T {
|
||||||
|
match res {
|
||||||
|
Ok(t) => t,
|
||||||
|
Err(err) => {
|
||||||
|
eprintln!("Error: {}", err);
|
||||||
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,9 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::synthesizer::{CircuitSynthesizer, SerializedField, SerializedIndex};
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use snarkvm_curves::bls12_377::Bls12_377;
|
use snarkvm_curves::bls12_377::Bls12_377;
|
||||||
use snarkvm_errors::curves::FieldError;
|
use snarkvm_errors::curves::FieldError;
|
||||||
use snarkvm_models::{
|
use snarkvm_models::{
|
||||||
@ -23,8 +24,7 @@ use snarkvm_models::{
|
|||||||
gadgets::r1cs::{ConstraintSystem, Index},
|
gadgets::r1cs::{ConstraintSystem, Index},
|
||||||
};
|
};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use crate::synthesizer::{CircuitSynthesizer, SerializedField, SerializedIndex};
|
||||||
use std::convert::TryFrom;
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct SerializedCircuit {
|
pub struct SerializedCircuit {
|
||||||
|
@ -14,12 +14,12 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use snarkvm_errors::curves::FieldError;
|
use std::{convert::TryFrom, str::FromStr};
|
||||||
use snarkvm_models::curves::{Field, Fp256, Fp256Parameters};
|
|
||||||
|
|
||||||
use num_bigint::BigUint;
|
use num_bigint::BigUint;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{convert::TryFrom, str::FromStr};
|
use snarkvm_errors::curves::FieldError;
|
||||||
|
use snarkvm_models::curves::{Field, Fp256, Fp256Parameters};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct SerializedField(pub String);
|
pub struct SerializedField(pub String);
|
||||||
|
@ -14,9 +14,8 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use snarkvm_models::gadgets::r1cs::Index;
|
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use snarkvm_models::gadgets::r1cs::Index;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub enum SerializedIndex {
|
pub enum SerializedIndex {
|
||||||
|
130
leo/tests/mod.rs
Normal file
130
leo/tests/mod.rs
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||||
|
// This file is part of the Leo library.
|
||||||
|
|
||||||
|
// The Leo library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// The Leo library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
commands::{
|
||||||
|
package::{Login, Logout},
|
||||||
|
Build,
|
||||||
|
Command,
|
||||||
|
Prove,
|
||||||
|
Run,
|
||||||
|
Setup,
|
||||||
|
Test,
|
||||||
|
Update,
|
||||||
|
UpdateAutomatic,
|
||||||
|
},
|
||||||
|
context::{create_context, Context},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Path to the only complex Leo program that we have
|
||||||
|
/// - relative to source dir - where Cargo.toml is located
|
||||||
|
const PEDERSEN_HASH_PATH: &str = "./examples/pedersen-hash/";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn build_pedersen_hash() -> Result<()> {
|
||||||
|
Build::new().apply(ctx()?, ())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn setup_pedersen_hash() -> Result<()> {
|
||||||
|
let build = Build::new().apply(ctx()?, ())?;
|
||||||
|
Setup::new(false).apply(ctx()?, build.clone())?;
|
||||||
|
Setup::new(true).apply(ctx()?, build)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn prove_pedersen_hash() -> Result<()> {
|
||||||
|
let build = Build::new().apply(ctx()?, ())?;
|
||||||
|
let setup = Setup::new(false).apply(ctx()?, build)?;
|
||||||
|
Prove::new(false).apply(ctx()?, setup.clone())?;
|
||||||
|
Prove::new(true).apply(ctx()?, setup)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn run_pedersen_hash() -> Result<()> {
|
||||||
|
let build = Build::new().apply(ctx()?, ())?;
|
||||||
|
let setup = Setup::new(false).apply(ctx()?, build)?;
|
||||||
|
let prove = Prove::new(false).apply(ctx()?, setup)?;
|
||||||
|
Run::new(false).apply(ctx()?, prove.clone())?;
|
||||||
|
Run::new(true).apply(ctx()?, prove)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn test_pedersen_hash() -> Result<()> {
|
||||||
|
let mut main_file = PathBuf::from(PEDERSEN_HASH_PATH);
|
||||||
|
main_file.push("src/main.leo");
|
||||||
|
|
||||||
|
Test::new(Vec::new()).apply(ctx()?, ())?;
|
||||||
|
Test::new(vec![main_file]).apply(ctx()?, ())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn test_logout() -> Result<()> {
|
||||||
|
Logout::new().apply(ctx()?, ())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decided to not go all-in on error messages since they might change in the future
|
||||||
|
// So this test only tells that error cases are errors
|
||||||
|
#[test]
|
||||||
|
pub fn login_incorrect_credentials_or_token() -> Result<()> {
|
||||||
|
// no credentials passed
|
||||||
|
let login = Login::new(None, None, None).apply(ctx()?, ());
|
||||||
|
assert!(login.is_err());
|
||||||
|
|
||||||
|
// incorrect token
|
||||||
|
let login = Login::new(Some("none".to_string()), None, None).apply(ctx()?, ());
|
||||||
|
assert!(login.is_err());
|
||||||
|
|
||||||
|
// only user, no pass
|
||||||
|
let login = Login::new(None, Some("user".to_string()), None).apply(ctx()?, ());
|
||||||
|
assert!(login.is_err());
|
||||||
|
|
||||||
|
// no user, only pass
|
||||||
|
let login = Login::new(None, None, Some("pass".to_string())).apply(ctx()?, ());
|
||||||
|
assert!(login.is_err());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn leo_update_and_update_automatic() -> Result<()> {
|
||||||
|
Update::new(true, true, None).apply(ctx()?, ())?;
|
||||||
|
Update::new(false, true, None).apply(ctx()?, ())?;
|
||||||
|
Update::new(false, false, None).apply(ctx()?, ())?;
|
||||||
|
|
||||||
|
Update::new(false, false, Some(UpdateAutomatic::Automatic { value: true })).apply(ctx()?, ())?;
|
||||||
|
Update::new(false, false, Some(UpdateAutomatic::Automatic { value: false })).apply(ctx()?, ())?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create context for Pedersen Hash example
|
||||||
|
fn ctx() -> Result<Context> {
|
||||||
|
let path = PathBuf::from(&PEDERSEN_HASH_PATH);
|
||||||
|
let ctx = create_context(path)?;
|
||||||
|
|
||||||
|
Ok(ctx)
|
||||||
|
}
|
@ -13,8 +13,10 @@
|
|||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
use crate::{config::Config, errors::UpdaterError};
|
|
||||||
|
|
||||||
|
use crate::config::Config;
|
||||||
|
|
||||||
|
use anyhow::{anyhow, Result};
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
use self_update::{backends::github, version::bump_is_greater, Status};
|
use self_update::{backends::github, version::bump_is_greater, Status};
|
||||||
|
|
||||||
@ -27,7 +29,7 @@ impl Updater {
|
|||||||
const LEO_REPO_OWNER: &'static str = "AleoHQ";
|
const LEO_REPO_OWNER: &'static str = "AleoHQ";
|
||||||
|
|
||||||
/// Show all available releases for `leo`.
|
/// Show all available releases for `leo`.
|
||||||
pub fn show_available_releases() -> Result<(), UpdaterError> {
|
pub fn show_available_releases() -> Result<()> {
|
||||||
let releases = github::ReleaseList::configure()
|
let releases = github::ReleaseList::configure()
|
||||||
.repo_owner(Self::LEO_REPO_OWNER)
|
.repo_owner(Self::LEO_REPO_OWNER)
|
||||||
.repo_name(Self::LEO_REPO_NAME)
|
.repo_name(Self::LEO_REPO_NAME)
|
||||||
@ -46,7 +48,7 @@ impl Updater {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Update `leo` to the latest release.
|
/// Update `leo` to the latest release.
|
||||||
pub fn update_to_latest_release(show_output: bool) -> Result<Status, UpdaterError> {
|
pub fn update_to_latest_release(show_output: bool) -> Result<Status> {
|
||||||
let status = github::Update::configure()
|
let status = github::Update::configure()
|
||||||
.repo_owner(Self::LEO_REPO_OWNER)
|
.repo_owner(Self::LEO_REPO_OWNER)
|
||||||
.repo_name(Self::LEO_REPO_NAME)
|
.repo_name(Self::LEO_REPO_NAME)
|
||||||
@ -62,7 +64,7 @@ impl Updater {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Check if there is an available update for `leo` and return the newest release.
|
/// Check if there is an available update for `leo` and return the newest release.
|
||||||
pub fn update_available() -> Result<String, UpdaterError> {
|
pub fn update_available() -> Result<String> {
|
||||||
let updater = github::Update::configure()
|
let updater = github::Update::configure()
|
||||||
.repo_owner(Self::LEO_REPO_OWNER)
|
.repo_owner(Self::LEO_REPO_OWNER)
|
||||||
.repo_name(Self::LEO_REPO_NAME)
|
.repo_name(Self::LEO_REPO_NAME)
|
||||||
@ -76,7 +78,11 @@ impl Updater {
|
|||||||
if bump_is_greater(¤t_version, &latest_release.version)? {
|
if bump_is_greater(¤t_version, &latest_release.version)? {
|
||||||
Ok(latest_release.version)
|
Ok(latest_release.version)
|
||||||
} else {
|
} else {
|
||||||
Err(UpdaterError::OldReleaseVersion(current_version, latest_release.version))
|
Err(anyhow!(
|
||||||
|
"Old release version {} {}",
|
||||||
|
current_version,
|
||||||
|
latest_release.version
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user