aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/src/repository/vcs
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/repository/vcs
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/repository/vcs')
-rw-r--r--crates/shirabe/src/repository/vcs/forgejo_driver.rs62
-rw-r--r--crates/shirabe/src/repository/vcs/fossil_driver.rs63
-rw-r--r--crates/shirabe/src/repository/vcs/git_bitbucket_driver.rs38
-rw-r--r--crates/shirabe/src/repository/vcs/git_driver.rs78
-rw-r--r--crates/shirabe/src/repository/vcs/github_driver.rs60
-rw-r--r--crates/shirabe/src/repository/vcs/gitlab_driver.rs56
-rw-r--r--crates/shirabe/src/repository/vcs/hg_driver.rs41
-rw-r--r--crates/shirabe/src/repository/vcs/perforce_driver.rs14
-rw-r--r--crates/shirabe/src/repository/vcs/svn_driver.rs39
-rw-r--r--crates/shirabe/src/repository/vcs/vcs_driver.rs21
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),
+ })
})
}