diff --git a/Cargo.toml b/Cargo.toml index 45e7674eae..3c3b014aeb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,7 +45,7 @@ path = "leo/lib.rs" [[bin]] name = "leo" -path = "leo/main.rs" +path = "leo/cli/main.rs" [features] default = [ ] diff --git a/leo/main.rs b/leo/cli/cli.rs similarity index 70% rename from leo/main.rs rename to leo/cli/cli.rs index 7ff965588f..5751abd9b7 100644 --- a/leo/main.rs +++ b/leo/cli/cli.rs @@ -14,14 +14,8 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -pub mod commands; -pub mod context; -pub mod logger; -pub mod updater; - -use crate::{commands::*, context::*}; +use crate::cli::{commands::*, context::*, helpers::*}; use leo_errors::Result; -use leo_span::symbol::create_session_if_not_set_then; use clap::Parser; use std::{path::PathBuf, process::exit}; @@ -75,6 +69,11 @@ enum Commands { #[clap(flatten)] command: Run, }, + #[clap(about = "Update the Leo CLI")] + Update { + #[clap(flatten)] + command: Update, + }, // #[clap(subcommand)] // Node(Node), // #[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(""), 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::>().join(" ")); - eprintln!("note: compiler flags: {:?}\n", CLI::parse()); - }) - }); -} - pub fn handle_error(res: Result) -> T { match res { Ok(t) => t, @@ -137,12 +112,8 @@ pub fn run_with_args(cli: CLI) -> Result<()> { Commands::Build { command } => command.try_execute(context), Commands::Clean { 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::Deploy { command } => command.try_execute(context), } } - -fn main() { - set_panic_hook(); - create_session_if_not_set_then(|_| handle_error(run_with_args(CLI::parse()))); -} diff --git a/leo/commands/build.rs b/leo/cli/commands/build.rs similarity index 84% rename from leo/commands/build.rs rename to leo/cli/commands/build.rs index eda83f5a62..cb9f6f123f 100644 --- a/leo/commands/build.rs +++ b/leo/cli/commands/build.rs @@ -14,14 +14,10 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use crate::{ - commands::{Command, ALEO_CLI_COMMAND}, - context::Context, -}; +use super::*; use leo_ast::Struct; use leo_compiler::{Compiler, CompilerOptions, InputAst, OutputOptions}; -use leo_errors::{emitter::Handler, CliError, CompilerError, PackageError, Result}; use leo_package::{ build::BuildDirectory, imports::ImportsDirectory, @@ -36,43 +32,12 @@ use snarkvm::{ prelude::{ProgramID, Testnet3}, }; -use clap::Parser; use indexmap::IndexMap; use std::{ io::Write, 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 for CompilerOptions { fn from(options: BuildOptions) -> Self { let mut out_options = Self { diff --git a/leo/commands/clean.rs b/leo/cli/commands/clean.rs similarity index 88% rename from leo/commands/clean.rs rename to leo/cli/commands/clean.rs index 11deeb965c..e0dd97c708 100644 --- a/leo/commands/clean.rs +++ b/leo/cli/commands/clean.rs @@ -14,13 +14,7 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use crate::{commands::Command, context::Context}; -use leo_errors::Result; -use leo_package::{build::BuildDirectory, outputs::OutputsDirectory}; - -use clap::Parser; -use colored::Colorize; -use tracing::span::Span; +use super::*; /// Clean outputs folder command #[derive(Parser, Debug)] diff --git a/leo/commands/deploy.rs b/leo/cli/commands/deploy.rs similarity index 90% rename from leo/commands/deploy.rs rename to leo/cli/commands/deploy.rs index 1258014e7e..6a679fe2b9 100644 --- a/leo/commands/deploy.rs +++ b/leo/cli/commands/deploy.rs @@ -14,19 +14,10 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use crate::{ - commands::{Command, ALEO_CLI_COMMAND}, - context::Context, -}; - -use leo_errors::{CliError, PackageError, Result}; -use leo_package::build::BuildDirectory; +use super::*; use aleo::commands::Deploy as AleoDeploy; -use clap::Parser; -use tracing::span::Span; - /// Deploys an Aleo program. #[derive(Parser, Debug)] pub struct Deploy; diff --git a/leo/commands/mod.rs b/leo/cli/commands/mod.rs similarity index 66% rename from leo/commands/mod.rs rename to leo/cli/commands/mod.rs index f783f5e222..fe2222e1c7 100644 --- a/leo/commands/mod.rs +++ b/leo/cli/commands/mod.rs @@ -14,7 +14,6 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -// local program commands pub mod build; pub use build::Build; @@ -33,14 +32,18 @@ pub use new::New; pub mod run; pub use run::Run; -use crate::context::*; -use leo_errors::Result; +pub mod update; +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; -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. pub trait Command { /// If the current command requires running another command beforehand @@ -102,3 +105,31 @@ pub trait Command { 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, +} diff --git a/leo/commands/new.rs b/leo/cli/commands/new.rs similarity index 93% rename from leo/commands/new.rs rename to leo/cli/commands/new.rs index 6a68a69a67..56faf5d846 100644 --- a/leo/commands/new.rs +++ b/leo/cli/commands/new.rs @@ -14,18 +14,10 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use crate::{ - commands::{Command, Network, ALEO_CLI_COMMAND}, - context::Context, -}; -use leo_errors::{CliError, PackageError, Result}; -use leo_package::{build::BUILD_DIRECTORY_NAME, package::Package}; +use super::*; use snarkvm::{cli::New as AleoNew, file::AleoFile}; -use clap::Parser; -use tracing::span::Span; - /// Create new Leo project #[derive(Parser, Debug)] pub struct New { diff --git a/leo/commands/node.rs b/leo/cli/commands/node.rs similarity index 92% rename from leo/commands/node.rs rename to leo/cli/commands/node.rs index 0e8185774b..6f026e8119 100644 --- a/leo/commands/node.rs +++ b/leo/cli/commands/node.rs @@ -14,18 +14,10 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use crate::{ - commands::{Command, ALEO_CLI_COMMAND}, - context::Context, -}; -use leo_errors::{CliError, PackageError, Result}; -use leo_package::build::BuildDirectory; +use super::*; use aleo::commands::Node as AleoNode; -use clap::Parser; -use tracing::span::Span; - /// Commands to operate a local development node. #[derive(Parser, Debug)] pub enum Node { diff --git a/leo/commands/run.rs b/leo/cli/commands/run.rs similarity index 92% rename from leo/commands/run.rs rename to leo/cli/commands/run.rs index b36698b13a..9f64a32ab8 100644 --- a/leo/commands/run.rs +++ b/leo/cli/commands/run.rs @@ -14,19 +14,10 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use super::build::BuildOptions; -use crate::{ - commands::{Build, Command, ALEO_CLI_COMMAND}, - context::Context, -}; -use leo_errors::{CliError, PackageError, Result}; -use leo_package::build::BuildDirectory; +use super::*; use snarkvm::cli::Run as AleoRun; -use clap::Parser; -use tracing::span::Span; - /// Build, Prove and Run Leo program with inputs #[derive(Parser, Debug)] pub struct Run { diff --git a/leo/cli/commands/update.rs b/leo/cli/commands/update.rs new file mode 100644 index 0000000000..b1342a4817 --- /dev/null +++ b/leo/cli/commands/update.rs @@ -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 . + +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 { + Ok(()) + } + + fn apply(self, _: Context, _: Self::Input) -> Result + 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(()) + } +} diff --git a/leo/context.rs b/leo/cli/helpers/context.rs similarity index 99% rename from leo/context.rs rename to leo/cli/helpers/context.rs index 96d68a94a8..ef7291ac3a 100644 --- a/leo/context.rs +++ b/leo/cli/helpers/context.rs @@ -14,11 +14,12 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use crate::commands::Network; +use super::*; use leo_errors::{CliError, PackageError, Result}; +use leo_package::build::{BuildDirectory, BUILD_DIRECTORY_NAME}; + use snarkvm::file::Manifest; -use leo_package::build::{BuildDirectory, BUILD_DIRECTORY_NAME}; use std::{ env::current_dir, fs::File, diff --git a/leo/logger.rs b/leo/cli/helpers/logger.rs similarity index 97% rename from leo/logger.rs rename to leo/cli/helpers/logger.rs index 510fe401d2..8e95ad3d94 100644 --- a/leo/logger.rs +++ b/leo/cli/helpers/logger.rs @@ -31,12 +31,12 @@ static START: Once = Once::new(); pub struct Format { format: F, #[allow(dead_code)] // todo: revisit this after merging span module - pub(crate) timer: T, - pub(crate) ansi: bool, - pub(crate) display_target: bool, - pub(crate) display_level: bool, - pub(crate) display_thread_id: bool, - pub(crate) display_thread_name: bool, + pub timer: T, + pub ansi: bool, + pub display_target: bool, + pub display_level: bool, + pub display_thread_id: bool, + pub display_thread_name: bool, } impl Format { diff --git a/leo/cli/helpers/mod.rs b/leo/cli/helpers/mod.rs new file mode 100644 index 0000000000..de2c63dc93 --- /dev/null +++ b/leo/cli/helpers/mod.rs @@ -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 . + +pub use super::*; + +pub mod context; +pub mod logger; +pub mod updater; diff --git a/leo/updater.rs b/leo/cli/helpers/updater.rs similarity index 95% rename from leo/updater.rs rename to leo/cli/helpers/updater.rs index 58e075372c..d226d9c2f3 100644 --- a/leo/updater.rs +++ b/leo/cli/helpers/updater.rs @@ -30,7 +30,7 @@ impl Updater { const LEO_REPO_OWNER: &'static str = "AleoHQ"; /// Show all available releases for `leo`. - pub fn show_available_releases() -> Result<()> { + pub fn show_available_releases() -> Result { let releases = github::ReleaseList::configure() .repo_owner(Self::LEO_REPO_OWNER) .repo_name(Self::LEO_REPO_NAME) @@ -44,10 +44,7 @@ impl Updater { let _ = writeln!(output, " * {}", release.version); } - // Forgo using tracing to list the available versions without a log status. - println!("{output}"); - - Ok(()) + Ok(output) } /// Update `leo` to the latest release. diff --git a/leo/cli/main.rs b/leo/cli/main.rs new file mode 100644 index 0000000000..5127e518d2 --- /dev/null +++ b/leo/cli/main.rs @@ -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 . + +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(""), 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::>().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()))); +} diff --git a/leo/cli/mod.rs b/leo/cli/mod.rs new file mode 100644 index 0000000000..cfa2720779 --- /dev/null +++ b/leo/cli/mod.rs @@ -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 . + +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; diff --git a/leo/tests/mod.rs b/leo/cli/tests/mod.rs similarity index 97% rename from leo/tests/mod.rs rename to leo/cli/tests/mod.rs index a2b4c02316..01ee7e9438 100644 --- a/leo/tests/mod.rs +++ b/leo/cli/tests/mod.rs @@ -33,13 +33,13 @@ use leo_errors::Result; #[test] pub fn init_logger() -> Result<()> { - crate::logger::init_logger("test_init_logger", 1)?; + crate::cli::helpers::logger::init_logger("test_init_logger", 1)?; Ok(()) } #[test] 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"); Ok(()) } diff --git a/leo/lib.rs b/leo/lib.rs index ce69ef94e4..910f23b73f 100644 --- a/leo/lib.rs +++ b/leo/lib.rs @@ -15,12 +15,7 @@ // along with the Leo library. If not, see . #![forbid(unsafe_code)] +#![allow(clippy::module_inception)] #![doc = include_str!("../README.md")] -pub mod commands; -pub mod context; -pub mod logger; -pub mod updater; - -#[cfg(test)] -mod tests; +pub mod cli;