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