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 test;
58pub use test::LeoTest;
59
60mod update;
61pub use update::LeoUpdate;
62
63pub mod upgrade;
64pub use upgrade::LeoUpgrade;
65
66use super::*;
67use crate::cli::{helpers::context::*, query::QueryCommands};
68
69use leo_errors::{CliError, Handler, PackageError, Result};
70use snarkvm::{
71    console::network::Network,
72    prelude::{Address, Ciphertext, Plaintext, PrivateKey, Record, Value, ViewKey, block::Transaction},
73};
74
75use clap::{Args, Parser};
76use colored::Colorize;
77use dialoguer::{Confirm, theme::ColorfulTheme};
78use std::{iter, str::FromStr};
79use tracing::span::Span;
80use ureq::http::Uri;
81
82/// Base trait for the Leo CLI, see methods and their documentation for details.
83pub trait Command {
84    /// If the current command requires running another command beforehand
85    /// and needs its output result, this is where the result type is defined.
86    /// Example: type Input: <CommandA as Command>::Out
87    type Input;
88
89    /// Defines the output of this command, which may be used as `Input` for another
90    /// command. If this command is not used as a prelude for another command,
91    /// this field may be left empty.
92    type Output;
93
94    /// Adds a span to the logger via `tracing::span`.
95    /// Because of the specifics of the macro implementation, it is not possible
96    /// to set the span name with a non-literal i.e. a dynamic variable even if this
97    /// variable is a &'static str.
98    fn log_span(&self) -> Span {
99        tracing::span!(tracing::Level::INFO, "Leo")
100    }
101
102    /// Runs the prelude and returns the Input of the current command.
103    fn prelude(&self, context: Context) -> Result<Self::Input>
104    where
105        Self: std::marker::Sized;
106
107    /// Runs the main operation of this command. This function is run within
108    /// context of 'execute' function, which sets logging and timers.
109    fn apply(self, context: Context, input: Self::Input) -> Result<Self::Output>
110    where
111        Self: std::marker::Sized;
112
113    /// A wrapper around the `apply` method.
114    /// This function sets up tracing, timing, and the context.
115    fn execute(self, context: Context) -> Result<Self::Output>
116    where
117        Self: std::marker::Sized,
118    {
119        let input = self.prelude(context.clone())?;
120
121        // Create the span for this command.
122        let span = self.log_span();
123        let span = span.enter();
124
125        // Calculate the execution time for this command.
126        let out = self.apply(context, input);
127
128        drop(span);
129
130        out
131    }
132
133    /// Executes command but empty the result. Comes in handy where there's a
134    /// need to make match arms compatible while keeping implementation-specific
135    /// output possible. Errors however are all of the type Error
136    fn try_execute(self, context: Context) -> Result<()>
137    where
138        Self: std::marker::Sized,
139    {
140        self.execute(context).map(|_| Ok(()))?
141    }
142}
143
144/// A helper function to parse an input string into a `Value`, handling record ciphertexts as well.
145pub fn parse_input<N: Network>(input: &str, private_key: &PrivateKey<N>) -> Result<Value<N>> {
146    // Trim whitespace from the input.
147    let input = input.trim();
148    // Check if the input is a record ciphertext.
149    if input.starts_with("record1") {
150        // Get the view key from the private key.
151        let view_key = ViewKey::<N>::try_from(private_key)
152            .map_err(|e| CliError::custom(format!("Failed to view key from the private key: {e}")))?;
153        // Parse the input as a record.
154        Record::<N, Ciphertext<N>>::from_str(input)
155            .and_then(|ciphertext| ciphertext.decrypt(&view_key))
156            .map(Value::Record)
157            .map_err(|e| CliError::custom(format!("Failed to parse input as record: {e}")).into())
158    } else {
159        Value::from_str(input).map_err(|e| CliError::custom(format!("Failed to parse input: {e}")).into())
160    }
161}