aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/src/command/config_command.rs
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-08-08 22:14:12 +0900
committernsfisis <nsfisis@gmail.com>2026-08-08 22:14:12 +0900
commitf4cad2123b2af0de72bda4ce039e16e74f163f4e (patch)
tree21803308c5ff41e23c9d3b117433eea16b4ff663 /crates/shirabe/src/command/config_command.rs
parent0209f63210e5b547b5c6b73367bb80ea86c255ec (diff)
downloadphp-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/config_command.rs')
-rw-r--r--crates/shirabe/src/command/config_command.rs184
1 files changed, 74 insertions, 110 deletions
diff --git a/crates/shirabe/src/command/config_command.rs b/crates/shirabe/src/command/config_command.rs
index 2727f36b..3b976ba2 100644
--- a/crates/shirabe/src/command/config_command.rs
+++ b/crates/shirabe/src/command/config_command.rs
@@ -86,11 +86,10 @@ impl ConfigCommand {
) -> anyhow::Result<()> {
let (validator, normalizer) = callbacks;
if 1 != values.len() {
- return Err(RuntimeException {
- message: "You can only pass one value. Example: shirabe config process-timeout 300"
+ return Err(RuntimeException::new(
+ "You can only pass one value. Example: shirabe config process-timeout 300"
.to_string(),
- code: 0,
- }
+ )
.into());
}
@@ -101,10 +100,11 @@ impl ConfigCommand {
} else {
String::new()
};
- return Err(RuntimeException {
- message: format!("\"{}\" is an invalid value{}", values[0].clone(), suffix),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "\"{}\" is an invalid value{}",
+ values[0].clone(),
+ suffix
+ ))
.into());
}
@@ -160,14 +160,11 @@ impl ConfigCommand {
} else {
String::new()
};
- return Err(RuntimeException {
- message: format!(
- "{} is an invalid value{}",
- PhpMixed::from(json_encode(&values_mixed).ok()),
- suffix
- ),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "{} is an invalid value{}",
+ PhpMixed::from(json_encode(&values_mixed).ok()),
+ suffix
+ ))
.into());
}
@@ -679,10 +676,9 @@ impl Command for ConfigCommand {
.unwrap_or_default();
if !setting_values.is_empty() && input.borrow().get_option("unset")?.as_bool() == Some(true)
{
- return Err(RuntimeException {
- message: "You can not combine a setting value with --unset".to_string(),
- code: 0,
- }
+ return Err(RuntimeException::new(
+ "You can not combine a setting value with --unset".to_string(),
+ )
.into());
}
@@ -731,10 +727,10 @@ impl Command for ConfigCommand {
{
Some(v) => v.clone(),
None => {
- return Err(InvalidArgumentException {
- message: format!("There is no {} repository defined", repo_key),
- code: 0,
- }
+ return Err(InvalidArgumentException::new(format!(
+ "There is no {} repository defined",
+ repo_key
+ ))
.into());
}
};
@@ -766,11 +762,9 @@ impl Command for ConfigCommand {
}
if !r#match {
- return Err(RuntimeException {
- message: format!("{} is not defined.", setting_key),
- code: 0,
- }
- .into());
+ return Err(
+ RuntimeException::new(format!("{} is not defined.", setting_key)).into(),
+ );
}
value = cursor;
@@ -847,11 +841,9 @@ impl Command for ConfigCommand {
value = v.clone();
source = "defaults".to_string();
} else {
- return Err(RuntimeException {
- message: format!("{} is not defined", setting_key),
- code: 0,
- }
- .into());
+ return Err(
+ RuntimeException::new(format!("{} is not defined", setting_key)).into(),
+ );
}
let value_str = if is_array(&value) || is_object(&value) || is_bool(&value) {
@@ -961,13 +953,10 @@ impl Command for ConfigCommand {
.as_bool()
.unwrap_or(false)
{
- return Err(RuntimeException {
- message: format!(
- "Invalid value for {}. Should be one of: auto, source, or dist",
- setting_key
- ),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "Invalid value for {}. Should be one of: auto, source, or dist",
+ setting_key
+ ))
.into());
}
@@ -998,10 +987,10 @@ impl Command for ConfigCommand {
}
if !boolean_validator(&PhpMixed::String(values[0].clone())) {
- return Err(RuntimeException {
- message: format!("\"{}\" is an invalid value", values[0].clone()),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "\"{}\" is an invalid value",
+ values[0].clone()
+ ))
.into());
}
@@ -1025,10 +1014,7 @@ impl Command for ConfigCommand {
|| multi_props.contains_key(&setting_key)
|| strpos(&setting_key, "extra.") == Some(0))
{
- return Err(InvalidArgumentException {
- message: format!("The {} property can not be set in the global config.json file. Use `composer global config` to apply changes to the global composer.json", setting_key),
- code: 0,
- }
+ return Err(InvalidArgumentException::new(format!("The {} property can not be set in the global config.json file. Use `composer global config` to apply changes to the global composer.json", setting_key))
.into());
}
if input.borrow().get_option("unset")?.as_bool() == Some(true)
@@ -1122,10 +1108,7 @@ impl Command for ConfigCommand {
}
}
- return Err(RuntimeException {
- message: "You must pass the type and a url. Example: shirabe config repositories.foo vcs https://bar.com".to_string(),
- code: 0,
- }
+ return Err(RuntimeException::new("You must pass the type and a url. Example: shirabe config repositories.foo vcs https://bar.com".to_string())
.into());
}
@@ -1308,10 +1291,10 @@ impl Command for ConfigCommand {
if input.borrow().get_option("json")?.as_bool() == Some(true) {
value = JsonFile::parse_json(Some(&values[0]), Some("composer.json"))?;
if !is_array(&value) {
- return Err(RuntimeException {
- message: format!("Expected an array or object for {}", setting_key),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "Expected an array or object for {}",
+ setting_key
+ ))
.into());
}
}
@@ -1349,10 +1332,10 @@ impl Command for ConfigCommand {
}
value = PhpMixed::Array(merged);
} else {
- return Err(RuntimeException {
- message: format!("Cannot merge array and object for {}", setting_key),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "Cannot merge array and object for {}",
+ setting_key
+ ))
.into());
}
}
@@ -1394,13 +1377,10 @@ impl Command for ConfigCommand {
let key = format!("{}.{}", matches[1], matches[2]);
if matches[1] == "bitbucket-oauth" {
if 2 != values.len() {
- return Err(RuntimeException {
- message: format!(
- "Expected two arguments (consumer-key, consumer-secret), got {}",
- values.len()
- ),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "Expected two arguments (consumer-key, consumer-secret), got {}",
+ values.len()
+ ))
.into());
}
self.config_source
@@ -1441,10 +1421,9 @@ impl Command for ConfigCommand {
"github-oauth" | "gitlab-oauth" | "gitlab-token" | "bearer"
) {
if 1 != values.len() {
- return Err(RuntimeException {
- message: "Too many arguments, expected only one token".to_string(),
- code: 0,
- }
+ return Err(RuntimeException::new(
+ "Too many arguments, expected only one token".to_string(),
+ )
.into());
}
self.config_source
@@ -1459,13 +1438,10 @@ impl Command for ConfigCommand {
.add_config_setting(&key, PhpMixed::String(values[0].clone()));
} else if matches[1] == "http-basic" {
if 2 != values.len() {
- return Err(RuntimeException {
- message: format!(
- "Expected two arguments (username, password), got {}",
- values.len()
- ),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "Expected two arguments (username, password), got {}",
+ values.len()
+ ))
.into());
}
self.config_source
@@ -1483,10 +1459,9 @@ impl Command for ConfigCommand {
.add_config_setting(&key, PhpMixed::Array(obj));
} else if matches[1] == "custom-headers" {
if values.is_empty() {
- return Err(RuntimeException {
- message: "Expected at least one argument (header), got none".to_string(),
- code: 0,
- }
+ return Err(RuntimeException::new(
+ "Expected at least one argument (header), got none".to_string(),
+ )
.into());
}
@@ -1494,12 +1469,10 @@ impl Command for ConfigCommand {
let mut formatted_headers: Vec<PhpMixed> = vec![];
for header in &values {
if !is_string(&PhpMixed::String(header.clone())) {
- return Err(RuntimeException {
- message:
- "Headers must be strings in \"Header-Name: Header-Value\" format"
- .to_string(),
- code: 0,
- }
+ return Err(RuntimeException::new(
+ "Headers must be strings in \"Header-Name: Header-Value\" format"
+ .to_string(),
+ )
.into());
}
@@ -1510,13 +1483,10 @@ impl Command for ConfigCommand {
header,
Some(&mut header_parts),
) {
- return Err(RuntimeException {
- message: format!(
- "Header \"{}\" is not in \"Header-Name: Header-Value\" format",
- header
- ),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "Header \"{}\" is not in \"Header-Name: Header-Value\" format",
+ header
+ ))
.into());
}
@@ -1535,13 +1505,10 @@ impl Command for ConfigCommand {
.add_config_setting(&key, PhpMixed::List(formatted_headers));
} else if matches[1] == "forgejo-token" {
if 2 != values.len() {
- return Err(RuntimeException {
- message: format!(
- "Expected two arguments (username, access token), got {}",
- values.len()
- ),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "Expected two arguments (username, access token), got {}",
+ values.len()
+ ))
.into());
}
self.config_source
@@ -1604,13 +1571,10 @@ impl Command for ConfigCommand {
return Ok(0);
}
- Err(InvalidArgumentException {
- message: format!(
- "Setting {} does not exist or is not supported by this command",
- setting_key
- ),
- code: 0,
- }
+ Err(InvalidArgumentException::new(format!(
+ "Setting {} does not exist or is not supported by this command",
+ setting_key
+ ))
.into())
}