aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/src/command/repository_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/repository_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/repository_command.rs')
-rw-r--r--crates/shirabe/src/command/repository_command.rs127
1 files changed, 59 insertions, 68 deletions
diff --git a/crates/shirabe/src/command/repository_command.rs b/crates/shirabe/src/command/repository_command.rs
index ab2cf2d4..47fd2d28 100644
--- a/crates/shirabe/src/command/repository_command.rs
+++ b/crates/shirabe/src/command/repository_command.rs
@@ -362,26 +362,20 @@ impl Command for RepositoryCommand {
}
"add" => {
if name.is_none() {
- return Err(anyhow::anyhow!(RuntimeException {
- message: "You must pass a repository name. Example: composer repo add foo vcs https://example.org".to_string(),
- code: 0,
- }));
+ return Err(RuntimeException::new("You must pass a repository name. Example: composer repo add foo vcs https://example.org".to_string()).into());
}
if arg1.is_none() {
- return Err(anyhow::anyhow!(RuntimeException {
- message: "You must pass the type and a url, or a JSON string.".to_string(),
- code: 0,
- }));
+ return Err(RuntimeException::new(
+ "You must pass the type and a url, or a JSON string.".to_string(),
+ )
+ .into());
}
let arg1_str = arg1.as_deref().unwrap();
let repo_config: PhpMixed = if Preg::is_match(php_regex!(r"{^\s*\{}"), arg1_str) {
JsonFile::parse_json(Some(arg1_str), None)?
} else {
if arg2.is_none() {
- return Err(anyhow::anyhow!(RuntimeException {
- message: "You must pass the type and a url. Example: composer repo add foo vcs https://example.org".to_string(),
- code: 0,
- }));
+ return Err(RuntimeException::new("You must pass the type and a url. Example: composer repo add foo vcs https://example.org".to_string()).into());
}
let mut m = IndexMap::new();
m.insert("type".to_string(), PhpMixed::String(arg1_str.to_string()));
@@ -400,19 +394,19 @@ impl Command for RepositoryCommand {
.as_string()
.map(|s| s.to_string());
if before.is_some() && after.is_some() {
- return Err(anyhow::anyhow!(RuntimeException {
- message: "You can not combine --before and --after".to_string(),
- code: 0,
- }));
+ return Err(RuntimeException::new(
+ "You can not combine --before and --after".to_string(),
+ )
+ .into());
}
if before.is_some() || after.is_some() {
if matches!(repo_config, PhpMixed::Bool(false)) {
- return Err(anyhow::anyhow!(RuntimeException {
- message: "Cannot use --before/--after with boolean repository values"
+ return Err(RuntimeException::new(
+ "Cannot use --before/--after with boolean repository values"
.to_string(),
- code: 0,
- }));
+ )
+ .into());
}
let reference_name = before.as_deref().or(after.as_deref()).unwrap();
let offset: i64 = if after.is_some() { 1 } else { 0 };
@@ -443,10 +437,10 @@ impl Command for RepositoryCommand {
}
"remove" | "rm" | "delete" => {
if name.is_none() {
- return Err(anyhow::anyhow!(RuntimeException {
- message: "You must pass the repository name to remove.".to_string(),
- code: 0,
- }));
+ return Err(RuntimeException::new(
+ "You must pass the repository name to remove.".to_string(),
+ )
+ .into());
}
let name_str = name.as_deref().unwrap();
self.config_source
@@ -465,10 +459,10 @@ impl Command for RepositoryCommand {
}
"set-url" | "seturl" => {
if name.is_none() || arg1.is_none() {
- return Err(anyhow::anyhow!(RuntimeException {
- message: "Usage: composer repo set-url <name> <new-url>".to_string(),
- code: 0,
- }));
+ return Err(RuntimeException::new(
+ "Usage: composer repo set-url <name> <new-url>".to_string(),
+ )
+ .into());
}
self.config_source
.borrow_mut()
@@ -479,10 +473,10 @@ impl Command for RepositoryCommand {
}
"get-url" | "geturl" => {
if name.is_none() {
- return Err(anyhow::anyhow!(RuntimeException {
- message: "Usage: composer repo get-url <name>".to_string(),
- code: 0,
- }));
+ return Err(RuntimeException::new(
+ "Usage: composer repo get-url <name>".to_string(),
+ )
+ .into());
}
let name_str = name.as_deref().unwrap();
if let Some(repo) = repos.get(name_str)
@@ -493,10 +487,11 @@ impl Command for RepositoryCommand {
self.get_io().write(url);
return Ok(0);
}
- return Err(anyhow::anyhow!(InvalidArgumentException {
- message: format!("The {} repository does not have a URL", name_str),
- code: 0,
- }));
+ return Err(InvalidArgumentException::new(format!(
+ "The {} repository does not have a URL",
+ name_str
+ ))
+ .into());
}
for (_key, val) in &repos {
if let PhpMixed::Array(ref repo_map) = *val
@@ -508,23 +503,25 @@ impl Command for RepositoryCommand {
self.get_io().write(url);
return Ok(0);
}
- return Err(anyhow::anyhow!(InvalidArgumentException {
- message: format!("The {} repository does not have a URL", name_str),
- code: 0,
- }));
+ return Err(InvalidArgumentException::new(format!(
+ "The {} repository does not have a URL",
+ name_str
+ ))
+ .into());
}
}
- Err(anyhow::anyhow!(InvalidArgumentException {
- message: format!("There is no {} repository defined", name_str),
- code: 0,
- }))
+ Err(InvalidArgumentException::new(format!(
+ "There is no {} repository defined",
+ name_str
+ ))
+ .into())
}
"disable" => {
if name.is_none() {
- return Err(anyhow::anyhow!(RuntimeException {
- message: "Usage: composer repo disable packagist.org".to_string(),
- code: 0,
- }));
+ return Err(RuntimeException::new(
+ "Usage: composer repo disable packagist.org".to_string(),
+ )
+ .into());
}
let name_str = name.as_deref().unwrap();
if ["packagist", "packagist.org"].contains(&name_str) {
@@ -540,17 +537,14 @@ impl Command for RepositoryCommand {
.add_repository("packagist.org", PhpMixed::Bool(false), append);
return Ok(0);
}
- Err(anyhow::anyhow!(RuntimeException {
- message: "Only packagist.org can be enabled/disabled using this command. Use add/remove for other repositories.".to_string(),
- code: 0,
- }))
+ Err(RuntimeException::new("Only packagist.org can be enabled/disabled using this command. Use add/remove for other repositories.".to_string()).into())
}
"enable" => {
if name.is_none() {
- return Err(anyhow::anyhow!(RuntimeException {
- message: "Usage: composer repo enable packagist.org".to_string(),
- code: 0,
- }));
+ return Err(RuntimeException::new(
+ "Usage: composer repo enable packagist.org".to_string(),
+ )
+ .into());
}
let name_str = name.as_deref().unwrap();
if ["packagist", "packagist.org"].contains(&name_str) {
@@ -561,19 +555,16 @@ impl Command for RepositoryCommand {
.remove_repository("packagist.org");
return Ok(0);
}
- Err(anyhow::anyhow!(RuntimeException {
- message: "Only packagist.org can be enabled/disabled using this command."
- .to_string(),
- code: 0,
- }))
+ Err(RuntimeException::new(
+ "Only packagist.org can be enabled/disabled using this command.".to_string(),
+ )
+ .into())
}
- _ => Err(anyhow::anyhow!(InvalidArgumentException {
- message: format!(
- "Unknown action \"{}\". Use list, add, remove, set-url, get-url, enable, disable",
- action
- ),
- code: 0,
- })),
+ _ => Err(InvalidArgumentException::new(format!(
+ "Unknown action \"{}\". Use list, add, remove, set-url, get-url, enable, disable",
+ action
+ ))
+ .into()),
}
}