mirror of
https://github.com/AleoHQ/leo.git
synced 2024-11-13 08:47:17 +03:00
Leo CLI is now on StructOpt and Anyhow
Features: - introduces new Command and Route traits for Leo commands and Aleo PM API - most of the CLI code replace with higher-level abstraction - StructOpt - anyhow used for error handling, no more custom error classes - improves API - now every status code has its business logic - adds global flags (e.g. --quiet to suppress output) - error messages improved for convenience and better user experience Closes: - #604 - #599 - #584 - #277 - #376
This commit is contained in:
parent
1898cc6840
commit
2ff2db2570
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 add argus4130/xnor
|
||||
leo remove xnor
|
||||
leo clean
|
||||
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"
|
||||
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]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.17"
|
||||
@ -1388,6 +1397,7 @@ dependencies = [
|
||||
name = "leo-lang"
|
||||
version = "1.2.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"colored",
|
||||
"console",
|
||||
@ -1416,6 +1426,7 @@ dependencies = [
|
||||
"snarkvm-gadgets",
|
||||
"snarkvm-models",
|
||||
"snarkvm-utilities",
|
||||
"structopt",
|
||||
"thiserror",
|
||||
"toml",
|
||||
"tracing",
|
||||
@ -2052,6 +2063,7 @@ dependencies = [
|
||||
"proc-macro-error-attr",
|
||||
"proc-macro2 1.0.24",
|
||||
"quote 1.0.7",
|
||||
"syn 1.0.60",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
@ -2809,6 +2821,30 @@ version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "subtle"
|
||||
version = "1.0.0"
|
||||
@ -3152,6 +3188,12 @@ dependencies = [
|
||||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.8"
|
||||
|
@ -89,6 +89,12 @@ default-features = false
|
||||
[dependencies.snarkvm-utilities]
|
||||
version = "0.0.3"
|
||||
|
||||
[dependencies.anyhow]
|
||||
version = "1.0"
|
||||
|
||||
[dependencies.structopt]
|
||||
version = "0.3"
|
||||
|
||||
[dependencies.clap]
|
||||
version = "2.33.3"
|
||||
|
||||
|
@ -7,7 +7,7 @@ circuit PedersenHash {
|
||||
}
|
||||
|
||||
function hash(self, bits: [bool; 256]) -> group {
|
||||
let mut digest: group = 0;
|
||||
let mut digest: group = 0group;
|
||||
for i in 0..256 {
|
||||
if bits[i] {
|
||||
digest += self.parameters[i];
|
||||
|
203
leo/api.rs
Normal file
203
leo/api.rs
Normal file
@ -0,0 +1,203 @@
|
||||
// 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 serde::Serialize;
|
||||
|
||||
use anyhow::{anyhow, Error, Result};
|
||||
use reqwest::{
|
||||
blocking::{Client, Response},
|
||||
Method,
|
||||
StatusCode,
|
||||
};
|
||||
|
||||
/// 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(())
|
||||
}
|
||||
}
|
@ -14,56 +14,51 @@
|
||||
// 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,
|
||||
synthesizer::{CircuitSynthesizer, SerializedCircuit},
|
||||
};
|
||||
use crate::synthesizer::{CircuitSynthesizer, SerializedCircuit};
|
||||
|
||||
use crate::{commands::Command, context::Context};
|
||||
|
||||
use leo_compiler::{compiler::Compiler, group::targets::edwards_bls12::EdwardsGroupType};
|
||||
use leo_package::{
|
||||
inputs::*,
|
||||
outputs::{ChecksumFile, CircuitFile, OutputsDirectory, OUTPUTS_DIRECTORY_NAME},
|
||||
root::Manifest,
|
||||
source::{LibraryFile, MainFile, LIBRARY_FILENAME, MAIN_FILENAME, SOURCE_DIRECTORY_NAME},
|
||||
};
|
||||
|
||||
use snarkvm_curves::{bls12_377::Bls12_377, edwards_bls12::Fq};
|
||||
use snarkvm_models::gadgets::r1cs::ConstraintSystem;
|
||||
|
||||
use clap::ArgMatches;
|
||||
use std::{convert::TryFrom, env::current_dir, time::Instant};
|
||||
use anyhow::Result;
|
||||
use std::convert::TryFrom;
|
||||
use structopt::StructOpt;
|
||||
use tracing::span::Span;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BuildCommand;
|
||||
/// Compile and build program command
|
||||
#[derive(StructOpt, Debug, Default)]
|
||||
#[structopt(setting = structopt::clap::AppSettings::ColoredHelp)]
|
||||
pub struct Build {}
|
||||
|
||||
impl CLI for BuildCommand {
|
||||
type Options = ();
|
||||
impl Build {
|
||||
pub fn new() -> Build {
|
||||
Build {}
|
||||
}
|
||||
}
|
||||
|
||||
impl Command for Build {
|
||||
type Input = ();
|
||||
type Output = Option<(Compiler<Fq, EdwardsGroupType>, bool)>;
|
||||
|
||||
const ABOUT: AboutType = "Compile the current package as a program";
|
||||
const ARGUMENTS: &'static [ArgumentType] = &[];
|
||||
const FLAGS: &'static [FlagType] = &[];
|
||||
const NAME: NameType = "build";
|
||||
const OPTIONS: &'static [OptionType] = &[];
|
||||
const SUBCOMMANDS: &'static [SubCommandType] = &[];
|
||||
fn log_span(&self) -> Span {
|
||||
tracing::span!(tracing::Level::INFO, "Build")
|
||||
}
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
fn parse(_arguments: &ArgMatches) -> Result<Self::Options, CLIError> {
|
||||
fn prelude(&self) -> Result<Self::Input> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
fn output(_options: Self::Options) -> Result<Self::Output, CLIError> {
|
||||
// Begin "Compiling" context for console logging
|
||||
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();
|
||||
fn apply(self, ctx: Context, _: Self::Input) -> Result<Self::Output> {
|
||||
let path = ctx.dir()?;
|
||||
let package_name = ctx.manifest()?.get_package_name();
|
||||
|
||||
// Sanitize the package path to the root directory
|
||||
let mut package_path = path.clone();
|
||||
@ -77,9 +72,6 @@ impl CLI for BuildCommand {
|
||||
|
||||
tracing::info!("Starting...");
|
||||
|
||||
// Start the timer
|
||||
let start = Instant::now();
|
||||
|
||||
// Compile the package starting with the lib.leo file
|
||||
if LibraryFile::exists_at(&package_path) {
|
||||
// Construct the path to the library file in the source directory
|
||||
@ -185,21 +177,9 @@ impl CLI for BuildCommand {
|
||||
|
||||
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)));
|
||||
}
|
||||
|
||||
drop(enter);
|
||||
|
||||
// Return None when compiling a package for publishing
|
||||
// The published package does not need to have a main.leo
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
@ -14,45 +14,39 @@
|
||||
// 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::{
|
||||
outputs::{ChecksumFile, ProofFile, ProvingKeyFile, VerificationKeyFile},
|
||||
root::Manifest,
|
||||
};
|
||||
|
||||
use clap::ArgMatches;
|
||||
use crate::{commands::Command, context::Context};
|
||||
use anyhow::Result;
|
||||
use leo_compiler::OutputFile;
|
||||
use leo_package::outputs::CircuitFile;
|
||||
use std::{convert::TryFrom, env::current_dir};
|
||||
use leo_package::outputs::{ChecksumFile, CircuitFile, ProofFile, ProvingKeyFile, VerificationKeyFile};
|
||||
use structopt::StructOpt;
|
||||
use tracing::span::Span;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CleanCommand;
|
||||
/// Clean outputs folder command
|
||||
#[derive(StructOpt, Debug, Default)]
|
||||
#[structopt(setting = structopt::clap::AppSettings::ColoredHelp)]
|
||||
pub struct Clean {}
|
||||
|
||||
impl CLI for CleanCommand {
|
||||
type Options = ();
|
||||
impl Clean {
|
||||
pub fn new() -> Clean {
|
||||
Clean {}
|
||||
}
|
||||
}
|
||||
|
||||
impl Command for Clean {
|
||||
type Input = ();
|
||||
type Output = ();
|
||||
|
||||
const ABOUT: AboutType = "Clean the output directory";
|
||||
const ARGUMENTS: &'static [ArgumentType] = &[];
|
||||
const FLAGS: &'static [FlagType] = &[];
|
||||
const NAME: NameType = "clean";
|
||||
const OPTIONS: &'static [OptionType] = &[];
|
||||
const SUBCOMMANDS: &'static [SubCommandType] = &[];
|
||||
fn log_span(&self) -> Span {
|
||||
tracing::span!(tracing::Level::INFO, "Cleaning")
|
||||
}
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
fn parse(_arguments: &ArgMatches) -> Result<Self::Options, CLIError> {
|
||||
fn prelude(&self) -> Result<Self::Input> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
fn output(_options: Self::Options) -> Result<Self::Output, CLIError> {
|
||||
// Begin "Clean" context for console logging
|
||||
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();
|
||||
fn apply(self, ctx: Context, _: Self::Input) -> Result<Self::Output> {
|
||||
let path = ctx.dir()?;
|
||||
let package_name = ctx.manifest()?.get_package_name();
|
||||
|
||||
// Remove the checksum from the output directory
|
||||
ChecksumFile::new(&package_name).remove(&path)?;
|
||||
@ -72,14 +66,6 @@ impl CLI for CleanCommand {
|
||||
// Remove the proof from the output directory
|
||||
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(())
|
||||
}
|
||||
}
|
||||
|
@ -14,65 +14,35 @@
|
||||
// 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::*,
|
||||
commands::BuildCommand,
|
||||
errors::{CLIError, RunError},
|
||||
};
|
||||
use leo_package::{
|
||||
root::Manifest,
|
||||
source::{MAIN_FILENAME, SOURCE_DIRECTORY_NAME},
|
||||
};
|
||||
use crate::{commands::Command, context::Context};
|
||||
use anyhow::Result;
|
||||
use structopt::StructOpt;
|
||||
use tracing::span::Span;
|
||||
|
||||
use clap::ArgMatches;
|
||||
use std::{convert::TryFrom, env::current_dir};
|
||||
/// Deploy Leo program to the network
|
||||
#[derive(StructOpt, Debug, Default)]
|
||||
#[structopt(setting = structopt::clap::AppSettings::ColoredHelp)]
|
||||
pub struct Deploy {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DeployCommand;
|
||||
impl Deploy {
|
||||
pub fn new() -> Deploy {
|
||||
Deploy {}
|
||||
}
|
||||
}
|
||||
|
||||
impl CLI for DeployCommand {
|
||||
type Options = ();
|
||||
impl Command for Deploy {
|
||||
type Input = ();
|
||||
type Output = ();
|
||||
|
||||
const ABOUT: AboutType = "Deploy the current package as a program to the network (*)";
|
||||
const ARGUMENTS: &'static [ArgumentType] = &[];
|
||||
const FLAGS: &'static [FlagType] = &[];
|
||||
const NAME: NameType = "deploy";
|
||||
const OPTIONS: &'static [OptionType] = &[];
|
||||
const SUBCOMMANDS: &'static [SubCommandType] = &[];
|
||||
fn log_span(&self) -> Span {
|
||||
tracing::span!(tracing::Level::INFO, "Deploy")
|
||||
}
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
fn parse(_arguments: &ArgMatches) -> Result<Self::Options, CLIError> {
|
||||
fn prelude(&self) -> Result<Self::Input> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
fn output(options: Self::Options) -> Result<Self::Output, CLIError> {
|
||||
// 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(),
|
||||
)))
|
||||
}
|
||||
}
|
||||
fn apply(self, _: Context, _: Self::Input) -> Result<Self::Output> {
|
||||
unimplemented!("Deploy command has not been implemented yet");
|
||||
}
|
||||
}
|
||||
|
@ -14,58 +14,52 @@
|
||||
// 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, InitError},
|
||||
};
|
||||
use crate::{commands::Command, context::Context};
|
||||
use anyhow::{anyhow, Result};
|
||||
use leo_package::LeoPackage;
|
||||
|
||||
use clap::ArgMatches;
|
||||
use std::env::current_dir;
|
||||
use structopt::StructOpt;
|
||||
use tracing::span::Span;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct InitCommand;
|
||||
/// Init Leo project command within current directory
|
||||
#[derive(StructOpt, Debug)]
|
||||
#[structopt(setting = structopt::clap::AppSettings::ColoredHelp)]
|
||||
pub struct Init {
|
||||
#[structopt(help = "Init as a library (containing lib.leo)", long = "lib", short = "l")]
|
||||
is_lib: Option<bool>,
|
||||
}
|
||||
|
||||
impl CLI for InitCommand {
|
||||
type Options = bool;
|
||||
impl Init {
|
||||
pub fn new(is_lib: Option<bool>) -> Init {
|
||||
Init { is_lib }
|
||||
}
|
||||
}
|
||||
|
||||
impl Command for Init {
|
||||
type Input = ();
|
||||
type Output = ();
|
||||
|
||||
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"))
|
||||
fn log_span(&self) -> Span {
|
||||
tracing::span!(tracing::Level::INFO, "Initializing")
|
||||
}
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
fn output(options: Self::Options) -> Result<Self::Output, CLIError> {
|
||||
// Begin "Initializing" context for console logging
|
||||
let span = tracing::span!(tracing::Level::INFO, "Initializing");
|
||||
let _enter = span.enter();
|
||||
fn prelude(&self) -> Result<Self::Input> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn apply(self, _: Context, _: Self::Input) -> Result<Self::Output> {
|
||||
let path = current_dir()?;
|
||||
|
||||
// Derive the package name
|
||||
let package_name = path
|
||||
.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();
|
||||
|
||||
// Verify the directory does not exist
|
||||
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)?;
|
||||
|
||||
tracing::info!("Successfully initialized package \"{}\"\n", package_name);
|
||||
LeoPackage::initialize(&package_name, self.is_lib.unwrap_or(false), &path)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -14,65 +14,35 @@
|
||||
// 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::*,
|
||||
commands::BuildCommand,
|
||||
errors::{CLIError, RunError},
|
||||
};
|
||||
use leo_package::{
|
||||
root::Manifest,
|
||||
source::{MAIN_FILENAME, SOURCE_DIRECTORY_NAME},
|
||||
};
|
||||
use crate::{commands::Command, context::Context};
|
||||
use anyhow::Result;
|
||||
use structopt::StructOpt;
|
||||
use tracing::span::Span;
|
||||
|
||||
use clap::ArgMatches;
|
||||
use std::{convert::TryFrom, env::current_dir};
|
||||
/// Lint Leo code command
|
||||
#[derive(StructOpt, Debug, Default)]
|
||||
#[structopt(setting = structopt::clap::AppSettings::ColoredHelp)]
|
||||
pub struct Lint {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LintCommand;
|
||||
impl Lint {
|
||||
pub fn new() -> Lint {
|
||||
Lint {}
|
||||
}
|
||||
}
|
||||
|
||||
impl CLI for LintCommand {
|
||||
type Options = ();
|
||||
impl Command for Lint {
|
||||
type Input = ();
|
||||
type Output = ();
|
||||
|
||||
const ABOUT: AboutType = "Lints the Leo files in the package (*)";
|
||||
const ARGUMENTS: &'static [ArgumentType] = &[];
|
||||
const FLAGS: &'static [FlagType] = &[];
|
||||
const NAME: NameType = "lint";
|
||||
const OPTIONS: &'static [OptionType] = &[];
|
||||
const SUBCOMMANDS: &'static [SubCommandType] = &[];
|
||||
fn log_span(&self) -> Span {
|
||||
tracing::span!(tracing::Level::INFO, "Linting")
|
||||
}
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
fn parse(_arguments: &ArgMatches) -> Result<Self::Options, CLIError> {
|
||||
fn prelude(&self) -> Result<Self::Input> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
fn output(options: Self::Options) -> Result<Self::Output, CLIError> {
|
||||
// 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(),
|
||||
)))
|
||||
}
|
||||
}
|
||||
fn apply(self, _: Context, _: Self::Input) -> Result<Self::Output> {
|
||||
unimplemented!("Lint command has not been implemented yet");
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
pub mod add;
|
||||
pub use self::add::*;
|
||||
use crate::context::{get_context, Context};
|
||||
use anyhow::Result;
|
||||
use std::time::Instant;
|
||||
use tracing::span::Span;
|
||||
|
||||
// local program commands
|
||||
pub mod build;
|
||||
pub use self::build::*;
|
||||
pub use build::Build;
|
||||
|
||||
pub mod clean;
|
||||
pub use self::clean::*;
|
||||
|
||||
pub mod deploy;
|
||||
pub use self::deploy::*;
|
||||
pub use clean::Clean;
|
||||
|
||||
pub mod init;
|
||||
pub use self::init::*;
|
||||
|
||||
pub mod lint;
|
||||
pub use self::lint::*;
|
||||
|
||||
pub mod login;
|
||||
pub use self::login::*;
|
||||
|
||||
pub mod logout;
|
||||
pub use self::logout::*;
|
||||
pub use init::Init;
|
||||
|
||||
pub mod new;
|
||||
pub use self::new::*;
|
||||
pub use new::New;
|
||||
|
||||
pub mod prove;
|
||||
pub use self::prove::*;
|
||||
|
||||
pub mod publish;
|
||||
pub use self::publish::*;
|
||||
pub use prove::Prove;
|
||||
|
||||
pub mod run;
|
||||
pub use self::run::*;
|
||||
pub use run::Run;
|
||||
|
||||
pub mod setup;
|
||||
pub use self::setup::*;
|
||||
pub use setup::Setup;
|
||||
|
||||
pub mod test;
|
||||
pub use self::test::*;
|
||||
|
||||
pub mod remove;
|
||||
pub use self::remove::*;
|
||||
|
||||
pub mod update;
|
||||
pub use self::update::*;
|
||||
pub use test::Test;
|
||||
|
||||
pub mod watch;
|
||||
pub use self::watch::*;
|
||||
pub use watch::Watch;
|
||||
|
||||
pub mod update;
|
||||
pub use update::{Sub as UpdateAutomatic, Update};
|
||||
|
||||
// aleo pm related commands
|
||||
pub mod package;
|
||||
|
||||
// not implemented
|
||||
pub mod deploy;
|
||||
pub use deploy::Deploy;
|
||||
|
||||
pub mod lint;
|
||||
pub use lint::Lint;
|
||||
|
||||
/// 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,59 @@
|
||||
// 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, NewError},
|
||||
};
|
||||
use crate::{commands::Command, context::Context};
|
||||
use anyhow::{anyhow, Result};
|
||||
|
||||
use leo_package::LeoPackage;
|
||||
|
||||
use clap::ArgMatches;
|
||||
use std::{env::current_dir, fs};
|
||||
use structopt::StructOpt;
|
||||
use tracing::span::Span;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct NewCommand;
|
||||
/// Create new Leo project
|
||||
#[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 {
|
||||
type Options = (Option<String>, bool);
|
||||
#[structopt(help = "Init as a library (containing lib.leo)", long = "lib", short = "l")]
|
||||
is_lib: bool,
|
||||
}
|
||||
|
||||
impl New {
|
||||
pub fn new(name: String, is_lib: bool) -> New {
|
||||
New { name, is_lib }
|
||||
}
|
||||
}
|
||||
|
||||
impl Command for New {
|
||||
type Input = ();
|
||||
type Output = ();
|
||||
|
||||
const ABOUT: AboutType = "Create a new Leo package in a new directory";
|
||||
const ARGUMENTS: &'static [ArgumentType] = &[
|
||||
// (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)),
|
||||
}
|
||||
fn log_span(&self) -> Span {
|
||||
tracing::span!(tracing::Level::INFO, "New")
|
||||
}
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
fn output(options: Self::Options) -> Result<Self::Output, CLIError> {
|
||||
// Begin "Initializing" context for console logging
|
||||
let span = tracing::span!(tracing::Level::INFO, "Initializing");
|
||||
let _enter = span.enter();
|
||||
fn prelude(&self) -> Result<Self::Input> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn apply(self, _: Context, _: Self::Input) -> Result<Self::Output> {
|
||||
let mut path = current_dir()?;
|
||||
|
||||
// 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(),
|
||||
};
|
||||
let package_name = self.name;
|
||||
|
||||
// Derive the package directory path
|
||||
path.push(&package_name);
|
||||
|
||||
// Verify the package directory path does not exist yet
|
||||
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
|
||||
fs::create_dir_all(&path)
|
||||
.map_err(|error| NewError::CreatingRootDirectory(path.as_os_str().to_owned(), error))?;
|
||||
fs::create_dir_all(&path).map_err(|err| anyhow!("Could not create directory {}", err))?;
|
||||
|
||||
LeoPackage::initialize(&package_name, options.1, &path)?;
|
||||
|
||||
tracing::info!("Successfully initialized package \"{}\"\n", package_name);
|
||||
LeoPackage::initialize(&package_name, self.is_lib, &path)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
160
leo/commands/package/add.rs
Normal file
160
leo/commands/package/add.rs
Normal file
@ -0,0 +1,160 @@
|
||||
// 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::imports::{ImportsDirectory, IMPORTS_DIRECTORY_NAME};
|
||||
use tracing::Span;
|
||||
|
||||
use std::{
|
||||
fs::{create_dir_all, File},
|
||||
io::{Read, Write},
|
||||
};
|
||||
|
||||
use crate::{commands::Command, context::Context};
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use structopt::StructOpt;
|
||||
|
||||
use crate::api::Fetch;
|
||||
|
||||
/// 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(())
|
||||
}
|
||||
}
|
118
leo/commands/package/login.rs
Normal file
118
leo/commands/package/login.rs
Normal file
@ -0,0 +1,118 @@
|
||||
// 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 crate::api::{Login as LoginRoute, Profile as ProfileRoute};
|
||||
|
||||
use crate::config::*;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use structopt::StructOpt;
|
||||
use tracing::Span;
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub const LOGIN_URL: &str = "v1/account/authenticate";
|
||||
pub const PROFILE_URL: &str = "v1/account/my_profile";
|
||||
|
||||
/// 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,38 @@
|
||||
// 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 logout
|
||||
//
|
||||
use crate::{commands::Command, context::Context};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LogoutCommand;
|
||||
|
||||
use crate::{cli::CLI, cli_types::*, config::remove_token, errors::CLIError};
|
||||
use crate::config::remove_token;
|
||||
use anyhow::Result;
|
||||
use std::io::ErrorKind;
|
||||
use structopt::StructOpt;
|
||||
use tracing::Span;
|
||||
|
||||
impl CLI for LogoutCommand {
|
||||
type Options = ();
|
||||
/// Remove credentials for Aleo PM from .leo directory
|
||||
#[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 = ();
|
||||
|
||||
const ABOUT: AboutType = "Logout from Aleo Package Manager";
|
||||
const ARGUMENTS: &'static [ArgumentType] = &[];
|
||||
const FLAGS: &'static [FlagType] = &[];
|
||||
const NAME: NameType = "logout";
|
||||
const OPTIONS: &'static [OptionType] = &[];
|
||||
const SUBCOMMANDS: &'static [SubCommandType] = &[];
|
||||
fn log_span(&self) -> Span {
|
||||
tracing::span!(tracing::Level::INFO, "Logout")
|
||||
}
|
||||
|
||||
/// no options and no arguments for this buddy
|
||||
fn parse(_: &clap::ArgMatches) -> Result<Self::Options, CLIError> {
|
||||
fn prelude(&self) -> Result<Self::Input> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// as simple as it could be - remove credentials file
|
||||
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();
|
||||
|
||||
fn apply(self, _ctx: Context, _: Self::Input) -> Result<Self::Output> {
|
||||
// the only error we're interested here is NotFound
|
||||
// however err in this case can also be of kind PermissionDenied or other
|
||||
if let Err(err) = remove_token() {
|
@ -14,11 +14,19 @@
|
||||
// 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 cli;
|
||||
pub use self::cli::*;
|
||||
pub mod add;
|
||||
pub use add::Add;
|
||||
|
||||
pub mod commands;
|
||||
pub use self::commands::*;
|
||||
pub mod login;
|
||||
pub use login::Login;
|
||||
|
||||
pub mod updater;
|
||||
pub use self::updater::*;
|
||||
pub mod logout;
|
||||
pub use logout::Logout;
|
||||
|
||||
pub mod publish;
|
||||
pub use publish::Publish;
|
||||
|
||||
pub mod remove;
|
||||
pub use remove::Remove;
|
||||
|
||||
pub use super::*;
|
@ -15,28 +15,22 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{
|
||||
cli::*,
|
||||
cli_types::*,
|
||||
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},
|
||||
commands::Command,
|
||||
context::{Context, PACKAGE_MANAGER_URL},
|
||||
};
|
||||
|
||||
use clap::ArgMatches;
|
||||
use anyhow::{anyhow, Result};
|
||||
use structopt::StructOpt;
|
||||
|
||||
use reqwest::{
|
||||
blocking::{multipart::Form, Client},
|
||||
header::{HeaderMap, HeaderValue},
|
||||
};
|
||||
|
||||
use super::build::Build;
|
||||
use serde::Deserialize;
|
||||
use std::{convert::TryFrom, env::current_dir};
|
||||
|
||||
use leo_package::{outputs::OutputsDirectory, root::ZipFile};
|
||||
|
||||
pub const PUBLISH_URL: &str = "v1/package/publish";
|
||||
|
||||
@ -45,54 +39,47 @@ struct ResponseJson {
|
||||
package_id: String,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PublishCommand;
|
||||
/// Publish package to Aleo Package Manager
|
||||
#[derive(StructOpt, Debug, Default)]
|
||||
#[structopt(setting = structopt::clap::AppSettings::ColoredHelp)]
|
||||
pub struct Publish {}
|
||||
|
||||
impl CLI for PublishCommand {
|
||||
type Options = ();
|
||||
impl Publish {
|
||||
pub fn new() -> Publish {
|
||||
Publish {}
|
||||
}
|
||||
}
|
||||
|
||||
impl Command for Publish {
|
||||
type Input = <Build as Command>::Output;
|
||||
type Output = Option<String>;
|
||||
|
||||
const ABOUT: AboutType = "Publish the current package to the Aleo Package Manager";
|
||||
const ARGUMENTS: &'static [ArgumentType] = &[];
|
||||
const FLAGS: &'static [FlagType] = &[];
|
||||
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(())
|
||||
/// Build program before publishing
|
||||
fn prelude(&self) -> Result<Self::Input> {
|
||||
Build::new().execute()
|
||||
}
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
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();
|
||||
|
||||
fn apply(self, ctx: Context, _input: Self::Input) -> Result<Self::Output> {
|
||||
// Get the package manifest
|
||||
let path = current_dir()?;
|
||||
let package_manifest = Manifest::try_from(path.as_path())?;
|
||||
let path = ctx.dir()?;
|
||||
let manifest = ctx.manifest()?;
|
||||
|
||||
let package_name = package_manifest.get_package_name();
|
||||
let package_version = package_manifest.get_package_version();
|
||||
let package_name = manifest.get_package_name();
|
||||
let package_version = manifest.get_package_version();
|
||||
|
||||
if package_manifest.get_package_description().is_none() {
|
||||
return Err(MissingPackageDescription.into());
|
||||
}
|
||||
|
||||
if package_manifest.get_package_license().is_none() {
|
||||
return Err(MissingPackageLicense.into());
|
||||
}
|
||||
|
||||
let package_remote = match package_manifest.get_package_remote() {
|
||||
Some(remote) => remote,
|
||||
None => return Err(MissingPackageRemote.into()),
|
||||
match (
|
||||
manifest.get_package_description(),
|
||||
manifest.get_package_license(),
|
||||
manifest.get_package_remote(),
|
||||
) {
|
||||
(None, _, _) => return Err(anyhow!("No package description")),
|
||||
(_, None, _) => return Err(anyhow!("Missing package license")),
|
||||
(_, _, None) => return Err(anyhow!("Missing package remote")),
|
||||
(_, _, _) => (),
|
||||
};
|
||||
|
||||
let package_remote = manifest.get_package_remote().unwrap();
|
||||
|
||||
// Create the output directory
|
||||
OutputsDirectory::create(&path)?;
|
||||
|
||||
@ -115,18 +102,9 @@ impl CLI for PublishCommand {
|
||||
// Client for make POST request
|
||||
let client = Client::new();
|
||||
|
||||
// Get token to make an authorized request
|
||||
let token = match read_token() {
|
||||
Ok(token) => token,
|
||||
|
||||
// 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)?
|
||||
}
|
||||
let token = match ctx.api.auth_token() {
|
||||
Some(token) => token,
|
||||
None => return Err(anyhow!("Login before publishing package: try leo login --help")),
|
||||
};
|
||||
|
||||
// Headers for request to publish package
|
||||
@ -149,12 +127,12 @@ impl CLI for PublishCommand {
|
||||
Ok(json) => json,
|
||||
Err(error) => {
|
||||
tracing::warn!("{:?}", error);
|
||||
return Err(PackageNotPublished("Package not published".into()).into());
|
||||
return Err(anyhow!("Package not published"));
|
||||
}
|
||||
},
|
||||
Err(error) => {
|
||||
tracing::warn!("{:?}", error);
|
||||
return Err(ConnectionUnavalaible("Connection error".into()).into());
|
||||
return Err(anyhow!("Connection unavailable"));
|
||||
}
|
||||
};
|
||||
|
60
leo/commands/package/remove.rs
Normal file
60
leo/commands/package/remove.rs
Normal file
@ -0,0 +1,60 @@
|
||||
// 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,64 @@
|
||||
// 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::*, commands::SetupCommand, errors::CLIError};
|
||||
use leo_package::{outputs::ProofFile, root::Manifest};
|
||||
use super::setup::Setup;
|
||||
use crate::{commands::Command, context::Context};
|
||||
use anyhow::Result;
|
||||
use structopt::StructOpt;
|
||||
|
||||
use leo_package::outputs::ProofFile;
|
||||
|
||||
use snarkvm_algorithms::snark::groth16::{Groth16, PreparedVerifyingKey, Proof};
|
||||
use snarkvm_curves::bls12_377::{Bls12_377, Fr};
|
||||
use snarkvm_models::algorithms::SNARK;
|
||||
use snarkvm_utilities::bytes::ToBytes;
|
||||
|
||||
use clap::ArgMatches;
|
||||
use rand::thread_rng;
|
||||
use std::{convert::TryFrom, env::current_dir, time::Instant};
|
||||
use tracing::span::Span;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ProveCommand;
|
||||
/// Init Leo project command in current directory
|
||||
#[derive(StructOpt, Debug, Default)]
|
||||
#[structopt(setting = structopt::clap::AppSettings::ColoredHelp)]
|
||||
pub struct Prove {
|
||||
#[structopt(long = "skip-key-check", help = "Skip key verification on Setup stage")]
|
||||
skip_key_check: bool,
|
||||
}
|
||||
|
||||
impl CLI for ProveCommand {
|
||||
type Options = bool;
|
||||
impl Prove {
|
||||
pub fn new(skip_key_check: bool) -> Prove {
|
||||
Prove { skip_key_check }
|
||||
}
|
||||
}
|
||||
|
||||
impl Command for Prove {
|
||||
type Input = <Setup as Command>::Output;
|
||||
type Output = (Proof<Bls12_377>, PreparedVerifyingKey<Bls12_377>);
|
||||
|
||||
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"))
|
||||
fn log_span(&self) -> Span {
|
||||
tracing::span!(tracing::Level::INFO, "Proving")
|
||||
}
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
fn output(do_setup_check: Self::Options) -> Result<Self::Output, CLIError> {
|
||||
let (program, parameters, prepared_verifying_key) = SetupCommand::output(do_setup_check)?;
|
||||
fn prelude(&self) -> Result<Self::Input> {
|
||||
Setup::new(self.skip_key_check).execute()
|
||||
}
|
||||
|
||||
// Begin "Proving" context for console logging
|
||||
let span = tracing::span!(tracing::Level::INFO, "Proving");
|
||||
let enter = span.enter();
|
||||
fn apply(self, ctx: Context, input: Self::Input) -> Result<Self::Output> {
|
||||
let (program, parameters, prepared_verifying_key) = input;
|
||||
|
||||
// Get the package name
|
||||
let path = current_dir()?;
|
||||
let package_name = Manifest::try_from(path.as_path())?.get_package_name();
|
||||
let path = ctx.dir()?;
|
||||
let package_name = ctx.manifest()?.get_package_name();
|
||||
|
||||
tracing::info!("Starting...");
|
||||
|
||||
// Start the timer
|
||||
let start = Instant::now();
|
||||
|
||||
let rng = &mut thread_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
|
||||
let mut proof = vec![];
|
||||
program_proof.write(&mut 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))
|
||||
}
|
||||
}
|
||||
|
@ -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,51 @@
|
||||
// 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::*, commands::ProveCommand, errors::CLIError};
|
||||
use crate::{commands::Command, context::Context};
|
||||
|
||||
use anyhow::Result;
|
||||
use structopt::StructOpt;
|
||||
|
||||
use leo_compiler::{compiler::Compiler, group::targets::edwards_bls12::EdwardsGroupType};
|
||||
|
||||
use snarkvm_algorithms::snark::groth16::Groth16;
|
||||
use snarkvm_curves::bls12_377::{Bls12_377, Fr};
|
||||
use snarkvm_models::algorithms::SNARK;
|
||||
|
||||
use clap::ArgMatches;
|
||||
use std::time::Instant;
|
||||
use super::prove::Prove;
|
||||
use tracing::span::Span;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RunCommand;
|
||||
/// Build, Prove and Run Leo program with inputs
|
||||
#[derive(StructOpt, Debug, Default)]
|
||||
#[structopt(setting = structopt::clap::AppSettings::ColoredHelp)]
|
||||
pub struct Run {
|
||||
#[structopt(long = "skip-key-check", help = "Skip key verification on Setup stage")]
|
||||
skip_key_check: bool,
|
||||
}
|
||||
|
||||
impl CLI for RunCommand {
|
||||
type Options = bool;
|
||||
impl Run {
|
||||
pub fn new(skip_key_check: bool) -> Run {
|
||||
Run { skip_key_check }
|
||||
}
|
||||
}
|
||||
|
||||
impl Command for Run {
|
||||
type Input = <Prove as Command>::Output;
|
||||
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"))
|
||||
fn log_span(&self) -> Span {
|
||||
tracing::span!(tracing::Level::INFO, "Verifying")
|
||||
}
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
fn output(do_setup_check: Self::Options) -> Result<(), CLIError> {
|
||||
let (proof, prepared_verifying_key) = ProveCommand::output(do_setup_check)?;
|
||||
fn prelude(&self) -> Result<Self::Input> {
|
||||
Prove::new(self.skip_key_check).execute()
|
||||
}
|
||||
|
||||
// Begin "Verifying" context for console logging
|
||||
let span = tracing::span!(tracing::Level::INFO, "Verifying");
|
||||
let enter = span.enter();
|
||||
fn apply(self, _ctx: Context, input: Self::Input) -> Result<Self::Output> {
|
||||
let (proof, prepared_verifying_key) = input;
|
||||
|
||||
tracing::info!("Starting...");
|
||||
|
||||
// Start the timer
|
||||
let start = Instant::now();
|
||||
|
||||
// Run the verifier
|
||||
let is_success = Groth16::<Bls12_377, Compiler<Fr, EdwardsGroupType>, Vec<Fr>>::verify(
|
||||
&prepared_verifying_key,
|
||||
@ -63,23 +66,12 @@ impl CLI for RunCommand {
|
||||
&proof,
|
||||
)?;
|
||||
|
||||
// End the timer
|
||||
let end = start.elapsed().as_millis();
|
||||
|
||||
// Log the verifier output
|
||||
match is_success {
|
||||
true => tracing::info!("Proof is valid"),
|
||||
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(())
|
||||
}
|
||||
}
|
||||
|
@ -14,82 +14,75 @@
|
||||
// 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::*,
|
||||
commands::BuildCommand,
|
||||
errors::{CLIError, RunError},
|
||||
};
|
||||
use crate::{commands::Command, context::Context};
|
||||
use anyhow::{anyhow, Result};
|
||||
|
||||
use leo_compiler::{compiler::Compiler, group::targets::edwards_bls12::EdwardsGroupType};
|
||||
use leo_package::{
|
||||
outputs::{ProvingKeyFile, VerificationKeyFile},
|
||||
root::Manifest,
|
||||
source::{MAIN_FILENAME, SOURCE_DIRECTORY_NAME},
|
||||
};
|
||||
|
||||
use rand::thread_rng;
|
||||
use snarkvm_algorithms::snark::groth16::{Groth16, Parameters, PreparedVerifyingKey, VerifyingKey};
|
||||
use snarkvm_curves::bls12_377::{Bls12_377, Fr};
|
||||
use snarkvm_models::algorithms::snark::SNARK;
|
||||
|
||||
use clap::ArgMatches;
|
||||
use rand::thread_rng;
|
||||
use std::{convert::TryFrom, env::current_dir, time::Instant};
|
||||
use structopt::StructOpt;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SetupCommand;
|
||||
use super::build::Build;
|
||||
use tracing::span::Span;
|
||||
|
||||
impl CLI for SetupCommand {
|
||||
type Options = bool;
|
||||
/// Run setup ceremony for Leo program Command
|
||||
#[derive(StructOpt, Debug, Default)]
|
||||
#[structopt(setting = structopt::clap::AppSettings::ColoredHelp)]
|
||||
pub struct Setup {
|
||||
#[structopt(long = "skip-key-check", help = "Skip key verification")]
|
||||
skip_key_check: bool,
|
||||
}
|
||||
|
||||
impl Setup {
|
||||
pub fn new(skip_key_check: bool) -> Setup {
|
||||
Setup { skip_key_check }
|
||||
}
|
||||
}
|
||||
|
||||
impl Command for Setup {
|
||||
type Input = <Build as Command>::Output;
|
||||
type Output = (
|
||||
Compiler<Fr, EdwardsGroupType>,
|
||||
Parameters<Bls12_377>,
|
||||
PreparedVerifyingKey<Bls12_377>,
|
||||
);
|
||||
|
||||
const ABOUT: AboutType = "Run a program setup";
|
||||
const ARGUMENTS: &'static [ArgumentType] = &[];
|
||||
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"))
|
||||
fn log_span(&self) -> Span {
|
||||
tracing::span!(tracing::Level::INFO, "Setup")
|
||||
}
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
fn output(do_check: Self::Options) -> Result<Self::Output, CLIError> {
|
||||
// Get the package name
|
||||
let path = current_dir()?;
|
||||
let package_name = Manifest::try_from(path.as_path())?.get_package_name();
|
||||
fn prelude(&self) -> Result<Self::Input> {
|
||||
Build::new().execute()
|
||||
}
|
||||
|
||||
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)) => {
|
||||
// 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
|
||||
let keys_exist = ProvingKeyFile::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
|
||||
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...");
|
||||
|
||||
// Start the timer for setup
|
||||
let setup_start = Instant::now();
|
||||
|
||||
// Run the program setup operation
|
||||
let rng = &mut thread_rng();
|
||||
let (proving_key, prepared_verifying_key) =
|
||||
Groth16::<Bls12_377, Compiler<Fr, _>, Vec<Fr>>::setup(&program, rng).unwrap();
|
||||
|
||||
// End the timer
|
||||
let end = setup_start.elapsed().as_millis();
|
||||
|
||||
// TODO (howardwu): Convert parameters to a 'proving key' struct for serialization.
|
||||
// Write the proving key file to the output directory
|
||||
let proving_key_file = ProvingKeyFile::new(&package_name);
|
||||
@ -107,20 +100,19 @@ impl CLI for SetupCommand {
|
||||
let _ = verification_key_file.write_to(&path, &verification_key)?;
|
||||
tracing::info!("Complete");
|
||||
|
||||
(end, proving_key, prepared_verifying_key)
|
||||
(proving_key, prepared_verifying_key)
|
||||
} else {
|
||||
tracing::info!("Detected saved setup");
|
||||
|
||||
// Start the timer for setup
|
||||
let setup_start = Instant::now();
|
||||
|
||||
// Read the proving key file from the output directory
|
||||
tracing::info!("Loading proving key...");
|
||||
if !do_check {
|
||||
|
||||
if self.skip_key_check {
|
||||
tracing::info!("Skipping curve check");
|
||||
}
|
||||
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");
|
||||
|
||||
// Read the verification key file from the output directory
|
||||
@ -132,20 +124,9 @@ impl CLI for SetupCommand {
|
||||
let prepared_verifying_key = PreparedVerifyingKey::<Bls12_377>::from(verifying_key);
|
||||
tracing::info!("Complete");
|
||||
|
||||
// End the timer
|
||||
let end = setup_start.elapsed().as_millis();
|
||||
|
||||
(end, proving_key, prepared_verifying_key)
|
||||
(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))
|
||||
}
|
||||
None => {
|
||||
@ -153,9 +134,7 @@ impl CLI for SetupCommand {
|
||||
main_file_path.push(SOURCE_DIRECTORY_NAME);
|
||||
main_file_path.push(MAIN_FILENAME);
|
||||
|
||||
Err(CLIError::RunError(RunError::MainFileDoesNotExist(
|
||||
main_file_path.into_os_string(),
|
||||
)))
|
||||
Err(anyhow!("Unable to build, check that main file exists"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,67 +14,85 @@
|
||||
// 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, TestError::ProgramFileDoesNotExist},
|
||||
};
|
||||
use crate::{commands::Command, context::Context};
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use structopt::StructOpt;
|
||||
|
||||
use leo_compiler::{compiler::Compiler, group::targets::edwards_bls12::EdwardsGroupType};
|
||||
use leo_package::{
|
||||
inputs::*,
|
||||
outputs::{OutputsDirectory, OUTPUTS_DIRECTORY_NAME},
|
||||
root::Manifest,
|
||||
source::{LibraryFile, MainFile, LIBRARY_FILENAME, MAIN_FILENAME, SOURCE_DIRECTORY_NAME},
|
||||
};
|
||||
|
||||
use snarkvm_curves::edwards_bls12::Fq;
|
||||
|
||||
use clap::ArgMatches;
|
||||
use std::{convert::TryFrom, env::current_dir, time::Instant};
|
||||
use std::{convert::TryFrom, path::PathBuf, time::Instant};
|
||||
use tracing::span::Span;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TestCommand;
|
||||
/// Build program and run tests command
|
||||
#[derive(StructOpt, Debug, Default)]
|
||||
#[structopt(setting = structopt::clap::AppSettings::ColoredHelp)]
|
||||
pub struct Test {
|
||||
#[structopt(short = "f", long = "file", name = "file")]
|
||||
files: Vec<PathBuf>,
|
||||
}
|
||||
|
||||
impl CLI for TestCommand {
|
||||
type Options = ();
|
||||
impl Test {
|
||||
pub fn new(files: Vec<PathBuf>) -> Test {
|
||||
Test { files }
|
||||
}
|
||||
}
|
||||
|
||||
impl Command for Test {
|
||||
type Input = ();
|
||||
type Output = ();
|
||||
|
||||
const ABOUT: AboutType = "Compile and run all tests in the current package";
|
||||
const ARGUMENTS: &'static [ArgumentType] = &[];
|
||||
const FLAGS: &'static [FlagType] = &[];
|
||||
const NAME: NameType = "test";
|
||||
const OPTIONS: &'static [OptionType] = &[];
|
||||
const SUBCOMMANDS: &'static [SubCommandType] = &[];
|
||||
fn log_span(&self) -> Span {
|
||||
tracing::span!(tracing::Level::INFO, "Test")
|
||||
}
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
fn parse(_arguments: &ArgMatches) -> Result<Self::Options, CLIError> {
|
||||
fn prelude(&self) -> Result<Self::Input> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
fn output(_options: Self::Options) -> Result<Self::Output, CLIError> {
|
||||
let path = current_dir()?;
|
||||
|
||||
fn apply(self, ctx: Context, _: Self::Input) -> Result<Self::Output> {
|
||||
// Get the package name
|
||||
let manifest = Manifest::try_from(path.as_path())?;
|
||||
let package_name = manifest.get_package_name();
|
||||
let package_name = ctx.manifest()?.get_package_name();
|
||||
|
||||
// Sanitize the package path to the root directory
|
||||
let mut package_path = path;
|
||||
let mut package_path = ctx.dir()?;
|
||||
if package_path.is_file() {
|
||||
package_path.pop();
|
||||
}
|
||||
|
||||
let mut file_path = package_path.clone();
|
||||
file_path.push(SOURCE_DIRECTORY_NAME);
|
||||
let mut to_test: Vec<PathBuf> = Vec::new();
|
||||
|
||||
// Verify a main or library file exists
|
||||
if MainFile::exists_at(&package_path) {
|
||||
// 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();
|
||||
file_path.push(SOURCE_DIRECTORY_NAME);
|
||||
file_path.push(MAIN_FILENAME);
|
||||
to_test.push(file_path);
|
||||
|
||||
// if main file is not present and no arguments - try library
|
||||
} else if LibraryFile::exists_at(&package_path) {
|
||||
let mut file_path = package_path.clone();
|
||||
file_path.push(SOURCE_DIRECTORY_NAME);
|
||||
file_path.push(LIBRARY_FILENAME);
|
||||
to_test.push(file_path);
|
||||
|
||||
// nothing found - skip
|
||||
} 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;
|
||||
@ -84,49 +102,45 @@ impl CLI for TestCommand {
|
||||
// Create the output directory
|
||||
OutputsDirectory::create(&package_path)?;
|
||||
|
||||
// Begin "Test" context for console logging
|
||||
let span = tracing::span!(tracing::Level::INFO, "Test");
|
||||
let enter = span.enter();
|
||||
// Finally test every passed file
|
||||
for file_path in to_test {
|
||||
tracing::info!("Running tests in file {:?}", file_path);
|
||||
|
||||
// Start the timer
|
||||
let start = Instant::now();
|
||||
let input_pairs = match InputPairs::try_from(package_path.as_path()) {
|
||||
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 program =
|
||||
Compiler::<Fq, EdwardsGroupType>::parse_program_without_input(package_name, file_path, output_directory)?;
|
||||
let timer = Instant::now();
|
||||
let program = Compiler::<Fq, EdwardsGroupType>::parse_program_without_input(
|
||||
package_name.clone(),
|
||||
file_path,
|
||||
output_directory.clone(),
|
||||
)?;
|
||||
|
||||
// Parse all inputs as input pairs
|
||||
let pairs = InputPairs::try_from(package_path.as_path())?;
|
||||
let temporary_program = program;
|
||||
let (passed, failed) = temporary_program.compile_test_constraints(input_pairs)?;
|
||||
let time_taken = timer.elapsed().as_millis();
|
||||
|
||||
// Run tests
|
||||
let temporary_program = program;
|
||||
let (passed, failed) = temporary_program.compile_test_constraints(pairs)?;
|
||||
|
||||
// Drop "Test" context for console logging
|
||||
drop(enter);
|
||||
|
||||
// Set the result of the test command to passed if no tests failed.
|
||||
if failed == 0 {
|
||||
// Begin "Done" context for console logging
|
||||
tracing::span!(tracing::Level::INFO, "Done").in_scope(|| {
|
||||
if failed == 0 {
|
||||
tracing::info!(
|
||||
"Tests passed in {} milliseconds. {} passed; {} failed;\n",
|
||||
start.elapsed().as_millis(),
|
||||
time_taken,
|
||||
passed,
|
||||
failed
|
||||
);
|
||||
});
|
||||
} else {
|
||||
// Begin "Done" context for console logging
|
||||
tracing::span!(tracing::Level::ERROR, "Done").in_scope(|| {
|
||||
} else {
|
||||
tracing::error!(
|
||||
"Tests failed in {} milliseconds. {} passed; {} failed;\n",
|
||||
start.elapsed().as_millis(),
|
||||
time_taken,
|
||||
passed,
|
||||
failed
|
||||
);
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -14,179 +14,96 @@
|
||||
// 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, cli_types::*, config::Config, updater::Updater};
|
||||
use crate::{commands::Command, config::Config, context::Context, updater::Updater};
|
||||
use anyhow::{anyhow, Result};
|
||||
use structopt::StructOpt;
|
||||
use tracing::span::Span;
|
||||
|
||||
use clap::AppSettings;
|
||||
/// Setting for automatic updates of Leo
|
||||
#[derive(Debug, StructOpt, PartialEq)]
|
||||
pub enum Sub {
|
||||
Automatic {
|
||||
#[structopt(name = "bool", help = "Boolean value: true or false", parse(try_from_str))]
|
||||
value: bool,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UpdateCommand;
|
||||
/// Update Leo to the latest version
|
||||
#[derive(StructOpt, Debug, Default)]
|
||||
#[structopt(setting = structopt::clap::AppSettings::ColoredHelp)]
|
||||
pub struct Update {
|
||||
/// List all available versions of Leo
|
||||
#[structopt(short, long)]
|
||||
list: bool,
|
||||
|
||||
impl CLI for UpdateCommand {
|
||||
// (show_all_versions, quiet)
|
||||
type Options = Option<(bool, bool, bool)>;
|
||||
type Output = ();
|
||||
/// For Aleo Studio only
|
||||
#[structopt(short, long)]
|
||||
studio: bool,
|
||||
|
||||
const ABOUT: AboutType = "Update Leo to the latest version";
|
||||
const ARGUMENTS: &'static [ArgumentType] = &[];
|
||||
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,
|
||||
],
|
||||
),
|
||||
];
|
||||
/// Setting for automatic updates of Leo
|
||||
#[structopt(subcommand)]
|
||||
automatic: Option<Sub>,
|
||||
}
|
||||
|
||||
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> {
|
||||
// Begin "Updating" context for console logging
|
||||
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);
|
||||
}
|
||||
},
|
||||
false => {
|
||||
let config = Config::read_config()?;
|
||||
|
||||
// If update is run with studio and the automatic update is off, finish quietly
|
||||
if studio && !config.update.automatic {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
match Updater::update_to_latest_release(!quiet) {
|
||||
Ok(status) => {
|
||||
if !quiet {
|
||||
if status.uptodate() {
|
||||
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) => {
|
||||
if !quiet {
|
||||
tracing::error!("Could not update Leo to the latest version");
|
||||
tracing::error!("{}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Update {
|
||||
pub fn new(list: bool, studio: bool, automatic: Option<Sub>) -> Update {
|
||||
Update {
|
||||
list,
|
||||
studio,
|
||||
automatic,
|
||||
}
|
||||
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);
|
||||
impl Command for Update {
|
||||
type Input = ();
|
||||
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 log_span(&self) -> Span {
|
||||
tracing::span!(tracing::Level::INFO, "Updating")
|
||||
}
|
||||
|
||||
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();
|
||||
fn prelude(&self) -> Result<Self::Input> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// 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)?;
|
||||
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));
|
||||
}
|
||||
|
||||
// If --quiet is not enabled, log the output.
|
||||
if !options.1 {
|
||||
// Read the `automatic` value now.
|
||||
let automatic = Config::read_config()?.update.automatic;
|
||||
// in case automatic subcommand was called
|
||||
if let Some(Sub::Automatic { value }) = self.automatic {
|
||||
Config::set_update_automatic(value)?;
|
||||
|
||||
// Log the output.
|
||||
tracing::debug!("automatic = {}", automatic);
|
||||
match automatic {
|
||||
true => tracing::info!("Automatic updates are enabled. Leo will update as new versions are released."),
|
||||
match value {
|
||||
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.")
|
||||
tracing::info!("Automatic updates are disabled. Leo will not update as new versions are released")
|
||||
}
|
||||
};
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Drop "Settings" context for console logging.
|
||||
drop(enter);
|
||||
let config = Config::read_config()?;
|
||||
// If update is run with studio and the automatic update is off, finish quietly
|
||||
if self.studio && !config.update.automatic {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
match Updater::update_to_latest_release(true) {
|
||||
Ok(status) => match (status.uptodate(), status.updated()) {
|
||||
(true, _) => tracing::info!("Leo is already on the latest version"),
|
||||
(_, true) => tracing::info!("Leo has successfully updated to version {}", status.version()),
|
||||
(_, _) => (),
|
||||
},
|
||||
Err(e) => {
|
||||
tracing::error!("Could not update Leo to the latest version");
|
||||
tracing::error!("{}", e);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -14,42 +14,55 @@
|
||||
// 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, cli_types::*, commands::BuildCommand, errors::CLIError};
|
||||
use clap::ArgMatches;
|
||||
use crate::{commands::Command, context::Context};
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use notify::{watcher, DebouncedEvent, RecursiveMode, Watcher};
|
||||
use std::{sync::mpsc::channel, time::Duration};
|
||||
use structopt::StructOpt;
|
||||
|
||||
use super::build::Build;
|
||||
use tracing::span::Span;
|
||||
|
||||
const LEO_SOURCE_DIR: &str = "src/";
|
||||
|
||||
// Time interval for watching files, in seconds
|
||||
const INTERVAL: u64 = 3;
|
||||
/// Watch file changes in src/ directory and run Build Command
|
||||
#[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 {
|
||||
type Options = ();
|
||||
impl Command for Watch {
|
||||
type Input = ();
|
||||
type Output = ();
|
||||
|
||||
const ABOUT: AboutType = "Watch for changes of Leo source files";
|
||||
const ARGUMENTS: &'static [ArgumentType] = &[];
|
||||
const FLAGS: &'static [FlagType] = &[];
|
||||
const NAME: NameType = "watch";
|
||||
const OPTIONS: &'static [OptionType] = &[];
|
||||
const SUBCOMMANDS: &'static [SubCommandType] = &[];
|
||||
fn log_span(&self) -> Span {
|
||||
tracing::span!(tracing::Level::INFO, "Watching")
|
||||
}
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
fn parse(_arguments: &ArgMatches) -> Result<Self::Options, CLIError> {
|
||||
fn prelude(&self) -> Result<Self::Input> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn output(_options: Self::Options) -> Result<Self::Output, CLIError> {
|
||||
// Begin "Watching" context for console logging
|
||||
let span = tracing::span!(tracing::Level::INFO, "Watching");
|
||||
let _enter = span.enter();
|
||||
|
||||
fn apply(self, _ctx: Context, _: Self::Input) -> Result<Self::Output> {
|
||||
let (tx, rx) = channel();
|
||||
let mut watcher = watcher(tx, Duration::from_secs(INTERVAL)).unwrap();
|
||||
watcher.watch(LEO_SOURCE_DIR, RecursiveMode::Recursive).unwrap();
|
||||
let mut watcher = watcher(tx, Duration::from_secs(self.interval)).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");
|
||||
|
||||
@ -57,7 +70,7 @@ impl CLI for WatchCommand {
|
||||
match rx.recv() {
|
||||
// See changes on the write event
|
||||
Ok(DebouncedEvent::Write(_write)) => {
|
||||
match BuildCommand::output(()) {
|
||||
match Build::new().execute() {
|
||||
Ok(_output) => {
|
||||
tracing::info!("Built successfully");
|
||||
}
|
||||
|
@ -14,8 +14,7 @@
|
||||
// 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::CLIError;
|
||||
|
||||
use anyhow::Error;
|
||||
use dirs::home_dir;
|
||||
use lazy_static::lazy_static;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -26,8 +25,6 @@ use std::{
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
pub const PACKAGE_MANAGER_URL: &str = "https://api.aleo.pm/";
|
||||
|
||||
pub const LEO_CREDENTIALS_FILE: &str = "credentials";
|
||||
pub const LEO_CONFIG_FILE: &str = "config.toml";
|
||||
|
||||
@ -75,7 +72,7 @@ impl Default for Config {
|
||||
|
||||
impl Config {
|
||||
/// 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_path = LEO_CONFIG_PATH.clone();
|
||||
|
||||
@ -112,7 +109,7 @@ impl Config {
|
||||
}
|
||||
|
||||
/// 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()?;
|
||||
|
||||
if config.update.automatic != automatic {
|
||||
|
73
leo/context.rs
Normal file
73
leo/context.rs
Normal file
@ -0,0 +1,73 @@
|
||||
// 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::env::current_dir;
|
||||
|
||||
use crate::{api::Api, config};
|
||||
use anyhow::Result;
|
||||
use leo_package::root::Manifest;
|
||||
use std::{convert::TryFrom, 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
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#[macro_use]
|
||||
extern crate thiserror;
|
||||
|
||||
pub mod cli;
|
||||
pub mod cli_types;
|
||||
pub mod api;
|
||||
pub mod commands;
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
pub mod config;
|
||||
pub mod errors;
|
||||
pub mod context;
|
||||
pub mod logger;
|
||||
pub mod synthesizer;
|
||||
pub mod updater;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
254
leo/main.rs
254
leo/main.rs
@ -14,80 +14,198 @@
|
||||
// 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_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 anyhow::Error;
|
||||
use std::process::exit;
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
fn main() -> Result<(), CLIError> {
|
||||
let app = App::new("leo")
|
||||
.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);
|
||||
use commands::{
|
||||
package::{Add, Login, Logout, Publish, Remove},
|
||||
Build,
|
||||
Clean,
|
||||
Command,
|
||||
Deploy,
|
||||
Init,
|
||||
Lint,
|
||||
New,
|
||||
Prove,
|
||||
Run,
|
||||
Setup,
|
||||
Test,
|
||||
Update,
|
||||
Watch,
|
||||
};
|
||||
|
||||
let mut help = app.clone();
|
||||
let arguments = app.get_matches();
|
||||
use structopt::{clap::AppSettings, StructOpt};
|
||||
|
||||
match arguments.subcommand() {
|
||||
("new", Some(arguments)) => NewCommand::process(arguments),
|
||||
("init", Some(arguments)) => InitCommand::process(arguments),
|
||||
("build", Some(arguments)) => BuildCommand::process(arguments),
|
||||
("watch", Some(arguments)) => WatchCommand::process(arguments),
|
||||
("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),
|
||||
}
|
||||
/// CLI Arguments entry point - includes global parameters and subcommands
|
||||
#[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,
|
||||
|
||||
Updater::print_cli();
|
||||
#[structopt(short, long, help = "Suppress CLI output")]
|
||||
quiet: bool,
|
||||
|
||||
help.print_help()?;
|
||||
println!();
|
||||
Ok(())
|
||||
#[structopt(subcommand)]
|
||||
command: CommandOpts,
|
||||
}
|
||||
|
||||
///Leo compiler and package manager
|
||||
#[derive(StructOpt, Debug)]
|
||||
#[structopt(setting = AppSettings::ColoredHelp)]
|
||||
enum CommandOpts {
|
||||
#[structopt(about = "Init new Leo project command in current directory")]
|
||||
Init {
|
||||
#[structopt(flatten)]
|
||||
cmd: Init,
|
||||
},
|
||||
|
||||
#[structopt(about = "Create new Leo project in new directory")]
|
||||
New {
|
||||
#[structopt(flatten)]
|
||||
cmd: New,
|
||||
},
|
||||
|
||||
#[structopt(about = "Compile current package as a program")]
|
||||
Build {
|
||||
#[structopt(flatten)]
|
||||
cmd: Build,
|
||||
},
|
||||
|
||||
#[structopt(about = "Run a program setup")]
|
||||
Setup {
|
||||
#[structopt(flatten)]
|
||||
cmd: Setup,
|
||||
},
|
||||
|
||||
#[structopt(about = "Run the program and produce a proof")]
|
||||
Prove {
|
||||
#[structopt(flatten)]
|
||||
cmd: Prove,
|
||||
},
|
||||
|
||||
#[structopt(about = "Run a program with input variables")]
|
||||
Run {
|
||||
#[structopt(flatten)]
|
||||
cmd: Run,
|
||||
},
|
||||
|
||||
#[structopt(about = "Clean current package: remove proof and circuits")]
|
||||
Clean {
|
||||
#[structopt(flatten)]
|
||||
cmd: Clean,
|
||||
},
|
||||
|
||||
#[structopt(about = "Watch for changes of Leo source files and run build")]
|
||||
Watch {
|
||||
#[structopt(flatten)]
|
||||
cmd: Watch,
|
||||
},
|
||||
|
||||
#[structopt(about = "Watch for changes of Leo source files and run build")]
|
||||
Update {
|
||||
#[structopt(flatten)]
|
||||
cmd: Update,
|
||||
},
|
||||
|
||||
#[structopt(about = "Compile and run all tests in the current package")]
|
||||
Test {
|
||||
#[structopt(flatten)]
|
||||
cmd: Test,
|
||||
},
|
||||
|
||||
#[structopt(about = "Import package from Aleo PM")]
|
||||
Add {
|
||||
#[structopt(flatten)]
|
||||
cmd: Add,
|
||||
},
|
||||
|
||||
#[structopt(about = "Login to the package manager and store credentials")]
|
||||
Login {
|
||||
#[structopt(flatten)]
|
||||
cmd: Login,
|
||||
},
|
||||
|
||||
#[structopt(about = "Logout - remove local credentials")]
|
||||
Logout {
|
||||
#[structopt(flatten)]
|
||||
cmd: Logout,
|
||||
},
|
||||
|
||||
#[structopt(about = "Publish package")]
|
||||
Publish {
|
||||
#[structopt(flatten)]
|
||||
cmd: Publish,
|
||||
},
|
||||
|
||||
#[structopt(about = "Remove imported package")]
|
||||
Remove {
|
||||
#[structopt(flatten)]
|
||||
cmd: Remove,
|
||||
},
|
||||
|
||||
#[structopt(about = "Lint package code (not implemented)")]
|
||||
Lint {
|
||||
#[structopt(flatten)]
|
||||
cmd: Lint,
|
||||
},
|
||||
|
||||
#[structopt(about = "Deploy the current package as a program to the network (*)")]
|
||||
Deploy {
|
||||
#[structopt(flatten)]
|
||||
cmd: 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 { cmd } => cmd.try_execute(),
|
||||
CommandOpts::New { cmd } => cmd.try_execute(),
|
||||
CommandOpts::Build { cmd } => cmd.try_execute(),
|
||||
CommandOpts::Setup { cmd } => cmd.try_execute(),
|
||||
CommandOpts::Prove { cmd } => cmd.try_execute(),
|
||||
CommandOpts::Test { cmd } => cmd.try_execute(),
|
||||
CommandOpts::Run { cmd } => cmd.try_execute(),
|
||||
CommandOpts::Clean { cmd } => cmd.try_execute(),
|
||||
CommandOpts::Watch { cmd } => cmd.try_execute(),
|
||||
CommandOpts::Update { cmd } => cmd.try_execute(),
|
||||
|
||||
CommandOpts::Add { cmd } => cmd.try_execute(),
|
||||
CommandOpts::Login { cmd } => cmd.try_execute(),
|
||||
CommandOpts::Logout { cmd } => cmd.try_execute(),
|
||||
CommandOpts::Publish { cmd } => cmd.try_execute(),
|
||||
CommandOpts::Remove { cmd } => cmd.try_execute(),
|
||||
|
||||
CommandOpts::Lint { cmd } => cmd.try_execute(),
|
||||
CommandOpts::Deploy { cmd } => cmd.try_execute(),
|
||||
});
|
||||
}
|
||||
|
||||
fn handle_error<T>(res: Result<T, Error>) -> T {
|
||||
match res {
|
||||
Ok(t) => t,
|
||||
Err(err) => {
|
||||
eprintln!("Error: {}", err);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
128
leo/tests/mod.rs
Normal file
128
leo/tests/mod.rs
Normal file
@ -0,0 +1,128 @@
|
||||
// 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::{
|
||||
package::{Login, Logout},
|
||||
Build,
|
||||
Command,
|
||||
Prove,
|
||||
Run,
|
||||
Setup,
|
||||
Test,
|
||||
Update,
|
||||
UpdateAutomatic,
|
||||
},
|
||||
context::{create_context, Context},
|
||||
};
|
||||
use anyhow::Result;
|
||||
use std::path::PathBuf;
|
||||
|
||||
/// 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,7 +13,8 @@
|
||||
|
||||
// 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::{config::Config, errors::UpdaterError};
|
||||
use crate::config::Config;
|
||||
use anyhow::{anyhow, Error};
|
||||
|
||||
use colored::Colorize;
|
||||
use self_update::{backends::github, version::bump_is_greater, Status};
|
||||
@ -27,7 +28,7 @@ impl Updater {
|
||||
const LEO_REPO_OWNER: &'static str = "AleoHQ";
|
||||
|
||||
/// Show all available releases for `leo`.
|
||||
pub fn show_available_releases() -> Result<(), UpdaterError> {
|
||||
pub fn show_available_releases() -> Result<(), Error> {
|
||||
let releases = github::ReleaseList::configure()
|
||||
.repo_owner(Self::LEO_REPO_OWNER)
|
||||
.repo_name(Self::LEO_REPO_NAME)
|
||||
@ -46,7 +47,7 @@ impl Updater {
|
||||
}
|
||||
|
||||
/// 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, Error> {
|
||||
let status = github::Update::configure()
|
||||
.repo_owner(Self::LEO_REPO_OWNER)
|
||||
.repo_name(Self::LEO_REPO_NAME)
|
||||
@ -62,7 +63,7 @@ impl Updater {
|
||||
}
|
||||
|
||||
/// 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, Error> {
|
||||
let updater = github::Update::configure()
|
||||
.repo_owner(Self::LEO_REPO_OWNER)
|
||||
.repo_name(Self::LEO_REPO_NAME)
|
||||
@ -76,7 +77,11 @@ impl Updater {
|
||||
if bump_is_greater(¤t_version, &latest_release.version)? {
|
||||
Ok(latest_release.version)
|
||||
} 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