diff --git a/Cargo.lock b/Cargo.lock index f1b0a8c900..481e0e0188 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5163,6 +5163,9 @@ checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" [[package]] name = "infra_utils" version = "0.0.0" +dependencies = [ + "thiserror", +] [[package]] name = "inout" diff --git a/crates/infra_utils/Cargo.toml b/crates/infra_utils/Cargo.toml index 69c33687b6..ed18931577 100644 --- a/crates/infra_utils/Cargo.toml +++ b/crates/infra_utils/Cargo.toml @@ -8,3 +8,6 @@ description = "Infrastructure utility." [lints] workspace = true + +[dependencies] +thiserror.workspace = true diff --git a/crates/infra_utils/src/path.rs b/crates/infra_utils/src/path.rs index 423585c4ae..9f2ce3cd15 100644 --- a/crates/infra_utils/src/path.rs +++ b/crates/infra_utils/src/path.rs @@ -2,6 +2,18 @@ use std::env; use std::path::{Path, PathBuf}; use std::sync::LazyLock; +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum PathResolutionError { + // TODO(Arni): Handle manifest dir not exist here? + #[error("No file exists at '{path}'")] + PathDoesNotExist { path: PathBuf }, + #[error(transparent)] + IoError(#[from] std::io::Error), +} + +// TODO(tsabary): wrap path-related env::* invocations in the repo as utility functions static PATH_TO_CARGO_MANIFEST_DIR: LazyLock> = LazyLock::new(|| env::var("CARGO_MANIFEST_DIR").ok().map(|dir| Path::new(&dir).into())); @@ -17,8 +29,15 @@ pub fn cargo_manifest_dir() -> Option { /// /// # Returns /// * An absolute `PathBuf` representing the resolved path starting from the project root. -pub fn resolve_project_relative_path(relative_path: &str) -> PathBuf { - path_of_project_root().join(relative_path) +pub fn resolve_project_relative_path(relative_path: &str) -> Result { + let base_dir = path_of_project_root(); + + let path = base_dir.join(relative_path); + if !path.try_exists()? { + return Err(PathResolutionError::PathDoesNotExist { path }); + } + + Ok(path) } fn path_of_project_root() -> PathBuf { diff --git a/crates/mempool_test_utils/src/starknet_api_test_utils.rs b/crates/mempool_test_utils/src/starknet_api_test_utils.rs index b0bb48bd02..b41ade8a5b 100644 --- a/crates/mempool_test_utils/src/starknet_api_test_utils.rs +++ b/crates/mempool_test_utils/src/starknet_api_test_utils.rs @@ -67,7 +67,7 @@ pub fn test_valid_resource_bounds() -> ValidResourceBounds { /// Get the contract class used for testing. pub fn contract_class() -> ContractClass { - env::set_current_dir(resolve_project_relative_path(TEST_FILES_FOLDER)) + env::set_current_dir(resolve_project_relative_path(TEST_FILES_FOLDER).unwrap()) .expect("Couldn't set working dir."); let json_file_path = Path::new(CONTRACT_CLASS_FILE); serde_json::from_reader(File::open(json_file_path).unwrap()).unwrap() diff --git a/crates/papyrus_config/Cargo.toml b/crates/papyrus_config/Cargo.toml index 82829b655b..a8e385ec25 100644 --- a/crates/papyrus_config/Cargo.toml +++ b/crates/papyrus_config/Cargo.toml @@ -11,6 +11,7 @@ development = ["tempfile"] # Dependency of a doc-test [dependencies] clap = { workspace = true, features = ["env", "string"] } +infra_utils.workspace = true itertools.workspace = true serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true, features = ["arbitrary_precision"] } diff --git a/crates/papyrus_config/src/config_test.rs b/crates/papyrus_config/src/config_test.rs index 66cbd31bfa..cdcdcd8a51 100644 --- a/crates/papyrus_config/src/config_test.rs +++ b/crates/papyrus_config/src/config_test.rs @@ -52,7 +52,8 @@ use crate::{ lazy_static! { static ref CUSTOM_CONFIG_PATH: PathBuf = - resolve_project_relative_path("crates/papyrus_config/resources/custom_config_example.json"); + resolve_project_relative_path("crates/papyrus_config/resources/custom_config_example.json") + .unwrap(); } #[derive(Clone, Copy, Default, Serialize, Deserialize, Debug, PartialEq, Validate)] diff --git a/crates/papyrus_config/src/lib.rs b/crates/papyrus_config/src/lib.rs index 7a383cef54..77e4106f16 100644 --- a/crates/papyrus_config/src/lib.rs +++ b/crates/papyrus_config/src/lib.rs @@ -49,6 +49,7 @@ use clap::parser::MatchesError; use dumping::REQUIRED_PARAM_DESCRIPTION_PREFIX; +use infra_utils::path::PathResolutionError; use serde::{Deserialize, Serialize}; use serde_json::Value; use validator::ValidationError; @@ -179,6 +180,8 @@ pub enum ConfigError { #[error(transparent)] CommandMatches(#[from] MatchesError), #[error(transparent)] + GetPathError(#[from] PathResolutionError), + #[error(transparent)] IOError(#[from] std::io::Error), // TODO(Eitan): Improve error message #[error("Insert a new param is not allowed: {param_path}.")] diff --git a/crates/papyrus_node/src/config/config_test.rs b/crates/papyrus_node/src/config/config_test.rs index a10df5f641..fe7a025a5a 100644 --- a/crates/papyrus_node/src/config/config_test.rs +++ b/crates/papyrus_node/src/config/config_test.rs @@ -73,14 +73,16 @@ fn get_args(additional_args: Vec<&str>) -> Vec { #[test] fn load_default_config() { - env::set_current_dir(resolve_project_relative_path("")).expect("Couldn't set working dir."); + env::set_current_dir(resolve_project_relative_path("").unwrap()) + .expect("Couldn't set working dir."); NodeConfig::load_and_process(get_args(vec![])).expect("Failed to load the config."); } #[test] fn load_http_headers() { let args = get_args(vec!["--central.http_headers", "NAME_1:VALUE_1 NAME_2:VALUE_2"]); - env::set_current_dir(resolve_project_relative_path("")).expect("Couldn't set working dir."); + env::set_current_dir(resolve_project_relative_path("").unwrap()) + .expect("Couldn't set working dir."); let config = NodeConfig::load_and_process(args).unwrap(); let target_http_headers = HashMap::from([ ("NAME_1".to_string(), "VALUE_1".to_string()), @@ -96,7 +98,8 @@ fn load_http_headers() { // Regression test which checks that the default config dumping hasn't changed. fn test_dump_default_config() { let mut default_config = NodeConfig::default(); - env::set_current_dir(resolve_project_relative_path("")).expect("Couldn't set working dir."); + env::set_current_dir(resolve_project_relative_path("").unwrap()) + .expect("Couldn't set working dir."); let dumped_default_config = default_config.dump(); insta::assert_json_snapshot!(dumped_default_config); @@ -108,7 +111,8 @@ fn test_dump_default_config() { #[test] fn test_default_config_process() { - env::set_current_dir(resolve_project_relative_path("")).expect("Couldn't set working dir."); + env::set_current_dir(resolve_project_relative_path("").unwrap()) + .expect("Couldn't set working dir."); assert_eq!(NodeConfig::load_and_process(get_args(vec![])).unwrap(), NodeConfig::default()); } @@ -120,7 +124,8 @@ fn test_update_dumped_config_by_command() { "--storage.db_config.path_prefix", "/abc", ]); - env::set_current_dir(resolve_project_relative_path("")).expect("Couldn't set working dir."); + env::set_current_dir(resolve_project_relative_path("").unwrap()) + .expect("Couldn't set working dir."); let config = NodeConfig::load_and_process(args).unwrap(); assert_eq!(config.central.retry_config.retry_max_delay_millis, 1234); @@ -130,7 +135,8 @@ fn test_update_dumped_config_by_command() { #[cfg(feature = "rpc")] #[test] fn default_config_file_is_up_to_date() { - env::set_current_dir(resolve_project_relative_path("")).expect("Couldn't set working dir."); + env::set_current_dir(resolve_project_relative_path("").unwrap()) + .expect("Couldn't set working dir."); let from_default_config_file: serde_json::Value = serde_json::from_reader(File::open(DEFAULT_CONFIG_PATH).unwrap()).unwrap(); diff --git a/crates/starknet_sequencer_node/src/config/config_test.rs b/crates/starknet_sequencer_node/src/config/config_test.rs index e503d4e877..1975e0447a 100644 --- a/crates/starknet_sequencer_node/src/config/config_test.rs +++ b/crates/starknet_sequencer_node/src/config/config_test.rs @@ -63,7 +63,8 @@ fn test_valid_component_execution_config( /// cargo run --bin sequencer_dump_config -q #[test] fn test_default_config_file_is_up_to_date() { - env::set_current_dir(resolve_project_relative_path("")).expect("Couldn't set working dir."); + env::set_current_dir(resolve_project_relative_path("").unwrap()) + .expect("Couldn't set working dir."); let from_default_config_file: serde_json::Value = serde_json::from_reader(File::open(DEFAULT_CONFIG_PATH).unwrap()).unwrap(); @@ -115,7 +116,8 @@ fn test_config_parsing() { #[test] fn test_required_params_setting() { // Load the default config file. - let file = std::fs::File::open(resolve_project_relative_path(DEFAULT_CONFIG_PATH)).unwrap(); + let file = + std::fs::File::open(resolve_project_relative_path(DEFAULT_CONFIG_PATH).unwrap()).unwrap(); let mut deserialized = serde_json::from_reader::<_, serde_json::Value>(file).unwrap(); let expected_required_params = deserialized.as_object_mut().unwrap(); expected_required_params.retain(|_, value| { diff --git a/crates/starknet_sequencer_node/src/config/node_config.rs b/crates/starknet_sequencer_node/src/config/node_config.rs index 7c40131b3e..2679e234e7 100644 --- a/crates/starknet_sequencer_node/src/config/node_config.rs +++ b/crates/starknet_sequencer_node/src/config/node_config.rs @@ -157,7 +157,7 @@ impl SequencerNodeConfig { ) -> Result { let config_file_name = match config_file_name { Some(file_name) => Path::new(file_name), - None => &resolve_project_relative_path(DEFAULT_CONFIG_PATH), + None => &resolve_project_relative_path(DEFAULT_CONFIG_PATH)?, }; let default_config_file = File::open(config_file_name)?; diff --git a/crates/starknet_sierra_compile/src/compile_test.rs b/crates/starknet_sierra_compile/src/compile_test.rs index 5b685a2fb8..a5be78fb23 100644 --- a/crates/starknet_sierra_compile/src/compile_test.rs +++ b/crates/starknet_sierra_compile/src/compile_test.rs @@ -26,7 +26,7 @@ fn command_line_compiler() -> CommandLineCompiler { CommandLineCompiler::new(SIERRA_TO_CASM_COMPILATION_CONFIG) } fn get_test_contract() -> ContractClass { - env::set_current_dir(resolve_project_relative_path(TEST_FILES_FOLDER)) + env::set_current_dir(resolve_project_relative_path(TEST_FILES_FOLDER).unwrap()) .expect("Failed to set current dir."); let sierra_path = Path::new(FAULTY_ACCOUNT_CLASS_FILE); contract_class_from_file(sierra_path)