Skip to content

Commit d758dea

Browse files
authored
Merge pull request #28601 from ProvableHQ/feat/cli-improvements
Overhaul `leo::{deploy, execute}`
2 parents 913edb3 + 58e1579 commit d758dea

File tree

24 files changed

+1382
-885
lines changed

24 files changed

+1382
-885
lines changed

Cargo.lock

Lines changed: 0 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,6 @@ only_testnet = [ ]
168168
[dependencies]
169169
dialoguer = "0.11.0"
170170
num-format = "0.4.4"
171-
text-tables = "0.3.1"
172171

173172
[dependencies.leo-ast]
174173
workspace = true

errors/src/errors/cli/cli_errors.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ create_messages!(
227227
invalid_network_name {
228228
args: (network: impl Display),
229229
msg: format!("Invalid network name: {network}"),
230-
help: Some("Valid network names are `testnet` and `mainnet`.".to_string()),
230+
help: Some("Valid network names are `testnet`, `mainnet`, and `canary`.".to_string()),
231231
}
232232

233233
@backtraced
@@ -327,4 +327,11 @@ create_messages!(
327327
msg: format!("Invalid program name `{name}`"),
328328
help: None,
329329
}
330+
331+
@backtraced
332+
custom {
333+
args: (msg: impl Display),
334+
msg: format!("{msg}"),
335+
help: None,
336+
}
330337
);

errors/src/errors/package/package_errors.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ create_messages!(
238238
/// For when file could not be read.
239239
@backtraced
240240
failed_to_read_file {
241-
args: (path: impl Display, error: impl ErrorArg),
241+
args: (path: impl Display, error: impl Display),
242242
msg: format!("failed to read file: {path}, error: {error}"),
243243
help: None,
244244
}

leo/cli/cli.rs

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ mod tests {
186186
inputs: vec!["1u32".to_string(), "2u32".to_string()],
187187
file: None,
188188
compiler_options: Default::default(),
189+
env_override: Default::default(),
189190
},
190191
},
191192
path: Some(project_directory.clone()),
@@ -231,6 +232,7 @@ mod tests {
231232
],
232233
file: None,
233234
compiler_options: Default::default(),
235+
env_override: Default::default(),
234236
},
235237
},
236238
path: Some(project_directory.clone()),
@@ -270,6 +272,7 @@ mod tests {
270272
name: "inner_1_main".to_string(),
271273
inputs: vec!["1u32".to_string(), "2u32".to_string()],
272274
compiler_options: Default::default(),
275+
env_override: Default::default(),
273276
file: None,
274277
},
275278
},
@@ -307,6 +310,7 @@ mod tests {
307310
name: "main".to_string(),
308311
inputs: vec!["1u32".to_string(), "2u32".to_string()],
309312
compiler_options: Default::default(),
313+
env_override: Default::default(),
310314
file: None,
311315
},
312316
},
@@ -322,7 +326,7 @@ mod tests {
322326

323327
#[cfg(test)]
324328
mod test_helpers {
325-
use crate::cli::{CLI, LeoAdd, LeoNew, cli::Commands, run_with_args};
329+
use crate::cli::{CLI, DependencySource, LeoAdd, LeoNew, cli::Commands, run_with_args};
326330
use leo_span::create_session_if_not_set_then;
327331
use std::path::Path;
328332

@@ -415,8 +419,7 @@ function external_nested_function:
415419
command: Commands::Add {
416420
command: LeoAdd {
417421
name: "nested_example_layer_0".to_string(),
418-
local: None,
419-
network: NETWORK.to_string(),
422+
source: DependencySource { local: None, network: true },
420423
clear: false,
421424
dev: false,
422425
},
@@ -528,8 +531,7 @@ program child.aleo {
528531
command: Commands::Add {
529532
command: LeoAdd {
530533
name: "parent".to_string(),
531-
local: Some(parent_directory.clone()),
532-
network: NETWORK.to_string(),
534+
source: DependencySource { local: Some(parent_directory.clone()), network: false },
533535
clear: false,
534536
dev: false,
535537
},
@@ -544,8 +546,7 @@ program child.aleo {
544546
command: Commands::Add {
545547
command: LeoAdd {
546548
name: "child".to_string(),
547-
local: Some(child_directory.clone()),
548-
network: NETWORK.to_string(),
549+
source: DependencySource { local: Some(child_directory.clone()), network: false },
549550
clear: false,
550551
dev: false,
551552
},
@@ -560,8 +561,7 @@ program child.aleo {
560561
command: Commands::Add {
561562
command: LeoAdd {
562563
name: "child".to_string(),
563-
local: Some(child_directory.clone()),
564-
network: NETWORK.to_string(),
564+
source: DependencySource { local: Some(child_directory.clone()), network: false },
565565
clear: false,
566566
dev: false,
567567
},
@@ -703,8 +703,7 @@ program outer.aleo {
703703
command: Commands::Add {
704704
command: LeoAdd {
705705
name: "inner_1".to_string(),
706-
local: Some(inner_1_directory.clone()),
707-
network: NETWORK.to_string(),
706+
source: DependencySource { local: Some(inner_1_directory.clone()), network: false },
708707
clear: false,
709708
dev: false,
710709
},
@@ -719,8 +718,7 @@ program outer.aleo {
719718
command: Commands::Add {
720719
command: LeoAdd {
721720
name: "inner_2".to_string(),
722-
local: Some(inner_2_directory.clone()),
723-
network: NETWORK.to_string(),
721+
source: DependencySource { local: Some(inner_2_directory.clone()), network: false },
724722
clear: false,
725723
dev: false,
726724
},
@@ -892,8 +890,7 @@ program outer_2.aleo {
892890
command: Commands::Add {
893891
command: LeoAdd {
894892
name: "inner_1".to_string(),
895-
local: Some(inner_1_directory.clone()),
896-
network: NETWORK.to_string(),
893+
source: DependencySource { local: Some(inner_1_directory.clone()), network: false },
897894
clear: false,
898895
dev: false,
899896
},
@@ -908,8 +905,7 @@ program outer_2.aleo {
908905
command: Commands::Add {
909906
command: LeoAdd {
910907
name: "inner_2".to_string(),
911-
local: Some(inner_2_directory.clone()),
912-
network: NETWORK.to_string(),
908+
source: DependencySource { local: Some(inner_2_directory.clone()), network: false },
913909
clear: false,
914910
dev: false,
915911
},

leo/cli/commands/add.rs

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
1616

1717
use super::*;
18-
use leo_package::{Dependency, Location, Manifest, NetworkName};
18+
use leo_package::{Dependency, Location, Manifest};
1919
use std::path::PathBuf;
2020

2121
/// Add a new on-chain or local dependency to the current package.
@@ -25,11 +25,8 @@ pub struct LeoAdd {
2525
#[clap(name = "NAME", help = "The dependency name. Ex: `credits.aleo` or `credits`.")]
2626
pub(crate) name: String,
2727

28-
#[clap(short = 'l', long, help = "Path to local dependency")]
29-
pub(crate) local: Option<PathBuf>,
30-
31-
#[clap(short = 'n', long, help = "Name of the network to use", default_value = "testnet")]
32-
pub(crate) network: String,
28+
#[clap(flatten)]
29+
pub(crate) source: DependencySource,
3330

3431
#[clap(short = 'c', long, help = "Clear all previous dependencies.", default_value = "false")]
3532
pub(crate) clear: bool,
@@ -38,6 +35,16 @@ pub struct LeoAdd {
3835
pub(crate) dev: bool,
3936
}
4037

38+
#[derive(Parser, Debug)]
39+
#[group(required = true, multiple = false)]
40+
pub struct DependencySource {
41+
#[clap(short = 'l', long, help = "Whether the dependency is local to the machine.", group = "source")]
42+
pub(crate) local: Option<PathBuf>,
43+
44+
#[clap(short = 'n', long, help = "Whether the dependency is on a live network.", group = "source")]
45+
pub(crate) network: bool,
46+
}
47+
4148
impl Command for LeoAdd {
4249
type Input = ();
4350
type Output = ();
@@ -64,13 +71,10 @@ impl Command for LeoAdd {
6471
return Err(CliError::invalid_program_name(name).into());
6572
}
6673

67-
let network: NetworkName = self.network.parse()?;
68-
6974
let new_dependency = Dependency {
7075
name: name.clone(),
71-
location: if self.local.is_some() { Location::Local } else { Location::Network },
72-
network: if self.local.is_some() { None } else { Some(network) },
73-
path: self.local.clone(),
76+
location: if self.source.local.is_some() { Location::Local } else { Location::Network },
77+
path: self.source.local.clone(),
7478
};
7579

7680
let deps = if self.dev { &mut manifest.dev_dependencies } else { &mut manifest.dependencies };
@@ -87,10 +91,10 @@ impl Command for LeoAdd {
8791
*matched_dep = new_dependency;
8892
} else {
8993
deps.as_mut().unwrap().push(new_dependency);
90-
if let Some(path) = self.local.as_ref() {
94+
if let Some(path) = self.source.local.as_ref() {
9195
tracing::info!("✅ Added local dependency to program `{name}` at path `{}`.", path.display());
9296
} else {
93-
tracing::info!("✅ Added network dependency `{name}` from network `{}`.", self.network);
97+
tracing::info!("✅ Added network dependency `{name}` from network `{}`.", self.source.network);
9498
}
9599
}
96100

leo/cli/commands/build.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ impl From<BuildOptions> for CompilerOptions {
4747
pub struct LeoBuild {
4848
#[clap(flatten)]
4949
pub(crate) options: BuildOptions,
50+
#[clap(flatten)]
51+
pub(crate) env_override: EnvOptions,
5052
}
5153

5254
impl Command for LeoBuild {
@@ -63,7 +65,7 @@ impl Command for LeoBuild {
6365

6466
fn apply(self, context: Context, _: Self::Input) -> Result<Self::Output> {
6567
// Parse the network.
66-
let network: NetworkName = context.get_network(&self.options.network)?.parse()?;
68+
let network: NetworkName = context.get_network(&self.env_override.network)?.parse()?;
6769
match network {
6870
NetworkName::MainnetV0 => handle_build::<MainnetV0>(&self, context),
6971
NetworkName::TestnetV0 => handle_build::<TestnetV0>(&self, context),
@@ -78,9 +80,9 @@ fn handle_build<N: Network>(command: &LeoBuild, context: Context) -> Result<<Leo
7880
let home_path = context.home()?;
7981

8082
let package = if command.options.build_tests {
81-
leo_package::Package::from_directory_with_tests(&package_path, &home_path)?
83+
leo_package::Package::from_directory_with_tests(&package_path, &home_path, command.options.no_cache)?
8284
} else {
83-
leo_package::Package::from_directory(&package_path, &home_path)?
85+
leo_package::Package::from_directory(&package_path, &home_path, command.options.no_cache)?
8486
};
8587

8688
let outputs_directory = package.outputs_directory();
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
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+
17+
use super::*;
18+
use leo_package::NetworkName;
19+
20+
/// Asks the user to confirm an action, with an optional `--yes` override.
21+
pub fn confirm(prompt: &str, skip_confirmation: bool) -> Result<bool> {
22+
if skip_confirmation {
23+
return Ok(true);
24+
}
25+
26+
let result = Confirm::with_theme(&ColorfulTheme::default())
27+
.with_prompt(prompt)
28+
.default(false)
29+
.interact()
30+
.map_err(|e| CliError::custom(format!("Failed to prompt user: {e}")).into());
31+
32+
// Print a newline for better formatting.
33+
println!();
34+
35+
result
36+
}
37+
38+
/// Asks the user to confirm a fee.
39+
pub fn confirm_fee<N: Network>(
40+
fee: &snarkvm::prelude::Fee<N>,
41+
private_key: &PrivateKey<N>,
42+
address: &Address<N>,
43+
endpoint: &str,
44+
network: NetworkName,
45+
context: &Context,
46+
skip: bool,
47+
) -> Result<bool> {
48+
// Get the fee amount.
49+
let total_cost = (*fee.amount()? as f64) / 1_000_000.0;
50+
if fee.is_fee_public() {
51+
let public_balance =
52+
get_public_balance(private_key, endpoint, &network.to_string(), context)? as f64 / 1_000_000.0;
53+
println!("💰Your current public balance is {public_balance} credits.\n");
54+
if public_balance < total_cost {
55+
return Err(PackageError::insufficient_balance(address, public_balance, total_cost).into());
56+
}
57+
}
58+
// Confirm the transaction.
59+
confirm(&format!("This transaction will cost you {total_cost} credits. Do you want to proceed?"), skip)
60+
}

leo/cli/commands/common/mod.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
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+
17+
mod interactive;
18+
pub use interactive::*;
19+
20+
mod options;
21+
pub use options::*;
22+
23+
mod query;
24+
pub use query::*;
25+
26+
use super::*;

0 commit comments

Comments
 (0)