diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-08-08 22:14:12 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-08-08 22:14:12 +0900 |
| commit | f4cad2123b2af0de72bda4ce039e16e74f163f4e (patch) | |
| tree | 21803308c5ff41e23c9d3b117433eea16b4ff663 /crates/shirabe/src/util/remote_filesystem.rs | |
| parent | 0209f63210e5b547b5c6b73367bb80ea86c255ec (diff) | |
| download | php-shirabe-f4cad2123b2af0de72bda4ce039e16e74f163f4e.tar.gz php-shirabe-f4cad2123b2af0de72bda4ce039e16e74f163f4e.tar.zst php-shirabe-f4cad2123b2af0de72bda4ce039e16e74f163f4e.zip | |
feat(php-shim): give ported exceptions PHP's class hierarchy
Ported exceptions were flat structs reached with `downcast_ref`, so
Composer's `catch (\RuntimeException $e)` only matched the exact leaf
type and `get_class($e)` had nothing to report. Each exception now
embeds an instance of the class it extends and travels inside an
`AnyThrowable`; `Catch::catch`/`catch_mut` walk that chain, and
`PhpClass::php_class_name` yields the PHP FQCN.
Dropping the `std::error::Error` impls from the exception types leaves
`AnyThrowable` as the only route into an `anyhow::Error`, so the walk
cannot be bypassed. A `no_exception_downcast` linter catches the
`downcast::<X>()` calls that would now silently answer `None`.
Three sites change behavior as a result: the `TransportException`
exit-code override reaches `MaxFileSizeExceededException`, the
`catch (\LogicException)` in findSimilar() reaches its subclasses, and
rendered exception titles carry the real class name rather than a
guess. `get_class_err()` is no longer a `todo!()`, which re-enables
FilesystemRepositoryTest::testCorruptedRepositoryFile.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe/src/util/remote_filesystem.rs')
| -rw-r--r-- | crates/shirabe/src/util/remote_filesystem.rs | 48 |
1 files changed, 25 insertions, 23 deletions
diff --git a/crates/shirabe/src/util/remote_filesystem.rs b/crates/shirabe/src/util/remote_filesystem.rs index 2dafc0d3..e2901b2c 100644 --- a/crates/shirabe/src/util/remote_filesystem.rs +++ b/crates/shirabe/src/util/remote_filesystem.rs @@ -14,6 +14,7 @@ use crate::util::http::ProxyManager; use crate::util::http::Response; use indexmap::IndexMap; use shirabe_external_packages::composer::pcre::{CaptureKey, Preg}; +use shirabe_php_shim::Catch as _; use shirabe_php_shim::{ PHP_URL_HOST, PHP_URL_PATH, PHP_URL_SCHEME, PHP_VERSION_ID, PhpMixed, RuntimeException, STREAM_NOTIFY_FAILURE, STREAM_NOTIFY_FILE_SIZE_IS, STREAM_NOTIFY_PROGRESS, @@ -216,12 +217,11 @@ impl RemoteFilesystem { let mut file_url = file_url.to_string(); if options.contains_key("prevent_ip_access_callable") { - return Err(anyhow::anyhow!(RuntimeException { - message: - "RemoteFilesystem doesn't support the 'prevent_ip_access_callable' config." - .to_string(), - code: 0, - })); + return Err(RuntimeException::new( + "RemoteFilesystem doesn't support the 'prevent_ip_access_callable' config." + .to_string(), + ) + .into()); } if let Some(token) = options.get("gitlab-token").cloned() { @@ -404,7 +404,7 @@ impl RemoteFilesystem { })(); let mut caught_e: Option<anyhow::Error> = None; if let Err(mut e) = inner_result { - if let Some(te) = e.downcast_mut::<TransportException>() { + if let Some(te) = e.catch_mut::<TransportException>() { if !http_response_header.is_empty() && !http_response_header[0].is_empty() { te.set_headers(http_response_header.clone()); te.set_status_code(Self::find_status_code(&http_response_header)); @@ -535,7 +535,7 @@ impl RemoteFilesystem { ); } - let mut e = TransportException::new_with_code( + let mut e = TransportException::new( format!( "The \"{}\" file could not be downloaded ({})", self.file_url, http_response_header[0] @@ -607,13 +607,14 @@ impl RemoteFilesystem { if result.is_some() && file_name.is_some() && !is_redirect { let result_str = result.as_deref().unwrap(); if result_str.is_empty() { - return Err(anyhow::anyhow!(TransportException::new( + return Err(TransportException::new( format!( "\"{}\" appears broken, and returned an empty 200 response", self.file_url ), 0, - ))); + ) + .into()); } // TODO(phase-c): PHP captures the file_put_contents warning here via set_error_handler @@ -623,7 +624,7 @@ impl RemoteFilesystem { let write_result = file_put_contents(file_name.as_deref().unwrap(), result_str.as_bytes()); if write_result.is_none() { - return Err(anyhow::anyhow!(TransportException::new( + return Err(TransportException::new( format!( "The \"{}\" file could not be written to {}: {}", self.file_url, @@ -631,7 +632,8 @@ impl RemoteFilesystem { put_error_message ), 0, - ))); + ) + .into()); } let _ = put_error_message; } @@ -659,7 +661,7 @@ impl RemoteFilesystem { } if result.is_none() { - let mut e = TransportException::new_with_code( + let mut e = TransportException::new( format!( "The \"{}\" file could not be downloaded: {}", self.file_url, error_message @@ -750,11 +752,12 @@ impl RemoteFilesystem { && let Some(max) = max_file_size && Platform::strlen(r) >= max { - return Err(anyhow::anyhow!(MaxFileSizeExceededException::new(format!( + return Err(MaxFileSizeExceededException::new(format!( "Maximum allowed download size reached. Downloaded {} of allowed {} bytes", Platform::strlen(r), max - )))); + )) + .into()); } if PHP_VERSION_ID >= 80400 { @@ -785,14 +788,15 @@ impl RemoteFilesystem { match notification_code { x if x == STREAM_NOTIFY_FAILURE => { if 400 == message_code { - return Err(anyhow::anyhow!(TransportException::new_with_code( + return Err(TransportException::new( format!( "The '{}' URL could not be accessed: {}", self.file_url, message.unwrap_or_default() ), message_code, - ))); + ) + .into()); } } x if x == STREAM_NOTIFY_FILE_SIZE_IS => { @@ -848,10 +852,7 @@ impl RemoteFilesystem { self.retry = result.retry; if self.retry { - return Err(anyhow::anyhow!(TransportException::new( - "RETRY".to_string(), - 0, - ))); + return Err(TransportException::new("RETRY".to_string(), 0).into()); } Ok(()) } @@ -1043,10 +1044,11 @@ impl RemoteFilesystem { // RemoteFilesystem as a String; from_utf8_lossy can corrupt binary payloads Some(d) => Some(String::from_utf8_lossy(&d).into_owned()), None => { - return Err(anyhow::anyhow!(TransportException::new( + return Err(TransportException::new( "Failed to decode zlib stream".to_string(), 0, - ))); + ) + .into()); } }; } |
