diff --git a/.gitignore b/.gitignore index 2c877a4d02c..5e155e2ecab 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,7 @@ tooling/noir_js/lib **/target !test_programs/acir_artifacts/*/target !test_programs/acir_artifacts/*/target/witness.gz +!test_programs/compile_success_empty/workspace_usually_gitignored/bin/Verifier.toml !compiler/wasm/noir-script/target gates_report.json diff --git a/test_programs/compile_failure/missing_nargo_toml/this_package_is_missing_a_Nargo.toml b/test_programs/compile_failure/missing_nargo_toml/this_package_is_missing_a_Nargo.toml new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test_programs/compile_success_empty/workspace_usually_gitignored/bin/Verifier.toml b/test_programs/compile_success_empty/workspace_usually_gitignored/bin/Verifier.toml new file mode 100644 index 00000000000..e228b8a4bf1 --- /dev/null +++ b/test_programs/compile_success_empty/workspace_usually_gitignored/bin/Verifier.toml @@ -0,0 +1 @@ +return = "" diff --git a/tooling/nargo_cli/Cargo.toml b/tooling/nargo_cli/Cargo.toml index c20be037e62..15d94735008 100644 --- a/tooling/nargo_cli/Cargo.toml +++ b/tooling/nargo_cli/Cargo.toml @@ -17,6 +17,7 @@ path = "src/main.rs" [build-dependencies] build-data.workspace = true +nargo_toml.workspace = true toml.workspace = true [dependencies] diff --git a/tooling/nargo_cli/build.rs b/tooling/nargo_cli/build.rs index 0ed2d4c07f7..1f478fbe3f8 100644 --- a/tooling/nargo_cli/build.rs +++ b/tooling/nargo_cli/build.rs @@ -3,6 +3,8 @@ use std::io::Write; use std::path::{Path, PathBuf}; use std::{env, fs}; +use nargo_toml::{find_package_root, ManifestError}; + const GIT_COMMIT: &&str = &"GIT_COMMIT"; fn main() { @@ -230,6 +232,11 @@ fn compile_success_empty_{test_name}() {{ panic!("`nargo info` failed with: {{}}", String::from_utf8(output.stderr).unwrap_or_default()); }} + // skip empty test packages + if std::str::from_utf8(&output.stdout).unwrap_or("").contains("cannot find any files visible to git at the following path") {{ + return () + }} + // `compile_success_empty` tests should be able to compile down to an empty circuit. let json: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap_or_else(|e| {{ panic!("JSON was not well-formatted {{:?}}\n\n{{:?}}", e, std::str::from_utf8(&output.stdout)) @@ -299,6 +306,16 @@ fn generate_compile_failure_tests(test_file: &mut File, test_data_dir: &Path) { }; let test_dir = &test_dir.path(); + match find_package_root(test_dir) { + Ok(_) => (), + Err(err) => { + // avoid testing when there are no files in the test_dir + return if matches!(err, ManifestError::InvisibleToGit(..)) { + continue; + }; + } + } + write!( test_file, r#" diff --git a/tooling/nargo_cli/src/cli/mod.rs b/tooling/nargo_cli/src/cli/mod.rs index ad778549ac0..2c1855b2c5f 100644 --- a/tooling/nargo_cli/src/cli/mod.rs +++ b/tooling/nargo_cli/src/cli/mod.rs @@ -1,6 +1,6 @@ use clap::{Args, Parser, Subcommand}; use const_format::formatcp; -use nargo_toml::find_package_root; +use nargo_toml::{find_package_root, ManifestError}; use noirc_driver::NOIR_ARTIFACT_VERSION_STRING; use std::path::PathBuf; @@ -100,7 +100,18 @@ pub(crate) fn start_cli() -> eyre::Result<()> { | NargoCommand::Backend(_) | NargoCommand::Dap(_) ) { - config.program_dir = find_package_root(&config.program_dir)?; + match find_package_root(&config.program_dir) { + Ok(program_dir) => config.program_dir = program_dir, + Err(err) => { + // avoid erroring when there are no files in the program_dir + return if matches!(err, ManifestError::InvisibleToGit(..)) { + println!("{}", err); + Ok(()) + } else { + Err(err.into()) + }; + } + } } let active_backend = get_active_backend(); diff --git a/tooling/nargo_toml/src/errors.rs b/tooling/nargo_toml/src/errors.rs index 77fe77bcdbb..8e0abf0a4c5 100644 --- a/tooling/nargo_toml/src/errors.rs +++ b/tooling/nargo_toml/src/errors.rs @@ -12,6 +12,10 @@ pub enum ManifestError { #[error("cannot find a Nargo.toml for {0}")] MissingFile(PathBuf), + /// Package doesn't contain any files that are visible to git + #[error("cannot find any files visible to git at the following path (skipping): {0}")] + InvisibleToGit(PathBuf), + #[error("Cannot read file {0} - does it exist?")] ReadFailed(PathBuf), diff --git a/tooling/nargo_toml/src/lib.rs b/tooling/nargo_toml/src/lib.rs index 985cb30dc24..d7c7f37b941 100644 --- a/tooling/nargo_toml/src/lib.rs +++ b/tooling/nargo_toml/src/lib.rs @@ -5,6 +5,7 @@ use std::{ collections::BTreeMap, + ffi::OsStr, path::{Component, Path, PathBuf}, }; @@ -92,7 +93,13 @@ pub fn find_package_manifest( } // Return the shallowest Nargo.toml, which will be the last in the list - found_toml_paths.pop().ok_or_else(|| ManifestError::MissingFile(current_path.to_path_buf())) + found_toml_paths.pop().ok_or_else(|| { + if is_package_visible_to_git(current_path) { + ManifestError::MissingFile(current_path.to_path_buf()) + } else { + ManifestError::InvisibleToGit(current_path.to_path_buf()) + } + }) } else { Err(ManifestError::NoCommonAncestor { root: root_path.to_path_buf(), @@ -100,6 +107,33 @@ pub fn find_package_manifest( }) } } + +/// Check whether the given path is visible to git. +/// A package can become invisible to git when its visible contents are deleted, +/// but its folders remain, as can happen from git merges. +fn is_package_visible_to_git(current_path: &Path) -> bool { + if current_path.is_file() { + // **/Verifier.toml + if current_path.file_name() != Some(OsStr::new("Verifier.toml")) { + return true; + } + } else { + // **/target + // !test_programs/acir_artifacts/*/target + if current_path.file_name() == Some(OsStr::new("target")) { + return current_path.to_str().unwrap_or("").contains("acir_artifacts"); + } + + for sub_path_entry in current_path.read_dir().expect("path to exist during compilation") { + let sub_path = sub_path_entry.expect("path to exist during compilation").path(); + if is_package_visible_to_git(&sub_path) { + return true; + } + } + } + false +} + /// Returns the [PathBuf] of the `Nargo.toml` file in the `current_path` directory. /// /// Returns a [ManifestError] if `current_path` does not contain a manifest file.