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