From 068558d65572e0725e53c1f40cf80076e3bdc61f Mon Sep 17 00:00:00 2001 From: Blaine Bublitz Date: Mon, 14 Aug 2023 14:49:52 -0700 Subject: [PATCH] feat(nargo): Add `--workspace` flag to run commands against all workspace packages --- crates/lsp/src/lib.rs | 6 +-- crates/nargo_cli/src/cli/check_cmd.rs | 13 +++-- .../nargo_cli/src/cli/codegen_verifier_cmd.rs | 13 +++-- crates/nargo_cli/src/cli/compile_cmd.rs | 13 +++-- crates/nargo_cli/src/cli/execute_cmd.rs | 13 +++-- crates/nargo_cli/src/cli/info_cmd.rs | 13 +++-- crates/nargo_cli/src/cli/prove_cmd.rs | 13 +++-- crates/nargo_cli/src/cli/test_cmd.rs | 13 +++-- crates/nargo_cli/src/cli/verify_cmd.rs | 13 +++-- crates/nargo_toml/src/lib.rs | 51 ++++++++++++------- 10 files changed, 117 insertions(+), 44 deletions(-) diff --git a/crates/lsp/src/lib.rs b/crates/lsp/src/lib.rs index b0768ccdeaa..e6608e84625 100644 --- a/crates/lsp/src/lib.rs +++ b/crates/lsp/src/lib.rs @@ -19,7 +19,7 @@ use lsp_types::{ PublishDiagnosticsParams, Range, ServerCapabilities, TextDocumentSyncOptions, }; use nargo::prepare_package; -use nargo_toml::{find_package_manifest, resolve_workspace_from_toml}; +use nargo_toml::{find_package_manifest, resolve_workspace_from_toml, PackageSelection}; use noirc_driver::check_crate; use noirc_errors::{DiagnosticKind, FileDiagnostic}; use noirc_frontend::hir::FunctionNameMatch; @@ -156,7 +156,7 @@ fn on_code_lens_request( return future::ready(Ok(None)); } }; - let workspace = match resolve_workspace_from_toml(&toml_path, None) { + let workspace = match resolve_workspace_from_toml(&toml_path, PackageSelection::All) { Ok(workspace) => workspace, Err(err) => { // If we found a manifest, but the workspace is invalid, we raise an error about it @@ -281,7 +281,7 @@ fn on_did_save_text_document( return ControlFlow::Continue(()); } }; - let workspace = match resolve_workspace_from_toml(&toml_path, None) { + let workspace = match resolve_workspace_from_toml(&toml_path, PackageSelection::All) { Ok(workspace) => workspace, Err(err) => { // If we found a manifest, but the workspace is invalid, we raise an error about it diff --git a/crates/nargo_cli/src/cli/check_cmd.rs b/crates/nargo_cli/src/cli/check_cmd.rs index a1b5018d334..4364c78a6dc 100644 --- a/crates/nargo_cli/src/cli/check_cmd.rs +++ b/crates/nargo_cli/src/cli/check_cmd.rs @@ -3,7 +3,7 @@ use acvm::Backend; use clap::Args; use iter_extended::btree_map; use nargo::{package::Package, prepare_package}; -use nargo_toml::{find_package_manifest, resolve_workspace_from_toml}; +use nargo_toml::{find_package_manifest, resolve_workspace_from_toml, PackageSelection}; use noirc_abi::{AbiParameter, AbiType, MAIN_RETURN_NAME}; use noirc_driver::{check_crate, compute_function_signature, CompileOptions}; use noirc_frontend::{ @@ -18,9 +18,13 @@ use super::NargoConfig; #[derive(Debug, Clone, Args)] pub(crate) struct CheckCommand { /// The name of the package to check - #[clap(long)] + #[clap(long, conflicts_with = "workspace")] package: Option, + /// Check all packages in the workspace + #[clap(long, conflicts_with = "package")] + workspace: bool, + #[clap(flatten)] compile_options: CompileOptions, } @@ -31,7 +35,10 @@ pub(crate) fn run( config: NargoConfig, ) -> Result<(), CliError> { let toml_path = find_package_manifest(&config.program_dir)?; - let workspace = resolve_workspace_from_toml(&toml_path, args.package)?; + let default_selection = + if args.workspace { PackageSelection::All } else { PackageSelection::DefaultOrAll }; + let selection = args.package.map_or(default_selection, PackageSelection::Selected); + let workspace = resolve_workspace_from_toml(&toml_path, selection)?; for package in &workspace { check_package(package, &args.compile_options)?; diff --git a/crates/nargo_cli/src/cli/codegen_verifier_cmd.rs b/crates/nargo_cli/src/cli/codegen_verifier_cmd.rs index bc7e1c80c0f..2a6cec1534a 100644 --- a/crates/nargo_cli/src/cli/codegen_verifier_cmd.rs +++ b/crates/nargo_cli/src/cli/codegen_verifier_cmd.rs @@ -20,7 +20,7 @@ use nargo::{ ops::{codegen_verifier, preprocess_program}, package::Package, }; -use nargo_toml::{find_package_manifest, resolve_workspace_from_toml}; +use nargo_toml::{find_package_manifest, resolve_workspace_from_toml, PackageSelection}; use noirc_driver::CompileOptions; use noirc_frontend::graph::CrateName; @@ -28,9 +28,13 @@ use noirc_frontend::graph::CrateName; #[derive(Debug, Clone, Args)] pub(crate) struct CodegenVerifierCommand { /// The name of the package to codegen - #[clap(long)] + #[clap(long, conflicts_with = "workspace")] package: Option, + /// Codegen all packages in the workspace + #[clap(long, conflicts_with = "package")] + workspace: bool, + #[clap(flatten)] compile_options: CompileOptions, } @@ -41,7 +45,10 @@ pub(crate) fn run( config: NargoConfig, ) -> Result<(), CliError> { let toml_path = find_package_manifest(&config.program_dir)?; - let workspace = resolve_workspace_from_toml(&toml_path, args.package)?; + let default_selection = + if args.workspace { PackageSelection::All } else { PackageSelection::DefaultOrAll }; + let selection = args.package.map_or(default_selection, PackageSelection::Selected); + let workspace = resolve_workspace_from_toml(&toml_path, selection)?; for package in &workspace { let circuit_build_path = workspace.package_build_path(package); diff --git a/crates/nargo_cli/src/cli/compile_cmd.rs b/crates/nargo_cli/src/cli/compile_cmd.rs index 2a6f802f748..08a24091a59 100644 --- a/crates/nargo_cli/src/cli/compile_cmd.rs +++ b/crates/nargo_cli/src/cli/compile_cmd.rs @@ -6,7 +6,7 @@ use nargo::artifacts::debug::DebugArtifact; use nargo::package::Package; use nargo::prepare_package; use nargo::{artifacts::contract::PreprocessedContract, NargoError}; -use nargo_toml::{find_package_manifest, resolve_workspace_from_toml}; +use nargo_toml::{find_package_manifest, resolve_workspace_from_toml, PackageSelection}; use noirc_driver::{ compile_contracts, compile_main, CompileOptions, CompiledContract, CompiledProgram, ErrorsAndWarnings, Warnings, @@ -46,9 +46,13 @@ pub(crate) struct CompileCommand { output_debug: bool, /// The name of the package to compile - #[clap(long)] + #[clap(long, conflicts_with = "workspace")] package: Option, + /// Compile all packages in the workspace + #[clap(long, conflicts_with = "package")] + workspace: bool, + #[clap(flatten)] compile_options: CompileOptions, } @@ -59,7 +63,10 @@ pub(crate) fn run( config: NargoConfig, ) -> Result<(), CliError> { let toml_path = find_package_manifest(&config.program_dir)?; - let workspace = resolve_workspace_from_toml(&toml_path, args.package)?; + let default_selection = + if args.workspace { PackageSelection::All } else { PackageSelection::DefaultOrAll }; + let selection = args.package.map_or(default_selection, PackageSelection::Selected); + let workspace = resolve_workspace_from_toml(&toml_path, selection)?; let circuit_dir = workspace.target_directory_path(); let mut common_reference_string = read_cached_common_reference_string(); diff --git a/crates/nargo_cli/src/cli/execute_cmd.rs b/crates/nargo_cli/src/cli/execute_cmd.rs index 1f0095fed5a..82455ea3163 100644 --- a/crates/nargo_cli/src/cli/execute_cmd.rs +++ b/crates/nargo_cli/src/cli/execute_cmd.rs @@ -5,7 +5,7 @@ use clap::Args; use nargo::constants::PROVER_INPUT_FILE; use nargo::package::Package; use nargo::NargoError; -use nargo_toml::{find_package_manifest, resolve_workspace_from_toml}; +use nargo_toml::{find_package_manifest, resolve_workspace_from_toml, PackageSelection}; use noirc_abi::input_parser::{Format, InputValue}; use noirc_abi::{Abi, InputMap}; use noirc_driver::{CompileOptions, CompiledProgram}; @@ -29,9 +29,13 @@ pub(crate) struct ExecuteCommand { prover_name: String, /// The name of the package to execute - #[clap(long)] + #[clap(long, conflicts_with = "workspace")] package: Option, + /// Execute all packages in the workspace + #[clap(long, conflicts_with = "package")] + workspace: bool, + #[clap(flatten)] compile_options: CompileOptions, } @@ -42,7 +46,10 @@ pub(crate) fn run( config: NargoConfig, ) -> Result<(), CliError> { let toml_path = find_package_manifest(&config.program_dir)?; - let workspace = resolve_workspace_from_toml(&toml_path, args.package)?; + let default_selection = + if args.workspace { PackageSelection::All } else { PackageSelection::DefaultOrAll }; + let selection = args.package.map_or(default_selection, PackageSelection::Selected); + let workspace = resolve_workspace_from_toml(&toml_path, selection)?; let witness_dir = &workspace.target_directory_path(); for package in &workspace { diff --git a/crates/nargo_cli/src/cli/info_cmd.rs b/crates/nargo_cli/src/cli/info_cmd.rs index a2900a6e249..48ccd76f9cd 100644 --- a/crates/nargo_cli/src/cli/info_cmd.rs +++ b/crates/nargo_cli/src/cli/info_cmd.rs @@ -2,7 +2,7 @@ use acvm::Backend; use clap::Args; use iter_extended::try_vecmap; use nargo::{package::Package, prepare_package}; -use nargo_toml::{find_package_manifest, resolve_workspace_from_toml}; +use nargo_toml::{find_package_manifest, resolve_workspace_from_toml, PackageSelection}; use noirc_driver::{compile_contracts, CompileOptions}; use noirc_frontend::graph::CrateName; use prettytable::{row, Table}; @@ -22,9 +22,13 @@ use super::{ #[derive(Debug, Clone, Args)] pub(crate) struct InfoCommand { /// The name of the package to detail - #[clap(long)] + #[clap(long, conflicts_with = "workspace")] package: Option, + /// Detail all packages in the workspace + #[clap(long, conflicts_with = "package")] + workspace: bool, + #[clap(flatten)] compile_options: CompileOptions, } @@ -35,7 +39,10 @@ pub(crate) fn run( config: NargoConfig, ) -> Result<(), CliError> { let toml_path = find_package_manifest(&config.program_dir)?; - let workspace = resolve_workspace_from_toml(&toml_path, args.package)?; + let default_selection = + if args.workspace { PackageSelection::All } else { PackageSelection::DefaultOrAll }; + let selection = args.package.map_or(default_selection, PackageSelection::Selected); + let workspace = resolve_workspace_from_toml(&toml_path, selection)?; let mut package_table = Table::new(); package_table.add_row( diff --git a/crates/nargo_cli/src/cli/prove_cmd.rs b/crates/nargo_cli/src/cli/prove_cmd.rs index 018e150f89f..66129f8748f 100644 --- a/crates/nargo_cli/src/cli/prove_cmd.rs +++ b/crates/nargo_cli/src/cli/prove_cmd.rs @@ -6,7 +6,7 @@ use nargo::artifacts::program::PreprocessedProgram; use nargo::constants::{PROVER_INPUT_FILE, VERIFIER_INPUT_FILE}; use nargo::ops::{preprocess_program, prove_execution, verify_proof}; use nargo::package::Package; -use nargo_toml::{find_package_manifest, resolve_workspace_from_toml}; +use nargo_toml::{find_package_manifest, resolve_workspace_from_toml, PackageSelection}; use noirc_abi::input_parser::Format; use noirc_driver::CompileOptions; use noirc_frontend::graph::CrateName; @@ -40,9 +40,13 @@ pub(crate) struct ProveCommand { verify: bool, /// The name of the package to prove - #[clap(long)] + #[clap(long, conflicts_with = "workspace")] package: Option, + /// Prove all packages in the workspace + #[clap(long, conflicts_with = "package")] + workspace: bool, + #[clap(flatten)] compile_options: CompileOptions, } @@ -53,7 +57,10 @@ pub(crate) fn run( config: NargoConfig, ) -> Result<(), CliError> { let toml_path = find_package_manifest(&config.program_dir)?; - let workspace = resolve_workspace_from_toml(&toml_path, args.package)?; + let default_selection = + if args.workspace { PackageSelection::All } else { PackageSelection::DefaultOrAll }; + let selection = args.package.map_or(default_selection, PackageSelection::Selected); + let workspace = resolve_workspace_from_toml(&toml_path, selection)?; let proof_dir = workspace.proofs_directory_path(); for package in &workspace { diff --git a/crates/nargo_cli/src/cli/test_cmd.rs b/crates/nargo_cli/src/cli/test_cmd.rs index 95d7f907196..bdce8e35096 100644 --- a/crates/nargo_cli/src/cli/test_cmd.rs +++ b/crates/nargo_cli/src/cli/test_cmd.rs @@ -3,7 +3,7 @@ use std::io::Write; use acvm::{acir::native_types::WitnessMap, Backend}; use clap::Args; use nargo::{ops::execute_circuit, package::Package, prepare_package}; -use nargo_toml::{find_package_manifest, resolve_workspace_from_toml}; +use nargo_toml::{find_package_manifest, resolve_workspace_from_toml, PackageSelection}; use noirc_driver::{compile_no_check, CompileOptions}; use noirc_frontend::{ graph::CrateName, @@ -31,9 +31,13 @@ pub(crate) struct TestCommand { exact: bool, /// The name of the package to test - #[clap(long)] + #[clap(long, conflicts_with = "workspace")] package: Option, + /// Test all packages in the workspace + #[clap(long, conflicts_with = "package")] + workspace: bool, + #[clap(flatten)] compile_options: CompileOptions, } @@ -44,7 +48,10 @@ pub(crate) fn run( config: NargoConfig, ) -> Result<(), CliError> { let toml_path = find_package_manifest(&config.program_dir)?; - let workspace = resolve_workspace_from_toml(&toml_path, args.package)?; + let default_selection = + if args.workspace { PackageSelection::All } else { PackageSelection::DefaultOrAll }; + let selection = args.package.map_or(default_selection, PackageSelection::Selected); + let workspace = resolve_workspace_from_toml(&toml_path, selection)?; let pattern = match &args.test_name { Some(name) => { diff --git a/crates/nargo_cli/src/cli/verify_cmd.rs b/crates/nargo_cli/src/cli/verify_cmd.rs index 5af28b4e25b..5319d7a4f39 100644 --- a/crates/nargo_cli/src/cli/verify_cmd.rs +++ b/crates/nargo_cli/src/cli/verify_cmd.rs @@ -18,7 +18,7 @@ use clap::Args; use nargo::constants::{PROOF_EXT, VERIFIER_INPUT_FILE}; use nargo::ops::{preprocess_program, verify_proof}; use nargo::{artifacts::program::PreprocessedProgram, package::Package}; -use nargo_toml::{find_package_manifest, resolve_workspace_from_toml}; +use nargo_toml::{find_package_manifest, resolve_workspace_from_toml, PackageSelection}; use noirc_abi::input_parser::Format; use noirc_driver::CompileOptions; use noirc_frontend::graph::CrateName; @@ -32,9 +32,13 @@ pub(crate) struct VerifyCommand { verifier_name: String, /// The name of the package verify - #[clap(long)] + #[clap(long, conflicts_with = "workspace")] package: Option, + /// Verify all packages in the workspace + #[clap(long, conflicts_with = "package")] + workspace: bool, + #[clap(flatten)] compile_options: CompileOptions, } @@ -45,7 +49,10 @@ pub(crate) fn run( config: NargoConfig, ) -> Result<(), CliError> { let toml_path = find_package_manifest(&config.program_dir)?; - let workspace = resolve_workspace_from_toml(&toml_path, args.package)?; + let default_selection = + if args.workspace { PackageSelection::All } else { PackageSelection::DefaultOrAll }; + let selection = args.package.map_or(default_selection, PackageSelection::Selected); + let workspace = resolve_workspace_from_toml(&toml_path, selection)?; let proofs_dir = workspace.proofs_directory_path(); for package in &workspace { diff --git a/crates/nargo_toml/src/lib.rs b/crates/nargo_toml/src/lib.rs index 0e05a0a7901..6189d6426ba 100644 --- a/crates/nargo_toml/src/lib.rs +++ b/crates/nargo_toml/src/lib.rs @@ -249,19 +249,20 @@ impl DependencyConfig { fn toml_to_workspace( nargo_toml: NargoToml, - selected_package: Option, + package_selection: PackageSelection, ) -> Result { let workspace = match nargo_toml.config { Config::Package { package_config } => { let member = package_config.resolve_to_package(&nargo_toml.root_dir)?; - if selected_package.is_none() || Some(&member.name) == selected_package.as_ref() { - Workspace { + match &package_selection { + PackageSelection::Selected(selected_name) if selected_name != &member.name => { + return Err(ManifestError::MissingSelectedPackage(member.name)) + } + _ => Workspace { root_dir: nargo_toml.root_dir, selected_package_index: Some(0), members: vec![member], - } - } else { - return Err(ManifestError::MissingSelectedPackage(member.name)); + }, } } Config::Workspace { workspace_config } => { @@ -272,17 +273,18 @@ fn toml_to_workspace( let package_toml_path = package_root_dir.join("Nargo.toml"); let member = resolve_package_from_toml(&package_toml_path)?; - match selected_package.as_ref() { - Some(selected_name) => { + match &package_selection { + PackageSelection::Selected(selected_name) => { if &member.name == selected_name { selected_package_index = Some(index); } } - None => { + PackageSelection::DefaultOrAll => { if Some(&member_path) == workspace_config.default_member.as_ref() { selected_package_index = Some(index); } } + PackageSelection::All => selected_package_index = None, } members.push(member); @@ -290,13 +292,21 @@ fn toml_to_workspace( // If the selected_package_index is still `None` but we have see a default_member or selected package, // we want to present an error to users - if selected_package_index.is_none() { - if let Some(selected_name) = selected_package { - return Err(ManifestError::MissingSelectedPackage(selected_name)); - } - if let Some(default_path) = workspace_config.default_member { - return Err(ManifestError::MissingDefaultPackage(default_path)); + match package_selection { + PackageSelection::Selected(selected_name) => { + if selected_package_index.is_none() { + return Err(ManifestError::MissingSelectedPackage(selected_name)); + } } + PackageSelection::DefaultOrAll => match workspace_config.default_member { + // If `default-member` is specified but we don't have a selected_package_index, we need to fail + Some(default_path) if selected_package_index.is_none() => { + return Err(ManifestError::MissingDefaultPackage(default_path)); + } + // However, if there wasn't a `default-member`, we select All, so no error is needed + _ => (), + }, + PackageSelection::All => (), } Workspace { root_dir: nargo_toml.root_dir, members, selected_package_index } @@ -331,14 +341,21 @@ fn resolve_package_from_toml(toml_path: &Path) -> Result } } +#[derive(Debug, PartialEq, Eq)] +pub enum PackageSelection { + Selected(CrateName), + DefaultOrAll, + All, +} + /// Resolves a Nargo.toml file into a `Workspace` struct as defined by our `nargo` core. pub fn resolve_workspace_from_toml( toml_path: &Path, - selected_package: Option, + package_selection: PackageSelection, ) -> Result { let nargo_toml = read_toml(toml_path)?; - toml_to_workspace(nargo_toml, selected_package) + toml_to_workspace(nargo_toml, package_selection) } #[test]