leo_lang/cli/commands/
mod.rs

1// Copyright (C) 2019-2025 Provable Inc.
2// This file is part of the Leo library.
3
4// The Leo library is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// The Leo library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
16
17mod add;
18pub use add::{DependencySource, LeoAdd};
19
20mod account;
21pub use account::Account;
22
23mod build;
24pub use build::LeoBuild;
25
26mod clean;
27pub use clean::LeoClean;
28
29mod common;
30pub use common::*;
31
32mod debug;
33pub use debug::LeoDebug;
34
35mod deploy;
36pub use deploy::LeoDeploy;
37use deploy::{Task, print_deployment_plan, print_deployment_stats};
38
39mod devnet;
40pub use devnet::LeoDevnet;
41
42mod execute;
43pub use execute::LeoExecute;
44
45pub mod query;
46pub use query::LeoQuery;
47
48mod new;
49pub use new::LeoNew;
50
51mod remove;
52pub use remove::LeoRemove;
53
54mod run;
55pub use run::LeoRun;
56
57mod synthesize;
58pub use synthesize::LeoSynthesize;
59
60mod test;
61pub use test::LeoTest;
62
63mod update;
64pub use update::LeoUpdate;
65
66pub mod upgrade;
67pub use upgrade::LeoUpgrade;
68
69use super::*;
70use crate::cli::{helpers::context::*, query::QueryCommands};
71
72use leo_errors::{CliError, Handler, PackageError, Result};
73use snarkvm::{
74    console::network::Network,
75    prelude::{Address, Ciphertext, Plaintext, PrivateKey, Record, Value, ViewKey, block::Transaction},
76};
77
78use clap::{Args, Parser};
79use colored::Colorize;
80use dialoguer::{Confirm, theme::ColorfulTheme};
81use std::{iter, str::FromStr};
82use tracing::span::Span;
83use ureq::http::Uri;
84
85/// Base trait for the Leo CLI, see methods and their documentation for details.
86pub trait Command {
87    /// If the current command requires running another command beforehand
88    /// and needs its output result, this is where the result type is defined.
89    /// Example: type Input: <CommandA as Command>::Out
90    type Input;
91
92    /// Defines the output of this command, which may be used as `Input` for another
93    /// command. If this command is not used as a prelude for another command,
94    /// this field may be left empty.
95    type Output;
96
97    /// Adds a span to the logger via `tracing::span`.
98    /// Because of the specifics of the macro implementation, it is not possible
99    /// to set the span name with a non-literal i.e. a dynamic variable even if this
100    /// variable is a &'static str.
101    fn log_span(&self) -> Span {
102        tracing::span!(tracing::Level::INFO, "Leo")
103    }
104
105    /// Runs the prelude and returns the Input of the current command.
106    fn prelude(&self, context: Context) -> Result<Self::Input>
107    where
108        Self: std::marker::Sized;
109
110    /// Runs the main operation of this command. This function is run within
111    /// context of 'execute' function, which sets logging and timers.
112    fn apply(self, context: Context, input: Self::Input) -> Result<Self::Output>
113    where
114        Self: std::marker::Sized;
115
116    /// A wrapper around the `apply` method.
117    /// This function sets up tracing, timing, and the context.
118    fn execute(self, context: Context) -> Result<Self::Output>
119    where
120        Self: std::marker::Sized,
121    {
122        let input = self.prelude(context.clone())?;
123
124        // Create the span for this command.
125        let span = self.log_span();
126        let span = span.enter();
127
128        // Calculate the execution time for this command.
129        let out = self.apply(context, input);
130
131        drop(span);
132
133        out
134    }
135
136    /// Executes command but empty the result. Comes in handy where there's a
137    /// need to make match arms compatible while keeping implementation-specific
138    /// output possible. Errors however are all of the type Error
139    fn try_execute(self, context: Context) -> Result<()>
140    where
141        Self: std::marker::Sized,
142    {
143        self.execute(context).map(|_| Ok(()))?
144    }
145}
146
147/// A helper function to parse an input string into a `Value`, handling record ciphertexts as well.
148pub fn parse_input<N: Network>(input: &str, private_key: &PrivateKey<N>) -> Result<Value<N>> {
149    // Trim whitespace from the input.
150    let input = input.trim();
151    // Check if the input is a record ciphertext.
152    if input.starts_with("record1") {
153        // Get the view key from the private key.
154        let view_key = ViewKey::<N>::try_from(private_key)
155            .map_err(|e| CliError::custom(format!("Failed to view key from the private key: {e}")))?;
156        // Parse the input as a record.
157        Record::<N, Ciphertext<N>>::from_str(input)
158            .and_then(|ciphertext| ciphertext.decrypt(&view_key))
159            .map(Value::Record)
160            .map_err(|e| CliError::custom(format!("Failed to parse input as record: {e}")).into())
161    } else {
162        Value::from_str(input).map_err(|e| CliError::custom(format!("Failed to parse input: {e}")).into())
163    }
164}