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/command/diagnose_command.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/command/diagnose_command.rs')
| -rw-r--r-- | crates/shirabe/src/command/diagnose_command.rs | 74 |
1 files changed, 42 insertions, 32 deletions
diff --git a/crates/shirabe/src/command/diagnose_command.rs b/crates/shirabe/src/command/diagnose_command.rs index 72b58dea..857e517d 100644 --- a/crates/shirabe/src/command/diagnose_command.rs +++ b/crates/shirabe/src/command/diagnose_command.rs @@ -38,11 +38,12 @@ use shirabe_external_packages::symfony::console::command::command::Command; use shirabe_external_packages::symfony::console::input::InputInterface; use shirabe_external_packages::symfony::console::output::OutputInterface; use shirabe_external_packages::symfony::process::ExecutableFinder; +use shirabe_php_shim::Catch as _; use shirabe_php_shim::{ - CmpOp, InvalidArgumentException, PHP_EOL, PhpMixed, disk_free_space, file_exists, - filter_var_boolean, get_class_err, hash, impl_php_class, implode, is_array, is_string, - php_regex, rtrim, str_contains, str_replace, str_starts_with, strpos, strstr, strstr3, - strtolower, trim, version_compare, + AnyThrowable, CmpOp, InvalidArgumentException, PHP_EOL, PhpClass as _, PhpMixed, + disk_free_space, file_exists, filter_var_boolean, hash, impl_php_class, implode, is_array, + is_string, php_regex, rtrim, str_contains, str_replace, str_starts_with, strpos, strstr, + strstr3, strtolower, trim, version_compare, }; #[derive(Debug)] @@ -106,7 +107,7 @@ impl DiagnoseCommand { match json.validate_schema(JsonFile::LOCK_SCHEMA, None) { Ok(_) => {} Err(e) => { - if let Some(jve) = e.downcast_ref::<JsonValidationException>() { + if let Some(jve) = e.catch::<JsonValidationException>() { let mut output = String::new(); for error in jve.get_errors() { output.push_str(&format!("<error>{}</error>{}", error, PHP_EOL)); @@ -191,7 +192,7 @@ impl DiagnoseCommand { ) { Ok(_) => {} Err(e) => { - if let Some(te) = e.downcast_ref::<TransportException>() { + if let Some(te) = e.catch::<TransportException>() { let hints = HttpDownloader::get_exception_hints(&e).unwrap_or_default(); if !hints.is_empty() { for hint in hints { @@ -202,7 +203,7 @@ impl DiagnoseCommand { result_list.push(PhpMixed::String(format!( "<error>[{}] {}</error>", std::any::type_name_of_val(te), - te.message + te.get_message() ))); } else { return Err(e); @@ -249,7 +250,7 @@ impl DiagnoseCommand { { Ok(_) => {} Err(e) => { - if let Some(te) = e.downcast_ref::<TransportException>() { + if let Some(te) = e.catch::<TransportException>() { let hints = HttpDownloader::get_exception_hints(&e).unwrap_or_default(); if !hints.is_empty() { for hint in hints { @@ -260,7 +261,7 @@ impl DiagnoseCommand { result_list.push(PhpMixed::String(format!( "<error>[{}] {}</error>", std::any::type_name_of_val(te), - te.message + te.get_message() ))); } else { return Err(e); @@ -394,7 +395,7 @@ impl DiagnoseCommand { ))) } Err(e) => { - if let Some(te) = e.downcast_ref::<TransportException>() + if let Some(te) = e.catch::<TransportException>() && te.get_code() == 401 { return Ok(PhpMixed::String(format!( @@ -404,7 +405,9 @@ impl DiagnoseCommand { } Ok(PhpMixed::String(format!( "<error>[{}] {}</error>", - get_class_err(&e), + AnyThrowable::of(e.as_ref()) + .expect("PHP reaches this only with a caught \\Throwable") + .php_class_name(), e ))) } @@ -540,13 +543,16 @@ impl DiagnoseCommand { Ok(Err(e)) => { return Ok(PhpMixed::String(format!( "<error>[{}] {}</error>", - "UnexpectedValueException", e.message + "UnexpectedValueException", + e.get_message() ))); } Err(e) => { return Ok(PhpMixed::String(format!( "<error>[{}] {}</error>", - get_class_err(&e), + AnyThrowable::of(e.as_ref()) + .expect("PHP reaches this only with a caught \\Throwable") + .php_class_name(), e ))); } @@ -960,13 +966,10 @@ impl DiagnoseCommand { PHP_EOL, PHP_EOL ), other => { - return Err(InvalidArgumentException { - message: format!( - "DiagnoseCommand: Unknown error type \"{}\". Please report at https://github.com/composer/composer/issues/new.", - other, - ), - code: 0, - } + return Err(InvalidArgumentException::new(format!( + "DiagnoseCommand: Unknown error type \"{}\". Please report at https://github.com/composer/composer/issues/new.", + other, + )) .into()); } }; @@ -1042,13 +1045,10 @@ impl DiagnoseCommand { PHP_EOL ), other => { - return Err(InvalidArgumentException { - message: format!( - "DiagnoseCommand: Unknown warning type \"{}\". Please report at https://github.com/composer/composer/issues/new.", - other, - ), - code: 0, - } + return Err(InvalidArgumentException::new(format!( + "DiagnoseCommand: Unknown warning type \"{}\". Please report at https://github.com/composer/composer/issues/new.", + other, + )) .into()); } }; @@ -1409,13 +1409,19 @@ impl Command for DiagnoseCommand { Ok(()) })(); if let Err(e) = proxy_check_result { - if let Some(_te) = e.downcast_ref::<TransportException>() { + if let Some(_te) = e.catch::<TransportException>() { io.write_no_newline("Checking HTTP proxy: "); let status = self.check_connectivity_and_composer_network_http_enablement(); self.output_result(if is_string(&status) { status } else { - PhpMixed::String(format!("<error>[{}] {}</error>", get_class_err(&e), e)) + PhpMixed::String(format!( + "<error>[{}] {}</error>", + AnyThrowable::of(e.as_ref()) + .expect("PHP reaches this only with a caught \\Throwable") + .php_class_name(), + e + )) }); } else { return Err(e); @@ -1455,20 +1461,24 @@ impl Command for DiagnoseCommand { } } Err(e) => { - if let Some(te) = e.downcast_ref::<TransportException>() { + if let Some(te) = e.catch::<TransportException>() { if te.get_code() == 401 { self.output_result(PhpMixed::String("<comment>The oauth token for github.com seems invalid, run \"composer config --global --unset github-oauth.github.com\" to remove it</comment>".to_string())); } else { self.output_result(PhpMixed::String(format!( "<error>[{}] {}</error>", - get_class_err(&e), + AnyThrowable::of(e.as_ref()) + .expect("PHP reaches this only with a caught \\Throwable") + .php_class_name(), e ))); } } else { self.output_result(PhpMixed::String(format!( "<error>[{}] {}</error>", - get_class_err(&e), + AnyThrowable::of(e.as_ref()) + .expect("PHP reaches this only with a caught \\Throwable") + .php_class_name(), e ))); } |
