diff --git a/Cargo.lock b/Cargo.lock index c4235b2c913..91445bfa37f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2010,6 +2010,7 @@ dependencies = [ "hex", "iter-extended", "nargo", + "nargo_toml", "noir_lsp", "noirc_abi", "noirc_driver", @@ -2028,6 +2029,20 @@ dependencies = [ "url", ] +[[package]] +name = "nargo_toml" +version = "0.9.0" +dependencies = [ + "dirs", + "fm", + "nargo", + "noirc_frontend", + "serde", + "thiserror", + "toml", + "url", +] + [[package]] name = "noir_lsp" version = "0.9.0" diff --git a/Cargo.toml b/Cargo.toml index 0b05d783e11..64696f57a28 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ members = [ "crates/noirc_driver", "crates/nargo", "crates/nargo_cli", + "crates/nargo_toml", "crates/fm", "crates/arena", "crates/noirc_abi", @@ -30,6 +31,7 @@ fm = { path = "crates/fm" } iter-extended = { path = "crates/iter-extended" } nargo = { path = "crates/nargo" } nargo_cli = { path = "crates/nargo_cli" } +nargo_toml = { path = "crates/nargo_toml" } noir_lsp = { path = "crates/lsp" } noirc_abi = { path = "crates/noirc_abi" } noirc_driver = { path = "crates/noirc_driver" } diff --git a/crates/nargo_cli/Cargo.toml b/crates/nargo_cli/Cargo.toml index 22ce540a4e6..52194a898d4 100644 --- a/crates/nargo_cli/Cargo.toml +++ b/crates/nargo_cli/Cargo.toml @@ -24,6 +24,7 @@ dirs.workspace = true url.workspace = true iter-extended.workspace = true nargo.workspace = true +nargo_toml.workspace = true noir_lsp.workspace = true noirc_driver.workspace = true noirc_frontend.workspace = true diff --git a/crates/nargo_cli/src/cli/check_cmd.rs b/crates/nargo_cli/src/cli/check_cmd.rs index 1d292fbf188..f44a6057ef8 100644 --- a/crates/nargo_cli/src/cli/check_cmd.rs +++ b/crates/nargo_cli/src/cli/check_cmd.rs @@ -1,13 +1,12 @@ use crate::{ errors::{CliError, CompileError}, - find_package_manifest, - manifest::resolve_workspace_from_toml, prepare_package, }; use acvm::Backend; use clap::Args; use iter_extended::btree_map; use nargo::package::Package; +use nargo_toml::{find_package_manifest, resolve_workspace_from_toml}; use noirc_abi::{AbiParameter, AbiType, MAIN_RETURN_NAME}; use noirc_driver::{check_crate, compute_function_signature, CompileOptions}; use noirc_frontend::{ @@ -116,11 +115,10 @@ fn create_input_toml_template( mod tests { use std::path::PathBuf; + use nargo_toml::{find_package_manifest, resolve_workspace_from_toml}; use noirc_abi::{AbiParameter, AbiType, AbiVisibility, Sign}; use noirc_driver::CompileOptions; - use crate::{find_package_manifest, manifest::resolve_workspace_from_toml}; - use super::create_input_toml_template; const TEST_DATA_DIR: &str = "tests/target_tests_data"; diff --git a/crates/nargo_cli/src/cli/codegen_verifier_cmd.rs b/crates/nargo_cli/src/cli/codegen_verifier_cmd.rs index 297b54fddb1..bc7e1c80c0f 100644 --- a/crates/nargo_cli/src/cli/codegen_verifier_cmd.rs +++ b/crates/nargo_cli/src/cli/codegen_verifier_cmd.rs @@ -14,13 +14,13 @@ use super::{ }, }; use crate::errors::CliError; -use crate::{find_package_manifest, manifest::resolve_workspace_from_toml}; use acvm::Backend; use clap::Args; use nargo::{ ops::{codegen_verifier, preprocess_program}, package::Package, }; +use nargo_toml::{find_package_manifest, resolve_workspace_from_toml}; use noirc_driver::CompileOptions; use noirc_frontend::graph::CrateName; diff --git a/crates/nargo_cli/src/cli/compile_cmd.rs b/crates/nargo_cli/src/cli/compile_cmd.rs index b514d771144..5df6d6d563b 100644 --- a/crates/nargo_cli/src/cli/compile_cmd.rs +++ b/crates/nargo_cli/src/cli/compile_cmd.rs @@ -4,6 +4,7 @@ use iter_extended::try_vecmap; use iter_extended::vecmap; use nargo::package::Package; use nargo::{artifacts::contract::PreprocessedContract, NargoError}; +use nargo_toml::{find_package_manifest, resolve_workspace_from_toml}; use noirc_driver::{ compile_contracts, compile_main, CompileOptions, CompiledProgram, ErrorsAndWarnings, Warnings, }; @@ -15,8 +16,7 @@ use clap::Args; use nargo::ops::{preprocess_contract_function, preprocess_program}; use crate::errors::{CliError, CompileError}; -use crate::manifest::resolve_workspace_from_toml; -use crate::{find_package_manifest, prepare_package}; +use crate::prepare_package; use super::fs::{ common_reference_string::{ diff --git a/crates/nargo_cli/src/cli/execute_cmd.rs b/crates/nargo_cli/src/cli/execute_cmd.rs index fa6b13a5134..1f0095fed5a 100644 --- a/crates/nargo_cli/src/cli/execute_cmd.rs +++ b/crates/nargo_cli/src/cli/execute_cmd.rs @@ -5,6 +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 noirc_abi::input_parser::{Format, InputValue}; use noirc_abi::{Abi, InputMap}; use noirc_driver::{CompileOptions, CompiledProgram}; @@ -16,8 +17,6 @@ use super::compile_cmd::compile_package; use super::fs::{inputs::read_inputs_from_file, witness::save_witness_to_dir}; use super::NargoConfig; use crate::errors::CliError; -use crate::find_package_manifest; -use crate::manifest::resolve_workspace_from_toml; /// Executes a circuit to calculate its return value #[derive(Debug, Clone, Args)] diff --git a/crates/nargo_cli/src/cli/info_cmd.rs b/crates/nargo_cli/src/cli/info_cmd.rs index bfa0e7985db..213f494d7a9 100644 --- a/crates/nargo_cli/src/cli/info_cmd.rs +++ b/crates/nargo_cli/src/cli/info_cmd.rs @@ -1,13 +1,11 @@ use acvm::Backend; use clap::Args; use nargo::package::Package; +use nargo_toml::{find_package_manifest, resolve_workspace_from_toml}; use noirc_driver::CompileOptions; use noirc_frontend::graph::CrateName; -use crate::{ - cli::compile_cmd::compile_package, errors::CliError, find_package_manifest, - manifest::resolve_workspace_from_toml, -}; +use crate::{cli::compile_cmd::compile_package, errors::CliError}; use super::NargoConfig; diff --git a/crates/nargo_cli/src/cli/mod.rs b/crates/nargo_cli/src/cli/mod.rs index 3ec23d8ed58..da4ff7d5a66 100644 --- a/crates/nargo_cli/src/cli/mod.rs +++ b/crates/nargo_cli/src/cli/mod.rs @@ -1,11 +1,10 @@ use clap::{Args, Parser, Subcommand}; use const_format::formatcp; +use nargo_toml::find_package_root; use std::path::PathBuf; use color_eyre::eyre; -use crate::find_package_root; - mod fs; mod check_cmd; diff --git a/crates/nargo_cli/src/cli/prove_cmd.rs b/crates/nargo_cli/src/cli/prove_cmd.rs index d7eaf2d1405..018e150f89f 100644 --- a/crates/nargo_cli/src/cli/prove_cmd.rs +++ b/crates/nargo_cli/src/cli/prove_cmd.rs @@ -6,6 +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 noirc_abi::input_parser::Format; use noirc_driver::CompileOptions; use noirc_frontend::graph::CrateName; @@ -21,8 +22,6 @@ use super::fs::{ proof::save_proof_to_dir, }; use super::NargoConfig; -use crate::find_package_manifest; -use crate::manifest::resolve_workspace_from_toml; use crate::{cli::execute_cmd::execute_program, errors::CliError}; /// Create proof for this program. The proof is returned as a hex encoded string. diff --git a/crates/nargo_cli/src/cli/test_cmd.rs b/crates/nargo_cli/src/cli/test_cmd.rs index e52e3e5aa8d..188b3d03ff5 100644 --- a/crates/nargo_cli/src/cli/test_cmd.rs +++ b/crates/nargo_cli/src/cli/test_cmd.rs @@ -3,14 +3,12 @@ use std::io::Write; use acvm::{acir::native_types::WitnessMap, Backend}; use clap::Args; use nargo::{ops::execute_circuit, package::Package}; +use nargo_toml::{find_package_manifest, resolve_workspace_from_toml}; use noirc_driver::{compile_no_check, CompileOptions}; use noirc_frontend::{graph::CrateName, hir::Context, node_interner::FuncId}; use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; -use crate::{ - cli::check_cmd::check_crate_and_report_errors, errors::CliError, find_package_manifest, - manifest::resolve_workspace_from_toml, prepare_package, -}; +use crate::{cli::check_cmd::check_crate_and_report_errors, errors::CliError, prepare_package}; use super::{compile_cmd::optimize_circuit, NargoConfig}; diff --git a/crates/nargo_cli/src/cli/verify_cmd.rs b/crates/nargo_cli/src/cli/verify_cmd.rs index cceaf997af7..5af28b4e25b 100644 --- a/crates/nargo_cli/src/cli/verify_cmd.rs +++ b/crates/nargo_cli/src/cli/verify_cmd.rs @@ -12,14 +12,13 @@ use super::{ }, }; use crate::errors::CliError; -use crate::find_package_manifest; -use crate::manifest::resolve_workspace_from_toml; use acvm::Backend; 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 noirc_abi::input_parser::Format; use noirc_driver::CompileOptions; use noirc_frontend::graph::CrateName; diff --git a/crates/nargo_cli/src/errors.rs b/crates/nargo_cli/src/errors.rs index ee7ea12f761..d801a56d3f5 100644 --- a/crates/nargo_cli/src/errors.rs +++ b/crates/nargo_cli/src/errors.rs @@ -3,7 +3,8 @@ use acvm::{ SmartContract, }; use hex::FromHexError; -use nargo::{package::PackageType, NargoError}; +use nargo::NargoError; +use nargo_toml::ManifestError; use noirc_abi::errors::{AbiError, InputParserError}; use noirc_errors::reporter::ReportedErrors; use noirc_frontend::graph::CrateName; @@ -96,58 +97,3 @@ impl From for CompileError { Self::ReportedErrors(errors) } } - -/// Errors covering situations where a package is either missing or malformed. -#[derive(Debug, Error)] -pub(crate) enum ManifestError { - /// Package doesn't have a manifest file - #[error("cannot find a Nargo.toml in {}", .0.display())] - MissingFile(PathBuf), - - #[error("Cannot read file {0} - does it exist?")] - ReadFailed(PathBuf), - - #[error("Nargo.toml is missing a parent directory")] - MissingParent, - - #[error("Missing `type` field in {0}")] - MissingPackageType(PathBuf), - - #[error("Cannot use `{1}` for `type` field in {0}")] - InvalidPackageType(PathBuf, String), - - /// Package manifest is unreadable. - #[error("Nargo.toml is badly formed, could not parse.\n\n {0}")] - MalformedFile(#[from] toml::de::Error), - - #[error("Unxpected workspace definition found in {0}")] - UnexpectedWorkspace(PathBuf), - - #[error("Cannot find file {entry} which was specified as the `entry` field in {toml}")] - MissingEntryFile { toml: PathBuf, entry: PathBuf }, - - #[error( - r#"Cannot find file {entry} which is defaulted due to specifying `type = "{package_type}"` in {toml}"# - )] - MissingDefaultEntryFile { toml: PathBuf, entry: PathBuf, package_type: PackageType }, - - /// Invalid character `-` in package name - #[error("invalid character `-` in package name")] - InvalidPackageName, - - /// Encountered error while downloading git repository. - #[error("{0}")] - GitError(String), - - #[error("Selected package `{0}` was not found")] - MissingSelectedPackage(CrateName), - - #[error("Default package was not found. Does {0} exist in your workspace?")] - MissingDefaultPackage(PathBuf), - - #[error("Package `{0}` has type `bin` but you cannot depend on binary packages")] - BinaryDependency(CrateName), - - #[error("Missing `name` field in {toml}")] - MissingNameField { toml: PathBuf }, -} diff --git a/crates/nargo_cli/src/lib.rs b/crates/nargo_cli/src/lib.rs index d90ce39259d..52a277ba48d 100644 --- a/crates/nargo_cli/src/lib.rs +++ b/crates/nargo_cli/src/lib.rs @@ -14,67 +14,11 @@ use noirc_frontend::{ graph::{CrateGraph, CrateId, CrateName}, hir::Context, }; -use std::{ - collections::BTreeMap, - fs::ReadDir, - path::{Path, PathBuf}, -}; - -use errors::ManifestError; +use std::collections::BTreeMap; mod backends; pub mod cli; mod errors; -mod git; -mod manifest; - -fn nargo_crates() -> PathBuf { - dirs::home_dir().unwrap().join("nargo") -} - -/// Returns the path of the root directory of the package containing `current_path`. -/// -/// Returns a `CliError` if no parent directories of `current_path` contain a manifest file. -fn find_package_root(current_path: &Path) -> Result { - let manifest_path = find_package_manifest(current_path)?; - - let package_root = - manifest_path.parent().expect("infallible: manifest file path can't be root directory"); - - Ok(package_root.to_path_buf()) -} - -/// Returns the path of the manifest file (`Nargo.toml`) of the package containing `current_path`. -/// -/// Returns a `CliError` if no parent directories of `current_path` contain a manifest file. -fn find_package_manifest(current_path: &Path) -> Result { - current_path - .ancestors() - .find_map(|dir| find_file(dir, "Nargo", "toml")) - .ok_or_else(|| ManifestError::MissingFile(current_path.to_path_buf())) -} - -// Looks for file named `file_name` in path -fn find_file>(path: P, file_name: &str, extension: &str) -> Option { - let entries = list_files_and_folders_in(path)?; - let file_name = format!("{file_name}.{extension}"); - - find_artifact(entries, &file_name) -} - -// There is no distinction between files and folders -fn find_artifact(entries: ReadDir, artifact_name: &str) -> Option { - let entry = entries - .into_iter() - .flatten() - .find(|entry| entry.file_name().to_str() == Some(artifact_name))?; - - Some(entry.path()) -} - -fn list_files_and_folders_in>(path: P) -> Option { - std::fs::read_dir(path).ok() -} fn prepare_dependencies( context: &mut Context, diff --git a/crates/nargo_toml/Cargo.toml b/crates/nargo_toml/Cargo.toml new file mode 100644 index 00000000000..f693403cd06 --- /dev/null +++ b/crates/nargo_toml/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "nargo_toml" +description = "Utilities for working with Nargo.toml files" +version.workspace = true +authors.workspace = true +edition.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +dirs.workspace = true +fm.workspace = true +nargo.workspace = true +noirc_frontend.workspace = true +serde.workspace = true +thiserror.workspace = true +toml.workspace = true +url.workspace = true + +[dev-dependencies] diff --git a/crates/nargo_toml/src/errors.rs b/crates/nargo_toml/src/errors.rs new file mode 100644 index 00000000000..97a39626be6 --- /dev/null +++ b/crates/nargo_toml/src/errors.rs @@ -0,0 +1,60 @@ +use std::path::PathBuf; + +use nargo::package::PackageType; +use noirc_frontend::graph::CrateName; +use thiserror::Error; + +/// Errors covering situations where a package is either missing or malformed. +#[derive(Debug, Error)] +pub enum ManifestError { + /// Package doesn't have a manifest file + #[error("cannot find a Nargo.toml in {}", .0.display())] + MissingFile(PathBuf), + + #[error("Cannot read file {0} - does it exist?")] + ReadFailed(PathBuf), + + #[error("Nargo.toml is missing a parent directory")] + MissingParent, + + #[error("Missing `type` field in {0}")] + MissingPackageType(PathBuf), + + #[error("Cannot use `{1}` for `type` field in {0}")] + InvalidPackageType(PathBuf, String), + + /// Package manifest is unreadable. + #[error("Nargo.toml is badly formed, could not parse.\n\n {0}")] + MalformedFile(#[from] toml::de::Error), + + #[error("Unxpected workspace definition found in {0}")] + UnexpectedWorkspace(PathBuf), + + #[error("Cannot find file {entry} which was specified as the `entry` field in {toml}")] + MissingEntryFile { toml: PathBuf, entry: PathBuf }, + + #[error( + r#"Cannot find file {entry} which is defaulted due to specifying `type = "{package_type}"` in {toml}"# + )] + MissingDefaultEntryFile { toml: PathBuf, entry: PathBuf, package_type: PackageType }, + + /// Invalid character `-` in package name + #[error("invalid character `-` in package name")] + InvalidPackageName, + + /// Encountered error while downloading git repository. + #[error("{0}")] + GitError(String), + + #[error("Selected package `{0}` was not found")] + MissingSelectedPackage(CrateName), + + #[error("Default package was not found. Does {0} exist in your workspace?")] + MissingDefaultPackage(PathBuf), + + #[error("Package `{0}` has type `bin` but you cannot depend on binary packages")] + BinaryDependency(CrateName), + + #[error("Missing `name` field in {toml}")] + MissingNameField { toml: PathBuf }, +} diff --git a/crates/nargo_cli/src/git.rs b/crates/nargo_toml/src/git.rs similarity index 88% rename from crates/nargo_cli/src/git.rs rename to crates/nargo_toml/src/git.rs index 850657a8af1..80e57247ae6 100644 --- a/crates/nargo_cli/src/git.rs +++ b/crates/nargo_toml/src/git.rs @@ -9,10 +9,14 @@ fn resolve_folder_name(base: &url::Url, tag: &str) -> String { folder_name } -pub(crate) fn git_dep_location(base: &url::Url, tag: &str) -> PathBuf { +fn nargo_crates() -> PathBuf { + dirs::home_dir().unwrap().join("nargo") +} + +fn git_dep_location(base: &url::Url, tag: &str) -> PathBuf { let folder_name = resolve_folder_name(base, tag); - super::nargo_crates().join(folder_name) + nargo_crates().join(folder_name) } /// XXX: I'd prefer to use a GitHub library however, there diff --git a/crates/nargo_cli/src/manifest.rs b/crates/nargo_toml/src/lib.rs similarity index 86% rename from crates/nargo_cli/src/manifest.rs rename to crates/nargo_toml/src/lib.rs index d55c0fbe0c0..4a9238ee021 100644 --- a/crates/nargo_cli/src/manifest.rs +++ b/crates/nargo_toml/src/lib.rs @@ -1,5 +1,6 @@ use std::{ collections::BTreeMap, + fs::ReadDir, path::{Path, PathBuf}, }; @@ -11,7 +12,55 @@ use nargo::{ use noirc_frontend::graph::CrateName; use serde::Deserialize; -use crate::{errors::ManifestError, git::clone_git_repo}; +mod errors; +mod git; + +pub use errors::ManifestError; +use git::clone_git_repo; + +/// Returns the path of the root directory of the package containing `current_path`. +/// +/// Returns a `CliError` if no parent directories of `current_path` contain a manifest file. +pub fn find_package_root(current_path: &Path) -> Result { + let manifest_path = find_package_manifest(current_path)?; + + let package_root = + manifest_path.parent().expect("infallible: manifest file path can't be root directory"); + + Ok(package_root.to_path_buf()) +} + +/// Returns the path of the manifest file (`Nargo.toml`) of the package containing `current_path`. +/// +/// Returns a `CliError` if no parent directories of `current_path` contain a manifest file. +pub fn find_package_manifest(current_path: &Path) -> Result { + current_path + .ancestors() + .find_map(|dir| find_file(dir, "Nargo", "toml")) + .ok_or_else(|| ManifestError::MissingFile(current_path.to_path_buf())) +} + +// Looks for file named `file_name` in path +fn find_file>(path: P, file_name: &str, extension: &str) -> Option { + let entries = list_files_and_folders_in(path)?; + let file_name = format!("{file_name}.{extension}"); + + find_artifact(entries, &file_name) +} + +// There is no distinction between files and folders +fn find_artifact(entries: ReadDir, artifact_name: &str) -> Option { + let entry = entries + .into_iter() + .flatten() + .find(|entry| entry.file_name().to_str() == Some(artifact_name))?; + + Some(entry.path()) +} + +fn list_files_and_folders_in>(path: P) -> Option { + std::fs::read_dir(path).ok() +} #[derive(Debug, Deserialize, Clone)] struct PackageConfig { @@ -277,7 +326,7 @@ fn resolve_package_from_toml(toml_path: &Path) -> Result } /// Resolves a Nargo.toml file into a `Workspace` struct as defined by our `nargo` core. -pub(crate) fn resolve_workspace_from_toml( +pub fn resolve_workspace_from_toml( toml_path: &Path, selected_package: Option, ) -> Result {