Feat/updater (#2410)

* implement leo update cli command and refactor cli directory structure

* simplify dependencies

* silence clippy warning
This commit is contained in:
Collin Chin 2023-06-12 14:39:02 -07:00 committed by GitHub
parent 4205d191f4
commit bb73b9fa31
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 236 additions and 146 deletions

View File

@ -45,7 +45,7 @@ path = "leo/lib.rs"
[[bin]] [[bin]]
name = "leo" name = "leo"
path = "leo/main.rs" path = "leo/cli/main.rs"
[features] [features]
default = [ ] default = [ ]

View File

@ -14,14 +14,8 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
pub mod commands; use crate::cli::{commands::*, context::*, helpers::*};
pub mod context;
pub mod logger;
pub mod updater;
use crate::{commands::*, context::*};
use leo_errors::Result; use leo_errors::Result;
use leo_span::symbol::create_session_if_not_set_then;
use clap::Parser; use clap::Parser;
use std::{path::PathBuf, process::exit}; use std::{path::PathBuf, process::exit};
@ -75,6 +69,11 @@ enum Commands {
#[clap(flatten)] #[clap(flatten)]
command: Run, command: Run,
}, },
#[clap(about = "Update the Leo CLI")]
Update {
#[clap(flatten)]
command: Update,
},
// #[clap(subcommand)] // #[clap(subcommand)]
// Node(Node), // Node(Node),
// #[clap(about = "Deploy a program")] // #[clap(about = "Deploy a program")]
@ -84,30 +83,6 @@ enum Commands {
// }, // },
} }
fn set_panic_hook() {
#[cfg(not(debug_assertions))]
std::panic::set_hook({
Box::new(move |e| {
eprintln!("thread `{}` {}", std::thread::current().name().unwrap_or("<unnamed>"), e);
eprintln!("stack backtrace: \n{:?}", backtrace::Backtrace::new());
eprintln!("error: internal compiler error: unexpected panic\n");
eprintln!("note: the compiler unexpectedly panicked. this is a bug.\n");
eprintln!(
"note: we would appreciate a bug report: https://github.com/AleoHQ/leo/issues/new?labels=bug,panic&template=bug.md&title=[Bug]\n"
);
eprintln!(
"note: {} {} running on {} {}\n",
env!("CARGO_PKG_NAME"),
env!("CARGO_PKG_VERSION"),
sys_info::os_type().unwrap_or_else(|e| e.to_string()),
sys_info::os_release().unwrap_or_else(|e| e.to_string()),
);
eprintln!("note: compiler args: {}\n", std::env::args().collect::<Vec<_>>().join(" "));
eprintln!("note: compiler flags: {:?}\n", CLI::parse());
})
});
}
pub fn handle_error<T>(res: Result<T>) -> T { pub fn handle_error<T>(res: Result<T>) -> T {
match res { match res {
Ok(t) => t, Ok(t) => t,
@ -137,12 +112,8 @@ pub fn run_with_args(cli: CLI) -> Result<()> {
Commands::Build { command } => command.try_execute(context), Commands::Build { command } => command.try_execute(context),
Commands::Clean { command } => command.try_execute(context), Commands::Clean { command } => command.try_execute(context),
Commands::Run { command } => command.try_execute(context), Commands::Run { command } => command.try_execute(context),
Commands::Update { command } => command.try_execute(context),
// Commands::Node(command) => command.try_execute(context), // Commands::Node(command) => command.try_execute(context),
// Commands::Deploy { command } => command.try_execute(context), // Commands::Deploy { command } => command.try_execute(context),
} }
} }
fn main() {
set_panic_hook();
create_session_if_not_set_then(|_| handle_error(run_with_args(CLI::parse())));
}

View File

@ -14,14 +14,10 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{ use super::*;
commands::{Command, ALEO_CLI_COMMAND},
context::Context,
};
use leo_ast::Struct; use leo_ast::Struct;
use leo_compiler::{Compiler, CompilerOptions, InputAst, OutputOptions}; use leo_compiler::{Compiler, CompilerOptions, InputAst, OutputOptions};
use leo_errors::{emitter::Handler, CliError, CompilerError, PackageError, Result};
use leo_package::{ use leo_package::{
build::BuildDirectory, build::BuildDirectory,
imports::ImportsDirectory, imports::ImportsDirectory,
@ -36,43 +32,12 @@ use snarkvm::{
prelude::{ProgramID, Testnet3}, prelude::{ProgramID, Testnet3},
}; };
use clap::Parser;
use indexmap::IndexMap; use indexmap::IndexMap;
use std::{ use std::{
io::Write, io::Write,
path::{Path, PathBuf}, path::{Path, PathBuf},
}; };
use tracing::span::Span;
/// Compiler Options wrapper for Build command. Also used by other commands which
/// require Build command output as their input.
#[derive(Parser, Clone, Debug, Default)]
pub struct BuildOptions {
#[clap(long, help = "Enables offline mode.")]
pub offline: bool,
#[clap(long, help = "Enable spans in AST snapshots.")]
pub enable_spans: bool,
#[clap(long, help = "Enables dead code elimination in the compiler.")]
pub enable_dce: bool,
#[clap(long, help = "Writes all AST snapshots for the different compiler phases.")]
pub enable_all_ast_snapshots: bool,
#[clap(long, help = "Writes Input AST snapshot of the initial parse.")]
pub enable_initial_input_ast_snapshot: bool,
#[clap(long, help = "Writes AST snapshot of the initial parse.")]
pub enable_initial_ast_snapshot: bool,
#[clap(long, help = "Writes AST snapshot of the unrolled AST.")]
pub enable_unrolled_ast_snapshot: bool,
#[clap(long, help = "Writes AST snapshot of the SSA AST.")]
pub enable_ssa_ast_snapshot: bool,
#[clap(long, help = "Writes AST snapshot of the flattened AST.")]
pub enable_flattened_ast_snapshot: bool,
#[clap(long, help = "Writes AST snapshot of the inlined AST.")]
pub enable_inlined_ast_snapshot: bool,
#[clap(long, help = "Writes AST snapshot of the dead code eliminated (DCE) AST.")]
pub enable_dce_ast_snapshot: bool,
}
impl From<BuildOptions> for CompilerOptions { impl From<BuildOptions> for CompilerOptions {
fn from(options: BuildOptions) -> Self { fn from(options: BuildOptions) -> Self {
let mut out_options = Self { let mut out_options = Self {

View File

@ -14,13 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{commands::Command, context::Context}; use super::*;
use leo_errors::Result;
use leo_package::{build::BuildDirectory, outputs::OutputsDirectory};
use clap::Parser;
use colored::Colorize;
use tracing::span::Span;
/// Clean outputs folder command /// Clean outputs folder command
#[derive(Parser, Debug)] #[derive(Parser, Debug)]

View File

@ -14,19 +14,10 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{ use super::*;
commands::{Command, ALEO_CLI_COMMAND},
context::Context,
};
use leo_errors::{CliError, PackageError, Result};
use leo_package::build::BuildDirectory;
use aleo::commands::Deploy as AleoDeploy; use aleo::commands::Deploy as AleoDeploy;
use clap::Parser;
use tracing::span::Span;
/// Deploys an Aleo program. /// Deploys an Aleo program.
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
pub struct Deploy; pub struct Deploy;

View File

@ -14,7 +14,6 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
// local program commands
pub mod build; pub mod build;
pub use build::Build; pub use build::Build;
@ -33,14 +32,18 @@ pub use new::New;
pub mod run; pub mod run;
pub use run::Run; pub use run::Run;
use crate::context::*; pub mod update;
use leo_errors::Result; pub use update::Update;
use super::*;
use crate::cli::helpers::context::*;
use leo_errors::{emitter::Handler, CliError, CompilerError, PackageError, Result};
use leo_package::{build::*, outputs::OutputsDirectory, package::*};
use clap::Parser;
use colored::Colorize;
use tracing::span::Span; use tracing::span::Span;
pub(crate) type Network = snarkvm::prelude::Testnet3;
pub(crate) const ALEO_CLI_COMMAND: &str = "snarkvm";
/// Base trait for the Leo CLI, see methods and their documentation for details. /// Base trait for the Leo CLI, see methods and their documentation for details.
pub trait Command { pub trait Command {
/// If the current command requires running another command beforehand /// If the current command requires running another command beforehand
@ -102,3 +105,31 @@ pub trait Command {
self.execute(context).map(|_| Ok(()))? self.execute(context).map(|_| Ok(()))?
} }
} }
/// Compiler Options wrapper for Build command. Also used by other commands which
/// require Build command output as their input.
#[derive(Parser, Clone, Debug, Default)]
pub struct BuildOptions {
#[clap(long, help = "Enables offline mode.")]
pub offline: bool,
#[clap(long, help = "Enable spans in AST snapshots.")]
pub enable_spans: bool,
#[clap(long, help = "Enables dead code elimination in the compiler.")]
pub enable_dce: bool,
#[clap(long, help = "Writes all AST snapshots for the different compiler phases.")]
pub enable_all_ast_snapshots: bool,
#[clap(long, help = "Writes Input AST snapshot of the initial parse.")]
pub enable_initial_input_ast_snapshot: bool,
#[clap(long, help = "Writes AST snapshot of the initial parse.")]
pub enable_initial_ast_snapshot: bool,
#[clap(long, help = "Writes AST snapshot of the unrolled AST.")]
pub enable_unrolled_ast_snapshot: bool,
#[clap(long, help = "Writes AST snapshot of the SSA AST.")]
pub enable_ssa_ast_snapshot: bool,
#[clap(long, help = "Writes AST snapshot of the flattened AST.")]
pub enable_flattened_ast_snapshot: bool,
#[clap(long, help = "Writes AST snapshot of the inlined AST.")]
pub enable_inlined_ast_snapshot: bool,
#[clap(long, help = "Writes AST snapshot of the dead code eliminated (DCE) AST.")]
pub enable_dce_ast_snapshot: bool,
}

View File

@ -14,18 +14,10 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{ use super::*;
commands::{Command, Network, ALEO_CLI_COMMAND},
context::Context,
};
use leo_errors::{CliError, PackageError, Result};
use leo_package::{build::BUILD_DIRECTORY_NAME, package::Package};
use snarkvm::{cli::New as AleoNew, file::AleoFile}; use snarkvm::{cli::New as AleoNew, file::AleoFile};
use clap::Parser;
use tracing::span::Span;
/// Create new Leo project /// Create new Leo project
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
pub struct New { pub struct New {

View File

@ -14,18 +14,10 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{ use super::*;
commands::{Command, ALEO_CLI_COMMAND},
context::Context,
};
use leo_errors::{CliError, PackageError, Result};
use leo_package::build::BuildDirectory;
use aleo::commands::Node as AleoNode; use aleo::commands::Node as AleoNode;
use clap::Parser;
use tracing::span::Span;
/// Commands to operate a local development node. /// Commands to operate a local development node.
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
pub enum Node { pub enum Node {

View File

@ -14,19 +14,10 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use super::build::BuildOptions; use super::*;
use crate::{
commands::{Build, Command, ALEO_CLI_COMMAND},
context::Context,
};
use leo_errors::{CliError, PackageError, Result};
use leo_package::build::BuildDirectory;
use snarkvm::cli::Run as AleoRun; use snarkvm::cli::Run as AleoRun;
use clap::Parser;
use tracing::span::Span;
/// Build, Prove and Run Leo program with inputs /// Build, Prove and Run Leo program with inputs
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
pub struct Run { pub struct Run {

View File

@ -0,0 +1,70 @@
// Copyright (C) 2019-2023 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 super::*;
use crate::cli::helpers::updater::Updater;
/// Update Leo to the latest version
#[derive(Debug, Parser)]
pub struct Update {
/// Lists all available versions of Leo
#[clap(short = 'l', long)]
list: bool,
/// Suppress outputs to terminal
#[clap(short = 'q', long)]
quiet: bool,
}
impl Command for Update {
type Input = ();
type Output = ();
fn log_span(&self) -> Span {
tracing::span!(tracing::Level::INFO, "Leo")
}
fn prelude(&self, _: Context) -> Result<Self::Input> {
Ok(())
}
fn apply(self, _: Context, _: Self::Input) -> Result<Self::Output>
where
Self: Sized,
{
match self.list {
true => match Updater::show_available_releases() {
Ok(output) => tracing::info!("{output}"),
Err(error) => tracing::info!("Failed to list the available versions of Leo\n{error}\n"),
},
false => {
let result = Updater::update_to_latest_release(!self.quiet);
if !self.quiet {
match result {
Ok(status) => {
if status.uptodate() {
tracing::info!("\nLeo is already on the latest version")
} else if status.updated() {
tracing::info!("\nLeo has updated to version {}", status.version())
}
}
Err(e) => tracing::info!("\nFailed to update Leo to the latest version\n{e}\n"),
}
}
}
}
Ok(())
}
}

View File

@ -14,11 +14,12 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::commands::Network; use super::*;
use leo_errors::{CliError, PackageError, Result}; use leo_errors::{CliError, PackageError, Result};
use leo_package::build::{BuildDirectory, BUILD_DIRECTORY_NAME};
use snarkvm::file::Manifest; use snarkvm::file::Manifest;
use leo_package::build::{BuildDirectory, BUILD_DIRECTORY_NAME};
use std::{ use std::{
env::current_dir, env::current_dir,
fs::File, fs::File,

View File

@ -31,12 +31,12 @@ static START: Once = Once::new();
pub struct Format<F = Full, T = SystemTime> { pub struct Format<F = Full, T = SystemTime> {
format: F, format: F,
#[allow(dead_code)] // todo: revisit this after merging span module #[allow(dead_code)] // todo: revisit this after merging span module
pub(crate) timer: T, pub timer: T,
pub(crate) ansi: bool, pub ansi: bool,
pub(crate) display_target: bool, pub display_target: bool,
pub(crate) display_level: bool, pub display_level: bool,
pub(crate) display_thread_id: bool, pub display_thread_id: bool,
pub(crate) display_thread_name: bool, pub display_thread_name: bool,
} }
impl<F, T> Format<F, T> { impl<F, T> Format<F, T> {

21
leo/cli/helpers/mod.rs Normal file
View File

@ -0,0 +1,21 @@
// Copyright (C) 2019-2023 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 use super::*;
pub mod context;
pub mod logger;
pub mod updater;

View File

@ -30,7 +30,7 @@ impl Updater {
const LEO_REPO_OWNER: &'static str = "AleoHQ"; const LEO_REPO_OWNER: &'static str = "AleoHQ";
/// Show all available releases for `leo`. /// Show all available releases for `leo`.
pub fn show_available_releases() -> Result<()> { pub fn show_available_releases() -> Result<String> {
let releases = github::ReleaseList::configure() let releases = github::ReleaseList::configure()
.repo_owner(Self::LEO_REPO_OWNER) .repo_owner(Self::LEO_REPO_OWNER)
.repo_name(Self::LEO_REPO_NAME) .repo_name(Self::LEO_REPO_NAME)
@ -44,10 +44,7 @@ impl Updater {
let _ = writeln!(output, " * {}", release.version); let _ = writeln!(output, " * {}", release.version);
} }
// Forgo using tracing to list the available versions without a log status. Ok(output)
println!("{output}");
Ok(())
} }
/// Update `leo` to the latest release. /// Update `leo` to the latest release.

49
leo/cli/main.rs Normal file
View File

@ -0,0 +1,49 @@
// Copyright (C) 2019-2023 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_lang::cli::*;
use leo_span::symbol::create_session_if_not_set_then;
use clap::Parser;
fn set_panic_hook() {
#[cfg(not(debug_assertions))]
std::panic::set_hook({
Box::new(move |e| {
eprintln!("thread `{}` {}", std::thread::current().name().unwrap_or("<unnamed>"), e);
eprintln!("stack backtrace: \n{:?}", backtrace::Backtrace::new());
eprintln!("error: internal compiler error: unexpected panic\n");
eprintln!("note: the compiler unexpectedly panicked. this is a bug.\n");
eprintln!(
"note: we would appreciate a bug report: https://github.com/AleoHQ/leo/issues/new?labels=bug,panic&template=bug.md&title=[Bug]\n"
);
eprintln!(
"note: {} {} running on {} {}\n",
env!("CARGO_PKG_NAME"),
env!("CARGO_PKG_VERSION"),
sys_info::os_type().unwrap_or_else(|e| e.to_string()),
sys_info::os_release().unwrap_or_else(|e| e.to_string()),
);
eprintln!("note: compiler args: {}\n", std::env::args().collect::<Vec<_>>().join(" "));
eprintln!("note: compiler flags: {:?}\n", CLI::parse());
})
});
}
fn main() {
set_panic_hook();
create_session_if_not_set_then(|_| handle_error(run_with_args(CLI::parse())));
}

30
leo/cli/mod.rs Normal file
View File

@ -0,0 +1,30 @@
// Copyright (C) 2019-2023 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/>.
mod cli;
pub use cli::*;
mod commands;
pub use commands::*;
mod helpers;
pub use helpers::*;
pub(crate) type Network = snarkvm::prelude::Testnet3;
pub(crate) const ALEO_CLI_COMMAND: &str = "snarkvm";
#[cfg(test)]
mod tests;

View File

@ -33,13 +33,13 @@ use leo_errors::Result;
#[test] #[test]
pub fn init_logger() -> Result<()> { pub fn init_logger() -> Result<()> {
crate::logger::init_logger("test_init_logger", 1)?; crate::cli::helpers::logger::init_logger("test_init_logger", 1)?;
Ok(()) Ok(())
} }
#[test] #[test]
pub fn format_event() -> Result<()> { pub fn format_event() -> Result<()> {
crate::logger::init_logger("test_format_event", 1)?; crate::cli::helpers::logger::init_logger("test_format_event", 1)?;
tracing::info!("test"); tracing::info!("test");
Ok(()) Ok(())
} }

View File

@ -15,12 +15,7 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
#![forbid(unsafe_code)] #![forbid(unsafe_code)]
#![allow(clippy::module_inception)]
#![doc = include_str!("../README.md")] #![doc = include_str!("../README.md")]
pub mod commands; pub mod cli;
pub mod context;
pub mod logger;
pub mod updater;
#[cfg(test)]
mod tests;