diff options
Diffstat (limited to 'crates')
29 files changed, 176 insertions, 168 deletions
diff --git a/crates/shirabe-class-map-generator/src/class_map.rs b/crates/shirabe-class-map-generator/src/class_map.rs index 10e7869..264fd35 100644 --- a/crates/shirabe-class-map-generator/src/class_map.rs +++ b/crates/shirabe-class-map-generator/src/class_map.rs @@ -2,7 +2,7 @@ use indexmap::IndexMap; use shirabe_external_packages::composer::pcre::Preg; -use shirabe_php_shim::{Countable, OutOfBoundsException, rtrim, strpos, strtr}; +use shirabe_php_shim::{OutOfBoundsException, rtrim, strpos, strtr}; #[derive(Debug, Clone)] pub struct PsrViolationEntry { @@ -137,9 +137,3 @@ impl ClassMap { &self.psr_violations } } - -impl Countable for ClassMap { - fn count(&self) -> i64 { - self.map.len() as i64 - } -} diff --git a/crates/shirabe-external-packages/src/symfony/finder/finder.rs b/crates/shirabe-external-packages/src/symfony/finder/finder.rs index 59a6ad1..a77a364 100644 --- a/crates/shirabe-external-packages/src/symfony/finder/finder.rs +++ b/crates/shirabe-external-packages/src/symfony/finder/finder.rs @@ -104,7 +104,6 @@ impl Finder { std::iter::empty() } - /// PHP: Finder implements Countable. pub fn len(&self) -> usize { todo!() } diff --git a/crates/shirabe-php-shim/src/lib.rs b/crates/shirabe-php-shim/src/lib.rs index 433b8db..f47e221 100644 --- a/crates/shirabe-php-shim/src/lib.rs +++ b/crates/shirabe-php-shim/src/lib.rs @@ -890,10 +890,6 @@ pub trait JsonSerializable { fn json_serialize(&self) -> PhpMixed; } -pub trait Countable { - fn count(&self) -> i64; -} - pub fn in_array(_needle: PhpMixed, _haystack: &PhpMixed, _strict: bool) -> bool { todo!() } @@ -959,6 +955,10 @@ pub fn touch2(_path: &str, _mtime: i64) -> bool { todo!() } +pub fn touch3(_path: &str, _mtime: i64, _atime: i64) -> bool { + todo!() +} + /// PHP `PHP_OS_FAMILY` constant: the family of the host OS. /// One of "Windows", "BSD", "Darwin", "Solaris", "Linux", "Unknown". pub fn php_os_family() -> &'static str { diff --git a/crates/shirabe/src/cache.rs b/crates/shirabe/src/cache.rs index 74e3c15..47665d0 100644 --- a/crates/shirabe/src/cache.rs +++ b/crates/shirabe/src/cache.rs @@ -4,12 +4,12 @@ use std::sync::Mutex; use anyhow::Result; use chrono::Utc; -use shirabe_external_packages::composer::pcre::Preg; +use shirabe_external_packages::composer::pcre::{CaptureKey, Preg}; use shirabe_external_packages::symfony::finder::Finder; use shirabe_php_shim::{ - abs, bin2hex, date_format_to_strftime, dirname, file_exists, file_get_contents, - file_put_contents, filemtime, hash_file, is_dir, is_writable, mkdir, random_bytes, random_int, - rename, time, unlink, + ErrorException, abs, bin2hex, clearstatcache, date_format_to_strftime, dirname, + disk_free_space, file_exists, file_get_contents, file_put_contents, filemtime, function_exists, + hash_file, is_dir, is_writable, mkdir, random_bytes, random_int, rename, time, unlink, }; use crate::io::IOInterface; @@ -129,18 +129,62 @@ impl Cache { .write_error(&format!("Writing {}{} into cache", self.root, file)); let temp_file_name = format!("{}{}{}.tmp", self.root, file, bin2hex(&random_bytes(5)),); - // TODO(phase-b): use anyhow::Result<Result<T, E>> to model PHP try/catch (ErrorException) - let attempt: Result<bool> = { - let put = file_put_contents(&temp_file_name, contents.as_bytes()); - Ok(put.is_some() - && put != Some(-1) - && rename(&temp_file_name, &format!("{}{}", self.root, file))) - }; + let dest = format!("{}{}", self.root, file); + let attempt = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { + file_put_contents(&temp_file_name, contents.as_bytes()).is_some() + && rename(&temp_file_name, &dest) + })); return match attempt { Ok(b) => Ok(b), - Err(e) => { - // TODO(phase-b): downcast e to ErrorException; handle partial write cleanup - Err(e) + Err(payload) => { + let e: ErrorException = match payload.downcast::<ErrorException>() { + Ok(boxed) => *boxed, + Err(payload) => std::panic::resume_unwind(payload), + }; + + // If the write failed despite isEnabled checks passing earlier, rerun the isEnabled checks to + // see if they are still current and recreate the cache dir if needed. Refs https://github.com/composer/composer/issues/11076 + if was_enabled { + clearstatcache(); + self.enabled = None; + + return self.write(&file, contents); + } + + self.io.write_error(&format!( + "<warning>Failed to write into cache: {}</warning>", + e.message, + )); + let mut m = indexmap::IndexMap::new(); + if Preg::match3( + r"{^file_put_contents\(\): Only ([0-9]+) of ([0-9]+) bytes written}", + &e.message, + Some(&mut m), + )? { + // Remove partial file. + unlink(&temp_file_name); + + let free_space = if function_exists("disk_free_space") { + disk_free_space(&dirname(&temp_file_name)) + .map(|space| space.to_string()) + .unwrap_or_default() + } else { + "unknown".to_string() + }; + let message = format!( + "<warning>Writing {} into cache failed after {} of {} bytes written, only {} bytes of free space available</warning>", + temp_file_name, + m.get(&CaptureKey::ByIndex(1)).cloned().unwrap_or_default(), + m.get(&CaptureKey::ByIndex(2)).cloned().unwrap_or_default(), + free_space, + ); + + self.io.write_error(&message); + + return Ok(false); + } + + Err(e.into()) } }; } @@ -185,21 +229,22 @@ impl Cache { .unwrap_or_default(); let full_path = format!("{}{}", self.root, file); if file_exists(&full_path) { - // TODO(phase-b): use anyhow::Result<Result<T, E>> to model PHP try/catch - let touch_result: Result<()> = { - shirabe_php_shim::touch( + let touch_result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { + shirabe_php_shim::touch3( &full_path, - // TODO(phase-b): PHP touch signature accepts (filename, mtime, atime) + filemtime(&full_path).unwrap_or(0), + time(), ); - Ok(()) - }; - if touch_result.is_err() { - // fallback in case the above failed due to incorrect ownership - // see https://github.com/composer/composer/issues/4070 - Silencer::call(|| { - shirabe_php_shim::touch(&full_path); - Ok(()) - })?; + })); + if let Err(payload) = touch_result { + match payload.downcast::<ErrorException>() { + Ok(_) => { + // fallback in case the above failed due to incorrect ownership + // see https://github.com/composer/composer/issues/4070 + Silencer::call(|| Ok(shirabe_php_shim::touch(&full_path)))?; + } + Err(payload) => std::panic::resume_unwind(payload), + } } self.io diff --git a/crates/shirabe/src/command/create_project_command.rs b/crates/shirabe/src/command/create_project_command.rs index f8fc511..c49d2fc 100644 --- a/crates/shirabe/src/command/create_project_command.rs +++ b/crates/shirabe/src/command/create_project_command.rs @@ -472,8 +472,7 @@ impl CreateProjectCommand { } } Err(e) => { - // TODO(phase-b): catch only PluginBlockedException - if let Some(_pbe) = e.downcast_ref::<PluginBlockedException>() { + if e.downcast_ref::<PluginBlockedException>().is_some() { io.write_error("<error>Hint: To allow running the config command recommended below before dependencies are installed, run create-project with --no-install.</error>"); io.write_error(&format!( "<error>You can then cd into {}, configure allow-plugins, and finally run a composer install to complete the process.</error>", diff --git a/crates/shirabe/src/command/self_update_command.rs b/crates/shirabe/src/command/self_update_command.rs index edc2db8..5948d34 100644 --- a/crates/shirabe/src/command/self_update_command.rs +++ b/crates/shirabe/src/command/self_update_command.rs @@ -26,6 +26,7 @@ use crate::config::Config; use crate::console::input::InputArgument; use crate::console::input::InputOption; use crate::downloader::FilesystemException; +use crate::downloader::TransportException; use crate::factory::Factory; use crate::io::IOInterface; use crate::io::IOInterfaceImmutable; @@ -435,15 +436,17 @@ impl SelfUpdateCommand { ) { Ok(r) => r.get_body().map(|s| s.to_string()), Err(e) => { - // TODO(phase-b): TransportException::get_status_code mapping from anyhow::Error - if false && e.to_string().contains("404") { + if e.downcast_ref::<TransportException>() + .and_then(|te| te.get_status_code()) + == Some(404) + { return Err(InvalidArgumentException { message: format!("Version \"{}\" could not be found.", update_version), code: 0, } .into()); } - return Err(e.into()); + return Err(e); } }; io.write_error3(" ", false, io_interface::NORMAL); diff --git a/crates/shirabe/src/dependency_resolver/pool.rs b/crates/shirabe/src/dependency_resolver/pool.rs index 06878e1..b12d760 100644 --- a/crates/shirabe/src/dependency_resolver/pool.rs +++ b/crates/shirabe/src/dependency_resolver/pool.rs @@ -3,7 +3,7 @@ use std::fmt; use indexmap::IndexMap; -use shirabe_php_shim::{Countable, STR_PAD_LEFT, abs, str_pad}; +use shirabe_php_shim::{STR_PAD_LEFT, abs, str_pad}; use shirabe_semver::compiling_matcher::CompilingMatcher; use shirabe_semver::constraint::AnyConstraint; use shirabe_semver::constraint::SimpleConstraint; @@ -381,13 +381,6 @@ impl Pool { } } -impl Countable for Pool { - /// Returns how many packages have been loaded into the pool - fn count(&self) -> i64 { - self.packages.len() as i64 - } -} - impl fmt::Display for Pool { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut str = String::from("Pool:\n"); diff --git a/crates/shirabe/src/dependency_resolver/solver.rs b/crates/shirabe/src/dependency_resolver/solver.rs index 28e1e7f..3d2113e 100644 --- a/crates/shirabe/src/dependency_resolver/solver.rs +++ b/crates/shirabe/src/dependency_resolver/solver.rs @@ -274,10 +274,10 @@ impl Solver { ); if self.problems.len() > 0 { - // TODO(phase-b): SolverProblemsException stores `Rc<RefCell<Rule>>` which is not + // TODO(phase-c): SolverProblemsException stores `Rc<RefCell<Rule>>` which is not // `Send + Sync`, so it cannot satisfy `anyhow::Error`'s bounds. Returning a - // placeholder error preserves control flow until the `Send + Sync` requirement - // is removed (single-threaded `Rc` model) or the exception type is reworked. + // placeholder error preserves control flow until the solver error path is reworked to + // a dedicated (non-anyhow) error type or the exception drops its dyn Rule payload. let _ = SolverProblemsException::new( std::mem::take(&mut self.problems), std::mem::take(&mut self.learned_pool), diff --git a/crates/shirabe/src/downloader/path_downloader.rs b/crates/shirabe/src/downloader/path_downloader.rs index d44bd8a..66f84b6 100644 --- a/crates/shirabe/src/downloader/path_downloader.rs +++ b/crates/shirabe/src/downloader/path_downloader.rs @@ -371,7 +371,6 @@ impl DownloaderInterface for PathDownloader { let mut is_fallback = false; if Self::STRATEGY_SYMLINK == current_strategy { - // TODO(phase-b): PHP catches IOException; shim symfony filesystem returns anyhow::Result. let symlink_result: Result<anyhow::Result<()>> = (|| { if Platform::is_windows() { diff --git a/crates/shirabe/src/installer.rs b/crates/shirabe/src/installer.rs index b770b48..1578fc1 100644 --- a/crates/shirabe/src/installer.rs +++ b/crates/shirabe/src/installer.rs @@ -353,7 +353,7 @@ impl Installer { .into(); let mut installed_repo = InstalledRepository::new(vec![ locked_repository_handle, - self.create_platform_repo(false).into(), + self.create_platform_repo(false)?.into(), crate::repository::RepositoryInterfaceHandle::new(RootPackageRepository::new( RootPackageInterfaceHandle::dup(&self.package), )), @@ -575,7 +575,7 @@ impl Installer { local_repo: crate::repository::RepositoryInterfaceHandle, do_install: bool, ) -> anyhow::Result<i64> { - let platform_repo = self.create_platform_repo(true); + let platform_repo = self.create_platform_repo(true)?; let aliases = self.get_root_aliases(true); let mut locked_repository: Option<crate::repository::LockArrayRepositoryHandle> = None; @@ -685,8 +685,9 @@ impl Installer { solver = None; } Err(e) => { - // TODO(phase-b): SolverProblemsException contains dyn Rule which isn't Send+Sync - // so anyhow::Error::downcast_ref can't extract it. Skipping detection. + // TODO(phase-c): SolverProblemsException contains dyn Rule which isn't Send+Sync + // so anyhow::Error::downcast_ref can't extract it. Skipping detection until the + // solver error path moves off anyhow (see solver.rs). let _ = (&repository_set, &request, &pool); return Err(e); } @@ -973,7 +974,7 @@ impl Installer { solver = None; } Err(e) => { - // TODO(phase-b): SolverProblemsException can't be downcast (dyn Rule not Send+Sync) + // TODO(phase-c): SolverProblemsException can't be downcast (dyn Rule not Send+Sync); see solver.rs let _ = (&repository_set, &request, &pool); return Err(e); } @@ -1020,7 +1021,7 @@ impl Installer { "<info>Verifying lock file contents can be installed on current platform.</info>", ); - let platform_repo = self.create_platform_repo(false); + let platform_repo = self.create_platform_repo(false)?; // creating repository set let policy = self.create_policy(false, None)?; // use aliases from lock file only, so empty root aliases here @@ -1127,7 +1128,7 @@ impl Installer { } } Err(e) => { - // TODO(phase-b): SolverProblemsException can't be downcast (dyn Rule not Send+Sync) + // TODO(phase-c): SolverProblemsException can't be downcast (dyn Rule not Send+Sync); see solver.rs let _ = (&repository_set, &request, &pool); return Err(e); } @@ -1258,7 +1259,10 @@ impl Installer { Ok(0) } - pub(crate) fn create_platform_repo(&mut self, for_update: bool) -> PlatformRepositoryHandle { + pub(crate) fn create_platform_repo( + &mut self, + for_update: bool, + ) -> anyhow::Result<PlatformRepositoryHandle> { let platform_overrides: IndexMap<String, PhpMixed> = if for_update { self.config .borrow_mut() @@ -1279,11 +1283,10 @@ impl Installer { .collect() }; - // TODO(phase-b): PlatformRepository::new returns Result, propagate - PlatformRepositoryHandle::new( - PlatformRepository::new(vec![], platform_overrides) - .expect("PlatformRepository::new should not fail"), - ) + Ok(PlatformRepositoryHandle::new(PlatformRepository::new( + vec![], + platform_overrides, + )?)) } fn create_repository_set( diff --git a/crates/shirabe/src/json/json_file.rs b/crates/shirabe/src/json/json_file.rs index a185084..cf92a77 100644 --- a/crates/shirabe/src/json/json_file.rs +++ b/crates/shirabe/src/json/json_file.rs @@ -404,9 +404,9 @@ impl JsonFile { validator.check(&data_converted, &schema_data)?; if !validator.is_valid() { - // TODO(phase-b): Validator::get_errors currently returns Vec<String>; original PHP - // exposes [{property, message}, ...]. Until shim is enriched, surface raw error - // strings without prop/message splitting. + // TODO(phase-c): Validator::get_errors currently returns Vec<String>; original PHP + // exposes [{property, message}, ...]. Until the validator shim is enriched, surface raw + // error strings without prop/message splitting. let errors: Vec<String> = validator.get_errors(); return Err(JsonValidationException::new( format!("\"{}\" does not match the expected JSON schema", source), @@ -431,8 +431,9 @@ impl JsonFile { let json = match json { Some(j) => j, None => { - // PHP: self::throwEncodeError(json_last_error()); - // TODO(phase-b): throw an error; downstream callers expect a String + // PHP: self::throwEncodeError(json_last_error()), which throws \RuntimeException. + // TODO(phase-c): faithfully propagating this requires encode/encode_with_options to + // return Result<String>, a signature change rippling across ~53 call sites. Self::throw_encode_error(json_last_error()).unwrap_or_default(); String::new() } diff --git a/crates/shirabe/src/package/locker.rs b/crates/shirabe/src/package/locker.rs index 2546780..ed53143 100644 --- a/crates/shirabe/src/package/locker.rs +++ b/crates/shirabe/src/package/locker.rs @@ -606,7 +606,6 @@ impl Locker { let is_locked = match self.is_locked_result() { Ok(b) => b, Err(e) => { - // TODO(phase-b): catch only ParsingException if e.downcast_ref::<ParsingException>().is_some() { false } else { diff --git a/crates/shirabe/src/repository/array_repository.rs b/crates/shirabe/src/repository/array_repository.rs index 1eeb428..df25235 100644 --- a/crates/shirabe/src/repository/array_repository.rs +++ b/crates/shirabe/src/repository/array_repository.rs @@ -7,7 +7,7 @@ use std::rc::Weak; use anyhow::Result; use indexmap::IndexMap; use shirabe_external_packages::composer::pcre::Preg; -use shirabe_php_shim::{Countable, LogicException, implode, preg_quote, strtolower}; +use shirabe_php_shim::{implode, preg_quote, strtolower}; use shirabe_semver::constraint::AnyConstraint; use shirabe_semver::constraint::SimpleConstraint; @@ -39,19 +39,10 @@ impl ArrayRepository { if self.packages.borrow().is_none() { self.initialize(); } - - if self.packages.borrow().is_none() { - // TODO(phase-b): propagate the error. - // PHP: throw new \LogicException('initialize failed to initialize the packages array') - panic!( - "{}", - LogicException { - message: "initialize failed to initialize the packages array".to_string(), - code: 0, - } - .message - ); - } + assert!( + self.packages.borrow().is_some(), + "initialize failed to initialize the packages array" + ); self.packages .borrow() @@ -155,25 +146,22 @@ impl ArrayRepository { } } -impl Countable for ArrayRepository { +impl RepositoryInterface for ArrayRepository { /// Returns the number of packages in this repository - /// - /// @return 0|positive-int Number of packages - fn count(&self) -> i64 { + fn count(&self) -> anyhow::Result<usize> { if self.packages.borrow().is_none() { self.initialize(); } - self.packages.borrow().as_ref().unwrap().len() as i64 + Ok(self.packages.borrow().as_ref().unwrap().len()) } -} -impl RepositoryInterface for ArrayRepository { fn get_repo_name(&self) -> String { + let count = self.count().expect("ArrayRepository::count is infallible"); format!( "array repo (defining {} package{})", - self.count(), - if self.count() > 1 { "s" } else { "" }, + count, + if count > 1 { "s" } else { "" }, ) } diff --git a/crates/shirabe/src/repository/composer_repository.rs b/crates/shirabe/src/repository/composer_repository.rs index f634e23..f07eb73 100644 --- a/crates/shirabe/src/repository/composer_repository.rs +++ b/crates/shirabe/src/repository/composer_repository.rs @@ -4,7 +4,7 @@ use indexmap::IndexMap; use shirabe_external_packages::composer::metadata_minifier::MetadataMinifier; use shirabe_external_packages::composer::pcre::{CaptureKey, Preg}; use shirabe_php_shim::{ - Countable, InvalidArgumentException, LogicException, PHP_EOL, PhpMixed, RuntimeException, + InvalidArgumentException, LogicException, PHP_EOL, PhpMixed, RuntimeException, UnexpectedValueException, extension_loaded, hash, http_build_query, in_array, json_decode, parse_url_all, realpath, strtolower, strtr, urlencode, var_export, }; @@ -1212,7 +1212,7 @@ impl ComposerRepository { } } - if Countable::count(&self.inner) > 0 { + if self.inner.count()? > 0 { for (k, v) in self.inner.get_providers(package_name.to_string())? { let mut entry: IndexMap<String, PhpMixed> = IndexMap::new(); entry.insert("name".to_string(), PhpMixed::String(v.name)); @@ -3401,13 +3401,11 @@ fn clone_root_data(rd: &RootData) -> RootData { } } -impl shirabe_php_shim::Countable for ComposerRepository { - fn count(&self) -> i64 { +impl RepositoryInterface for ComposerRepository { + fn count(&self) -> anyhow::Result<usize> { self.inner.count() } -} -impl RepositoryInterface for ComposerRepository { fn has_package(&self, package: PackageInterfaceHandle) -> bool { self.inner.has_package(package) } diff --git a/crates/shirabe/src/repository/composite_repository.rs b/crates/shirabe/src/repository/composite_repository.rs index 97fad44..dafedfc 100644 --- a/crates/shirabe/src/repository/composite_repository.rs +++ b/crates/shirabe/src/repository/composite_repository.rs @@ -62,13 +62,16 @@ impl CompositeRepository { } } -impl shirabe_php_shim::Countable for CompositeRepository { - fn count(&self) -> i64 { - self.repositories.iter().map(|r| r.count()).sum() +impl RepositoryInterface for CompositeRepository { + fn count(&self) -> anyhow::Result<usize> { + let mut total = 0; + for repository in &self.repositories { + total += repository.count()?; + } + + Ok(total) } -} -impl RepositoryInterface for CompositeRepository { fn get_repo_name(&self) -> String { let names: Vec<String> = self .repositories diff --git a/crates/shirabe/src/repository/filter_repository.rs b/crates/shirabe/src/repository/filter_repository.rs index a49382a..0e05c25 100644 --- a/crates/shirabe/src/repository/filter_repository.rs +++ b/crates/shirabe/src/repository/filter_repository.rs @@ -148,26 +148,20 @@ impl FilterRepository { } } -impl shirabe_php_shim::Countable for FilterRepository { - fn count(&self) -> i64 { - if self.repo.count() > 0 { - // TODO(phase-b): propagate the error - // self.get_packages()?.len() as i64 - self.repo - .get_packages() - .map(|pkgs| { - pkgs.iter() - .filter(|p| self.is_allowed(&p.get_name())) - .count() as i64 - }) - .unwrap_or(0) +impl RepositoryInterface for FilterRepository { + fn count(&self) -> anyhow::Result<usize> { + if self.repo.count()? > 0 { + Ok(self + .repo + .get_packages()? + .iter() + .filter(|p| self.is_allowed(&p.get_name())) + .count()) } else { - 0 + Ok(0) } } -} -impl RepositoryInterface for FilterRepository { fn has_package(&self, package: PackageInterfaceHandle) -> bool { self.repo.has_package(package) } diff --git a/crates/shirabe/src/repository/handle.rs b/crates/shirabe/src/repository/handle.rs index aa79d5e..6721bb2 100644 --- a/crates/shirabe/src/repository/handle.rs +++ b/crates/shirabe/src/repository/handle.rs @@ -4,7 +4,6 @@ use std::cell::{Ref, RefCell, RefMut}; use std::rc::{Rc, Weak}; use indexmap::IndexMap; -use shirabe_php_shim::Countable; use shirabe_semver::constraint::AnyConstraint; use crate::package::BasePackageHandle; @@ -84,7 +83,7 @@ impl RepositoryInterfaceHandle { .map(PlatformRepositoryHandle::from_rc) } - pub fn count(&self) -> i64 { + pub fn count(&self) -> anyhow::Result<usize> { self.0.borrow().count() } diff --git a/crates/shirabe/src/repository/installed_array_repository.rs b/crates/shirabe/src/repository/installed_array_repository.rs index 64098e9..487a6da 100644 --- a/crates/shirabe/src/repository/installed_array_repository.rs +++ b/crates/shirabe/src/repository/installed_array_repository.rs @@ -1,7 +1,6 @@ //! ref: composer/src/Composer/Repository/InstalledArrayRepository.php use indexmap::IndexMap; -use shirabe_php_shim::Countable; use shirabe_semver::constraint::AnyConstraint; use crate::package::BasePackageHandle; @@ -41,7 +40,10 @@ impl InstalledRepositoryInterface for InstalledArrayRepository { } fn is_fresh(&self) -> bool { - self.inner.count() == 0 + self.inner + .count() + .expect("WritableArrayRepository::count is infallible") + == 0 } } @@ -87,13 +89,11 @@ impl WritableRepositoryInterface for InstalledArrayRepository { } } -impl Countable for InstalledArrayRepository { - fn count(&self) -> i64 { +impl RepositoryInterface for InstalledArrayRepository { + fn count(&self) -> anyhow::Result<usize> { todo!() } -} -impl RepositoryInterface for InstalledArrayRepository { fn has_package(&self, _package: PackageInterfaceHandle) -> bool { todo!() } diff --git a/crates/shirabe/src/repository/installed_filesystem_repository.rs b/crates/shirabe/src/repository/installed_filesystem_repository.rs index 1f6be2c..185749e 100644 --- a/crates/shirabe/src/repository/installed_filesystem_repository.rs +++ b/crates/shirabe/src/repository/installed_filesystem_repository.rs @@ -2,7 +2,6 @@ use anyhow::Result; use indexmap::IndexMap; -use shirabe_php_shim::Countable; use shirabe_semver::constraint::AnyConstraint; use crate::json::JsonFile; @@ -97,13 +96,11 @@ impl WritableRepositoryInterface for InstalledFilesystemRepository { } } -impl Countable for InstalledFilesystemRepository { - fn count(&self) -> i64 { +impl RepositoryInterface for InstalledFilesystemRepository { + fn count(&self) -> anyhow::Result<usize> { todo!() } -} -impl RepositoryInterface for InstalledFilesystemRepository { fn has_package(&self, _package: PackageInterfaceHandle) -> bool { todo!() } diff --git a/crates/shirabe/src/repository/installed_repository.rs b/crates/shirabe/src/repository/installed_repository.rs index 8b611ae..f6b9643 100644 --- a/crates/shirabe/src/repository/installed_repository.rs +++ b/crates/shirabe/src/repository/installed_repository.rs @@ -381,13 +381,11 @@ impl InstalledRepository { } } -impl shirabe_php_shim::Countable for InstalledRepository { - fn count(&self) -> i64 { +impl RepositoryInterface for InstalledRepository { + fn count(&self) -> anyhow::Result<usize> { self.inner.count() } -} -impl RepositoryInterface for InstalledRepository { fn get_repo_name(&self) -> String { let names: Vec<String> = self .inner diff --git a/crates/shirabe/src/repository/lock_array_repository.rs b/crates/shirabe/src/repository/lock_array_repository.rs index 250ca90..390fae3 100644 --- a/crates/shirabe/src/repository/lock_array_repository.rs +++ b/crates/shirabe/src/repository/lock_array_repository.rs @@ -9,7 +9,6 @@ use crate::repository::{ RepositoryInterfaceWeakHandle, SearchResult, }; use indexmap::IndexMap; -use shirabe_php_shim::Countable; use shirabe_semver::constraint::AnyConstraint; #[derive(Debug)] @@ -31,13 +30,11 @@ impl LockArrayRepository { } } -impl Countable for LockArrayRepository { - fn count(&self) -> i64 { +impl RepositoryInterface for LockArrayRepository { + fn count(&self) -> anyhow::Result<usize> { self.inner.count() } -} -impl RepositoryInterface for LockArrayRepository { fn has_package(&self, package: PackageInterfaceHandle) -> bool { self.inner.has_package(package) } diff --git a/crates/shirabe/src/repository/platform_repository.rs b/crates/shirabe/src/repository/platform_repository.rs index a35874d..1dec137 100644 --- a/crates/shirabe/src/repository/platform_repository.rs +++ b/crates/shirabe/src/repository/platform_repository.rs @@ -1939,13 +1939,11 @@ impl PlatformRepository { } } -impl shirabe_php_shim::Countable for PlatformRepository { - fn count(&self) -> i64 { +impl crate::repository::RepositoryInterface for PlatformRepository { + fn count(&self) -> anyhow::Result<usize> { self.inner.count() } -} -impl crate::repository::RepositoryInterface for PlatformRepository { fn has_package(&self, package: PackageInterfaceHandle) -> bool { self.inner.has_package(package) } diff --git a/crates/shirabe/src/repository/repository_interface.rs b/crates/shirabe/src/repository/repository_interface.rs index e3a5548..6dbc01d 100644 --- a/crates/shirabe/src/repository/repository_interface.rs +++ b/crates/shirabe/src/repository/repository_interface.rs @@ -4,7 +4,6 @@ use crate::package::BasePackageHandle; use crate::package::PackageInterfaceHandle; use crate::repository::AdvisoryProviderInterface; use indexmap::IndexMap; -use shirabe_php_shim::Countable; use shirabe_semver::constraint::AnyConstraint; pub enum FindPackageConstraint { @@ -52,7 +51,9 @@ pub const SEARCH_FULLTEXT: i64 = 0; pub const SEARCH_NAME: i64 = 1; pub const SEARCH_VENDOR: i64 = 2; -pub trait RepositoryInterface: Countable + std::fmt::Debug { +pub trait RepositoryInterface: std::fmt::Debug { + fn count(&self) -> anyhow::Result<usize>; + fn has_package(&self, package: PackageInterfaceHandle) -> bool; fn find_package( diff --git a/crates/shirabe/src/repository/root_package_repository.rs b/crates/shirabe/src/repository/root_package_repository.rs index 985f86e..4357ed6 100644 --- a/crates/shirabe/src/repository/root_package_repository.rs +++ b/crates/shirabe/src/repository/root_package_repository.rs @@ -25,13 +25,11 @@ impl RootPackageRepository { } } -impl shirabe_php_shim::Countable for RootPackageRepository { - fn count(&self) -> i64 { +impl RepositoryInterface for RootPackageRepository { + fn count(&self) -> anyhow::Result<usize> { self.inner.count() } -} -impl RepositoryInterface for RootPackageRepository { fn has_package(&self, package: PackageInterfaceHandle) -> bool { self.inner.has_package(package) } diff --git a/crates/shirabe/src/repository/vcs/git_bitbucket_driver.rs b/crates/shirabe/src/repository/vcs/git_bitbucket_driver.rs index de1f814..7eb253a 100644 --- a/crates/shirabe/src/repository/vcs/git_bitbucket_driver.rs +++ b/crates/shirabe/src/repository/vcs/git_bitbucket_driver.rs @@ -707,7 +707,6 @@ impl GitBitbucketDriver { match self.inner.get_contents(url) { Ok(r) => Ok(r), Err(e) => { - // TODO(phase-b): only handle TransportException let mut bitbucket_util = Bitbucket::new( self.inner.io.clone(), self.inner.config.clone(), @@ -772,7 +771,9 @@ impl GitBitbucketDriver { match self.setup_fallback_driver(&self.generate_ssh_url()) { Ok(()) => Ok(true), Err(e) => { - // TODO(phase-b): only catch RuntimeException + // TODO(phase-c): PHP catches \RuntimeException (and all its subclasses), letting + // other exceptions propagate without this cleanup. Modeling that precisely needs the + // PHP exception hierarchy, which is intentionally not reproduced (see CLAUDE.md). self.fallback_driver = None; self.inner.io.write_error(&format!( diff --git a/crates/shirabe/src/repository/vcs/vcs_driver.rs b/crates/shirabe/src/repository/vcs/vcs_driver.rs index dc88387..1c05933 100644 --- a/crates/shirabe/src/repository/vcs/vcs_driver.rs +++ b/crates/shirabe/src/repository/vcs/vcs_driver.rs @@ -78,11 +78,13 @@ impl VcsDriverBase { PhpMixed::Array(a) => a.into_iter().map(|(k, v)| (k, *v)).collect(), _ => IndexMap::new(), }; - // TODO(phase-b): map anyhow::Error from HttpDownloader::get into TransportException. self.http_downloader .borrow_mut() .get(url, options) - .map_err(|e| TransportException::new(e.to_string(), 0)) + .map_err(|e| match e.downcast::<TransportException>() { + Ok(te) => te, + Err(other) => TransportException::new(other.to_string(), 0), + }) } // Helper for concrete drivers: produces the same value as the trait default @@ -319,11 +321,13 @@ pub trait VcsDriver: VcsDriverInterface { PhpMixed::Array(a) => a.into_iter().map(|(k, v)| (k, *v)).collect(), _ => IndexMap::new(), }; - // TODO(phase-b): map anyhow::Error from HttpDownloader::get into TransportException. self.http_downloader() .borrow_mut() .get(url, options) - .map_err(|e| TransportException::new(e.to_string(), 0)) + .map_err(|e| match e.downcast::<TransportException>() { + Ok(te) => te, + Err(other) => TransportException::new(other.to_string(), 0), + }) } fn cleanup(&self) {} diff --git a/crates/shirabe/src/repository/vcs_repository.rs b/crates/shirabe/src/repository/vcs_repository.rs index 7817172..ef58fe2 100644 --- a/crates/shirabe/src/repository/vcs_repository.rs +++ b/crates/shirabe/src/repository/vcs_repository.rs @@ -315,7 +315,6 @@ impl VcsRepository { } Ok(None) => {} Err(e) => { - // TODO(phase-b): unify exception handling below if let Some(te) = e.downcast_ref::<TransportException>() { if self.should_rethrow_transport_exception(te) { return Err(e); diff --git a/crates/shirabe/src/repository/writable_array_repository.rs b/crates/shirabe/src/repository/writable_array_repository.rs index 1c07b8c..bf9d094 100644 --- a/crates/shirabe/src/repository/writable_array_repository.rs +++ b/crates/shirabe/src/repository/writable_array_repository.rs @@ -5,7 +5,6 @@ use crate::repository::ArrayRepository; use crate::repository::RepositoryInterface; use crate::repository::RepositoryInterfaceWeakHandle; use anyhow::Result; -use shirabe_php_shim::Countable; #[derive(Debug)] pub struct WritableArrayRepository { @@ -84,7 +83,7 @@ impl WritableArrayRepository { self.inner.get_repo_name() } - pub fn count(&self) -> i64 { - Countable::count(&self.inner) + pub fn count(&self) -> anyhow::Result<usize> { + self.inner.count() } } diff --git a/crates/shirabe/src/util/process_executor.rs b/crates/shirabe/src/util/process_executor.rs index 40a212b..b62debe 100644 --- a/crates/shirabe/src/util/process_executor.rs +++ b/crates/shirabe/src/util/process_executor.rs @@ -305,7 +305,6 @@ impl ProcessExecutor { let final_result: Result<()> = match result { Ok(()) => Ok(()), Err(e) => { - // TODO(phase-b): catch ProcessSignaledException if let Some(pse) = e.downcast_ref::<ProcessSignaledException>() { if signal_handler.is_triggered() { // exiting as we were signaled and the child process exited too due to the signal |
