use crate::cli::{commands::*, context::*, helpers::*};
use clap::Parser;
use leo_errors::{CliError, Result};
use serde::Serialize;
use std::{path::PathBuf, process::exit};
#[derive(Parser, Debug)]
#[clap(name = "leo", author = "The Leo Team <leo@provable.com>", version, long_version = env!("LEO_VERSION_STRING"))]
pub struct CLI {
#[clap(short, global = true, help = "Print additional information for debugging")]
debug: bool,
#[clap(short, global = true, help = "Suppress CLI output")]
quiet: bool,
#[clap(long, global = true, help = "Write results as JSON to a file. Defaults to build/json-outputs/<command>.json if no path specified.", num_args = 0..=1, require_equals = true, default_missing_value = "")]
json_output: Option<String>,
#[clap(long, global = true, help = "Disable Leo's daily check for version updates")]
disable_update_check: bool,
#[clap(subcommand)]
command: Commands,
#[clap(long, global = true, help = "Path to Leo program root folder")]
path: Option<PathBuf>,
#[clap(long, global = true, help = "Path to aleo program registry")]
pub home: Option<PathBuf>,
}
#[derive(Parser, Debug)]
enum Commands {
#[clap(about = "Create a new Aleo account, sign and verify messages")]
Account {
#[clap(subcommand)]
command: Account,
},
#[clap(about = "Create a new Leo package in a new directory")]
New {
#[clap(flatten)]
command: LeoNew,
},
#[clap(about = "Run a program with input variables", visible_alias = "r")]
Run {
#[clap(flatten)]
command: LeoRun,
},
#[clap(about = "Test a Leo program", visible_alias = "t")]
Test {
#[clap(flatten)]
command: LeoTest,
},
#[clap(about = "Execute a program with input variables")]
Execute {
#[clap(flatten)]
command: LeoExecute,
},
#[clap(name = "fmt", about = "Format Leo source files")]
Fmt {
#[clap(flatten)]
command: LeoFormat,
},
#[clap(about = "Deploy a program")]
Deploy {
#[clap(flatten)]
command: LeoDeploy,
},
#[clap(about = "Run a local devnet")]
Devnet {
#[clap(flatten)]
command: LeoDevnet,
},
#[clap(about = "Run a local devnode")]
Devnode {
#[clap(flatten)]
command: LeoDevnode,
},
#[clap(about = "Query live data from the Aleo network")]
Query {
#[clap(flatten)]
command: LeoQuery,
},
#[clap(about = "Compile the current package as a program", visible_alias = "b")]
Build {
#[clap(flatten)]
command: LeoBuild,
},
#[clap(about = "Generate ABI from an Aleo bytecode file")]
Abi {
#[clap(flatten)]
command: LeoAbi,
},
#[clap(about = "Add a new on-chain or local dependency to the current package.")]
Add {
#[clap(flatten)]
command: LeoAdd,
},
#[clap(about = "Remove a dependency from the current package.")]
Remove {
#[clap(flatten)]
command: LeoRemove,
},
#[clap(about = "Clean the output directory")]
Clean {
#[clap(flatten)]
command: LeoClean,
},
#[clap(about = "Synthesize individual keys")]
Synthesize {
#[clap(flatten)]
command: LeoSynthesize,
},
#[clap(about = "Update the Leo CLI")]
Update {
#[clap(flatten)]
command: LeoUpdate,
},
#[clap(about = "Upgrade the program on a network")]
Upgrade {
#[clap(flatten)]
command: LeoUpgrade,
},
}
impl Commands {
fn name(&self) -> &'static str {
match self {
Commands::Account { .. } => "account",
Commands::New { .. } => "new",
Commands::Run { .. } => "run",
Commands::Test { .. } => "test",
Commands::Execute { .. } => "execute",
Commands::Fmt { .. } => "fmt",
Commands::Deploy { .. } => "deploy",
Commands::Devnet { .. } => "devnet",
Commands::Devnode { .. } => "devnode",
Commands::Query { .. } => "query",
Commands::Build { .. } => "build",
Commands::Abi { .. } => "abi",
Commands::Add { .. } => "add",
Commands::Remove { .. } => "remove",
Commands::Clean { .. } => "clean",
Commands::Synthesize { .. } => "synthesize",
Commands::Update { .. } => "update",
Commands::Upgrade { .. } => "upgrade",
}
}
}
pub fn handle_error<T>(res: Result<T>) -> T {
match res {
Ok(t) => t,
Err(err) => {
eprintln!("{err}");
exit(err.exit_code());
}
}
}
#[derive(Serialize)]
#[serde(untagged)]
#[allow(clippy::large_enum_variant)]
enum JsonOutput {
Deploy(DeployOutput),
Run(RunOutput),
Execute(ExecuteOutput),
Test(TestOutput),
Query(serde_json::Value),
Synthesize(SynthesizeOutput),
}
pub fn run_with_args(cli: CLI) -> Result<()> {
let quiet = cli.quiet || cli.json_output.is_some();
if !quiet && let Ok(vars) = dotenvy::dotenv_iter().map(|v| v.flatten().collect::<Vec<_>>()) {
if !vars.is_empty() {
println!("📢 Loading environment variables from a `.env` file in the directory tree.");
}
for (k, v) in vars {
println!(" - {k}={v}");
}
}
dotenvy::dotenv().ok();
let is_devnode = matches!(&cli.command, Commands::Devnode { .. });
if !quiet && !is_devnode {
logger::init_logger("leo", match cli.debug {
false => 1,
true => 2,
})?;
}
if !quiet
&& !cli.disable_update_check
&& let Ok(true) = updater::Updater::check_for_updates(false)
{
let _ = updater::Updater::print_cli();
}
let context = handle_error(Context::new(cli.path.clone(), cli.home, false));
let command_name = cli.command.name();
let mut command_output: Option<JsonOutput> = None;
match cli.command {
Commands::Add { command } => command.try_execute(context)?,
Commands::Account { command } => command.try_execute(context)?,
Commands::New { command } => command.try_execute(context)?,
Commands::Build { command } => command.try_execute(context)?,
Commands::Abi { command } => command.try_execute(context)?,
Commands::Query { command } => {
let result = command.execute(context)?;
let data = serde_json::from_str(&result).unwrap_or_else(|_| serde_json::Value::String(result));
command_output = Some(JsonOutput::Query(data));
}
Commands::Clean { command } => command.try_execute(context)?,
Commands::Deploy { command } => command_output = Some(JsonOutput::Deploy(command.execute(context)?)),
Commands::Fmt { command } => command.try_execute(context)?,
Commands::Devnet { command } => command.try_execute(context)?,
Commands::Devnode { command } => command.try_execute(context)?,
Commands::Run { command } => command_output = Some(JsonOutput::Run(command.execute(context)?)),
Commands::Test { command } => command_output = Some(JsonOutput::Test(command.execute(context)?)),
Commands::Execute { command } => command_output = Some(JsonOutput::Execute(command.execute(context)?)),
Commands::Remove { command } => command.try_execute(context)?,
Commands::Synthesize { command } => command_output = Some(JsonOutput::Synthesize(command.execute(context)?)),
Commands::Update { command } => command.try_execute(context)?,
Commands::Upgrade { command } => command_output = Some(JsonOutput::Deploy(command.execute(context)?)),
}
if let Some(json_output_arg) = cli.json_output
&& let Some(output) = &command_output
{
let json = serde_json::to_string_pretty(output).expect("JSON serialization failed");
let path = if json_output_arg.is_empty() {
cli.path
.unwrap_or_else(|| PathBuf::from("."))
.join("build")
.join("json-outputs")
.join(format!("{command_name}.json"))
} else {
PathBuf::from(json_output_arg)
};
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent)
.map_err(|e| CliError::custom(format!("Failed to create directory: {e}")))?;
}
std::fs::write(&path, json)
.map_err(|e| CliError::custom(format!("Failed to write JSON output to {}: {e}", path.display())))?;
}
if let Some(JsonOutput::Test(output)) = &command_output
&& output.failed > 0
{
return Err(CliError::tests_failed(output.failed, output.tests.len()).into());
}
Ok(())
}
#[cfg(test)]
mod tests {
use crate::cli::{
CLI,
cli::{Commands, test_helpers},
run_with_args,
};
use leo_ast::NetworkName;
use leo_span::create_session_if_not_set_then;
use serial_test::serial;
use std::env::temp_dir;
#[test]
#[serial]
fn nested_network_dependency_run_test() {
let temp_dir = temp_dir();
let project_directory = temp_dir.join("nested");
test_helpers::sample_nested_package(&temp_dir);
let env_override = crate::cli::commands::EnvOptions {
network: Some(NetworkName::TestnetV0),
endpoint: Some("http://localhost:3030".to_string()),
..Default::default()
};
let run = CLI {
debug: false,
quiet: false,
json_output: None,
disable_update_check: false,
command: Commands::Run {
command: crate::cli::commands::LeoRun {
name: "example".to_string(),
inputs: vec!["1u32".to_string(), "2u32".to_string()],
env_override,
build_options: Default::default(),
with: vec![],
},
},
path: Some(project_directory.clone()),
home: Some(temp_dir.join(".aleo")),
};
create_session_if_not_set_then(|_| {
run_with_args(run).expect("Failed to execute `leo run`");
});
}
#[test]
#[serial]
fn nested_local_dependency_run_test() {
let temp_dir = temp_dir();
let project_name = "grandparent";
let project_directory = temp_dir.join(project_name);
if project_directory.exists() {
std::fs::remove_dir_all(project_directory.clone()).unwrap();
}
test_helpers::sample_grandparent_package(&temp_dir);
let run = CLI {
debug: false,
quiet: false,
json_output: None,
disable_update_check: false,
command: Commands::Run {
command: crate::cli::commands::LeoRun {
name: "double_wrapper_mint".to_string(),
inputs: vec![
"aleo13tngrq7506zwdxj0cxjtvp28pk937jejhne0rt4zp0z370uezuysjz2prs".to_string(),
"2u32".to_string(),
],
env_override: Default::default(),
build_options: Default::default(),
with: vec![],
},
},
path: Some(project_directory.clone()),
home: None,
};
create_session_if_not_set_then(|_| {
run_with_args(run).expect("Failed to execute `leo run`");
});
}
#[test]
#[serial]
fn relaxed_shadowing_run_test() {
let temp_dir = temp_dir();
let project_name = "outer";
let project_directory = temp_dir.join(project_name);
if project_directory.exists() {
std::fs::remove_dir_all(project_directory.clone()).unwrap();
}
test_helpers::sample_shadowing_package(&temp_dir);
let run = CLI {
debug: false,
quiet: false,
json_output: None,
disable_update_check: false,
command: Commands::Run {
command: crate::cli::commands::LeoRun {
name: "inner_1_main".to_string(),
inputs: vec!["1u32".to_string(), "2u32".to_string()],
build_options: Default::default(),
env_override: Default::default(),
with: vec![],
},
},
path: Some(project_directory.clone()),
home: None,
};
create_session_if_not_set_then(|_| {
run_with_args(run).expect("Failed to execute `leo run`");
});
}
#[test]
#[serial]
fn relaxed_struct_shadowing_run_test() {
let temp_dir = temp_dir();
let project_name = "outer_2";
let project_directory = temp_dir.join(project_name);
if project_directory.exists() {
std::fs::remove_dir_all(project_directory.clone()).unwrap();
}
test_helpers::sample_struct_shadowing_package(&temp_dir);
let run = CLI {
debug: false,
quiet: false,
json_output: None,
disable_update_check: false,
command: Commands::Run {
command: crate::cli::commands::LeoRun {
name: "main".to_string(),
inputs: vec!["1u32".to_string(), "2u32".to_string()],
env_override: Default::default(),
build_options: Default::default(),
with: vec![],
},
},
path: Some(project_directory.clone()),
home: None,
};
create_session_if_not_set_then(|_| {
run_with_args(run).expect("Failed to execute `leo run`");
});
}
#[test]
#[serial]
fn new_library_test() {
let temp_dir = temp_dir();
let lib_name = "my_test_lib";
let lib_directory = temp_dir.join(lib_name);
if lib_directory.exists() {
std::fs::remove_dir_all(&lib_directory).unwrap();
}
let new_cmd = CLI {
debug: false,
quiet: false,
json_output: None,
disable_update_check: false,
command: Commands::New {
command: crate::cli::commands::LeoNew { name: lib_name.to_string(), library: true },
},
path: Some(lib_directory.clone()),
home: None,
};
create_session_if_not_set_then(|_| {
run_with_args(new_cmd).expect("Failed to execute `leo new --library`");
});
assert!(lib_directory.exists(), "Library directory should exist");
let src_dir = lib_directory.join("src");
assert!(src_dir.join("lib.leo").exists(), "src/lib.leo should exist");
assert!(!src_dir.join("main.leo").exists(), "src/main.leo should NOT exist for a library");
let manifest_path = lib_directory.join(leo_package::MANIFEST_FILENAME);
let manifest = leo_package::Manifest::read_from_file(&manifest_path).unwrap();
assert_eq!(manifest.program, lib_name, "Manifest program name should be the bare library name");
let _ = std::fs::remove_dir_all(&lib_directory);
}
}
#[cfg(test)]
mod test_helpers {
use crate::cli::{CLI, DependencySource, LeoAdd, LeoNew, cli::Commands, run_with_args};
use leo_span::create_session_if_not_set_then;
use std::path::Path;
pub(crate) fn sample_nested_package(temp_dir: &Path) {
let name = "nested";
let project_directory = temp_dir.join(name);
if project_directory.exists() {
std::fs::remove_dir_all(project_directory.clone()).unwrap();
}
let new = CLI {
debug: false,
quiet: false,
json_output: None,
disable_update_check: false,
command: Commands::New { command: LeoNew { name: name.to_string(), library: false } },
path: Some(project_directory.clone()),
home: None,
};
create_session_if_not_set_then(|_| {
run_with_args(new).expect("Failed to execute `leo run`");
});
let program_str = "
import nested_example_layer_0.aleo;
program nested.aleo {
fn example(public a: u32, b: u32) -> u32 {
let c: u32 = nested_example_layer_0.aleo::main(a, b);
return c;
}
@noupgrade
constructor() {}
}
";
let nested_example_layer_0 = "
import nested_example_layer_2.aleo;
import nested_example_layer_1.aleo;
program nested_example_layer_0.aleo;
function main:
input r0 as u32.public;
input r1 as u32.private;
call nested_example_layer_1.aleo/external_function r0 r1 into r2;
output r2 as u32.private;
";
let nested_example_layer_1 = "
import nested_example_layer_2.aleo;
program nested_example_layer_1.aleo;
function external_function:
input r0 as u32.public;
input r1 as u32.private;
call nested_example_layer_2.aleo/external_nested_function r0 r1 into r2;
output r2 as u32.private;
";
let nested_example_layer_2 = "
program nested_example_layer_2.aleo;
function external_nested_function:
input r0 as u32.public;
input r1 as u32.private;
add r0 r1 into r2;
output r2 as u32.private;
";
std::fs::write(project_directory.join("src").join("main.leo"), program_str).unwrap();
let add = CLI {
debug: false,
quiet: false,
json_output: None,
disable_update_check: false,
command: Commands::Add {
command: LeoAdd {
name: "nested_example_layer_0".to_string(),
source: DependencySource { local: None, network: true, edition: Some(0) },
clear: false,
dev: false,
},
},
path: Some(project_directory.clone()),
home: None,
};
create_session_if_not_set_then(|_| {
run_with_args(add).expect("Failed to execute `leo add`");
});
let registry = temp_dir.join(".aleo").join("registry").join("testnet");
std::fs::create_dir_all(®istry).unwrap();
let dir = registry.join("nested_example_layer_0").join("0");
std::fs::create_dir_all(&dir).unwrap();
std::fs::write(dir.join("nested_example_layer_0.aleo"), nested_example_layer_0).unwrap();
let dir = registry.join("nested_example_layer_1").join("0");
std::fs::create_dir_all(&dir).unwrap();
std::fs::write(dir.join("nested_example_layer_1.aleo"), nested_example_layer_1).unwrap();
let dir = registry.join("nested_example_layer_2").join("0");
std::fs::create_dir_all(&dir).unwrap();
std::fs::write(dir.join("nested_example_layer_2.aleo"), nested_example_layer_2).unwrap();
}
pub(crate) fn sample_grandparent_package(temp_dir: &Path) {
let grandparent_directory = temp_dir.join("grandparent");
let parent_directory = grandparent_directory.join("parent");
let child_directory = parent_directory.join("child");
if grandparent_directory.exists() {
std::fs::remove_dir_all(grandparent_directory.clone()).unwrap();
}
let create_grandparent_project = CLI {
debug: false,
quiet: false,
json_output: None,
disable_update_check: false,
command: Commands::New { command: LeoNew { name: "grandparent".to_string(), library: false } },
path: Some(grandparent_directory.clone()),
home: None,
};
let create_parent_project = CLI {
debug: false,
quiet: false,
json_output: None,
disable_update_check: false,
command: Commands::New { command: LeoNew { name: "parent".to_string(), library: false } },
path: Some(parent_directory.clone()),
home: None,
};
let create_child_project = CLI {
debug: false,
quiet: false,
json_output: None,
disable_update_check: false,
command: Commands::New { command: LeoNew { name: "child".to_string(), library: false } },
path: Some(child_directory.clone()),
home: None,
};
let grandparent_program = "
import child.aleo;
import parent.aleo;
program grandparent.aleo {
fn double_wrapper_mint(owner: address, val: u32) -> child.aleo::A {
return parent.aleo::wrapper_mint(owner, val);
}
@noupgrade
constructor() {}
}
";
let parent_program = "
import child.aleo;
program parent.aleo {
fn wrapper_mint(owner: address, val: u32) -> child.aleo::A {
return child.aleo::mint(owner, val);
}
@noupgrade
constructor() {}
}
";
let child_program = "
// The 'a' program.
program child.aleo {
record A {
owner: address,
val: u32,
}
fn mint(owner: address, val: u32) -> A {
return A {owner: owner, val: val};
}
@noupgrade
constructor() {}
}
";
let add_grandparent_dependency_1 = CLI {
debug: false,
quiet: false,
json_output: None,
disable_update_check: false,
command: Commands::Add {
command: LeoAdd {
name: "parent".to_string(),
source: DependencySource { local: Some(parent_directory.clone()), network: false, edition: None },
clear: false,
dev: false,
},
},
path: Some(grandparent_directory.clone()),
home: None,
};
let add_grandparent_dependency_2 = CLI {
debug: false,
quiet: false,
json_output: None,
disable_update_check: false,
command: Commands::Add {
command: LeoAdd {
name: "child".to_string(),
source: DependencySource { local: Some(child_directory.clone()), network: false, edition: None },
clear: false,
dev: false,
},
},
path: Some(grandparent_directory.clone()),
home: None,
};
let add_parent_dependency = CLI {
debug: false,
quiet: false,
json_output: None,
disable_update_check: false,
command: Commands::Add {
command: LeoAdd {
name: "child".to_string(),
source: DependencySource { local: Some(child_directory.clone()), network: false, edition: None },
clear: false,
dev: false,
},
},
path: Some(parent_directory.clone()),
home: None,
};
create_session_if_not_set_then(|_| {
run_with_args(create_grandparent_project).unwrap();
run_with_args(create_parent_project).unwrap();
run_with_args(create_child_project).unwrap();
std::fs::write(grandparent_directory.join("src").join("main.leo"), grandparent_program).unwrap();
std::fs::write(parent_directory.join("src").join("main.leo"), parent_program).unwrap();
std::fs::write(child_directory.join("src").join("main.leo"), child_program).unwrap();
run_with_args(add_grandparent_dependency_1).unwrap();
run_with_args(add_grandparent_dependency_2).unwrap();
run_with_args(add_parent_dependency).unwrap();
});
}
pub(crate) fn sample_shadowing_package(temp_dir: &Path) {
let outer_directory = temp_dir.join("outer");
let inner_1_directory = outer_directory.join("inner_1");
let inner_2_directory = outer_directory.join("inner_2");
if outer_directory.exists() {
std::fs::remove_dir_all(outer_directory.clone()).unwrap();
}
let create_outer_project = CLI {
debug: false,
quiet: false,
json_output: None,
disable_update_check: false,
command: Commands::New { command: LeoNew { name: "outer".to_string(), library: false } },
path: Some(outer_directory.clone()),
home: None,
};
let create_inner_1_project = CLI {
debug: false,
quiet: false,
json_output: None,
disable_update_check: false,
command: Commands::New { command: LeoNew { name: "inner_1".to_string(), library: false } },
path: Some(inner_1_directory.clone()),
home: None,
};
let create_inner_2_project = CLI {
debug: false,
quiet: false,
json_output: None,
disable_update_check: false,
command: Commands::New { command: LeoNew { name: "inner_2".to_string(), library: false } },
path: Some(inner_2_directory.clone()),
home: None,
};
let outer_program = "
import inner_1.aleo;
import inner_2.aleo;
program outer.aleo {
record inner_1_record {
owner: address,
arg1: u32,
arg2: u32,
arg3: u32,
}
fn inner_1_main(public a: u32, b: u32) -> (inner_1.aleo::inner_1_record, inner_2.aleo::inner_2_record, inner_1_record) {
let c: inner_1.aleo::ex_struct = inner_1.aleo::ex_struct {arg1: 1u32, arg2: 1u32};
let rec_1:inner_1.aleo::inner_1_record = inner_1.aleo::inner_1_main(1u32,1u32, c);
let rec_2:inner_2.aleo::inner_2_record = inner_2.aleo::inner_2_main(1u32,1u32);
return (rec_1, rec_2, inner_1_record {owner: aleo14tnetva3xfvemqyg5ujzvr0qfcaxdanmgjx2wsuh2xrpvc03uc9s623ps7, arg1: 1u32, arg2: 1u32, arg3: 1u32});
}
@noupgrade
constructor() {}
}
";
let inner_1_program = "
struct ex_struct {
arg1: u32,
arg2: u32,
}
program inner_1.aleo {
mapping inner_1_mapping: u32 => u32;
record inner_1_record {
owner: address,
val: u32,
}
fn inner_1_main(public a: u32, b: u32, c: ex_struct) -> inner_1_record {
return inner_1_record {
owner: self.caller,
val: c.arg1,
};
}
@noupgrade
constructor() {}
}
";
let inner_2_program = "
program inner_2.aleo {
mapping inner_2_mapping: u32 => u32;
record inner_2_record {
owner: address,
val: u32,
}
fn inner_2_main(public a: u32, b: u32) -> inner_2_record {
let c: u32 = a + b;
return inner_2_record {
owner: self.caller,
val: a,
};
}
@noupgrade
constructor() {}
}
";
let add_outer_dependency_1 = CLI {
debug: false,
quiet: false,
json_output: None,
disable_update_check: false,
command: Commands::Add {
command: LeoAdd {
name: "inner_1".to_string(),
source: DependencySource { local: Some(inner_1_directory.clone()), network: false, edition: None },
clear: false,
dev: false,
},
},
path: Some(outer_directory.clone()),
home: None,
};
let add_outer_dependency_2 = CLI {
debug: false,
quiet: false,
json_output: None,
disable_update_check: false,
command: Commands::Add {
command: LeoAdd {
name: "inner_2".to_string(),
source: DependencySource { local: Some(inner_2_directory.clone()), network: false, edition: None },
clear: false,
dev: false,
},
},
path: Some(outer_directory.clone()),
home: None,
};
create_session_if_not_set_then(|_| {
run_with_args(create_outer_project).unwrap();
run_with_args(create_inner_1_project).unwrap();
run_with_args(create_inner_2_project).unwrap();
std::fs::write(outer_directory.join("src").join("main.leo"), outer_program).unwrap();
std::fs::write(inner_1_directory.join("src").join("main.leo"), inner_1_program).unwrap();
std::fs::write(inner_2_directory.join("src").join("main.leo"), inner_2_program).unwrap();
run_with_args(add_outer_dependency_1).unwrap();
run_with_args(add_outer_dependency_2).unwrap();
});
}
pub(crate) fn sample_struct_shadowing_package(temp_dir: &Path) {
let outer_directory = temp_dir.join("outer_2");
let inner_1_directory = outer_directory.join("inner_1");
let inner_2_directory = outer_directory.join("inner_2");
if outer_directory.exists() {
std::fs::remove_dir_all(outer_directory.clone()).unwrap();
}
let create_outer_project = CLI {
debug: false,
quiet: false,
json_output: None,
disable_update_check: false,
command: Commands::New { command: LeoNew { name: "outer_2".to_string(), library: false } },
path: Some(outer_directory.clone()),
home: None,
};
let create_inner_1_project = CLI {
debug: false,
quiet: false,
json_output: None,
disable_update_check: false,
command: Commands::New { command: LeoNew { name: "inner_1".to_string(), library: false } },
path: Some(inner_1_directory.clone()),
home: None,
};
let create_inner_2_project = CLI {
debug: false,
quiet: false,
json_output: None,
disable_update_check: false,
command: Commands::New { command: LeoNew { name: "inner_2".to_string(), library: false } },
path: Some(inner_2_directory.clone()),
home: None,
};
let outer_program = "
import inner_1.aleo;
import inner_2.aleo;
struct Foo {
a: u32,
b: u32,
c: Boo,
}
struct Boo {
a: u32,
b: u32,
}
struct Goo {
a: u32,
b: u32,
c: u32,
}
program outer_2.aleo {
record Hello {
owner: address,
a: u32,
}
fn main(public a: u32, b: u32) -> (inner_2.aleo::Yoo, Hello) {
let d: inner_1.aleo::Foo = inner_1.aleo::main(1u32,1u32);
let e: u32 = inner_1.aleo::main_2(inner_1.aleo::Foo {a: a, b: b, c: inner_1.aleo::Boo {a:1u32, b:1u32}});
let f: Boo = Boo {a:1u32, b:1u32};
let g: inner_2.aleo::Foo = inner_2.aleo::main(1u32, 1u32);
inner_2.aleo::Yo_Consumer(inner_2.aleo::Yo());
let h: inner_2.aleo::Yoo = inner_2.aleo::Yo();
let i: inner_2.aleo::Goo = inner_2.aleo::Goo_creator();
let j: Hello = Hello {owner: self.signer, a:1u32};
return (h, j);
}
@noupgrade
constructor() {}
}
";
let inner_1_program = "
struct Foo {
a: u32,
b: u32,
c: Boo,
}
struct Boo {
a: u32,
b: u32,
}
program inner_1.aleo {
fn main(public a: u32, b: u32) -> Foo {
return Foo {a: a, b: b, c: Boo {a:1u32, b:1u32}};
}
fn main_2(a:Foo)->u32{
return a.a;
}
@noupgrade
constructor() {}
}";
let inner_2_program = "
struct Foo {
a: u32,
b: u32,
c: Boo,
}
struct Boo {
a: u32,
b: u32,
}
struct Goo {
a: u32,
b: u32,
c: u32,
}
program inner_2.aleo {
record Yoo {
owner: address,
a: u32,
}
fn main(public a: u32, b: u32) -> Foo {
return Foo {a: a, b: b, c: Boo {a:1u32, b:1u32}};
}
fn Yo()-> Yoo {
return Yoo {owner: self.signer, a:1u32};
}
fn Yo_Consumer(a: Yoo)->u32 {
return a.a;
}
fn Goo_creator() -> Goo {
return Goo {a:100u32, b:1u32, c:1u32};
}
@noupgrade
constructor() {}
}";
let add_outer_dependency_1 = CLI {
debug: false,
quiet: false,
json_output: None,
disable_update_check: false,
command: Commands::Add {
command: LeoAdd {
name: "inner_1".to_string(),
source: DependencySource { local: Some(inner_1_directory.clone()), network: false, edition: None },
clear: false,
dev: false,
},
},
path: Some(outer_directory.clone()),
home: None,
};
let add_outer_dependency_2 = CLI {
debug: false,
quiet: false,
json_output: None,
disable_update_check: false,
command: Commands::Add {
command: LeoAdd {
name: "inner_2".to_string(),
source: DependencySource { local: Some(inner_2_directory.clone()), network: false, edition: None },
clear: false,
dev: false,
},
},
path: Some(outer_directory.clone()),
home: None,
};
create_session_if_not_set_then(|_| {
run_with_args(create_outer_project).unwrap();
run_with_args(create_inner_1_project).unwrap();
run_with_args(create_inner_2_project).unwrap();
std::fs::write(outer_directory.join("src").join("main.leo"), outer_program).unwrap();
std::fs::write(inner_1_directory.join("src").join("main.leo"), inner_1_program).unwrap();
std::fs::write(inner_2_directory.join("src").join("main.leo"), inner_2_program).unwrap();
run_with_args(add_outer_dependency_1).unwrap();
run_with_args(add_outer_dependency_2).unwrap();
});
}
}