aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/src/util
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/util
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/util')
-rw-r--r--crates/shirabe/src/util/auth_helper.rs6
-rw-r--r--crates/shirabe/src/util/bitbucket.rs49
-rw-r--r--crates/shirabe/src/util/config_validator.rs5
-rw-r--r--crates/shirabe/src/util/error_handler.rs8
-rw-r--r--crates/shirabe/src/util/filesystem.rs98
-rw-r--r--crates/shirabe/src/util/forgejo.rs5
-rw-r--r--crates/shirabe/src/util/forgejo_url.rs8
-rw-r--r--crates/shirabe/src/util/git.rs36
-rw-r--r--crates/shirabe/src/util/github.rs3
-rw-r--r--crates/shirabe/src/util/gitlab.rs34
-rw-r--r--crates/shirabe/src/util/http/curl_downloader.rs58
-rw-r--r--crates/shirabe/src/util/http/proxy_item.rs34
-rw-r--r--crates/shirabe/src/util/http/proxy_manager.rs6
-rw-r--r--crates/shirabe/src/util/http/request_proxy.rs9
-rw-r--r--crates/shirabe/src/util/http_downloader.rs26
-rw-r--r--crates/shirabe/src/util/no_proxy_pattern.rs49
-rw-r--r--crates/shirabe/src/util/perforce.rs37
-rw-r--r--crates/shirabe/src/util/platform.rs13
-rw-r--r--crates/shirabe/src/util/process_executor.rs49
-rw-r--r--crates/shirabe/src/util/remote_filesystem.rs48
-rw-r--r--crates/shirabe/src/util/stream_context_factory.rs26
-rw-r--r--crates/shirabe/src/util/svn.rs31
-rw-r--r--crates/shirabe/src/util/tar.rs36
-rw-r--r--crates/shirabe/src/util/zip.rs39
24 files changed, 289 insertions, 424 deletions
diff --git a/crates/shirabe/src/util/auth_helper.rs b/crates/shirabe/src/util/auth_helper.rs
index a323c37e..69a84857 100644
--- a/crates/shirabe/src/util/auth_helper.rs
+++ b/crates/shirabe/src/util/auth_helper.rs
@@ -80,11 +80,7 @@ impl AuthHelper {
) {
return Ok(PhpMixed::String(input));
}
- Err(RuntimeException {
- message: "Please answer (y)es or (n)o".to_string(),
- code: 0,
- }
- .into())
+ Err(RuntimeException::new("Please answer (y)es or (n)o".to_string()).into())
}),
None,
PhpMixed::String("y".to_string()),
diff --git a/crates/shirabe/src/util/bitbucket.rs b/crates/shirabe/src/util/bitbucket.rs
index 50d4b700..d8e245a9 100644
--- a/crates/shirabe/src/util/bitbucket.rs
+++ b/crates/shirabe/src/util/bitbucket.rs
@@ -9,10 +9,11 @@ use crate::io::io_interface;
use crate::util::HttpDownloader;
use crate::util::ProcessExecutor;
use indexmap::IndexMap;
+use shirabe_php_shim::Catch as _;
use shirabe_php_shim::{LogicException, PhpMixed, time};
fn transport_error_code(err: &anyhow::Error) -> Option<i64> {
- err.downcast_ref::<TransportException>().map(|te| te.code)
+ err.catch::<TransportException>().map(|te| te.get_code())
}
#[derive(Debug)]
@@ -167,24 +168,18 @@ impl Bitbucket {
let token_map = match token {
PhpMixed::Array(ref m) => m.clone(),
_ => {
- return Err(LogicException {
- message: format!(
- "Expected a token configured with expires_in and access_token present, got {}",
- shirabe_php_shim::json_encode(&token).unwrap_or_default()
- ),
- code: 0,
- }
+ return Err(LogicException::new(format!(
+ "Expected a token configured with expires_in and access_token present, got {}",
+ shirabe_php_shim::json_encode(&token).unwrap_or_default()
+ ))
.into());
}
};
if !token_map.contains_key("expires_in") || !token_map.contains_key("access_token") {
- return Err(LogicException {
- message: format!(
- "Expected a token configured with expires_in and access_token present, got {}",
- shirabe_php_shim::json_encode(&token).unwrap_or_default()
- ),
- code: 0,
- }
+ return Err(LogicException::new(format!(
+ "Expected a token configured with expires_in and access_token present, got {}",
+ shirabe_php_shim::json_encode(&token).unwrap_or_default()
+ ))
.into());
}
self.token = Some(token_map.into_iter().collect());
@@ -350,11 +345,7 @@ impl Bitbucket {
match access_token {
Some(t) => Ok(t),
- None => Err(LogicException {
- message: "Failed to initialize token above".to_string(),
- code: 0,
- }
- .into()),
+ None => Err(LogicException::new("Failed to initialize token above".to_string()).into()),
}
}
@@ -370,9 +361,10 @@ impl Bitbucket {
.get_config_source_mut()
.remove_config_setting(&format!("bitbucket-oauth.{}", origin_url))?;
- let token = self.token.as_ref().ok_or_else(|| LogicException {
- message: "Expected a token configured with expires_in present, got null".to_string(),
- code: 0,
+ let token = self.token.as_ref().ok_or_else(|| {
+ LogicException::new(
+ "Expected a token configured with expires_in present, got null".to_string(),
+ )
})?;
let expires_in = token
.get("expires_in")
@@ -380,13 +372,10 @@ impl Bitbucket {
.ok_or_else(|| {
let token_mixed =
PhpMixed::Array(token.iter().map(|(k, v)| (k.clone(), v.clone())).collect());
- LogicException {
- message: format!(
- "Expected a token configured with expires_in present, got {}",
- shirabe_php_shim::json_encode(&token_mixed).unwrap_or_default()
- ),
- code: 0,
- }
+ LogicException::new(format!(
+ "Expected a token configured with expires_in present, got {}",
+ shirabe_php_shim::json_encode(&token_mixed).unwrap_or_default()
+ ))
})?;
let t = self.time.unwrap_or_else(time);
diff --git a/crates/shirabe/src/util/config_validator.rs b/crates/shirabe/src/util/config_validator.rs
index 9b6b292d..978a5cd2 100644
--- a/crates/shirabe/src/util/config_validator.rs
+++ b/crates/shirabe/src/util/config_validator.rs
@@ -10,6 +10,7 @@ use crate::package::loader::ValidatingArrayLoader;
use indexmap::IndexMap;
use serde::de::Error as _;
use shirabe_external_packages::composer::pcre::Preg;
+use shirabe_php_shim::Catch as _;
use shirabe_php_shim::{PhpMixed, php_regex};
use shirabe_spdx_licenses::SpdxLicenses;
@@ -55,7 +56,7 @@ impl ConfigValidator {
match schema_result {
Ok(()) => {}
Err(e) => {
- if let Some(validation_e) = e.downcast_ref::<JsonValidationException>() {
+ if let Some(validation_e) = e.catch::<JsonValidationException>() {
for message in validation_e.get_errors() {
if lax_valid {
publish_errors.push(message.clone());
@@ -298,7 +299,7 @@ impl ConfigValidator {
) {
Ok(_) => {}
Err(e) => {
- if let Some(invalid_e) = e.downcast_ref::<InvalidPackageException>() {
+ if let Some(invalid_e) = e.catch::<InvalidPackageException>() {
errors.extend_from_slice(invalid_e.get_errors());
}
}
diff --git a/crates/shirabe/src/util/error_handler.rs b/crates/shirabe/src/util/error_handler.rs
index 2e574fe0..dcea940e 100644
--- a/crates/shirabe/src/util/error_handler.rs
+++ b/crates/shirabe/src/util/error_handler.rs
@@ -58,13 +58,7 @@ impl ErrorHandler {
return Ok(true);
}
- return Err(ErrorException {
- message,
- code: 0,
- severity: level,
- filename: file,
- lineno: line,
- });
+ return Err(ErrorException::new(message, 0, level, file, line, None));
}
let io = IO.with(|cell| cell.borrow().clone());
diff --git a/crates/shirabe/src/util/filesystem.rs b/crates/shirabe/src/util/filesystem.rs
index daf26e22..7010fd86 100644
--- a/crates/shirabe/src/util/filesystem.rs
+++ b/crates/shirabe/src/util/filesystem.rs
@@ -124,9 +124,11 @@ impl Filesystem {
// `rm -rf`/`rmdir` subprocess via the String-based ProcessExecutor, so it has to be
// representable as UTF-8.
let directory = directory.as_ref();
- let directory = directory.to_str().ok_or_else(|| RuntimeException {
- message: format!("Path contains invalid UTF-8: {}", directory.display()),
- code: 0,
+ let directory = directory.to_str().ok_or_else(|| {
+ RuntimeException::new(format!(
+ "Path contains invalid UTF-8: {}",
+ directory.display()
+ ))
})?;
let edge_case_result = self.remove_edge_cases(directory, true)?;
if let Some(r) = edge_case_result {
@@ -246,10 +248,7 @@ impl Filesystem {
}
if Preg::is_match3(php_regex!("{^(?:[a-z]:)?[/\\\\]+$}i"), directory, None) {
- return Err(RuntimeException {
- message: format!("Aborting an attempted deletion of {}, this was probably not intended, if it is a real use case please report it.", directory),
- code: 0,
- }
+ return Err(RuntimeException::new(format!("Aborting an attempted deletion of {}, this was probably not intended, if it is a real use case please report it.", directory))
.into());
}
@@ -309,42 +308,36 @@ impl Filesystem {
pub fn ensure_directory_exists(&mut self, directory: &str) -> anyhow::Result<()> {
if !is_dir(directory) {
if file_exists(directory) {
- return Err(RuntimeException {
- message: format!("{} exists and is not a directory.", directory),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "{} exists and is not a directory.",
+ directory
+ ))
.into());
}
if is_link(directory) && !self.unlink_implementation(Path::new(directory)) {
- return Err(RuntimeException {
- message: format!(
- "Could not delete symbolic link {}: {}",
- directory,
- error_get_last()
- .as_ref()
- .and_then(|m| m.get("message"))
- .and_then(|v| v.as_string())
- .unwrap_or("")
- ),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "Could not delete symbolic link {}: {}",
+ directory,
+ error_get_last()
+ .as_ref()
+ .and_then(|m| m.get("message"))
+ .and_then(|v| v.as_string())
+ .unwrap_or("")
+ ))
.into());
}
if !mkdir(directory, 0o777, true) {
- let e = RuntimeException {
- message: format!(
- "{} does not exist and could not be created: {}",
- directory,
- error_get_last()
- .as_ref()
- .and_then(|m| m.get("message"))
- .and_then(|v| v.as_string())
- .unwrap_or("")
- ),
- code: 0,
- };
+ let e = RuntimeException::new(format!(
+ "{} does not exist and could not be created: {}",
+ directory,
+ error_get_last()
+ .as_ref()
+ .and_then(|m| m.get("message"))
+ .and_then(|v| v.as_string())
+ .unwrap_or("")
+ ));
// in pathological cases with paths like path/to/broken-symlink/../foo is_dir will fail to detect path/to/foo
// but normalizing the ../ away first makes it work so we attempt this just in case, and if it still fails we
@@ -390,7 +383,7 @@ impl Filesystem {
message.push_str("\nThis can be due to an antivirus or the Windows Search Indexer locking the file while they are analyzed");
}
- return Err(RuntimeException { message, code: 0 }.into());
+ return Err(RuntimeException::new(message).into());
}
}
@@ -423,7 +416,7 @@ impl Filesystem {
message.push_str("\nThis can be due to an antivirus or the Windows Search Indexer locking the file while they are analyzed");
}
- return Err(RuntimeException { message, code: 0 }.into());
+ return Err(RuntimeException::new(message).into());
}
}
@@ -464,7 +457,7 @@ impl Filesystem {
// if copy fails we attempt to copy it manually as this can help bypass issues with VirtualBox shared folders
// see https://github.com/composer/composer/issues/12057
- if str_contains(&e.message, "Bad address") {
+ if str_contains(e.get_message(), "Bad address") {
let (source_handle, target_handle) =
match (fopen(source, "r"), fopen(&target, "w")) {
(Ok(source_handle), Ok(target_handle)) => {
@@ -520,13 +513,11 @@ impl Filesystem {
// TODO(phase-c):
// The fallbacks below (copy_then_remove and the mv/xcopy subprocesses) operate on
// path strings, so beyond this point the paths have to be representable as UTF-8.
- let source = source.to_str().ok_or_else(|| RuntimeException {
- message: format!("Path contains invalid UTF-8: {}", source.display()),
- code: 0,
+ let source = source.to_str().ok_or_else(|| {
+ RuntimeException::new(format!("Path contains invalid UTF-8: {}", source.display()))
})?;
- let target = target.to_str().ok_or_else(|| RuntimeException {
- message: format!("Path contains invalid UTF-8: {}", target.display()),
- code: 0,
+ let target = target.to_str().ok_or_else(|| {
+ RuntimeException::new(format!("Path contains invalid UTF-8: {}", target.display()))
})?;
if !function_exists("proc_open") {
@@ -735,11 +726,9 @@ impl Filesystem {
pub fn size(&self, path: impl AsRef<Path>) -> anyhow::Result<i64> {
let path = path.as_ref();
if !file_exists(path) {
- return Err(RuntimeException {
- message: format!("{} does not exist.", path.display()),
- code: 0,
- }
- .into());
+ return Err(
+ RuntimeException::new(format!("{} does not exist.", path.display())).into(),
+ );
}
if is_dir(path) {
return self.directory_size(path);
@@ -987,13 +976,10 @@ impl Filesystem {
/// Creates an NTFS junction.
pub fn junction(&mut self, target: &str, junction: &str) -> anyhow::Result<()> {
if !Platform::is_windows() {
- return Err(LogicException {
- message: format!(
- "Function {} is not available on non-Windows platform",
- "Composer\\Util\\Filesystem"
- ),
- code: 0,
- }
+ return Err(LogicException::new(format!(
+ "Function {} is not available on non-Windows platform",
+ "Composer\\Util\\Filesystem"
+ ))
.into());
}
if !is_dir(target) {
diff --git a/crates/shirabe/src/util/forgejo.rs b/crates/shirabe/src/util/forgejo.rs
index 34d44b7b..6c18e4f6 100644
--- a/crates/shirabe/src/util/forgejo.rs
+++ b/crates/shirabe/src/util/forgejo.rs
@@ -6,6 +6,7 @@ use crate::io::IOInterface;
use crate::io::IOInterfaceImmutable;
use crate::io::io_interface;
use crate::util::HttpDownloader;
+use shirabe_php_shim::Catch as _;
#[derive(Debug)]
pub struct Forgejo {
@@ -121,8 +122,8 @@ impl Forgejo {
Ok(_) => {}
Err(e) => {
let code = e
- .downcast_ref::<crate::downloader::TransportException>()
- .map(|te| te.code)
+ .catch::<crate::downloader::TransportException>()
+ .map(|te| te.get_code())
.unwrap_or(0);
if [403, 401, 404].contains(&code) {
self.io.write_error3(
diff --git a/crates/shirabe/src/util/forgejo_url.rs b/crates/shirabe/src/util/forgejo_url.rs
index ce5a8948..639426e1 100644
--- a/crates/shirabe/src/util/forgejo_url.rs
+++ b/crates/shirabe/src/util/forgejo_url.rs
@@ -27,10 +27,10 @@ impl ForgejoUrl {
pub fn create(repo_url: &str) -> anyhow::Result<Self> {
match Self::try_from(Some(repo_url)) {
Some(url) => Ok(url),
- None => Err(InvalidArgumentException {
- message: format!("This is not a valid Forgejo URL: {}", repo_url),
- code: 0,
- }
+ None => Err(InvalidArgumentException::new(format!(
+ "This is not a valid Forgejo URL: {}",
+ repo_url
+ ))
.into()),
}
}
diff --git a/crates/shirabe/src/util/git.rs b/crates/shirabe/src/util/git.rs
index a6f8d79e..3eec0947 100644
--- a/crates/shirabe/src/util/git.rs
+++ b/crates/shirabe/src/util/git.rs
@@ -64,11 +64,7 @@ impl Git {
);
match io {
None => {
- return Err(RuntimeException {
- message: msg,
- code: 0,
- }
- .into());
+ return Err(RuntimeException::new(msg).into());
}
Some(io) => {
io.write_error3(
@@ -215,13 +211,10 @@ impl Git {
};
if Preg::is_match(php_regex!(r"{^ssh://[^@]+@[^:]+:[^0-9]+}"), 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.",
- 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.",
+ url
+ ))
.into());
}
@@ -1277,22 +1270,15 @@ impl Git {
Option::<&str>::None,
) != 0
{
- return Err(RuntimeException {
- message: Url::sanitize(format!(
- "Failed to clone {}, git was not found, check that it is installed and in your PATH env.\n\n{}",
- url,
- self.process.borrow().get_error_output()
- )),
- code: 0,
- }
+ return Err(RuntimeException::new(Url::sanitize(format!(
+ "Failed to clone {}, git was not found, check that it is installed and in your PATH env.\n\n{}",
+ url,
+ self.process.borrow().get_error_output()
+ )))
.into());
}
- Err(RuntimeException {
- message: Url::sanitize(message.to_string()),
- code: 0,
- }
- .into())
+ Err(RuntimeException::new(Url::sanitize(message.to_string())).into())
}
/// Retrieves the current git version.
diff --git a/crates/shirabe/src/util/github.rs b/crates/shirabe/src/util/github.rs
index 01a5dd1f..066f0ff5 100644
--- a/crates/shirabe/src/util/github.rs
+++ b/crates/shirabe/src/util/github.rs
@@ -9,6 +9,7 @@ use crate::util::HttpDownloader;
use crate::util::ProcessExecutor;
use indexmap::IndexMap;
use shirabe_external_packages::composer::pcre::{CaptureKey, Preg};
+use shirabe_php_shim::Catch as _;
use shirabe_php_shim::{PhpMixed, date, in_array_loose, php_regex, stripos, strtolower};
#[derive(Debug)]
@@ -233,7 +234,7 @@ impl GitHub {
Ok(_) => {}
Err(te) => {
let code = te
- .downcast_ref::<crate::downloader::TransportException>()
+ .catch::<crate::downloader::TransportException>()
.map(|t| t.get_code())
.unwrap_or(0);
if code == 403 || code == 401 {
diff --git a/crates/shirabe/src/util/gitlab.rs b/crates/shirabe/src/util/gitlab.rs
index c14ad46a..cdeb0f21 100644
--- a/crates/shirabe/src/util/gitlab.rs
+++ b/crates/shirabe/src/util/gitlab.rs
@@ -10,6 +10,7 @@ use crate::util::HttpDownloader;
use crate::util::ProcessExecutor;
use indexmap::IndexMap;
use shirabe_external_packages::composer::pcre::Preg;
+use shirabe_php_shim::Catch as _;
use shirabe_php_shim::{
PhpMixed, RuntimeException, http_build_query, in_array_strict, json_decode, php_regex, time,
};
@@ -248,9 +249,9 @@ impl GitLab {
Err(e) => {
// 401 is bad credentials,
// 403 is max login attempts exceeded
- match e.downcast::<TransportException>() {
- Ok(te) if te.code == 403 || te.code == 401 => {
- if te.code == 401 {
+ match e.catch::<TransportException>() {
+ Some(te) if te.get_code() == 403 || te.get_code() == 401 => {
+ if te.get_code() == 401 {
let response =
te.get_response().and_then(|r| json_decode(r, true).ok());
let is_invalid_grant = response
@@ -301,8 +302,7 @@ impl GitLab {
continue;
}
- Ok(te) => return Err(te.into()),
- Err(e) => return Err(e),
+ _ => return Err(e),
}
}
};
@@ -360,10 +360,9 @@ impl GitLab {
return Ok(true);
}
- Err(RuntimeException {
- message: "Invalid GitLab credentials 5 times in a row, aborting.".to_string(),
- code: 0,
- }
+ Err(RuntimeException::new(
+ "Invalid GitLab credentials 5 times in a row, aborting.".to_string(),
+ )
.into())
}
@@ -374,16 +373,17 @@ impl GitLab {
) -> anyhow::Result<bool> {
let response = match self.refresh_token(scheme, origin_url) {
Ok(r) => r,
- Err(e) => match e.downcast::<TransportException>() {
- Ok(te) => {
+ Err(e) => match e.catch::<TransportException>() {
+ Some(te) => {
+ let message = te.get_message().to_string();
self.io.write_error3(
- &format!("Couldn't refresh access token: {}", te.message),
+ &format!("Couldn't refresh access token: {}", message),
true,
io_interface::NORMAL,
);
return Ok(false);
}
- Err(e) => return Err(e),
+ None => return Err(e),
},
};
@@ -488,10 +488,10 @@ impl GitLab {
let refresh_token = match refresh_token {
Some(t) => t,
None => {
- return Err(RuntimeException {
- message: format!("No GitLab refresh token present for {}.", origin_url),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "No GitLab refresh token present for {}.",
+ origin_url
+ ))
.into());
}
};
diff --git a/crates/shirabe/src/util/http/curl_downloader.rs b/crates/shirabe/src/util/http/curl_downloader.rs
index 604dae77..6409c9d5 100644
--- a/crates/shirabe/src/util/http/curl_downloader.rs
+++ b/crates/shirabe/src/util/http/curl_downloader.rs
@@ -60,7 +60,7 @@ static TIMEOUT_WARNING: AtomicBool = AtomicBool::new(false);
enum Decision {
Retry { url: String, delay_ms: Option<u64> },
Done(Response),
- Failed(TransportException),
+ Failed(anyhow::Error),
}
impl CurlDownloader {
@@ -108,7 +108,7 @@ impl CurlDownloader {
url: &str,
mut options: IndexMap<String, PhpMixed>,
copy_to: Option<&str>,
- ) -> anyhow::Result<Result<Response, TransportException>> {
+ ) -> anyhow::Result<Result<Response, anyhow::Error>> {
let mut attributes: IndexMap<String, PhpMixed> = {
let mut m = IndexMap::new();
m.insert("retryAuthFailure".to_string(), PhpMixed::Bool(true));
@@ -178,7 +178,7 @@ impl CurlDownloader {
.as_ref()
.map(|pm| pm.get_proxy_for_request(url))
.transpose()
- .map_err(|e| anyhow::anyhow!(e.message))?
+ .map_err(|e| anyhow::anyhow!(e.get_message().to_string()))?
.and_then(|p| p.get_status(Some(" using proxy (%s)")).ok())
.unwrap_or_default();
// `attributes.redirects == 0 && attributes.retries == 0` in PHP is always true here since
@@ -206,7 +206,7 @@ impl CurlDownloader {
)?;
let send_options =
crate::util::StreamContextFactory::init_options(&current_url, send_options, true)
- .map_err(|e| anyhow::anyhow!(e.message))?;
+ .map_err(|e| anyhow::anyhow!(e.get_message().to_string()))?;
let send_result = self
.send_once(&current_url, &send_options, copy_to, &attributes)
@@ -304,26 +304,24 @@ impl CurlDownloader {
if let Some(filename) = filename {
unlink_silent(format!("{}~", filename));
}
- // PHP throws a MaxFileSizeExceededException (a TransportException subclass) with
- // the raw "Maximum allowed download size reached..." message verbatim rather than
- // wrapping it in the generic curl-error text.
+ // The message carries the raw "Maximum allowed download size reached..." text
+ // rather than the generic curl-error wrapper used below.
if transport_err.is_max_file_size {
return Ok(Decision::Failed(
- MaxFileSizeExceededException(TransportException::new(
- transport_err.message,
- 0,
- ))
- .0,
+ MaxFileSizeExceededException::new(transport_err.message).into(),
));
}
- return Ok(Decision::Failed(TransportException::new(
- format!(
- "curl error while downloading {}: {}",
- Url::sanitize(url.to_string()),
- transport_err.message
- ),
- 0,
- )));
+ return Ok(Decision::Failed(
+ TransportException::new(
+ format!(
+ "curl error while downloading {}: {}",
+ Url::sanitize(url.to_string()),
+ transport_err.message
+ ),
+ 0,
+ )
+ .into(),
+ ));
}
};
@@ -373,7 +371,7 @@ impl CurlDownloader {
});
}
Ok(_) => {}
- Err(e) => return Ok(Decision::Failed(e)),
+ Err(e) => return Ok(Decision::Failed((*e).into())),
}
// Handle 3xx redirects, 304 Not Modified excluded.
@@ -401,7 +399,7 @@ impl CurlDownloader {
if let Some(filename) = filename {
unlink_silent(format!("{}~", filename));
}
- return Ok(Decision::Failed(e));
+ return Ok(Decision::Failed((*e).into()));
}
}
}
@@ -443,7 +441,7 @@ impl CurlDownloader {
e.set_headers(curl_response.inner.get_headers().clone());
e.set_status_code(Some(curl_response.inner.get_status_code()));
e.set_response(curl_response.inner.get_body().map(|s| s.to_string()));
- return Ok(Decision::Failed(e));
+ return Ok(Decision::Failed((*e).into()));
}
// storeAuth on success.
@@ -625,7 +623,7 @@ impl CurlDownloader {
url: &str,
attributes: &IndexMap<String, PhpMixed>,
response: &CurlResponse,
- ) -> anyhow::Result<Result<String, TransportException>> {
+ ) -> anyhow::Result<Result<String, Box<TransportException>>> {
let mut target_url = String::new();
if let Some(location_header) = response.inner.get_header("location")
&& !location_header.is_empty()
@@ -682,14 +680,14 @@ impl CurlDownloader {
return Ok(Ok(target_url));
}
- Ok(Err(TransportException::new(
+ Ok(Err(Box::new(TransportException::new(
format!(
"The \"{}\" file could not be downloaded, got redirect without Location ({})",
url,
response.inner.get_status_message().unwrap_or_default()
),
0,
- )))
+ ))))
}
fn is_authenticated_retry_needed(
@@ -699,7 +697,7 @@ impl CurlDownloader {
filename: Option<&str>,
attributes: &IndexMap<String, PhpMixed>,
response: &CurlResponse,
- ) -> anyhow::Result<Result<PromptAuthResult, TransportException>> {
+ ) -> anyhow::Result<Result<PromptAuthResult, Box<TransportException>>> {
let retry_auth_failure = attributes
.get("retryAuthFailure")
.and_then(|b| b.as_bool())
@@ -808,7 +806,7 @@ impl CurlDownloader {
filename: Option<&str>,
response: &CurlResponse,
error_message: &str,
- ) -> TransportException {
+ ) -> Box<TransportException> {
if let Some(filename) = filename {
unlink_silent(format!("{}~", filename));
}
@@ -836,13 +834,13 @@ impl CurlDownloader {
);
}
- TransportException::new(
+ Box::new(TransportException::new(
format!(
"The \"{}\" file could not be downloaded ({}){}",
url, error_message, details
),
response.inner.get_status_code(),
- )
+ ))
}
fn method_is_get(options: &IndexMap<String, PhpMixed>) -> bool {
diff --git a/crates/shirabe/src/util/http/proxy_item.rs b/crates/shirabe/src/util/http/proxy_item.rs
index 1a0b3ee8..73948f88 100644
--- a/crates/shirabe/src/util/http/proxy_item.rs
+++ b/crates/shirabe/src/util/http/proxy_item.rs
@@ -20,28 +20,22 @@ impl ProxyItem {
let syntax_error = format!("unsupported `{}` syntax", env_name);
if strpbrk(&proxy_url, "\r\n\t").is_some() {
- return Err(RuntimeException {
- message: syntax_error,
- code: 0,
- });
+ return Err(RuntimeException::new(syntax_error));
}
let proxy_parsed = parse_url_all(&proxy_url);
let proxy = match proxy_parsed.as_array() {
None => {
- return Err(RuntimeException {
- message: syntax_error,
- code: 0,
- });
+ return Err(RuntimeException::new(syntax_error));
}
Some(a) => a.clone(),
};
if !proxy.contains_key("host") {
- return Err(RuntimeException {
- message: format!("unable to find proxy host in {}", env_name),
- code: 0,
- });
+ return Err(RuntimeException::new(format!(
+ "unable to find proxy host in {}",
+ env_name
+ )));
}
let scheme = if proxy.contains_key("scheme") {
@@ -100,16 +94,16 @@ impl ProxyItem {
// but is considered valid depending on the PHP or Curl version.
let port = match port {
None => {
- return Err(RuntimeException {
- message: format!("unable to find proxy port in {}", env_name),
- code: 0,
- });
+ return Err(RuntimeException::new(format!(
+ "unable to find proxy port in {}",
+ env_name
+ )));
}
Some(0) => {
- return Err(RuntimeException {
- message: format!("port 0 is reserved in {}", env_name),
- code: 0,
- });
+ return Err(RuntimeException::new(format!(
+ "port 0 is reserved in {}",
+ env_name
+ )));
}
Some(p) => p,
};
diff --git a/crates/shirabe/src/util/http/proxy_manager.rs b/crates/shirabe/src/util/http/proxy_manager.rs
index 82e8ebc5..13f0b521 100644
--- a/crates/shirabe/src/util/http/proxy_manager.rs
+++ b/crates/shirabe/src/util/http/proxy_manager.rs
@@ -71,12 +71,12 @@ impl ProxyManager {
pub fn get_proxy_for_request(
&self,
request_url: &str,
- ) -> Result<RequestProxy, TransportException> {
+ ) -> Result<RequestProxy, Box<TransportException>> {
if let Some(ref error) = self.error {
- return Err(TransportException::new(
+ return Err(Box::new(TransportException::new(
format!("Unable to use a proxy: {}", error),
0,
- ));
+ )));
}
let scheme = request_url.split("://").next().unwrap_or("").to_string();
diff --git a/crates/shirabe/src/util/http/request_proxy.rs b/crates/shirabe/src/util/http/request_proxy.rs
index 1262622f..78a64078 100644
--- a/crates/shirabe/src/util/http/request_proxy.rs
+++ b/crates/shirabe/src/util/http/request_proxy.rs
@@ -48,7 +48,7 @@ impl RequestProxy {
pub fn get_curl_options(
&self,
ssl_options: &IndexMap<String, PhpMixed>,
- ) -> Result<IndexMap<i64, PhpMixed>, TransportException> {
+ ) -> Result<IndexMap<i64, PhpMixed>, Box<TransportException>> {
// PHP guards an HTTPS proxy behind `is_secure() && !supports_secure_proxy()` because
// libcurl < 7.52.0 cannot speak TLS to a proxy. Shirabe always can (see
// supports_secure_proxy), so the guard is dropped.
@@ -90,10 +90,9 @@ impl RequestProxy {
return Ok(format.replace("%s", self.status.as_deref().unwrap()));
}
- Err(InvalidArgumentException {
- message: "String format specifier is missing".to_string(),
- code: 0,
- })
+ Err(InvalidArgumentException::new(
+ "String format specifier is missing".to_string(),
+ ))
}
pub fn is_excluded_by_no_proxy(&self) -> bool {
diff --git a/crates/shirabe/src/util/http_downloader.rs b/crates/shirabe/src/util/http_downloader.rs
index b60664da..e53ad82f 100644
--- a/crates/shirabe/src/util/http_downloader.rs
+++ b/crates/shirabe/src/util/http_downloader.rs
@@ -17,6 +17,7 @@ use crate::util::http::Response;
use crate::util::sync_executor;
use indexmap::IndexMap;
use shirabe_external_packages::composer::pcre::{CaptureKey, Preg};
+use shirabe_php_shim::Catch as _;
use shirabe_php_shim::{
InvalidArgumentException, LogicException, PhpMixed, array_replace_recursive, extension_loaded,
file_get_contents, function_exists, implode, is_numeric, php_regex, rawurldecode,
@@ -205,19 +206,14 @@ impl HttpDownloader {
return self.mock_get(url, &options);
}
if url.is_empty() {
- return Err(InvalidArgumentException {
- message: "$url must not be an empty string".to_string(),
- code: 0,
- }
+ return Err(InvalidArgumentException::new(
+ "$url must not be an empty string".to_string(),
+ )
.into());
}
if !sync && !self.allow_async {
- return Err(LogicException {
- message:
- "You must use the HttpDownloader instance which is part of a Composer\\Loop instance to be able to run async http requests"
- .to_string(),
- code: 0,
- }
+ return Err(LogicException::new("You must use the HttpDownloader instance which is part of a Composer\\Loop instance to be able to run async http requests"
+ .to_string())
.into());
}
@@ -321,7 +317,7 @@ impl HttpDownloader {
let curl = self.curl.as_ref().unwrap();
return match curl.download(&origin, url, options, copy_to).await {
Ok(Ok(response)) => Ok(response),
- Ok(Err(transport_exception)) => Err(transport_exception.into()),
+ Ok(Err(e)) => Err(e),
Err(e) => Err(e),
};
}
@@ -463,7 +459,7 @@ impl HttpDownloader {
/// @internal
pub fn get_exception_hints(e: &anyhow::Error) -> Option<Vec<String>> {
- let e_as_transport: Option<&TransportException> = e.downcast_ref::<TransportException>();
+ let e_as_transport: Option<&TransportException> = e.catch::<TransportException>();
e_as_transport?;
let e_as_transport = e_as_transport.unwrap();
@@ -600,11 +596,7 @@ impl HttpDownloader {
options: &IndexMap<String, PhpMixed>,
) -> anyhow::Result<Response> {
if file_url.is_empty() {
- return Err(LogicException {
- message: "url cannot be an empty string".to_string(),
- code: 0,
- }
- .into());
+ return Err(LogicException::new("url cannot be an empty string".to_string()).into());
}
let mock = self
diff --git a/crates/shirabe/src/util/no_proxy_pattern.rs b/crates/shirabe/src/util/no_proxy_pattern.rs
index 582fdb68..83adb09f 100644
--- a/crates/shirabe/src/util/no_proxy_pattern.rs
+++ b/crates/shirabe/src/util/no_proxy_pattern.rs
@@ -153,27 +153,24 @@ impl NoProxyPattern {
let mask = network.netmask.as_deref().unwrap_or_default();
let ip = target.ip.as_slice();
if net.is_empty() {
- return Err(RuntimeException {
- message: format!(
- "Could not parse network IP {}",
- String::from_utf8_lossy(net)
- ),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "Could not parse network IP {}",
+ String::from_utf8_lossy(net)
+ ))
.into());
}
if mask.is_empty() {
- return Err(RuntimeException {
- message: format!("Could not parse netmask {}", String::from_utf8_lossy(mask)),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "Could not parse netmask {}",
+ String::from_utf8_lossy(mask)
+ ))
.into());
}
if ip.is_empty() {
- return Err(RuntimeException {
- message: format!("Could not parse target IP {}", String::from_utf8_lossy(ip)),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "Could not parse target IP {}",
+ String::from_utf8_lossy(ip)
+ ))
.into());
}
@@ -327,23 +324,17 @@ impl NoProxyPattern {
// Get the network from the address and mask
if netmask.is_empty() {
- return Err(RuntimeException {
- message: format!(
- "Could not parse netmask {}",
- String::from_utf8_lossy(&netmask)
- ),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "Could not parse netmask {}",
+ String::from_utf8_lossy(&netmask)
+ ))
.into());
}
if range_ip.is_empty() {
- return Err(RuntimeException {
- message: format!(
- "Could not parse range IP {}",
- String::from_utf8_lossy(range_ip)
- ),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "Could not parse range IP {}",
+ String::from_utf8_lossy(range_ip)
+ ))
.into());
}
diff --git a/crates/shirabe/src/util/perforce.rs b/crates/shirabe/src/util/perforce.rs
index ac455fc7..d98f1edf 100644
--- a/crates/shirabe/src/util/perforce.rs
+++ b/crates/shirabe/src/util/perforce.rs
@@ -359,17 +359,13 @@ impl Perforce {
if index.is_none() {
return Ok(false);
}
- return Err(Exception {
- message: format!("p4 command not found in path: {}", error_output),
- code: 0,
- }
+ return Err(Exception::new(format!(
+ "p4 command not found in path: {}",
+ error_output
+ ))
.into());
}
- return Err(Exception {
- message: format!("Invalid user name: {}", user),
- code: 0,
- }
- .into());
+ return Err(Exception::new(format!("Invalid user name: {}", user)).into());
}
Ok(true)
@@ -497,11 +493,7 @@ impl Perforce {
let spec = match fopen(&client_spec, "w") {
Ok(spec) => spec,
Err(e) => {
- return Err(Exception {
- message: e.to_string(),
- code: 0,
- }
- .into());
+ return Err(Exception::new(e.to_string()).into());
}
};
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
@@ -509,11 +501,7 @@ impl Perforce {
}));
if let Err(e) = result {
fclose(&spec);
- return Err(Exception {
- message: format!("{:?}", e),
- code: 0,
- }
- .into());
+ return Err(Exception::new(format!("{:?}", e)).into());
}
fclose(&spec);
Ok(())
@@ -565,13 +553,10 @@ impl Perforce {
process.run(None, indexmap::IndexMap::new())?;
if !process.is_successful() {
- return Err(Exception {
- message: format!(
- "Error logging in:{}",
- self.process.borrow().get_error_output()
- ),
- code: 0,
- }
+ return Err(Exception::new(format!(
+ "Error logging in:{}",
+ self.process.borrow().get_error_output()
+ ))
.into());
}
}
diff --git a/crates/shirabe/src/util/platform.rs b/crates/shirabe/src/util/platform.rs
index a71fea92..2bb5cf99 100644
--- a/crates/shirabe/src/util/platform.rs
+++ b/crates/shirabe/src/util/platform.rs
@@ -36,10 +36,9 @@ impl Platform {
return Ok(String::new());
}
- return Err(RuntimeException {
- message: "Could not determine the current working directory".to_string(),
- code: 0,
- }
+ return Err(RuntimeException::new(
+ "Could not determine the current working directory".to_string(),
+ )
.into());
}
@@ -159,11 +158,7 @@ impl Platform {
}
}
- Err(RuntimeException {
- message: "Could not determine user directory".to_string(),
- code: 0,
- }
- .into())
+ Err(RuntimeException::new("Could not determine user directory".to_string()).into())
}
/// @return bool Whether the host machine is running on the Windows Subsystem for Linux (WSL)
diff --git a/crates/shirabe/src/util/process_executor.rs b/crates/shirabe/src/util/process_executor.rs
index 463c5d19..b9373b6f 100644
--- a/crates/shirabe/src/util/process_executor.rs
+++ b/crates/shirabe/src/util/process_executor.rs
@@ -13,6 +13,7 @@ use shirabe_external_packages::symfony::process::Process;
use shirabe_external_packages::symfony::process::ProcessMock;
use shirabe_external_packages::symfony::process::exception::ProcessSignaledException;
use shirabe_external_packages::symfony::process::exception::RuntimeException as SymfonyProcessRuntimeException;
+use shirabe_php_shim::Catch as _;
use shirabe_php_shim::{
LogicException, PHP_EOL, PhpMixed, RuntimeException, array_intersect, array_map,
escapeshellarg, explode, implode, in_array_strict, is_array, is_dir, is_numeric, is_string,
@@ -253,17 +254,13 @@ impl ProcessExecutor {
Some(Self::get_timeout() as f64),
)?;
} else {
- return Err(LogicException {
- message: "Invalid command type".to_string(),
- code: 0,
- }
- .into());
+ return Err(LogicException::new("Invalid command type".to_string()).into());
}
if !Platform::is_windows() && tty {
// PHP: try { $process->setTty(true); } catch (RuntimeException $e) { /* ignore */ }
if let Err(e) = process.set_tty(true)
- && e.downcast_ref::<SymfonyProcessRuntimeException>().is_none()
+ && !e.is_instanceof::<SymfonyProcessRuntimeException>()
{
return Err(e);
}
@@ -312,7 +309,7 @@ impl ProcessExecutor {
let final_result: anyhow::Result<()> = match result {
Ok(()) => Ok(()),
Err(e) => {
- if let Some(pse) = e.downcast_ref::<ProcessSignaledException>() {
+ if let Some(pse) = e.catch::<ProcessSignaledException>() {
if signal_handler.is_triggered() {
// exiting as we were signaled and the child process exited too due to the signal
signal_handler.exit_with_last_signal();
@@ -451,21 +448,18 @@ impl ProcessExecutor {
// strict-mode mismatch) extends `\RuntimeException`, so PHP call sites that
// `catch (\RuntimeException $e)` around a mock-driven git/hg/svn call (e.g.
// `GitDriver::supports`) treat a mismatch as an ordinary recoverable failure. Using
- // the same `RuntimeException` type here keeps `downcast_ref::<RuntimeException>()`
- // checks working the same way against a mismatch.
- return Err(RuntimeException {
- message: format!(
- "Received unexpected command {:?} in \"{}\"{}{}{}Received calls:{}{}",
- command,
- cwd.unwrap_or(""),
- PHP_EOL,
- expected,
- PHP_EOL,
- PHP_EOL,
- received
- ),
- code: 0,
- }
+ // the same `RuntimeException` type here keeps `catch::<RuntimeException>()` checks
+ // working the same way against a mismatch.
+ return Err(RuntimeException::new(format!(
+ "Received unexpected command {:?} in \"{}\"{}{}{}Received calls:{}{}",
+ command,
+ cwd.unwrap_or(""),
+ PHP_EOL,
+ expected,
+ PHP_EOL,
+ PHP_EOL,
+ received
+ ))
.into());
}
@@ -645,10 +639,7 @@ impl ProcessExecutor {
Box::pin(async move {
if !allow_async {
- return Err(LogicException {
- message: "You must use the ProcessExecutor instance which is part of a Composer\\Loop instance to be able to run async processes".to_string(),
- code: 0,
- }
+ return Err(LogicException::new("You must use the ProcessExecutor instance which is part of a Composer\\Loop instance to be able to run async processes".to_string())
.into());
}
@@ -682,11 +673,7 @@ impl ProcessExecutor {
Some(Self::get_timeout() as f64),
)?
} else {
- return Err(LogicException {
- message: "Invalid command type".to_string(),
- code: 0,
- }
- .into());
+ return Err(LogicException::new("Invalid command type".to_string()).into());
};
process.start(None, IndexMap::new())?;
diff --git a/crates/shirabe/src/util/remote_filesystem.rs b/crates/shirabe/src/util/remote_filesystem.rs
index 2dafc0d3..e2901b2c 100644
--- a/crates/shirabe/src/util/remote_filesystem.rs
+++ b/crates/shirabe/src/util/remote_filesystem.rs
@@ -14,6 +14,7 @@ use crate::util::http::ProxyManager;
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::{
PHP_URL_HOST, PHP_URL_PATH, PHP_URL_SCHEME, PHP_VERSION_ID, PhpMixed, RuntimeException,
STREAM_NOTIFY_FAILURE, STREAM_NOTIFY_FILE_SIZE_IS, STREAM_NOTIFY_PROGRESS,
@@ -216,12 +217,11 @@ impl RemoteFilesystem {
let mut file_url = file_url.to_string();
if options.contains_key("prevent_ip_access_callable") {
- return Err(anyhow::anyhow!(RuntimeException {
- message:
- "RemoteFilesystem doesn't support the 'prevent_ip_access_callable' config."
- .to_string(),
- code: 0,
- }));
+ return Err(RuntimeException::new(
+ "RemoteFilesystem doesn't support the 'prevent_ip_access_callable' config."
+ .to_string(),
+ )
+ .into());
}
if let Some(token) = options.get("gitlab-token").cloned() {
@@ -404,7 +404,7 @@ impl RemoteFilesystem {
})();
let mut caught_e: Option<anyhow::Error> = None;
if let Err(mut e) = inner_result {
- if let Some(te) = e.downcast_mut::<TransportException>() {
+ if let Some(te) = e.catch_mut::<TransportException>() {
if !http_response_header.is_empty() && !http_response_header[0].is_empty() {
te.set_headers(http_response_header.clone());
te.set_status_code(Self::find_status_code(&http_response_header));
@@ -535,7 +535,7 @@ impl RemoteFilesystem {
);
}
- let mut e = TransportException::new_with_code(
+ let mut e = TransportException::new(
format!(
"The \"{}\" file could not be downloaded ({})",
self.file_url, http_response_header[0]
@@ -607,13 +607,14 @@ impl RemoteFilesystem {
if result.is_some() && file_name.is_some() && !is_redirect {
let result_str = result.as_deref().unwrap();
if result_str.is_empty() {
- return Err(anyhow::anyhow!(TransportException::new(
+ return Err(TransportException::new(
format!(
"\"{}\" appears broken, and returned an empty 200 response",
self.file_url
),
0,
- )));
+ )
+ .into());
}
// TODO(phase-c): PHP captures the file_put_contents warning here via set_error_handler
@@ -623,7 +624,7 @@ impl RemoteFilesystem {
let write_result =
file_put_contents(file_name.as_deref().unwrap(), result_str.as_bytes());
if write_result.is_none() {
- return Err(anyhow::anyhow!(TransportException::new(
+ return Err(TransportException::new(
format!(
"The \"{}\" file could not be written to {}: {}",
self.file_url,
@@ -631,7 +632,8 @@ impl RemoteFilesystem {
put_error_message
),
0,
- )));
+ )
+ .into());
}
let _ = put_error_message;
}
@@ -659,7 +661,7 @@ impl RemoteFilesystem {
}
if result.is_none() {
- let mut e = TransportException::new_with_code(
+ let mut e = TransportException::new(
format!(
"The \"{}\" file could not be downloaded: {}",
self.file_url, error_message
@@ -750,11 +752,12 @@ impl RemoteFilesystem {
&& let Some(max) = max_file_size
&& Platform::strlen(r) >= max
{
- return Err(anyhow::anyhow!(MaxFileSizeExceededException::new(format!(
+ return Err(MaxFileSizeExceededException::new(format!(
"Maximum allowed download size reached. Downloaded {} of allowed {} bytes",
Platform::strlen(r),
max
- ))));
+ ))
+ .into());
}
if PHP_VERSION_ID >= 80400 {
@@ -785,14 +788,15 @@ impl RemoteFilesystem {
match notification_code {
x if x == STREAM_NOTIFY_FAILURE => {
if 400 == message_code {
- return Err(anyhow::anyhow!(TransportException::new_with_code(
+ return Err(TransportException::new(
format!(
"The '{}' URL could not be accessed: {}",
self.file_url,
message.unwrap_or_default()
),
message_code,
- )));
+ )
+ .into());
}
}
x if x == STREAM_NOTIFY_FILE_SIZE_IS => {
@@ -848,10 +852,7 @@ impl RemoteFilesystem {
self.retry = result.retry;
if self.retry {
- return Err(anyhow::anyhow!(TransportException::new(
- "RETRY".to_string(),
- 0,
- )));
+ return Err(TransportException::new("RETRY".to_string(), 0).into());
}
Ok(())
}
@@ -1043,10 +1044,11 @@ impl RemoteFilesystem {
// RemoteFilesystem as a String; from_utf8_lossy can corrupt binary payloads
Some(d) => Some(String::from_utf8_lossy(&d).into_owned()),
None => {
- return Err(anyhow::anyhow!(TransportException::new(
+ return Err(TransportException::new(
"Failed to decode zlib stream".to_string(),
0,
- )));
+ )
+ .into());
}
};
}
diff --git a/crates/shirabe/src/util/stream_context_factory.rs b/crates/shirabe/src/util/stream_context_factory.rs
index cae00c08..b407e897 100644
--- a/crates/shirabe/src/util/stream_context_factory.rs
+++ b/crates/shirabe/src/util/stream_context_factory.rs
@@ -22,7 +22,7 @@ impl StreamContextFactory {
url: &str,
default_options: IndexMap<String, PhpMixed>,
default_params: IndexMap<String, PhpMixed>,
- ) -> anyhow::Result<PhpMixed, TransportException> {
+ ) -> anyhow::Result<PhpMixed, Box<TransportException>> {
let mut options: IndexMap<String, PhpMixed> = {
let mut http = IndexMap::new();
// specify defaults again to try and work better with curlwrappers enabled
@@ -66,7 +66,7 @@ impl StreamContextFactory {
url: &str,
mut options: IndexMap<String, PhpMixed>,
for_curl: bool,
- ) -> anyhow::Result<IndexMap<String, PhpMixed>, TransportException> {
+ ) -> anyhow::Result<IndexMap<String, PhpMixed>, Box<TransportException>> {
// Make sure the headers are in an array form
let has_header = options
.get("http")
@@ -105,23 +105,23 @@ impl StreamContextFactory {
if proxy.is_secure() {
if !extension_loaded("openssl") {
- return Err(TransportException::new(
+ return Err(Box::new(TransportException::new(
"You must enable the openssl extension to use a secure proxy."
.to_string(),
0,
- ));
+ )));
}
if is_https_request {
- return Err(TransportException::new(
+ return Err(Box::new(TransportException::new(
"You must enable the curl extension to make https requests through a secure proxy.".to_string(),
0,
- ));
+ )));
}
} else if is_https_request && !extension_loaded("openssl") {
- return Err(TransportException::new(
+ return Err(Box::new(TransportException::new(
"You must enable the openssl extension to make https requests through a proxy.".to_string(),
0,
- ));
+ )));
}
// Header will be a Proxy-Authorization string or not set
@@ -224,7 +224,7 @@ impl StreamContextFactory {
// `logger` was a PSR LoggerInterface; CaBundle is slated for removal so
// it is now an unused `()` placeholder.
logger: (),
- ) -> anyhow::Result<IndexMap<String, PhpMixed>, TransportException> {
+ ) -> anyhow::Result<IndexMap<String, PhpMixed>, Box<TransportException>> {
let ciphers = [
"ECDHE-RSA-AES128-GCM-SHA256",
"ECDHE-ECDSA-AES128-GCM-SHA256",
@@ -336,10 +336,10 @@ impl StreamContextFactory {
if let Some(ref cafile) = cafile
&& (!Filesystem::is_readable(cafile) || !CaBundle::validate_ca_file(cafile, logger))
{
- return Err(TransportException::new(
+ return Err(Box::new(TransportException::new(
"The configured cafile was not valid or could not be read.".to_string(),
0,
- ));
+ )));
}
let capath = defaults
@@ -351,10 +351,10 @@ impl StreamContextFactory {
if let Some(ref capath) = capath
&& (!shirabe_php_shim::is_dir(capath) || !Filesystem::is_readable(capath))
{
- return Err(TransportException::new(
+ return Err(Box::new(TransportException::new(
"The configured capath was not valid or could not be read.".to_string(),
0,
- ));
+ )));
}
// Disable TLS compression to prevent CRIME attacks where supported.
diff --git a/crates/shirabe/src/util/svn.rs b/crates/shirabe/src/util/svn.rs
index a2974760..aaa0c6d1 100644
--- a/crates/shirabe/src/util/svn.rs
+++ b/crates/shirabe/src/util/svn.rs
@@ -177,11 +177,7 @@ impl Svn {
&& stripos(&full_output, "svn: E170001:").is_none()
&& stripos(&full_output, "svn: E215004:").is_none()
{
- return Err(RuntimeException {
- message: full_output,
- code: 0,
- }
- .into());
+ return Err(RuntimeException::new(full_output).into());
}
if !self.has_auth() {
@@ -196,11 +192,7 @@ impl Svn {
return self.execute_with_auth_retry(svn_command, cwd, url, path, verbose);
}
- Err(RuntimeException {
- message: format!("wrong credentials provided ({})", full_output),
- code: 0,
- }
- .into())
+ Err(RuntimeException::new(format!("wrong credentials provided ({})", full_output)).into())
}
pub fn set_cache_credentials(&mut self, cache_credentials: bool) {
@@ -213,10 +205,9 @@ impl Svn {
pub(crate) fn do_auth_dance(&mut self) -> anyhow::Result<&mut Self> {
// cannot ask for credentials in non interactive mode
if !self.io.is_interactive() {
- return Err(RuntimeException {
- message: "can not ask for authentication in non interactive mode".to_string(),
- code: 0,
- }
+ return Err(RuntimeException::new(
+ "can not ask for authentication in non interactive mode".to_string(),
+ )
.into());
}
@@ -310,11 +301,7 @@ impl Svn {
/// @throws \LogicException
pub(crate) fn get_password(&self) -> anyhow::Result<String> {
if self.credentials.is_none() {
- return Err(LogicException {
- message: "No svn auth detected.".to_string(),
- code: 0,
- }
- .into());
+ return Err(LogicException::new("No svn auth detected.".to_string()).into());
}
Ok(self.credentials.as_ref().unwrap().password.clone())
@@ -325,11 +312,7 @@ impl Svn {
/// @throws \LogicException
pub(crate) fn get_username(&self) -> anyhow::Result<String> {
if self.credentials.is_none() {
- return Err(LogicException {
- message: "No svn auth detected.".to_string(),
- code: 0,
- }
- .into());
+ return Err(LogicException::new("No svn auth detected.".to_string()).into());
}
Ok(self.credentials.as_ref().unwrap().username.clone())
diff --git a/crates/shirabe/src/util/tar.rs b/crates/shirabe/src/util/tar.rs
index f5b0ebbe..94320edb 100644
--- a/crates/shirabe/src/util/tar.rs
+++ b/crates/shirabe/src/util/tar.rs
@@ -20,10 +20,8 @@ impl Tar {
/// UTF-8 could never survive the JSON parsing that follows in PHP either.
fn content_to_string(content: Vec<u8>) -> anyhow::Result<String> {
String::from_utf8(content).map_err(|_| {
- anyhow::anyhow!(RuntimeException {
- message: "composer.json in the archive is not valid UTF-8".to_string(),
- code: 0,
- })
+ RuntimeException::new("composer.json in the archive is not valid UTF-8".to_string())
+ .into()
})
}
@@ -38,17 +36,14 @@ impl Tar {
if folder_file.is_dir() {
top_level_paths.insert(name, true);
if top_level_paths.len() > 1 {
- return Err(anyhow::anyhow!(RuntimeException {
- message: format!(
- "Archive has more than one top level directories, and no composer.json was found on the top level, so it's an invalid archive. Top level paths found were: {}",
- top_level_paths
- .keys()
- .cloned()
- .collect::<Vec<_>>()
- .join(",")
- ),
- code: 0,
- }));
+ return Err(RuntimeException::new(format!(
+ "Archive has more than one top level directories, and no composer.json was found on the top level, so it's an invalid archive. Top level paths found were: {}",
+ top_level_paths
+ .keys()
+ .cloned()
+ .collect::<Vec<_>>()
+ .join(",")
+ )).into());
}
}
}
@@ -63,11 +58,10 @@ impl Tar {
return Self::content_to_string(file.get_content());
}
- Err(anyhow::anyhow!(RuntimeException {
- message:
- "No composer.json found either at the top level or within the topmost directory"
- .to_string(),
- code: 0,
- }))
+ Err(RuntimeException::new(
+ "No composer.json found either at the top level or within the topmost directory"
+ .to_string(),
+ )
+ .into())
}
}
diff --git a/crates/shirabe/src/util/zip.rs b/crates/shirabe/src/util/zip.rs
index a671d63b..0ba177d0 100644
--- a/crates/shirabe/src/util/zip.rs
+++ b/crates/shirabe/src/util/zip.rs
@@ -10,10 +10,9 @@ pub struct Zip;
impl Zip {
pub fn get_composer_json(path_to_zip: &str) -> anyhow::Result<Option<String>> {
if !extension_loaded("zip") {
- return Err(RuntimeException {
- message: "The Zip Util requires PHP's zip extension".to_string(),
- code: 0,
- }
+ return Err(RuntimeException::new(
+ "The Zip Util requires PHP's zip extension".to_string(),
+ )
.into());
}
@@ -64,13 +63,10 @@ impl Zip {
if dir_name == "." {
top_level_paths.insert(name, true);
if top_level_paths.len() > 1 {
- return Err(RuntimeException {
- message: format!(
- "Archive has more than one top level directories, and no composer.json was found on the top level, so it's an invalid archive. Top level paths found were: {}",
- implode(",", &top_level_paths.keys().cloned().collect::<Vec<_>>())
- ),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "Archive has more than one top level directories, and no composer.json was found on the top level, so it's an invalid archive. Top level paths found were: {}",
+ implode(",", &top_level_paths.keys().cloned().collect::<Vec<_>>())
+ ))
.into());
}
continue;
@@ -80,13 +76,10 @@ impl Zip {
if !dir_name.contains('\\') && !dir_name.contains('/') {
top_level_paths.insert(format!("{}/", dir_name), true);
if top_level_paths.len() > 1 {
- return Err(RuntimeException {
- message: format!(
- "Archive has more than one top level directories, and no composer.json was found on the top level, so it's an invalid archive. Top level paths found were: {}",
- implode(",", &top_level_paths.keys().cloned().collect::<Vec<_>>())
- ),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "Archive has more than one top level directories, and no composer.json was found on the top level, so it's an invalid archive. Top level paths found were: {}",
+ implode(",", &top_level_paths.keys().cloned().collect::<Vec<_>>())
+ ))
.into());
}
}
@@ -101,12 +94,10 @@ impl Zip {
}
}
- Err(RuntimeException {
- message:
- "No composer.json found either at the top level or within the topmost directory"
- .to_string(),
- code: 0,
- }
+ Err(RuntimeException::new(
+ "No composer.json found either at the top level or within the topmost directory"
+ .to_string(),
+ )
.into())
}
}