leo_lang/cli/
cli.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
17use crate::cli::{commands::*, context::*, helpers::*};
18use clap::Parser;
19use leo_errors::Result;
20use std::{path::PathBuf, process::exit};
21
22/// CLI Arguments entry point - includes global parameters and subcommands
23#[derive(Parser, Debug)]
24#[clap(name = "leo", author = "The Leo Team <leo@provable.com>", version)]
25pub struct CLI {
26    #[clap(short, global = true, help = "Print additional information for debugging")]
27    debug: bool,
28
29    #[clap(short, global = true, help = "Suppress CLI output")]
30    quiet: bool,
31
32    #[clap(subcommand)]
33    command: Commands,
34
35    #[clap(long, global = true, help = "Path to Leo program root folder")]
36    path: Option<PathBuf>,
37
38    #[clap(long, global = true, help = "Path to aleo program registry")]
39    pub home: Option<PathBuf>,
40}
41
42///Leo compiler and package manager
43#[derive(Parser, Debug)]
44enum Commands {
45    #[clap(about = "Create a new Aleo account, sign and verify messages")]
46    Account {
47        #[clap(subcommand)]
48        command: Account,
49    },
50    #[clap(about = "Create a new Leo package in a new directory")]
51    New {
52        #[clap(flatten)]
53        command: LeoNew,
54    },
55    #[clap(about = "Run a program with input variables")]
56    Run {
57        #[clap(flatten)]
58        command: LeoRun,
59    },
60    #[clap(about = "Test a Leo program")]
61    Test {
62        #[clap(flatten)]
63        command: LeoTest,
64    },
65    #[clap(about = "Execute a program with input variables")]
66    Execute {
67        #[clap(flatten)]
68        command: LeoExecute,
69    },
70    #[clap(about = "Deploy a program")]
71    Deploy {
72        #[clap(flatten)]
73        command: LeoDeploy,
74    },
75    #[clap(about = "Run a local devnet")]
76    Devnet {
77        #[clap(flatten)]
78        command: LeoDevnet,
79    },
80    #[clap(about = "Query live data from the Aleo network")]
81    Query {
82        #[clap(flatten)]
83        command: LeoQuery,
84    },
85    #[clap(about = "Compile the current package as a program")]
86    Build {
87        #[clap(flatten)]
88        command: LeoBuild,
89    },
90    #[clap(about = "Debug the current package via the interpreter")]
91    Debug {
92        #[clap(flatten)]
93        command: LeoDebug,
94    },
95    #[clap(about = "Add a new on-chain or local dependency to the current package.")]
96    Add {
97        #[clap(flatten)]
98        command: LeoAdd,
99    },
100    #[clap(about = "Remove a dependency from the current package.")]
101    Remove {
102        #[clap(flatten)]
103        command: LeoRemove,
104    },
105    #[clap(about = "Clean the output directory")]
106    Clean {
107        #[clap(flatten)]
108        command: LeoClean,
109    },
110    #[clap(about = "Synthesize individual keys")]
111    Synthesize {
112        #[clap(flatten)]
113        command: LeoSynthesize,
114    },
115    #[clap(about = "Update the Leo CLI")]
116    Update {
117        #[clap(flatten)]
118        command: LeoUpdate,
119    },
120    #[clap(about = "Upgrade the program on a network")]
121    Upgrade {
122        #[clap(flatten)]
123        command: LeoUpgrade,
124    },
125}
126
127pub fn handle_error<T>(res: Result<T>) -> T {
128    match res {
129        Ok(t) => t,
130        Err(err) => {
131            eprintln!("{err}");
132            exit(err.exit_code());
133        }
134    }
135}
136
137/// Run command with custom build arguments.
138pub fn run_with_args(cli: CLI) -> Result<()> {
139    // Print the variables found in the `.env` files.
140    if let Ok(vars) = dotenvy::dotenv_iter().map(|v| v.flatten().collect::<Vec<_>>()) {
141        if !vars.is_empty() {
142            println!("📢 Loading environment variables from a `.env` file in the directory tree.");
143        }
144        for (k, v) in vars {
145            println!("  - {k}={v}");
146        }
147    }
148    // Initialize the `.env` file.
149    dotenvy::dotenv().ok();
150
151    if !cli.quiet {
152        // Init logger with optional debug flag.
153        logger::init_logger("leo", match cli.debug {
154            false => 1,
155            true => 2,
156        })?;
157    }
158
159    //  Check for updates. If not forced, it checks once per day.
160    if let Ok(true) = updater::Updater::check_for_updates(false) {
161        let _ = updater::Updater::print_cli();
162    }
163
164    // Get custom root folder and create context for it.
165    // If not specified, default context will be created in cwd.
166    let context = handle_error(Context::new(cli.path, cli.home, false));
167
168    match cli.command {
169        Commands::Add { command } => command.try_execute(context),
170        Commands::Account { command } => command.try_execute(context),
171        Commands::New { command } => command.try_execute(context),
172        Commands::Build { command } => command.try_execute(context),
173        Commands::Debug { command } => command.try_execute(context),
174        Commands::Query { command } => command.try_execute(context),
175        Commands::Clean { command } => command.try_execute(context),
176        Commands::Deploy { command } => command.try_execute(context),
177        Commands::Devnet { command } => command.try_execute(context),
178        Commands::Run { command } => command.try_execute(context),
179        Commands::Test { command } => command.try_execute(context),
180        Commands::Execute { command } => command.try_execute(context),
181        Commands::Remove { command } => command.try_execute(context),
182        Commands::Synthesize { command } => command.try_execute(context),
183        Commands::Update { command } => command.try_execute(context),
184        Commands::Upgrade { command } => command.try_execute(context),
185    }
186}
187
188#[cfg(test)]
189mod tests {
190    use crate::cli::{
191        CLI,
192        cli::{Commands, test_helpers},
193        run_with_args,
194    };
195    use leo_ast::NetworkName;
196    use leo_span::create_session_if_not_set_then;
197    use serial_test::serial;
198    use std::env::temp_dir;
199
200    #[test]
201    #[serial]
202    fn nested_network_dependency_run_test() {
203        // Set current directory to temporary directory
204        let temp_dir = temp_dir();
205        let project_directory = temp_dir.join("nested");
206
207        // Create file structure
208        test_helpers::sample_nested_package(&temp_dir);
209
210        // Set the env options.
211        let env_override = crate::cli::commands::EnvOptions {
212            network: Some(NetworkName::TestnetV0),
213            endpoint: Some("http://localhost:3030".to_string()),
214            ..Default::default()
215        };
216
217        // Run program
218        let run = CLI {
219            debug: false,
220            quiet: false,
221            command: Commands::Run {
222                command: crate::cli::commands::LeoRun {
223                    name: "example".to_string(),
224                    inputs: vec!["1u32".to_string(), "2u32".to_string()],
225                    env_override,
226                    build_options: Default::default(),
227                },
228            },
229            path: Some(project_directory.clone()),
230            home: Some(temp_dir.join(".aleo")),
231        };
232
233        create_session_if_not_set_then(|_| {
234            run_with_args(run).expect("Failed to execute `leo run`");
235        });
236
237        // TODO: Clear tmp directory
238        // let registry = temp_dir.join(".aleo").join("registry").join("mainnet");
239        // std::fs::remove_dir_all(registry).unwrap();
240        // std::fs::remove_dir_all(project_directory).unwrap();
241    }
242
243    #[test]
244    #[serial]
245    fn nested_local_dependency_run_test() {
246        // Set current directory to temporary directory
247        let temp_dir = temp_dir();
248        let project_name = "grandparent";
249        let project_directory = temp_dir.join(project_name);
250
251        // Remove it if it already exists
252        if project_directory.exists() {
253            std::fs::remove_dir_all(project_directory.clone()).unwrap();
254        }
255
256        // Create file structure
257        test_helpers::sample_grandparent_package(&temp_dir);
258
259        // Run program
260        let run = CLI {
261            debug: false,
262            quiet: false,
263            command: Commands::Run {
264                command: crate::cli::commands::LeoRun {
265                    name: "double_wrapper_mint".to_string(),
266                    inputs: vec![
267                        "aleo13tngrq7506zwdxj0cxjtvp28pk937jejhne0rt4zp0z370uezuysjz2prs".to_string(),
268                        "2u32".to_string(),
269                    ],
270                    env_override: Default::default(),
271                    build_options: Default::default(),
272                },
273            },
274            path: Some(project_directory.clone()),
275            home: None,
276        };
277
278        create_session_if_not_set_then(|_| {
279            run_with_args(run).expect("Failed to execute `leo run`");
280        });
281
282        // TODO: Clear tmp directory
283        // std::fs::remove_dir_all(project_directory).unwrap();
284    }
285
286    #[test]
287    #[serial]
288    fn relaxed_shadowing_run_test() {
289        // Set current directory to temporary directory
290        let temp_dir = temp_dir();
291        let project_name = "outer";
292        let project_directory = temp_dir.join(project_name);
293
294        // Remove it if it already exists
295        if project_directory.exists() {
296            std::fs::remove_dir_all(project_directory.clone()).unwrap();
297        }
298
299        // Create file structure
300        test_helpers::sample_shadowing_package(&temp_dir);
301
302        // Run program
303        let run = CLI {
304            debug: false,
305            quiet: false,
306            command: Commands::Run {
307                command: crate::cli::commands::LeoRun {
308                    name: "inner_1_main".to_string(),
309                    inputs: vec!["1u32".to_string(), "2u32".to_string()],
310                    build_options: Default::default(),
311                    env_override: Default::default(),
312                },
313            },
314            path: Some(project_directory.clone()),
315            home: None,
316        };
317
318        create_session_if_not_set_then(|_| {
319            run_with_args(run).expect("Failed to execute `leo run`");
320        });
321    }
322
323    #[test]
324    #[serial]
325    fn relaxed_struct_shadowing_run_test() {
326        // Set current directory to temporary directory
327        let temp_dir = temp_dir();
328        let project_name = "outer_2";
329        let project_directory = temp_dir.join(project_name);
330
331        // Remove it if it already exists
332        if project_directory.exists() {
333            std::fs::remove_dir_all(project_directory.clone()).unwrap();
334        }
335
336        // Create file structure
337        test_helpers::sample_struct_shadowing_package(&temp_dir);
338
339        // Run program
340        let run = CLI {
341            debug: false,
342            quiet: false,
343            command: Commands::Run {
344                command: crate::cli::commands::LeoRun {
345                    name: "main".to_string(),
346                    inputs: vec!["1u32".to_string(), "2u32".to_string()],
347                    env_override: Default::default(),
348                    build_options: Default::default(),
349                },
350            },
351            path: Some(project_directory.clone()),
352            home: None,
353        };
354
355        create_session_if_not_set_then(|_| {
356            run_with_args(run).expect("Failed to execute `leo run`");
357        });
358    }
359}
360
361#[cfg(test)]
362mod test_helpers {
363    use crate::cli::{CLI, DependencySource, LeoAdd, LeoNew, cli::Commands, run_with_args};
364    use leo_span::create_session_if_not_set_then;
365    use std::path::Path;
366
367    const NETWORK: &str = "testnet";
368    const ENDPOINT: &str = "https://api.explorer.provable.com/v1";
369
370    pub(crate) fn sample_nested_package(temp_dir: &Path) {
371        let name = "nested";
372
373        // Remove it if it already exists
374        let project_directory = temp_dir.join(name);
375        if project_directory.exists() {
376            std::fs::remove_dir_all(project_directory.clone()).unwrap();
377        }
378
379        // Create new Leo project
380        let new = CLI {
381            debug: false,
382            quiet: false,
383            command: Commands::New {
384                command: LeoNew {
385                    name: name.to_string(),
386                    network: NETWORK.to_string(),
387                    endpoint: ENDPOINT.to_string(),
388                },
389            },
390            path: Some(project_directory.clone()),
391            home: None,
392        };
393
394        create_session_if_not_set_then(|_| {
395            run_with_args(new).expect("Failed to execute `leo run`");
396        });
397
398        // `nested.aleo` program
399        let program_str = "
400import nested_example_layer_0.aleo;
401program nested.aleo {
402    transition example(public a: u32, b: u32) -> u32 {
403        let c: u32 = nested_example_layer_0.aleo/main(a, b);
404        return c;
405    }
406
407    @noupgrade
408    async constructor() {}
409}
410";
411        // `nested_example_layer_0.aleo` program
412        let nested_example_layer_0 = "
413import nested_example_layer_2.aleo;
414import nested_example_layer_1.aleo;
415
416program nested_example_layer_0.aleo;
417
418function main:
419    input r0 as u32.public;
420    input r1 as u32.private;
421    call nested_example_layer_1.aleo/external_function r0 r1 into r2;
422    output r2 as u32.private;
423";
424
425        // `nested_example_layer_1.aleo` program
426        let nested_example_layer_1 = "
427import nested_example_layer_2.aleo;
428
429program nested_example_layer_1.aleo;
430
431function external_function:
432    input r0 as u32.public;
433    input r1 as u32.private;
434    call nested_example_layer_2.aleo/external_nested_function r0 r1 into r2;
435    output r2 as u32.private;
436";
437
438        // `nested_example_layer_2.aleo` program
439        let nested_example_layer_2 = "
440program nested_example_layer_2.aleo;
441
442function external_nested_function:
443    input r0 as u32.public;
444    input r1 as u32.private;
445    add r0 r1 into r2;
446    output r2 as u32.private;
447";
448
449        // Overwrite `src/main.leo` file
450        std::fs::write(project_directory.join("src").join("main.leo"), program_str).unwrap();
451
452        // Add dependencies
453        let add = CLI {
454            debug: false,
455            quiet: false,
456            command: Commands::Add {
457                command: LeoAdd {
458                    name: "nested_example_layer_0".to_string(),
459                    source: DependencySource { local: None, network: true, edition: Some(0) },
460                    clear: false,
461                    dev: false,
462                },
463            },
464            path: Some(project_directory.clone()),
465            home: None,
466        };
467
468        create_session_if_not_set_then(|_| {
469            run_with_args(add).expect("Failed to execute `leo add`");
470        });
471
472        // Add custom `.aleo` directory with the appropriate cache entries.
473        let registry = temp_dir.join(".aleo").join("registry").join("testnet");
474        std::fs::create_dir_all(&registry).unwrap();
475
476        let dir = registry.join("nested_example_layer_0").join("0");
477        std::fs::create_dir_all(&dir).unwrap();
478        std::fs::write(dir.join("nested_example_layer_0.aleo"), nested_example_layer_0).unwrap();
479
480        let dir = registry.join("nested_example_layer_1").join("0");
481        std::fs::create_dir_all(&dir).unwrap();
482        std::fs::write(dir.join("nested_example_layer_1.aleo"), nested_example_layer_1).unwrap();
483
484        let dir = registry.join("nested_example_layer_2").join("0");
485        std::fs::create_dir_all(&dir).unwrap();
486        std::fs::write(dir.join("nested_example_layer_2.aleo"), nested_example_layer_2).unwrap();
487    }
488
489    pub(crate) fn sample_grandparent_package(temp_dir: &Path) {
490        let grandparent_directory = temp_dir.join("grandparent");
491        let parent_directory = grandparent_directory.join("parent");
492        let child_directory = parent_directory.join("child");
493
494        if grandparent_directory.exists() {
495            std::fs::remove_dir_all(grandparent_directory.clone()).unwrap();
496        }
497
498        // Create project file structure `grandparent/parent/child`
499        let create_grandparent_project = CLI {
500            debug: false,
501            quiet: false,
502            command: Commands::New {
503                command: LeoNew {
504                    name: "grandparent".to_string(),
505                    network: NETWORK.to_string(),
506                    endpoint: ENDPOINT.to_string(),
507                },
508            },
509            path: Some(grandparent_directory.clone()),
510            home: None,
511        };
512
513        let create_parent_project = CLI {
514            debug: false,
515            quiet: false,
516            command: Commands::New {
517                command: LeoNew {
518                    name: "parent".to_string(),
519                    network: NETWORK.to_string(),
520                    endpoint: ENDPOINT.to_string(),
521                },
522            },
523            path: Some(parent_directory.clone()),
524            home: None,
525        };
526
527        let create_child_project = CLI {
528            debug: false,
529            quiet: false,
530            command: Commands::New {
531                command: LeoNew {
532                    name: "child".to_string(),
533                    network: NETWORK.to_string(),
534                    endpoint: ENDPOINT.to_string(),
535                },
536            },
537            path: Some(child_directory.clone()),
538            home: None,
539        };
540
541        // Add source files `grandparent/src/main.leo`, `grandparent/parent/src/main.leo`, and `grandparent/parent/child/src/main.leo`
542        let grandparent_program = "
543import child.aleo;
544import parent.aleo;
545program grandparent.aleo {
546    transition double_wrapper_mint(owner: address, val: u32) -> child.aleo/A {
547        return parent.aleo/wrapper_mint(owner, val);
548    }
549
550    @noupgrade
551    async constructor() {}
552}
553";
554        let parent_program = "
555import child.aleo;
556program parent.aleo {
557    transition wrapper_mint(owner: address, val: u32) ->  child.aleo/A {
558        return child.aleo/mint(owner, val);
559    }
560
561    @noupgrade
562    async constructor() {}
563}
564";
565
566        let child_program = "
567// The 'a' program.
568program child.aleo {
569    record A {
570        owner: address,
571        val: u32,
572    }
573    transition mint(owner: address, val: u32) -> A {
574        return A {owner: owner, val: val};
575    }
576
577    @noupgrade
578    async constructor() {}
579}
580";
581
582        // Add dependencies `grandparent/program.json` and `grandparent/parent/program.json`
583        let add_grandparent_dependency_1 = CLI {
584            debug: false,
585            quiet: false,
586            command: Commands::Add {
587                command: LeoAdd {
588                    name: "parent".to_string(),
589                    source: DependencySource { local: Some(parent_directory.clone()), network: false, edition: None },
590                    clear: false,
591                    dev: false,
592                },
593            },
594            path: Some(grandparent_directory.clone()),
595            home: None,
596        };
597
598        let add_grandparent_dependency_2 = CLI {
599            debug: false,
600            quiet: false,
601            command: Commands::Add {
602                command: LeoAdd {
603                    name: "child".to_string(),
604                    source: DependencySource { local: Some(child_directory.clone()), network: false, edition: None },
605                    clear: false,
606                    dev: false,
607                },
608            },
609            path: Some(grandparent_directory.clone()),
610            home: None,
611        };
612
613        let add_parent_dependency = CLI {
614            debug: false,
615            quiet: false,
616            command: Commands::Add {
617                command: LeoAdd {
618                    name: "child".to_string(),
619                    source: DependencySource { local: Some(child_directory.clone()), network: false, edition: None },
620                    clear: false,
621                    dev: false,
622                },
623            },
624            path: Some(parent_directory.clone()),
625            home: None,
626        };
627
628        // Execute all commands
629        create_session_if_not_set_then(|_| {
630            // Create projects
631            run_with_args(create_grandparent_project).unwrap();
632            run_with_args(create_parent_project).unwrap();
633            run_with_args(create_child_project).unwrap();
634
635            // Write files
636            std::fs::write(grandparent_directory.join("src").join("main.leo"), grandparent_program).unwrap();
637            std::fs::write(parent_directory.join("src").join("main.leo"), parent_program).unwrap();
638            std::fs::write(child_directory.join("src").join("main.leo"), child_program).unwrap();
639
640            // Add dependencies
641            run_with_args(add_grandparent_dependency_1).unwrap();
642            run_with_args(add_grandparent_dependency_2).unwrap();
643            run_with_args(add_parent_dependency).unwrap();
644        });
645    }
646
647    pub(crate) fn sample_shadowing_package(temp_dir: &Path) {
648        let outer_directory = temp_dir.join("outer");
649        let inner_1_directory = outer_directory.join("inner_1");
650        let inner_2_directory = outer_directory.join("inner_2");
651
652        if outer_directory.exists() {
653            std::fs::remove_dir_all(outer_directory.clone()).unwrap();
654        }
655
656        // Create project file structure `outer/inner_1` and `outer/inner_2`
657        let create_outer_project = CLI {
658            debug: false,
659            quiet: false,
660            command: Commands::New {
661                command: LeoNew {
662                    name: "outer".to_string(),
663                    network: NETWORK.to_string(),
664                    endpoint: ENDPOINT.to_string(),
665                },
666            },
667            path: Some(outer_directory.clone()),
668            home: None,
669        };
670
671        let create_inner_1_project = CLI {
672            debug: false,
673            quiet: false,
674            command: Commands::New {
675                command: LeoNew {
676                    name: "inner_1".to_string(),
677                    network: NETWORK.to_string(),
678                    endpoint: ENDPOINT.to_string(),
679                },
680            },
681            path: Some(inner_1_directory.clone()),
682            home: None,
683        };
684
685        let create_inner_2_project = CLI {
686            debug: false,
687            quiet: false,
688            command: Commands::New {
689                command: LeoNew {
690                    name: "inner_2".to_string(),
691                    network: NETWORK.to_string(),
692                    endpoint: ENDPOINT.to_string(),
693                },
694            },
695            path: Some(inner_2_directory.clone()),
696            home: None,
697        };
698
699        // Add source files `outer/src/main.leo` and `outer/inner/src/main.leo`
700        let outer_program = "import inner_1.aleo;
701import inner_2.aleo;
702program outer.aleo {
703
704    struct ex_struct {
705        arg1: u32,
706        arg2: u32,
707    }
708
709    record inner_1_record {
710        owner: address,
711        arg1: u32,
712        arg2: u32,
713        arg3: u32,
714    }
715
716    transition inner_1_main(public a: u32, b: u32) -> (inner_1.aleo/inner_1_record, inner_2.aleo/inner_1_record, inner_1_record) {
717        let c: ex_struct = ex_struct {arg1: 1u32, arg2: 1u32};
718        let rec_1:inner_1.aleo/inner_1_record = inner_1.aleo/inner_1_main(1u32,1u32, c);
719        let rec_2:inner_2.aleo/inner_1_record = inner_2.aleo/inner_1_main(1u32,1u32);
720        return (rec_1, rec_2, inner_1_record {owner: aleo14tnetva3xfvemqyg5ujzvr0qfcaxdanmgjx2wsuh2xrpvc03uc9s623ps7, arg1: 1u32, arg2: 1u32, arg3: 1u32});
721    }
722
723    @noupgrade
724    async constructor() {}
725}";
726        let inner_1_program = "program inner_1.aleo {
727    mapping inner_1_mapping: u32 => u32;
728    record inner_1_record {
729        owner: address,
730        val: u32,
731    }
732    struct ex_struct {
733        arg1: u32,
734        arg2: u32,
735    }
736    transition inner_1_main(public a: u32, b: u32, c: ex_struct) -> inner_1_record {
737        return inner_1_record {
738            owner: self.caller,
739            val: c.arg1,
740        };
741    }
742
743    @noupgrade
744    async constructor() {}
745}";
746        let inner_2_program = "program inner_2.aleo {
747    mapping inner_2_mapping: u32 => u32;
748    record inner_1_record {
749        owner: address,
750        val: u32,
751    }
752    transition inner_1_main(public a: u32, b: u32) -> inner_1_record {
753        let c: u32 = a + b;
754        return inner_1_record {
755            owner: self.caller,
756            val: a,
757        };
758    }
759
760    @noupgrade
761    async constructor() {}
762}";
763        // Add dependencies `outer/program.json`
764        let add_outer_dependency_1 = CLI {
765            debug: false,
766            quiet: false,
767            command: Commands::Add {
768                command: LeoAdd {
769                    name: "inner_1".to_string(),
770                    source: DependencySource { local: Some(inner_1_directory.clone()), network: false, edition: None },
771                    clear: false,
772                    dev: false,
773                },
774            },
775            path: Some(outer_directory.clone()),
776            home: None,
777        };
778
779        let add_outer_dependency_2 = CLI {
780            debug: false,
781            quiet: false,
782            command: Commands::Add {
783                command: LeoAdd {
784                    name: "inner_2".to_string(),
785                    source: DependencySource { local: Some(inner_2_directory.clone()), network: false, edition: None },
786                    clear: false,
787                    dev: false,
788                },
789            },
790            path: Some(outer_directory.clone()),
791            home: None,
792        };
793
794        // Execute all commands
795        create_session_if_not_set_then(|_| {
796            // Create projects
797            run_with_args(create_outer_project).unwrap();
798            run_with_args(create_inner_1_project).unwrap();
799            run_with_args(create_inner_2_project).unwrap();
800
801            // Write files
802            std::fs::write(outer_directory.join("src").join("main.leo"), outer_program).unwrap();
803            std::fs::write(inner_1_directory.join("src").join("main.leo"), inner_1_program).unwrap();
804            std::fs::write(inner_2_directory.join("src").join("main.leo"), inner_2_program).unwrap();
805
806            // Add dependencies
807            run_with_args(add_outer_dependency_1).unwrap();
808            run_with_args(add_outer_dependency_2).unwrap();
809        });
810    }
811
812    pub(crate) fn sample_struct_shadowing_package(temp_dir: &Path) {
813        let outer_directory = temp_dir.join("outer_2");
814        let inner_1_directory = outer_directory.join("inner_1");
815        let inner_2_directory = outer_directory.join("inner_2");
816
817        if outer_directory.exists() {
818            std::fs::remove_dir_all(outer_directory.clone()).unwrap();
819        }
820
821        // Create project file structure `outer_2/inner_1` and `outer_2/inner_2`
822        let create_outer_project = CLI {
823            debug: false,
824            quiet: false,
825            command: Commands::New {
826                command: LeoNew {
827                    name: "outer_2".to_string(),
828                    network: NETWORK.to_string(),
829                    endpoint: ENDPOINT.to_string(),
830                },
831            },
832            path: Some(outer_directory.clone()),
833            home: None,
834        };
835
836        let create_inner_1_project = CLI {
837            debug: false,
838            quiet: false,
839            command: Commands::New {
840                command: LeoNew {
841                    name: "inner_1".to_string(),
842                    network: NETWORK.to_string(),
843                    endpoint: ENDPOINT.to_string(),
844                },
845            },
846            path: Some(inner_1_directory.clone()),
847            home: None,
848        };
849
850        let create_inner_2_project = CLI {
851            debug: false,
852            quiet: false,
853            command: Commands::New {
854                command: LeoNew {
855                    name: "inner_2".to_string(),
856                    network: NETWORK.to_string(),
857                    endpoint: ENDPOINT.to_string(),
858                },
859            },
860            path: Some(inner_2_directory.clone()),
861            home: None,
862        };
863
864        // Add source files `outer_2/src/main.leo` and `outer_2/inner/src/main.leo`
865        let outer_program = "
866import inner_1.aleo;
867import inner_2.aleo;
868program outer_2.aleo {
869    struct Foo {
870        a: u32,
871        b: u32,
872        c: Boo,
873    }
874    struct Boo {
875        a: u32,
876        b: u32,
877    }
878    struct Goo {
879        a: u32,
880        b: u32,
881        c: u32,
882    }
883    record Hello {
884        owner: address,
885        a: u32,
886    }
887    transition main(public a: u32, b: u32) -> (inner_2.aleo/Yoo, Hello) {
888        let d: Foo = inner_1.aleo/main(1u32,1u32);
889        let e: u32 = inner_1.aleo/main_2(Foo {a: a, b: b, c: Boo {a:1u32, b:1u32}});
890        let f: Boo = Boo {a:1u32, b:1u32};
891        let g: Foo = inner_2.aleo/main(1u32, 1u32);
892        inner_2.aleo/Yo_Consumer(inner_2.aleo/Yo());
893        let h: inner_2.aleo/Yoo = inner_2.aleo/Yo();
894        let i: Goo = inner_2.aleo/Goo_creator();
895        let j: Hello = Hello {owner: self.signer, a:1u32};
896
897        return (h, j);
898    }
899
900    @noupgrade
901    async constructor() {}
902}
903";
904        let inner_1_program = "program inner_1.aleo {
905    struct Foo {
906        a: u32,
907        b: u32,
908        c: Boo,
909    }
910    struct Boo {
911        a: u32,
912        b: u32,
913    }
914    transition main(public a: u32, b: u32) -> Foo {
915        return Foo {a: a, b: b, c: Boo {a:1u32, b:1u32}};
916    }
917    transition main_2(a:Foo)->u32{
918        return a.a;
919    }
920
921    @noupgrade
922    async constructor() {}   
923}";
924        let inner_2_program = "program inner_2.aleo {
925    struct Foo {
926        a: u32,
927        b: u32,
928        c: Boo,
929    }
930    struct Boo {
931        a: u32,
932        b: u32,
933    }
934    record Yoo {
935        owner: address,
936        a: u32,
937    }
938    struct Goo {
939        a: u32,
940        b: u32,
941        c: u32,
942    }
943    transition main(public a: u32, b: u32) -> Foo {
944        return Foo {a: a, b: b, c: Boo {a:1u32, b:1u32}};
945    }
946    transition Yo()-> Yoo {
947        return Yoo {owner: self.signer, a:1u32};
948    }
949    transition Yo_Consumer(a: Yoo)->u32 {
950        return a.a;
951    }
952    transition Goo_creator() -> Goo {
953        return Goo {a:100u32, b:1u32, c:1u32};
954    }
955
956    @noupgrade
957    async constructor() {}
958}";
959        // Add dependencies `outer_2/program.json`
960        let add_outer_dependency_1 = CLI {
961            debug: false,
962            quiet: false,
963            command: Commands::Add {
964                command: LeoAdd {
965                    name: "inner_1".to_string(),
966                    source: DependencySource { local: Some(inner_1_directory.clone()), network: false, edition: None },
967                    clear: false,
968                    dev: false,
969                },
970            },
971            path: Some(outer_directory.clone()),
972            home: None,
973        };
974
975        let add_outer_dependency_2 = CLI {
976            debug: false,
977            quiet: false,
978            command: Commands::Add {
979                command: LeoAdd {
980                    name: "inner_2".to_string(),
981                    source: DependencySource { local: Some(inner_2_directory.clone()), network: false, edition: None },
982                    clear: false,
983                    dev: false,
984                },
985            },
986            path: Some(outer_directory.clone()),
987            home: None,
988        };
989
990        // Execute all commands
991        create_session_if_not_set_then(|_| {
992            // Create projects
993            run_with_args(create_outer_project).unwrap();
994            run_with_args(create_inner_1_project).unwrap();
995            run_with_args(create_inner_2_project).unwrap();
996
997            // Write files
998            std::fs::write(outer_directory.join("src").join("main.leo"), outer_program).unwrap();
999            std::fs::write(inner_1_directory.join("src").join("main.leo"), inner_1_program).unwrap();
1000            std::fs::write(inner_2_directory.join("src").join("main.leo"), inner_2_program).unwrap();
1001
1002            // Add dependencies
1003            run_with_args(add_outer_dependency_1).unwrap();
1004            run_with_args(add_outer_dependency_2).unwrap();
1005        });
1006    }
1007}