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/repository/vcs | |
| 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/repository/vcs')
| -rw-r--r-- | crates/shirabe/src/repository/vcs/forgejo_driver.rs | 62 | ||||
| -rw-r--r-- | crates/shirabe/src/repository/vcs/fossil_driver.rs | 63 | ||||
| -rw-r--r-- | crates/shirabe/src/repository/vcs/git_bitbucket_driver.rs | 38 | ||||
| -rw-r--r-- | crates/shirabe/src/repository/vcs/git_driver.rs | 78 | ||||
| -rw-r--r-- | crates/shirabe/src/repository/vcs/github_driver.rs | 60 | ||||
| -rw-r--r-- | crates/shirabe/src/repository/vcs/gitlab_driver.rs | 56 | ||||
| -rw-r--r-- | crates/shirabe/src/repository/vcs/hg_driver.rs | 41 | ||||
| -rw-r--r-- | crates/shirabe/src/repository/vcs/perforce_driver.rs | 14 | ||||
| -rw-r--r-- | crates/shirabe/src/repository/vcs/svn_driver.rs | 39 | ||||
| -rw-r--r-- | crates/shirabe/src/repository/vcs/vcs_driver.rs | 21 |
10 files changed, 195 insertions, 277 deletions
diff --git a/crates/shirabe/src/repository/vcs/forgejo_driver.rs b/crates/shirabe/src/repository/vcs/forgejo_driver.rs index 0719701f..e4ebe379 100644 --- a/crates/shirabe/src/repository/vcs/forgejo_driver.rs +++ b/crates/shirabe/src/repository/vcs/forgejo_driver.rs @@ -16,6 +16,7 @@ use crate::util::ForgejoUrl; 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::{ PhpMixed, RuntimeException, base64_decode, explode, extension_loaded, php_regex, urlencode, }; @@ -107,7 +108,7 @@ impl ForgejoDriver { ); let response = self .get_contents(&resource_url, false) - .map_err(|e| anyhow::anyhow!("{}", e.message))?; + .map_err(|e| anyhow::anyhow!("{}", e.get_message()))?; let mut resource = response.decode_json()?; // The Forgejo contents API only returns files up to 1MB as base64 encoded files; @@ -134,7 +135,7 @@ impl ForgejoDriver { if let Some(git_url) = git_url { resource = self .get_contents(&git_url, false) - .map_err(|e| anyhow::anyhow!("{}", e.message))? + .map_err(|e| anyhow::anyhow!("{}", e.get_message()))? .decode_json()?; } } @@ -157,22 +158,22 @@ impl ForgejoDriver { Some(b64) => match base64_decode(&b64) { Some(bytes) => match String::from_utf8(bytes) { Ok(s) => Ok(Some(s)), - Err(_) => Err(RuntimeException { - message: format!("Could not retrieve {} for {}", file, identifier), - code: 0, - } + Err(_) => Err(RuntimeException::new(format!( + "Could not retrieve {} for {}", + file, identifier + )) .into()), }, - None => Err(RuntimeException { - message: format!("Could not retrieve {} for {}", file, identifier), - code: 0, - } + None => Err(RuntimeException::new(format!( + "Could not retrieve {} for {}", + file, identifier + )) .into()), }, - None => Err(RuntimeException { - message: format!("Could not retrieve {} for {}", file, identifier), - code: 0, - } + None => Err(RuntimeException::new(format!( + "Could not retrieve {} for {}", + file, identifier + )) .into()), } } @@ -193,7 +194,7 @@ impl ForgejoDriver { ); let commit = self .get_contents(&resource_url, false) - .map_err(|e| anyhow::anyhow!("{}", e.message))? + .map_err(|e| anyhow::anyhow!("{}", e.get_message()))? .decode_json()?; let date_str = if let PhpMixed::Array(ref arr) = commit { @@ -208,9 +209,8 @@ impl ForgejoDriver { None }; - let date_str = date_str.ok_or_else(|| RuntimeException { - message: format!("Could not parse commit date for {}", identifier), - code: 0, + let date_str = date_str.ok_or_else(|| { + RuntimeException::new(format!("Could not parse commit date for {}", identifier)) })?; let date: chrono::DateTime<chrono::FixedOffset> = shirabe_php_shim::date_create(&date_str)?; @@ -243,7 +243,7 @@ impl ForgejoDriver { while let Some(url) = resource { let response = self .get_contents(&url, false) - .map_err(|e| anyhow::anyhow!("{}", e.message))?; + .map_err(|e| anyhow::anyhow!("{}", e.get_message()))?; let branch_data = response.decode_json()?; if let PhpMixed::List(ref list) = branch_data { for branch in list { @@ -286,7 +286,7 @@ impl ForgejoDriver { while let Some(url) = resource { let response = self .get_contents(&url, false) - .map_err(|e| anyhow::anyhow!("{}", e.message))?; + .map_err(|e| anyhow::anyhow!("{}", e.get_message()))?; let tags_data = response.decode_json()?; if let PhpMixed::List(ref list) = tags_data { for tag in list { @@ -599,7 +599,7 @@ impl ForgejoDriver { &mut self, url: &str, fetching_repo_data: bool, - ) -> anyhow::Result<Response, TransportException> { + ) -> anyhow::Result<Response, Box<TransportException>> { match self.inner.get_contents(url) { Ok(response) => Ok(response), Err(e) => match e.get_code() { @@ -610,14 +610,7 @@ impl ForgejoDriver { if !self.inner.io.is_interactive() { self.attempt_clone_fallback() - .map_err(|inner_e| TransportException { - message: inner_e.to_string(), - code: 0, - headers: None, - response: None, - status_code: None, - response_info: vec![], - })?; + .map_err(|inner_e| TransportException::new(inner_e.to_string(), 0))?; return Ok(Response::new( "dummy".to_string(), @@ -645,14 +638,7 @@ impl ForgejoDriver { ); let auth_result = forgejo .authorize_o_auth_interactively(&origin_url, message.as_deref()) - .map_err(|inner_e| TransportException { - message: inner_e.to_string(), - code: 0, - headers: None, - response: None, - status_code: None, - response_info: vec![], - })?; + .map_err(|inner_e| TransportException::new(inner_e.to_string(), 0))?; if let Ok(true) = auth_result { return self.inner.get_contents(url); @@ -734,7 +720,7 @@ impl crate::repository::vcs::VcsDriverInterface for ForgejoDriver { match self.get_composer_information(identifier) { Ok(info) => Ok(info.is_some()), Err(e) => { - if e.downcast_ref::<TransportException>().is_some() { + if e.is_instanceof::<TransportException>() { Ok(false) } else { Err(e) diff --git a/crates/shirabe/src/repository/vcs/fossil_driver.rs b/crates/shirabe/src/repository/vcs/fossil_driver.rs index 1b61ed4d..3795d1ca 100644 --- a/crates/shirabe/src/repository/vcs/fossil_driver.rs +++ b/crates/shirabe/src/repository/vcs/fossil_driver.rs @@ -12,6 +12,7 @@ use crate::util::ProcessExecutor; use chrono::{DateTime, FixedOffset, Utc}; use indexmap::IndexMap; use shirabe_external_packages::composer::pcre::Preg; +use shirabe_php_shim::Catch as _; use shirabe_php_shim::{ PhpMixed, RuntimeException, dirname, is_dir, is_file, is_writable, php_regex, }; @@ -77,10 +78,7 @@ impl FossilDriver { .unwrap_or("") .to_string(); if !Cache::is_usable(&cache_repo_dir) || !Cache::is_usable(&cache_vcs_dir) { - return Err(RuntimeException { - message: "FossilDriver requires a usable cache directory, and it looks like you set it to be disabled".to_string(), - code: 0, - } + return Err(RuntimeException::new("FossilDriver requires a usable cache directory, and it looks like you set it to be disabled".to_string()) .into()); } @@ -105,13 +103,10 @@ impl FossilDriver { None, ) != 0 { - return Err(RuntimeException { - message: format!( - "fossil was not found, check that it is installed and in your PATH env.\n\n{}", - self.inner.process.borrow().get_error_output() - ), - code: 0, - } + return Err(RuntimeException::new(format!( + "fossil was not found, check that it is installed and in your PATH env.\n\n{}", + self.inner.process.borrow().get_error_output() + )) .into()); } Ok(()) @@ -124,13 +119,10 @@ impl FossilDriver { fs.ensure_directory_exists(&self.checkout_dir)?; if !is_writable(dirname(&self.checkout_dir)) { - return Err(RuntimeException { - message: format!( - "Can not clone {} to access package information. The \"{}\" directory is not writable by the current user.", - self.inner.url, self.checkout_dir - ), - code: 0, - } + return Err(RuntimeException::new(format!( + "Can not clone {} to access package information. The \"{}\" directory is not writable by the current user.", + self.inner.url, self.checkout_dir + )) .into()); } @@ -173,13 +165,10 @@ impl FossilDriver { ) != 0 { let output = self.inner.process.borrow().get_error_output().to_string(); - return Err(RuntimeException { - message: format!( - "Failed to clone {} to repository {}\n\n{}", - self.inner.url, repo_file, output - ), - code: 0, - } + return Err(RuntimeException::new(format!( + "Failed to clone {} to repository {}\n\n{}", + self.inner.url, repo_file, output + )) .into()); } @@ -192,13 +181,10 @@ impl FossilDriver { ) != 0 { let output = self.inner.process.borrow().get_error_output().to_string(); - return Err(RuntimeException { - message: format!( - "Failed to open repository {} in {}\n\n{}", - repo_file, self.checkout_dir, output - ), - code: 0, - } + return Err(RuntimeException::new(format!( + "Failed to open repository {} in {}\n\n{}", + repo_file, self.checkout_dir, output + )) .into()); } } @@ -231,13 +217,10 @@ impl FossilDriver { pub fn get_file_content(&self, file: &str, identifier: &str) -> anyhow::Result<Option<String>> { if identifier.starts_with('-') { - return Err(RuntimeException { - message: format!( - "Invalid fossil identifier detected. Identifier must not start with a -, given: {}", - identifier - ), - code: 0, - } + return Err(RuntimeException::new(format!( + "Invalid fossil identifier detected. Identifier must not start with a -, given: {}", + identifier + )) .into()); } @@ -420,7 +403,7 @@ impl crate::repository::vcs::VcsDriverInterface for FossilDriver { match self.get_composer_information(identifier) { Ok(info) => Ok(info.is_some()), Err(e) => { - if e.downcast_ref::<TransportException>().is_some() { + if e.is_instanceof::<TransportException>() { Ok(false) } else { Err(e) diff --git a/crates/shirabe/src/repository/vcs/git_bitbucket_driver.rs b/crates/shirabe/src/repository/vcs/git_bitbucket_driver.rs index 8fe93018..d833b576 100644 --- a/crates/shirabe/src/repository/vcs/git_bitbucket_driver.rs +++ b/crates/shirabe/src/repository/vcs/git_bitbucket_driver.rs @@ -16,6 +16,7 @@ use crate::util::http::Response; use chrono::{DateTime, FixedOffset}; use indexmap::IndexMap; use shirabe_external_packages::composer::pcre::{CaptureKey, Preg}; +use shirabe_php_shim::Catch as _; use shirabe_php_shim::{ InvalidArgumentException, LogicException, PhpMixed, RuntimeException, array_key_exists, array_search_mixed, extension_loaded, http_build_query_mixed, implode, is_array, php_regex, @@ -90,13 +91,10 @@ impl GitBitbucketDriver { &self.inner.url, Some(&mut m), ) { - return Err(InvalidArgumentException { - message: format!( - "The Bitbucket repository URL {} is invalid. It must be the HTTPS URL of a Bitbucket repository.", - self.inner.url.clone(), - ), - code: 0, - } + return Err(InvalidArgumentException::new(format!( + "The Bitbucket repository URL {} is invalid. It must be the HTTPS URL of a Bitbucket repository.", + self.inner.url.clone(), + )) .into()); } @@ -706,7 +704,7 @@ impl GitBitbucketDriver { if !self.inner.io.has_authentication(&self.inner.origin_url) && bitbucket_util.authorize_oauth(&self.inner.origin_url) { - return self.inner.get_contents(url).map_err(anyhow::Error::from); + return self.inner.get_contents(url).map_err(|e| (*e).into()); } if !self.inner.io.is_interactive() && fetching_repo_data { @@ -722,7 +720,7 @@ impl GitBitbucketDriver { } } - Err(e.into()) + Err((*e).into()) } } } @@ -742,7 +740,7 @@ impl GitBitbucketDriver { match self.setup_fallback_driver(&self.generate_ssh_url()) { Ok(()) => Ok(true), Err(e) => { - if e.downcast_ref::<RuntimeException>().is_some() { + if e.is_instanceof::<RuntimeException>() { self.fallback_driver = None; self.inner.io.write_error(&format!( @@ -799,11 +797,10 @@ impl GitBitbucketDriver { if self.root_identifier.is_none() { if !self.get_repo_data()? { if self.fallback_driver.is_none() { - return Err(LogicException { - message: "A fallback driver should be setup if getRepoData returns false" + return Err(LogicException::new( + "A fallback driver should be setup if getRepoData returns false" .to_string(), - code: 0, - } + ) .into()); } @@ -811,13 +808,10 @@ impl GitBitbucketDriver { } if self.vcs_type.as_deref() != Some("git") { - return Err(RuntimeException { - message: format!( - "{} does not appear to be a git repository, use {} but remember that Bitbucket no longer supports the mercurial repositories. https://bitbucket.org/blog/sunsetting-mercurial-support-in-bitbucket", - self.inner.url, self.clone_https_url - ), - code: 0, - } + return Err(RuntimeException::new(format!( + "{} does not appear to be a git repository, use {} but remember that Bitbucket no longer supports the mercurial repositories. https://bitbucket.org/blog/sunsetting-mercurial-support-in-bitbucket", + self.inner.url, self.clone_https_url + )) .into()); } @@ -918,7 +912,7 @@ impl crate::repository::vcs::VcsDriverInterface for GitBitbucketDriver { match self.get_composer_information(identifier) { Ok(info) => Ok(info.is_some()), Err(e) => { - if e.downcast_ref::<TransportException>().is_some() { + if e.is_instanceof::<TransportException>() { Ok(false) } else { Err(e) diff --git a/crates/shirabe/src/repository/vcs/git_driver.rs b/crates/shirabe/src/repository/vcs/git_driver.rs index 1376ebbc..9f8a6b32 100644 --- a/crates/shirabe/src/repository/vcs/git_driver.rs +++ b/crates/shirabe/src/repository/vcs/git_driver.rs @@ -15,6 +15,7 @@ use chrono::TimeZone; use chrono::{DateTime, FixedOffset, Utc}; use indexmap::IndexMap; use shirabe_external_packages::composer::pcre::{CaptureKey, Preg}; +use shirabe_php_shim::Catch as _; use shirabe_php_shim::{ InvalidArgumentException, RuntimeException, dirname, is_dir, is_writable, realpath, sys_get_temp_dir, @@ -52,13 +53,10 @@ impl GitDriver { if Filesystem::is_local_path(&self.inner.url) { self.inner.url = Preg::replace(php_regex!(r"{[\\/]\.git/?$}"), "", &self.inner.url); if !is_dir(&self.inner.url) { - return Err(RuntimeException { - message: format!( - "Failed to read package information from {} as the path does not exist", - self.inner.url - ), - code: 0, - } + return Err(RuntimeException::new(format!( + "Failed to read package information from {} as the path does not exist", + self.inner.url + )) .into()); } self.repo_dir = self.inner.url.clone(); @@ -73,10 +71,7 @@ impl GitDriver { .unwrap_or("") .to_string(); if !Cache::is_usable(&cache_vcs_dir) { - return Err(RuntimeException { - message: "GitDriver requires a usable cache directory, and it looks like you set it to be disabled".to_string(), - code: 0, - } + return Err(RuntimeException::new("GitDriver requires a usable cache directory, and it looks like you set it to be disabled".to_string()) .into()); } @@ -96,25 +91,19 @@ impl GitDriver { fs.ensure_directory_exists(&dirname(&self.repo_dir))?; if !is_writable(dirname(&self.repo_dir)) { - return Err(RuntimeException { - message: format!( - "Can not clone {} to access package information. The \"{}\" directory is not writable by the current user.", - self.inner.url, - dirname(&self.repo_dir) - ), - code: 0, - } + return Err(RuntimeException::new(format!( + "Can not clone {} to access package information. The \"{}\" directory is not writable by the current user.", + self.inner.url, + dirname(&self.repo_dir) + )) .into()); } if Preg::is_match(php_regex!(r"{^ssh://[^@]+@[^:]+:[^0-9]+}"), &self.inner.url) { - return Err(InvalidArgumentException { - message: format!( - "The source URL {} is invalid, ssh URLs should have a port number after \":\".\nUse ssh://git@example.com:22/path or just git@example.com:path if you do not want to provide a password or custom port.", - self.inner.url - ), - code: 0, - } + return Err(InvalidArgumentException::new(format!( + "The source URL {} is invalid, ssh URLs should have a port number after \":\".\nUse ssh://git@example.com:22/path or just git@example.com:path if you do not want to provide a password or custom port.", + self.inner.url + )) .into()); } @@ -126,13 +115,10 @@ impl GitDriver { ); if !git_util.sync_mirror(&self.inner.url, &self.repo_dir)? { if !is_dir(&self.repo_dir) { - return Err(RuntimeException { - message: format!( - "Failed to clone {} to read package information from it", - self.inner.url - ), - code: 0, - } + return Err(RuntimeException::new(format!( + "Failed to clone {} to read package information from it", + self.inner.url + )) .into()); } self.inner.io.write_error3(&format!( @@ -250,13 +236,10 @@ impl GitDriver { identifier: &str, ) -> anyhow::Result<Option<String>> { if identifier.starts_with('-') { - return Err(RuntimeException { - message: format!( - "Invalid git identifier detected. Identifier must not start with a -, given: {}", - identifier - ), - code: 0, - } + return Err(RuntimeException::new(format!( + "Invalid git identifier detected. Identifier must not start with a -, given: {}", + identifier + )) .into()); } @@ -283,13 +266,10 @@ impl GitDriver { identifier: &str, ) -> anyhow::Result<Option<DateTime<FixedOffset>>> { if identifier.starts_with('-') { - return Err(RuntimeException { - message: format!( - "Invalid git identifier detected. Identifier must not start with a -, given: {}", - identifier - ), - code: 0, - } + return Err(RuntimeException::new(format!( + "Invalid git identifier detected. Identifier must not start with a -, given: {}", + identifier + )) .into()); } @@ -459,7 +439,7 @@ impl GitDriver { ) { Ok(_) => Ok(true), Err(e) => { - if e.downcast_ref::<RuntimeException>().is_some() { + if e.is_instanceof::<RuntimeException>() { Ok(false) } else { Err(e) @@ -543,7 +523,7 @@ impl crate::repository::vcs::VcsDriverInterface for GitDriver { match self.get_composer_information(identifier) { Ok(info) => Ok(info.is_some()), Err(e) => { - if e.downcast_ref::<TransportException>().is_some() { + if e.is_instanceof::<TransportException>() { Ok(false) } else { Err(e) diff --git a/crates/shirabe/src/repository/vcs/github_driver.rs b/crates/shirabe/src/repository/vcs/github_driver.rs index d656ae61..72bcc8ae 100644 --- a/crates/shirabe/src/repository/vcs/github_driver.rs +++ b/crates/shirabe/src/repository/vcs/github_driver.rs @@ -15,6 +15,7 @@ use crate::util::http::Response; use chrono::{DateTime, FixedOffset}; use indexmap::IndexMap; use shirabe_external_packages::composer::pcre::{CaptureKey, Preg}; +use shirabe_php_shim::Catch as _; use shirabe_php_shim::{ InvalidArgumentException, PhpMixed, RuntimeException, array_diff, array_key_exists, array_map, array_search_mixed, base64_decode, basename, empty, explode, extension_loaded, in_array_loose, @@ -77,13 +78,10 @@ impl GitHubDriver { &self.inner.url, Some(&mut match_), ) { - return Err(InvalidArgumentException { - message: format!( - "The GitHub repository URL {} is invalid.", - self.inner.url.clone(), - ), - code: 0, - } + return Err(InvalidArgumentException::new(format!( + "The GitHub repository URL {} is invalid.", + self.inner.url.clone(), + )) .into()); } @@ -737,7 +735,7 @@ impl GitHubDriver { ); let mut resource = self .get_contents(&resource_url, false) - .map_err(|e| anyhow::anyhow!("{}", e.message))? + .map_err(|e| anyhow::anyhow!("{}", e.get_message()))? .decode_json()?; // The GitHub contents API only returns files up to 1MB as base64 encoded files @@ -765,7 +763,7 @@ impl GitHubDriver { .to_string(); resource = self .get_contents(&git_url, false) - .map_err(|e| anyhow::anyhow!("{}", e.message))? + .map_err(|e| anyhow::anyhow!("{}", e.get_message()))? .decode_json()?; } @@ -789,10 +787,10 @@ impl GitHubDriver { let content = match content { Some(c) => String::from_utf8_lossy(&c).to_string(), None => { - return Err(RuntimeException { - message: format!("Could not retrieve {} for {}", file, identifier), - code: 0, - } + return Err(RuntimeException::new(format!( + "Could not retrieve {} for {}", + file, identifier + )) .into()); } }; @@ -817,7 +815,7 @@ impl GitHubDriver { ); let commit = self .get_contents(&resource, false) - .map_err(|e| anyhow::anyhow!("{}", e.message))? + .map_err(|e| anyhow::anyhow!("{}", e.get_message()))? .decode_json()?; let date_str = match commit { @@ -853,7 +851,7 @@ impl GitHubDriver { loop { let response = self .get_contents(resource.as_deref().unwrap_or(""), false) - .map_err(|e| anyhow::anyhow!("{}", e.message))?; + .map_err(|e| anyhow::anyhow!("{}", e.get_message()))?; let tags_data = response.decode_json()?; if let PhpMixed::List(ref list) = tags_data { for tag in list { @@ -903,7 +901,7 @@ impl GitHubDriver { loop { let response = self .get_contents(resource.as_deref().unwrap_or(""), false) - .map_err(|e| anyhow::anyhow!("{}", e.message))?; + .map_err(|e| anyhow::anyhow!("{}", e.get_message()))?; let branch_data = response.decode_json()?; if let PhpMixed::List(ref list) = branch_data { for branch in list { @@ -1015,7 +1013,7 @@ impl GitHubDriver { &mut self, url: &str, fetching_repo_data: bool, - ) -> anyhow::Result<Response, TransportException> { + ) -> anyhow::Result<Response, Box<TransportException>> { let response_result = self.inner.get_contents(url); match response_result { Ok(r) => Ok(r), @@ -1028,7 +1026,7 @@ impl GitHubDriver { ) .map_err(|err| TransportException::new(err.to_string(), 0))?; - match e.code { + match e.get_code() { 401 | 404 => { // try to authorize only if we are fetching the main /repos/foo/bar data, otherwise it must be a real 404 if !fetching_repo_data { @@ -1178,10 +1176,10 @@ impl GitHubDriver { }; } Err(e) => { - if e.code == 499 { + if e.get_code() == 499 { self.attempt_clone_fallback(Some(&e))?; } else { - return Err(e.into()); + return Err((*e).into()); } } } @@ -1232,13 +1230,11 @@ impl GitHubDriver { e: Option<&TransportException>, ) -> anyhow::Result<bool> { if !self.allow_git_fallback { - return Err(RuntimeException { - message: format!( - "Fallback to git driver disabled{}", - e.map(|e| format!(": {}", e.message)).unwrap_or_default() - ), - code: 0, - } + return Err(RuntimeException::new(format!( + "Fallback to git driver disabled{}", + e.map(|e| format!(": {}", e.get_message())) + .unwrap_or_default() + )) .into()); } @@ -1269,11 +1265,9 @@ impl GitHubDriver { pub(crate) fn setup_git_driver(&mut self, url: &str) -> anyhow::Result<()> { if !self.allow_git_fallback { - return Err(RuntimeException { - message: "Fallback to git driver disabled".to_string(), - code: 0, - } - .into()); + return Err( + RuntimeException::new("Fallback to git driver disabled".to_string()).into(), + ); } let mut repo_config: IndexMap<String, PhpMixed> = IndexMap::new(); repo_config.insert("url".to_string(), PhpMixed::String(url.to_string())); @@ -1377,7 +1371,7 @@ impl crate::repository::vcs::VcsDriverInterface for GitHubDriver { match self.get_composer_information(identifier) { Ok(info) => Ok(info.is_some()), Err(e) => { - if e.downcast_ref::<TransportException>().is_some() { + if e.is_instanceof::<TransportException>() { Ok(false) } else { Err(e) diff --git a/crates/shirabe/src/repository/vcs/gitlab_driver.rs b/crates/shirabe/src/repository/vcs/gitlab_driver.rs index 5fe513f6..8432ed65 100644 --- a/crates/shirabe/src/repository/vcs/gitlab_driver.rs +++ b/crates/shirabe/src/repository/vcs/gitlab_driver.rs @@ -16,6 +16,7 @@ use crate::util::http::Response; use chrono::{DateTime, FixedOffset}; use indexmap::IndexMap; use shirabe_external_packages::composer::pcre::{CaptureKey, Preg}; +use shirabe_php_shim::Catch as _; use shirabe_php_shim::{ InvalidArgumentException, LogicException, PhpMixed, RuntimeException, array_search_mixed, array_shift, ctype_alnum, empty, explode, extension_loaded, implode, in_array_loose, is_array, @@ -82,13 +83,10 @@ impl GitLabDriver { pub fn initialize(&mut self) -> anyhow::Result<()> { let mut match_: IndexMap<CaptureKey, String> = IndexMap::new(); if !Preg::is_match3(Self::URL_REGEX, &self.inner.url, Some(&mut match_)) { - return Err(InvalidArgumentException { - message: format!( - "The GitLab repository URL {} is invalid. It must be the HTTP URL of a GitLab project.", - self.inner.url.clone(), - ), - code: 0, - } + return Err(InvalidArgumentException::new(format!( + "The GitLab repository URL {} is invalid. It must be the HTTP URL of a GitLab project.", + self.inner.url.clone(), + )) .into()); } @@ -134,13 +132,10 @@ impl GitLabDriver { let origin = match origin { Some(o) => o, None => { - return Err(LogicException { - message: format!( - "It should not be possible to create a gitlab driver with an unparsable origin URL ({})", - self.inner.url - ), - code: 0, - } + return Err(LogicException::new(format!( + "It should not be possible to create a gitlab driver with an unparsable origin URL ({})", + self.inner.url + )) .into()); } }; @@ -153,10 +148,9 @@ impl GitLabDriver { { // https treated as a synonym for http. if !matches!(protocol, "git" | "http" | "https") { - return Err(RuntimeException { - message: "gitlab-protocol must be one of git, http.".to_string(), - code: 0, - } + return Err(RuntimeException::new( + "gitlab-protocol must be one of git, http.".to_string(), + ) .into()); } self.protocol = if protocol == "git" { @@ -424,8 +418,8 @@ impl GitLabDriver { let content = match self.get_contents(&resource, false) { Ok(response) => response.get_body().map(|s| s.to_string()), Err(e) => { - if e.code != 404 { - return Err(e.into()); + if e.get_code() != 404 { + return Err((*e).into()); } return Ok(None); @@ -617,7 +611,7 @@ impl GitLabDriver { loop { let response = self .get_contents(resource.as_deref().unwrap_or(""), false) - .map_err(|e| anyhow::anyhow!("{}", e.message))?; + .map_err(|e| anyhow::anyhow!("{}", e.get_message()))?; let data = response.decode_json()?; if let PhpMixed::List(ref list) = data { @@ -676,7 +670,7 @@ impl GitLabDriver { let resource = self.get_api_url(); let project = self .get_contents(&resource, true) - .map_err(|e| anyhow::anyhow!("{}", e.message))? + .map_err(|e| anyhow::anyhow!("{}", e.get_message()))? .decode_json()?; self.project = match project { PhpMixed::Array(m) => Some(m), @@ -769,7 +763,7 @@ impl GitLabDriver { &mut self, url: &str, fetching_repo_data: bool, - ) -> anyhow::Result<Response, TransportException> { + ) -> anyhow::Result<Response, Box<TransportException>> { let response_result = self.inner.get_contents(url); match response_result { Ok(response) => { @@ -839,21 +833,21 @@ impl GitLabDriver { .and_then(|v| v.as_string()) == Some("disabled") { - return Err(TransportException::new( + return Err(Box::new(TransportException::new( "The GitLab repository is disabled in the project".to_string(), 400, - )); + ))); } if !empty(&json_map.get("id").cloned().unwrap_or(PhpMixed::Null)) { self.is_private = false; } - return Err(TransportException::new( + return Err(Box::new(TransportException::new( "GitLab API seems to not be authenticated as it did not return a default_branch" .to_string(), 401, - )); + ))); } } @@ -868,7 +862,7 @@ impl GitLabDriver { ) .map_err(|err| TransportException::new(err.to_string(), 0))?; - match e.code { + match e.get_code() { 401 | 404 => { // try to authorize only if we are fetching the main /repos/foo/bar data, otherwise it must be a real 404 if !fetching_repo_data { @@ -901,7 +895,9 @@ impl GitLabDriver { self.inner.io.write_error3( &format!( "<warning>Failed to download {}/{}:{}</warning>", - self.namespace, self.repository, e.message + self.namespace, + self.repository, + e.get_message() ), true, io_interface::NORMAL, @@ -1142,7 +1138,7 @@ impl crate::repository::vcs::VcsDriverInterface for GitLabDriver { match self.get_composer_information(identifier) { Ok(info) => Ok(info.is_some()), Err(e) => { - if e.downcast_ref::<TransportException>().is_some() { + if e.is_instanceof::<TransportException>() { Ok(false) } else { Err(e) diff --git a/crates/shirabe/src/repository/vcs/hg_driver.rs b/crates/shirabe/src/repository/vcs/hg_driver.rs index 0283ed38..41aeebd9 100644 --- a/crates/shirabe/src/repository/vcs/hg_driver.rs +++ b/crates/shirabe/src/repository/vcs/hg_driver.rs @@ -12,6 +12,7 @@ use crate::util::Url; use chrono::{DateTime, FixedOffset, Utc}; use indexmap::IndexMap; use shirabe_external_packages::composer::pcre::{CaptureKey, Preg}; +use shirabe_php_shim::Catch as _; use shirabe_php_shim::{PhpMixed, RuntimeException, dirname, is_dir, is_writable, php_regex}; #[derive(Debug)] @@ -53,10 +54,7 @@ impl HgDriver { .unwrap_or("") .to_string(); if !Cache::is_usable(&cache_vcs_dir) { - return Err(RuntimeException { - message: "HgDriver requires a usable cache directory, and it looks like you set it to be disabled".to_string(), - code: 0, - }.into()); + return Err(RuntimeException::new("HgDriver requires a usable cache directory, and it looks like you set it to be disabled".to_string()).into()); } let sanitized = Preg::replace( @@ -70,13 +68,10 @@ impl HgDriver { fs.ensure_directory_exists(&cache_vcs_dir)?; if !is_writable(dirname(&self.repo_dir)) { - return Err(RuntimeException { - message: format!( - "Can not clone {} to access package information. The \"{}\" directory is not writable by the current user.", - self.inner.url, cache_vcs_dir - ), - code: 0, - }.into()); + return Err(RuntimeException::new(format!( + "Can not clone {} to access package information. The \"{}\" directory is not writable by the current user.", + self.inner.url, cache_vcs_dir + )).into()); } self.inner.config.borrow_mut().prohibit_url_by_config( @@ -167,13 +162,10 @@ impl HgDriver { pub fn get_file_content(&self, file: &str, identifier: &str) -> anyhow::Result<Option<String>> { if identifier.starts_with('-') { - return Err(RuntimeException { - message: format!( - "Invalid hg identifier detected. Identifier must not start with a -, given: {}", - identifier - ), - code: 0, - } + return Err(RuntimeException::new(format!( + "Invalid hg identifier detected. Identifier must not start with a -, given: {}", + identifier + )) .into()); } @@ -203,13 +195,10 @@ impl HgDriver { identifier: &str, ) -> anyhow::Result<Option<DateTime<FixedOffset>>> { if identifier.starts_with('-') { - return Err(RuntimeException { - message: format!( - "Invalid hg identifier detected. Identifier must not start with a -, given: {}", - identifier - ), - code: 0, - } + return Err(RuntimeException::new(format!( + "Invalid hg identifier detected. Identifier must not start with a -, given: {}", + identifier + )) .into()); } @@ -443,7 +432,7 @@ impl crate::repository::vcs::VcsDriverInterface for HgDriver { match self.get_composer_information(identifier) { Ok(info) => Ok(info.is_some()), Err(e) => { - if e.downcast_ref::<TransportException>().is_some() { + if e.is_instanceof::<TransportException>() { Ok(false) } else { Err(e) diff --git a/crates/shirabe/src/repository/vcs/perforce_driver.rs b/crates/shirabe/src/repository/vcs/perforce_driver.rs index 452ac5a2..af16cd8c 100644 --- a/crates/shirabe/src/repository/vcs/perforce_driver.rs +++ b/crates/shirabe/src/repository/vcs/perforce_driver.rs @@ -79,10 +79,7 @@ impl PerforceDriver { .unwrap_or("") .to_string(); if !Cache::is_usable(&cache_vcs_dir) { - return Err(RuntimeException { - message: "PerforceDriver requires a usable cache directory, and it looks like you set it to be disabled".to_string(), - code: 0, - }.into()); + return Err(RuntimeException::new("PerforceDriver requires a usable cache directory, and it looks like you set it to be disabled".to_string()).into()); } let repo_dir = format!("{}/{}", cache_vcs_dir, self.depot); @@ -180,11 +177,10 @@ impl PerforceDriver { } pub fn get_contents(&self, _url: &str) -> anyhow::Result<Response> { - Err(BadMethodCallException { - message: "Not implemented/used in PerforceDriver".to_string(), - code: 0, - } - .into()) + Err( + BadMethodCallException::new("Not implemented/used in PerforceDriver".to_string()) + .into(), + ) } pub fn supports( diff --git a/crates/shirabe/src/repository/vcs/svn_driver.rs b/crates/shirabe/src/repository/vcs/svn_driver.rs index 716b1943..84e3a20d 100644 --- a/crates/shirabe/src/repository/vcs/svn_driver.rs +++ b/crates/shirabe/src/repository/vcs/svn_driver.rs @@ -14,6 +14,7 @@ use crate::util::Url; use chrono::{DateTime, FixedOffset, Utc}; use indexmap::IndexMap; use shirabe_external_packages::composer::pcre::{CaptureKey, Preg}; +use shirabe_php_shim::Catch as _; use shirabe_php_shim::{ PhpMixed, RuntimeException, php_regex, stripos, strrpos, strtr, substr, trim, }; @@ -199,14 +200,14 @@ impl SvnDriver { Ok(c) => c, Err(e) => { // PHP catches only TransportException; other exceptions propagate uncaught. - if e.downcast_ref::<TransportException>().is_none() { + if !e.is_instanceof::<TransportException>() { return Err(e); } let message = e - .downcast_ref::<TransportException>() + .catch::<TransportException>() .unwrap() - .message - .clone(); + .get_message() + .to_string(); if stripos(&message, "path not found").is_none() && stripos(&message, "svn: warning: W160013").is_none() { @@ -277,8 +278,8 @@ impl SvnDriver { ) { Ok(o) => o, Err(e) => { - if let Some(e) = e.downcast_ref::<RuntimeException>() { - return Err(TransportException::new(e.message.clone(), 0).into()); + if let Some(e) = e.catch::<RuntimeException>() { + return Err(TransportException::new(e.get_message().to_string(), 0).into()); } return Err(e); } @@ -567,24 +568,18 @@ impl SvnDriver { Ok(o) => Ok(o), Err(e) => { if self.util.as_mut().unwrap().binary_version().is_none() { - return Err(RuntimeException { - message: format!( - "Failed to load {}, svn was not found, check that it is installed and in your PATH env.\n\n{}", - self.inner.url, - self.inner.process.borrow().get_error_output(), - ), - code: 0, - } + return Err(RuntimeException::new(format!( + "Failed to load {}, svn was not found, check that it is installed and in your PATH env.\n\n{}", + self.inner.url, + self.inner.process.borrow().get_error_output(), + )) .into()); } - Err(RuntimeException { - message: format!( - "Repository {} could not be processed, {}", - self.inner.url, e, - ), - code: 0, - } + Err(RuntimeException::new(format!( + "Repository {} could not be processed, {}", + self.inner.url, e, + )) .into()) } } @@ -655,7 +650,7 @@ impl crate::repository::vcs::VcsDriverInterface for SvnDriver { match self.get_composer_information(identifier) { Ok(info) => Ok(info.is_some()), Err(e) => { - if e.downcast_ref::<TransportException>().is_some() { + if e.is_instanceof::<TransportException>() { Ok(false) } else { Err(e) diff --git a/crates/shirabe/src/repository/vcs/vcs_driver.rs b/crates/shirabe/src/repository/vcs/vcs_driver.rs index 3321201c..42f679df 100644 --- a/crates/shirabe/src/repository/vcs/vcs_driver.rs +++ b/crates/shirabe/src/repository/vcs/vcs_driver.rs @@ -13,6 +13,7 @@ use crate::util::http::Response; use chrono::{DateTime, FixedOffset}; use indexmap::IndexMap; use shirabe_external_packages::composer::pcre::Preg; +use shirabe_php_shim::Catch as _; use shirabe_php_shim::{DATE_RFC3339, PhpMixed, extension_loaded, php_regex}; #[derive(Debug)] @@ -66,7 +67,7 @@ impl VcsDriverBase { "http" } - pub fn get_contents(&self, url: &str) -> anyhow::Result<Response, TransportException> { + pub fn get_contents(&self, url: &str) -> anyhow::Result<Response, Box<TransportException>> { let options_mixed = self .repo_config .get("options") @@ -79,9 +80,11 @@ impl VcsDriverBase { self.http_downloader .borrow_mut() .get(url, options) - .map_err(|e| match e.downcast::<TransportException>() { - Ok(te) => te, - Err(other) => TransportException::new(other.to_string(), 0), + .map_err(|e| { + Box::new(match e.catch::<TransportException>() { + Some(te) => te.clone(), + None => TransportException::new(e.to_string(), 0), + }) }) } @@ -299,7 +302,7 @@ pub trait VcsDriver: VcsDriverInterface { "http" } - fn get_contents(&self, url: &str) -> anyhow::Result<Response, TransportException> { + fn get_contents(&self, url: &str) -> anyhow::Result<Response, Box<TransportException>> { let options_mixed = self .repo_config() .get("options") @@ -312,9 +315,11 @@ pub trait VcsDriver: VcsDriverInterface { self.http_downloader() .borrow_mut() .get(url, options) - .map_err(|e| match e.downcast::<TransportException>() { - Ok(te) => te, - Err(other) => TransportException::new(other.to_string(), 0), + .map_err(|e| { + Box::new(match e.catch::<TransportException>() { + Some(te) => te.clone(), + None => TransportException::new(e.to_string(), 0), + }) }) } |
