diff --git a/Cargo.lock b/Cargo.lock index 80bb753d594c0..4a75d98a5536a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -170,8 +170,11 @@ dependencies = [ "cached-framework-packages", "clap 3.1.8", "hex", + "move-binary-format", "move-cli", "move-core-types", + "move-package", + "move-unit-test", "move-vm-types", "rand 0.8.4", "reqwest", @@ -179,6 +182,7 @@ dependencies = [ "serde_json", "serde_yaml", "short-hex-str", + "tempfile", "thiserror", "tokio", "tokio-util 0.6.9", diff --git a/crates/aptos/Cargo.toml b/crates/aptos/Cargo.toml index 35758a448d7be..890be4c7085c1 100644 --- a/crates/aptos/Cargo.toml +++ b/crates/aptos/Cargo.toml @@ -20,6 +20,7 @@ serde = "1.0.124" serde_json = "1.0.64" serde_yaml = "0.8.17" thiserror = "1.0.24" +tempfile = "3.2.0" tokio = { version = "1.8.1", features = ["full"] } tokio-util = { version = "0.6.4", features = ["compat"] } @@ -36,8 +37,11 @@ aptos-rest-client = { path = "../../crates/aptos-rest-client"} aptos-workspace-hack = { version = "0.1", path = "../aptos-workspace-hack" } aptos-vm = { path = "../../aptos-move/aptos-vm" } bcs = "0.1.2" -move-cli = { git = "https://github.com/diem/move", rev = "3fe033b112eae7df2d15ab3467624165ae510caa" } short-hex-str = { path = "../short-hex-str" } cached-framework-packages = { path = "../../aptos-move/framework/cached-packages" } +move-binary-format = { git = "https://github.com/diem/move", rev = "3fe033b112eae7df2d15ab3467624165ae510caa" } +move-cli = { git = "https://github.com/diem/move", rev = "3fe033b112eae7df2d15ab3467624165ae510caa" } move-core-types = { git = "https://github.com/diem/move", rev = "3fe033b112eae7df2d15ab3467624165ae510caa", features=["address32"] } +move-package = { git = "https://github.com/diem/move", rev = "3fe033b112eae7df2d15ab3467624165ae510caa" } +move-unit-test = { git = "https://github.com/diem/move", rev = "3fe033b112eae7df2d15ab3467624165ae510caa" } move-vm-types = { git = "https://github.com/diem/move", rev = "3fe033b112eae7df2d15ab3467624165ae510caa" } diff --git a/crates/aptos/src/common/types.rs b/crates/aptos/src/common/types.rs index a2f3ed3241028..a49cf6f58514b 100644 --- a/crates/aptos/src/common/types.rs +++ b/crates/aptos/src/common/types.rs @@ -52,6 +52,8 @@ pub enum Error { UnexpectedError(String), #[error("Aborted command")] AbortedError, + #[error("Move compiliation failed: {0}")] + MoveCompiliationError(String), } #[derive(Debug, Default, Serialize, Deserialize)] @@ -344,3 +346,14 @@ pub struct NodeOptions { )] pub url: reqwest::Url, } + +/// Options for a move package dir +#[derive(Debug, Parser)] +pub struct MovePackageDir { + /// Path to a move package (the folder with a Move.toml file) + #[clap(long, parse(from_os_str))] + pub package_dir: PathBuf, + /// Path to save the compiled move package + #[clap(long, parse(from_os_str))] + pub output_dir: Option, +} diff --git a/crates/aptos/src/move_tool/chain.rs b/crates/aptos/src/move_tool/chain.rs deleted file mode 100644 index 18cc09c4e82fd..0000000000000 --- a/crates/aptos/src/move_tool/chain.rs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Aptos -// SPDX-License-Identifier: Apache-2.0 - -use crate::CliResult; -use aptos_types::account_address::AccountAddress; -use clap::{Parser, Subcommand}; - -/// CLI tool for performing onchain tasks -/// -#[derive(Debug, Subcommand)] -pub enum ChainTool { - List(ListResources), -} - -impl ChainTool { - pub async fn execute(self) -> CliResult { - match self { - ChainTool::List(tool) => tool.execute(), - } - } -} - -#[derive(Debug, Parser)] -pub struct ListResources { - account: AccountAddress, -} - -impl ListResources { - pub fn execute(self) -> CliResult { - Ok("".to_string()) - } -} diff --git a/crates/aptos/src/move_tool/mod.rs b/crates/aptos/src/move_tool/mod.rs index 5e5950f37d1e0..337ae2105f134 100644 --- a/crates/aptos/src/move_tool/mod.rs +++ b/crates/aptos/src/move_tool/mod.rs @@ -6,50 +6,95 @@ //! TODO: Examples //! -use crate::CliResult; +use crate::{ + common::{types::MovePackageDir, utils::to_common_result}, + CliResult, Error, +}; +use aptos_vm::natives::aptos_natives; use clap::{Parser, Subcommand}; -use move_core_types::errmap::ErrorMapping; -use move_vm_types::gas_schedule::INITIAL_COST_SCHEDULE; - -pub mod chain; +use move_cli::package::cli::{run_move_unit_tests, UnitTestResult}; +use move_package::{compilation::compiled_package::CompiledPackage, BuildConfig}; +use move_unit_test::UnitTestingConfig; +use std::path::Path; /// CLI tool for performing Move tasks /// #[derive(Subcommand)] pub enum MoveTool { - Command(MoveCli), + Compile(CompilePackage), + Test(TestPackage), } impl MoveTool { pub async fn execute(self) -> CliResult { match self { - // TODO: Rethink using the Move CLI and think about how we can make the experience better - MoveTool::Command(tool) => tool.execute(), + MoveTool::Compile(tool) => to_common_result(tool.execute().await), + MoveTool::Test(tool) => to_common_result(tool.execute().await), } } } +/// Compiles a package and returns the [`ModuleId`]s +#[derive(Parser)] +pub struct CompilePackage { + #[clap(flatten)] + move_options: MovePackageDir, +} + +impl CompilePackage { + pub async fn execute(&self) -> Result, Error> { + let build_config = BuildConfig { + generate_docs: true, + install_dir: self.move_options.output_dir.clone(), + ..Default::default() + }; + let compiled_package = compile_move(build_config, self.move_options.package_dir.as_path())?; + // TODO: This can be serialized once move is updated + let mut ids = Vec::new(); + compiled_package + .compiled_modules() + .iter_modules() + .iter() + .for_each(|module| ids.push(module.self_id().to_string())); + Ok(ids) + } +} + +/// Run Move unit tests against a package path #[derive(Parser)] -pub struct MoveCli { +pub struct TestPackage { #[clap(flatten)] - move_args: move_cli::Move, - #[clap(subcommand)] - command: move_cli::Command, + move_options: MovePackageDir, } -impl MoveCli { - fn execute(self) -> CliResult { - let error_descriptions: ErrorMapping = - bcs::from_bytes(cached_framework_packages::error_map()) - .map_err(|err| err.to_string())?; - move_cli::run_cli( - aptos_vm::natives::aptos_natives(), - &INITIAL_COST_SCHEDULE, - &error_descriptions, - &self.move_args, - &self.command, +impl TestPackage { + pub async fn execute(&self) -> Result<&'static str, Error> { + let config = BuildConfig { + test_mode: true, + install_dir: self.move_options.output_dir.clone(), + ..Default::default() + }; + let result = run_move_unit_tests( + self.move_options.package_dir.as_path(), + config, + UnitTestingConfig::default_with_bound(Some(100_000)), + aptos_natives(), + false, ) - .map(|_| "".to_string()) - .map_err(|err| err.to_string()) + .map_err(|err| Error::UnexpectedError(err.to_string()))?; + + // TODO: commit back up to the move repo + match result { + UnitTestResult::Success => Ok("Success"), + UnitTestResult::Failure => Ok("Failure"), + } } } + +/// Compiles a Move package dir, and returns the compiled modules. +fn compile_move(build_config: BuildConfig, package_dir: &Path) -> Result { + // TODO: Add caching + build_config + .compile_package(package_dir, &mut Vec::new()) + .map_err(|err| Error::MoveCompiliationError(err.to_string())) +}