aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/src/downloader
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/downloader
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/downloader')
-rw-r--r--crates/shirabe/src/downloader/archive_downloader.rs16
-rw-r--r--crates/shirabe/src/downloader/download_manager.rs71
-rw-r--r--crates/shirabe/src/downloader/file_downloader.rs54
-rw-r--r--crates/shirabe/src/downloader/filesystem_exception.rs18
-rw-r--r--crates/shirabe/src/downloader/fossil_downloader.rs24
-rw-r--r--crates/shirabe/src/downloader/git_downloader.rs188
-rw-r--r--crates/shirabe/src/downloader/gzip_downloader.rs5
-rw-r--r--crates/shirabe/src/downloader/hg_downloader.rs44
-rw-r--r--crates/shirabe/src/downloader/max_file_size_exceeded_exception.rs14
-rw-r--r--crates/shirabe/src/downloader/path_downloader.rs100
-rw-r--r--crates/shirabe/src/downloader/rar_downloader.rs27
-rw-r--r--crates/shirabe/src/downloader/svn_downloader.rs73
-rw-r--r--crates/shirabe/src/downloader/transport_exception.rs34
-rw-r--r--crates/shirabe/src/downloader/vcs_downloader.rs78
-rw-r--r--crates/shirabe/src/downloader/zip_downloader.rs84
15 files changed, 334 insertions, 496 deletions
diff --git a/crates/shirabe/src/downloader/archive_downloader.rs b/crates/shirabe/src/downloader/archive_downloader.rs
index 6ddf29b6..d2ee4a75 100644
--- a/crates/shirabe/src/downloader/archive_downloader.rs
+++ b/crates/shirabe/src/downloader/archive_downloader.rs
@@ -9,6 +9,7 @@ use crate::util::Filesystem;
use crate::util::Platform;
use indexmap::IndexMap;
use shirabe_external_packages::symfony::finder::Finder;
+use shirabe_php_shim::Catch as _;
use shirabe_php_shim::{
DIRECTORY_SEPARATOR, PhpMixed, RuntimeException, bin2hex, file_exists, is_dir, random_bytes,
realpath,
@@ -155,7 +156,7 @@ pub trait ArchiveDownloader {
Ok(false) => {}
Err(e) => {
// ignore error, and simply do not renameAsOne
- if e.downcast_ref::<RuntimeException>().is_none() {
+ if !e.is_instanceof::<RuntimeException>() {
return Err(e);
}
}
@@ -273,14 +274,11 @@ fn rename_recursively(
);
if is_dir(&target) {
if !is_dir(file) {
- return Err(RuntimeException {
- message: format!(
- "Installing {} would lead to overwriting the {} directory with a file from the package, invalid operation.",
- package,
- target.display()
- ),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "Installing {} would lead to overwriting the {} directory with a file from the package, invalid operation.",
+ package,
+ target.display()
+ ))
.into());
}
rename_recursively(filesystem, package.clone(), file, &target)?;
diff --git a/crates/shirabe/src/downloader/download_manager.rs b/crates/shirabe/src/downloader/download_manager.rs
index 423eda28..8c10de5d 100644
--- a/crates/shirabe/src/downloader/download_manager.rs
+++ b/crates/shirabe/src/downloader/download_manager.rs
@@ -9,6 +9,7 @@ use crate::package::PackageInterfaceHandle;
use crate::util::Filesystem;
use indexmap::IndexMap;
use shirabe_external_packages::composer::pcre::Preg;
+use shirabe_php_shim::Catch as _;
use shirabe_php_shim::{
InvalidArgumentException, LogicException, PhpMixed, RuntimeException, array_keys,
array_reverse, array_shift, dirname, implode, in_array_strict, preg_quote, rtrim, str_replace,
@@ -99,14 +100,11 @@ impl DownloadManager {
) -> anyhow::Result<std::rc::Rc<std::cell::RefCell<dyn DownloaderInterface>>> {
let r#type = strtolower(r#type);
if !self.downloaders.contains_key(&r#type) {
- return Err(InvalidArgumentException {
- message: format!(
- "Unknown downloader type: {}. Available types: {}.",
- r#type,
- implode(", ", &array_keys(&self.downloaders)),
- ),
- code: 0,
- }
+ return Err(InvalidArgumentException::new(format!(
+ "Unknown downloader type: {}. Available types: {}.",
+ r#type,
+ implode(", ", &array_keys(&self.downloaders)),
+ ))
.into());
}
@@ -134,28 +132,22 @@ impl DownloadManager {
} else if installation_source.as_deref() == Some("source") {
self.get_downloader(&package.get_source_type().unwrap_or_default())?
} else {
- return Err(InvalidArgumentException {
- message: format!(
- "Package {} does not have an installation source set",
- package,
- ),
- code: 0,
- }
+ return Err(InvalidArgumentException::new(format!(
+ "Package {} does not have an installation source set",
+ package,
+ ))
.into());
};
let downloader_installation_source = downloader.borrow().get_installation_source();
if installation_source.as_deref() != Some(&downloader_installation_source) {
- return Err(LogicException {
- message: format!(
- "Downloader \"{}\" is a {} type downloader and can not be used to download {} for package {}",
- downloader.borrow().php_class_name(),
- downloader_installation_source,
- installation_source.unwrap_or_default(),
- package,
- ),
- code: 0,
- }
+ return Err(LogicException::new(format!(
+ "Downloader \"{}\" is a {} type downloader and can not be used to download {} for package {}",
+ downloader.borrow().php_class_name(),
+ downloader_installation_source,
+ installation_source.unwrap_or_default(),
+ package,
+ ))
.into());
}
@@ -227,19 +219,18 @@ impl DownloadManager {
{
Ok(r) => r,
Err(e) => {
- let is_runtime = e.downcast_ref::<RuntimeException>().is_some();
- let is_irrecoverable =
- e.downcast_ref::<IrrecoverableDownloadException>().is_some();
- if is_runtime && !is_irrecoverable {
+ if e.is_instanceof::<RuntimeException>()
+ && !e.is_instanceof::<IrrecoverableDownloadException>()
+ {
if sources.is_empty() {
return Err(e);
}
let message = e
- .downcast_ref::<RuntimeException>()
+ .catch::<RuntimeException>()
.unwrap()
- .message
- .clone();
+ .get_message()
+ .to_string();
self.io.write_error3(
&format!(
" <warning>Failed to download {} from {}: {}</warning>",
@@ -352,17 +343,17 @@ impl DownloadManager {
Ok(p) => return Ok(p),
Err(e) => {
// PHP catches only \RuntimeException; other exceptions propagate uncaught.
- if e.downcast_ref::<RuntimeException>().is_none() {
+ if !e.is_instanceof::<RuntimeException>() {
return Err(e);
}
if !self.io.is_interactive() {
return Err(e);
}
let message = e
- .downcast_ref::<RuntimeException>()
+ .catch::<RuntimeException>()
.unwrap()
- .message
- .clone();
+ .get_message()
+ .to_string();
self.io.write_error3(
&format!("<error> Update failed ({})</error>", message),
true,
@@ -477,10 +468,10 @@ impl DownloadManager {
}
if sources.is_empty() {
- return Err(InvalidArgumentException {
- message: format!("Package {} must have a source or dist specified", package),
- code: 0,
- }
+ return Err(InvalidArgumentException::new(format!(
+ "Package {} must have a source or dist specified",
+ package
+ ))
.into());
}
diff --git a/crates/shirabe/src/downloader/file_downloader.rs b/crates/shirabe/src/downloader/file_downloader.rs
index cdcf750e..9b86ee56 100644
--- a/crates/shirabe/src/downloader/file_downloader.rs
+++ b/crates/shirabe/src/downloader/file_downloader.rs
@@ -25,6 +25,7 @@ use crate::util::Silencer;
use crate::util::Url as UrlUtil;
use crate::util::sync_executor;
use indexmap::IndexMap;
+use shirabe_php_shim::Catch as _;
use shirabe_php_shim::{
DIRECTORY_SEPARATOR, InvalidArgumentException, PATHINFO_BASENAME, PATHINFO_EXTENSION,
PHP_URL_PATH, PhpMixed, RuntimeException, UnexpectedValueException, array_search, file_exists,
@@ -359,11 +360,9 @@ impl FileDownloader {
url: &str,
) -> anyhow::Result<String> {
if !shirabe_php_shim::extension_loaded("openssl") && Some(0) == strpos(url, "https:") {
- return Err(RuntimeException {
- message: "You must enable the openssl extension to download files via https"
- .to_string(),
- code: 0,
- }
+ return Err(RuntimeException::new(
+ "You must enable the openssl extension to download files via https".to_string(),
+ )
.into());
}
@@ -400,10 +399,9 @@ impl DownloaderInterface for FileDownloader {
output: bool,
) -> anyhow::Result<Option<PhpMixed>> {
if package.get_dist_url().is_none() {
- return Err(InvalidArgumentException {
- message: "The given package is missing url information".to_string(),
- code: 0,
- }
+ return Err(InvalidArgumentException::new(
+ "The given package is missing url information".to_string(),
+ )
.into());
}
@@ -558,15 +556,15 @@ impl DownloaderInterface for FileDownloader {
}
self.clear_last_cache_write(package.clone());
- if e.downcast_ref::<IrrecoverableDownloadException>().is_some() {
+ if e.is_instanceof::<IrrecoverableDownloadException>() {
return Err(e);
}
- if e.downcast_ref::<MaxFileSizeExceededException>().is_some() {
+ if e.is_instanceof::<MaxFileSizeExceededException>() {
return Err(e);
}
- if let Some(te) = e.downcast_ref::<TransportException>() {
+ if let Some(te) = e.catch::<TransportException>() {
// if we got an http response with a proper code, then requesting again will probably not help, abort
if 0 != te.get_code() && !matches!(te.get_code(), 500 | 502 | 503 | 504)
{
@@ -592,7 +590,7 @@ impl DownloaderInterface for FileDownloader {
}
if !urls.is_empty() {
let code = e
- .downcast_ref::<TransportException>()
+ .catch::<TransportException>()
.map_or(0, |te| te.get_code());
if self.io.borrow().is_debug() {
self.io.borrow().write_error(&format!(
@@ -628,13 +626,10 @@ impl DownloaderInterface for FileDownloader {
// === $result->then(verify) ===
if !file_exists(&file_name) {
- return Err(UnexpectedValueException {
- message: format!(
- "{} could not be saved to {}, make sure the directory is writable and you have internet connectivity",
- url.base, file_name
- ),
- code: 0,
- }
+ return Err(UnexpectedValueException::new(format!(
+ "{} could not be saved to {}, make sure the directory is writable and you have internet connectivity",
+ url.base, file_name
+ ))
.into());
}
@@ -642,13 +637,10 @@ impl DownloaderInterface for FileDownloader {
&& !checksum.is_empty()
&& hash_file("sha1", &file_name).as_deref() != Some(checksum)
{
- return Err(UnexpectedValueException {
- message: format!(
- "The checksum verification of the file failed (downloaded from {})",
- url.base
- ),
- code: 0,
- }
+ return Err(UnexpectedValueException::new(format!(
+ "The checksum verification of the file failed (downloaded from {})",
+ url.base
+ ))
.into());
}
@@ -809,10 +801,10 @@ impl DownloaderInterface for FileDownloader {
}
let result = Filesystem::remove_directory_async_via(&self.filesystem, path).await?;
if !result {
- return Err(RuntimeException {
- message: format!("Could not completely delete {}, aborting.", path),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "Could not completely delete {}, aborting.",
+ path
+ ))
.into());
}
diff --git a/crates/shirabe/src/downloader/filesystem_exception.rs b/crates/shirabe/src/downloader/filesystem_exception.rs
index f0aa831f..6e90e328 100644
--- a/crates/shirabe/src/downloader/filesystem_exception.rs
+++ b/crates/shirabe/src/downloader/filesystem_exception.rs
@@ -7,17 +7,15 @@ pub struct FilesystemException(pub Exception);
impl FilesystemException {
pub fn new(message: String, code: i64) -> Self {
- FilesystemException(Exception {
- message: format!("Filesystem exception: \n{}", message),
+ FilesystemException(Exception::with_code(
+ format!("Filesystem exception: \n{}", message),
code,
- })
+ ))
}
}
-impl std::fmt::Display for FilesystemException {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- self.0.fmt(f)
- }
-}
-
-impl std::error::Error for FilesystemException {}
+shirabe_php_shim::impl_php_exception!(
+ FilesystemException,
+ 0,
+ r"Composer\Downloader\FilesystemException"
+);
diff --git a/crates/shirabe/src/downloader/fossil_downloader.rs b/crates/shirabe/src/downloader/fossil_downloader.rs
index 72409a1f..86a44f0b 100644
--- a/crates/shirabe/src/downloader/fossil_downloader.rs
+++ b/crates/shirabe/src/downloader/fossil_downloader.rs
@@ -47,14 +47,11 @@ impl FossilDownloader {
.execute(&command, output, cwd.as_deref())?
!= 0
{
- return Err(RuntimeException {
- message: format!(
- "Failed to execute {}\n\n{}",
- command.join(" "),
- self.inner.process.borrow().get_error_output()
- ),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "Failed to execute {}\n\n{}",
+ command.join(" "),
+ self.inner.process.borrow().get_error_output()
+ ))
.into());
}
Ok(())
@@ -168,13 +165,10 @@ impl VcsDownloader for FossilDownloader {
));
if !self.has_metadata_repository(path) {
- return Err(RuntimeException {
- message: format!(
- "The .fslckout file is missing from {}, see https://getcomposer.org/commit-deps for more information",
- path
- ),
- code: 0,
- }.into());
+ return Err(RuntimeException::new(format!(
+ "The .fslckout file is missing from {}, see https://getcomposer.org/commit-deps for more information",
+ path
+ )).into());
}
let real_path = shirabe_php_shim::realpath(path);
diff --git a/crates/shirabe/src/downloader/git_downloader.rs b/crates/shirabe/src/downloader/git_downloader.rs
index 275050fd..0a32d2fd 100644
--- a/crates/shirabe/src/downloader/git_downloader.rs
+++ b/crates/shirabe/src/downloader/git_downloader.rs
@@ -86,14 +86,11 @@ impl GitDownloader {
.execute_args(&command, &mut output, Some(&path))
!= 0
{
- return Err(RuntimeException {
- message: format!(
- "Failed to execute {}\n\n{}",
- implode(" ", &command),
- self.inner.process.borrow().get_error_output(),
- ),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "Failed to execute {}\n\n{}",
+ implode(" ", &command),
+ self.inner.process.borrow().get_error_output(),
+ ))
.into());
}
@@ -186,14 +183,11 @@ impl GitDownloader {
Some(&path),
) != 0
{
- return Err(RuntimeException {
- message: format!(
- "Failed to execute {}\n\n{}",
- implode(" ", &command),
- self.inner.process.borrow().get_error_output(),
- ),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "Failed to execute {}\n\n{}",
+ implode(" ", &command),
+ self.inner.process.borrow().get_error_output(),
+ ))
.into());
}
@@ -232,14 +226,11 @@ impl GitDownloader {
.execute_args(&command, &mut output, Some(&path))
!= 0
{
- return Err(RuntimeException {
- message: format!(
- "Failed to execute {}\n\n{}",
- implode(" ", &command),
- self.inner.process.borrow().get_error_output(),
- ),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "Failed to execute {}\n\n{}",
+ implode(" ", &command),
+ self.inner.process.borrow().get_error_output(),
+ ))
.into());
}
refs = trim(&output, None);
@@ -486,15 +477,12 @@ impl GitDownloader {
let command = format!("{} && {}", implode(" ", &command1), implode(" ", &command2));
- Err(RuntimeException {
- message: Url::sanitize(format!(
- "Failed to execute {}\n\n{}{}",
- command,
- self.inner.process.borrow().get_error_output(),
- exception_extra,
- )),
- code: 0,
- }
+ Err(RuntimeException::new(Url::sanitize(format!(
+ "Failed to execute {}\n\n{}{}",
+ command,
+ self.inner.process.borrow().get_error_output(),
+ exception_extra,
+ )))
.into())
}
@@ -570,11 +558,9 @@ impl GitDownloader {
Some(&path),
) != 0
{
- return Err(RuntimeException {
- message: format!("Could not reset changes\n\n:{}", output),
- code: 0,
- }
- .into());
+ return Err(
+ RuntimeException::new(format!("Could not reset changes\n\n:{}", output)).into(),
+ );
}
let mut output = String::new();
if self.inner.process.borrow_mut().execute_args(
@@ -583,11 +569,9 @@ impl GitDownloader {
Some(&path),
) != 0
{
- return Err(RuntimeException {
- message: format!("Could not reset changes\n\n:{}", output),
- code: 0,
- }
- .into());
+ return Err(
+ RuntimeException::new(format!("Could not reset changes\n\n:{}", output)).into(),
+ );
}
self.has_discarded_changes.borrow_mut().insert(path, true);
@@ -609,11 +593,9 @@ impl GitDownloader {
Some(&path),
) != 0
{
- return Err(RuntimeException {
- message: format!("Could not stash changes\n\n:{}", output),
- code: 0,
- }
- .into());
+ return Err(
+ RuntimeException::new(format!("Could not stash changes\n\n:{}", output)).into(),
+ );
}
self.has_stashed_changes.borrow_mut().insert(path, true);
@@ -631,11 +613,9 @@ impl GitDownloader {
Some(&path),
) != 0
{
- return Err(RuntimeException {
- message: format!("Could not view diff\n\n:{}", output),
- code: 0,
- }
- .into());
+ return Err(
+ RuntimeException::new(format!("Could not view diff\n\n:{}", output)).into(),
+ );
}
self.inner
@@ -692,10 +672,10 @@ impl GitDownloader {
path: &str,
) -> anyhow::Result<()> {
if self.get_local_changes(package, path)?.is_some() {
- return Err(RuntimeException {
- message: format!("Source directory {} has uncommitted changes.", path),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "Source directory {} has uncommitted changes.",
+ path
+ ))
.into());
}
@@ -738,14 +718,11 @@ impl ChangeReportInterface for GitDownloader {
.execute_args(&command, &mut output, Some(path))
!= 0
{
- return Err(RuntimeException {
- message: format!(
- "Failed to execute {}\n\n{}",
- implode(" ", &command),
- self.inner.process.borrow().get_error_output(),
- ),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "Failed to execute {}\n\n{}",
+ implode(" ", &command),
+ self.inner.process.borrow().get_error_output(),
+ ))
.into());
}
@@ -848,10 +825,9 @@ impl VcsDownloader for GitDownloader {
.insert(r#ref.as_deref().unwrap_or("").to_string(), true);
}
} else if git_version.is_none() {
- return Err(RuntimeException {
- message: "git was not found in your PATH, skipping source download".to_string(),
- code: 0,
- }
+ return Err(RuntimeException::new(
+ "git was not found in your PATH, skipping source download".to_string(),
+ )
.into());
}
@@ -975,13 +951,10 @@ impl VcsDownloader for GitDownloader {
],
];
if Platform::get_env("COMPOSER_DISABLE_NETWORK").is_some() {
- return Err(RuntimeException {
- message: format!(
- "The required git reference for {} is not in cache and network is disabled, aborting",
- package.get_name(),
- ),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "The required git reference for {} is not in cache and network is disabled, aborting",
+ package.get_name(),
+ ))
.into());
}
}
@@ -1022,13 +995,10 @@ impl VcsDownloader for GitDownloader {
GitUtil::clean_env(&self.inner.process);
let path = self.normalize_path(path);
if !self.has_metadata_repository(&path) {
- return Err(RuntimeException {
- message: format!(
- "The .git directory is missing from {}, see https://getcomposer.org/commit-deps for more information",
- path
- ),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "The .git directory is missing from {}, see https://getcomposer.org/commit-deps for more information",
+ path
+ ))
.into());
}
@@ -1060,13 +1030,10 @@ impl VcsDownloader for GitDownloader {
msg = format!("Checking out {}", self.get_short_hash(&r#ref));
remote_url = "%url%".to_string();
if Platform::get_env("COMPOSER_DISABLE_NETWORK").is_some() {
- return Err(RuntimeException {
- message: format!(
- "The required git reference for {} is not in cache and network is disabled, aborting",
- target.get_name(),
- ),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "The required git reference for {} is not in cache and network is disabled, aborting",
+ target.get_name(),
+ ))
.into());
}
}
@@ -1196,13 +1163,10 @@ impl VcsDownloader for GitDownloader {
.as_bool()
!= Some(true))
{
- return Err(RuntimeException {
- message: format!(
- "Source directory {} has unpushed changes on the current branch: \n{}",
- path, unpushed
- ),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "Source directory {} has unpushed changes on the current branch: \n{}",
+ path, unpushed
+ ))
.into());
}
@@ -1285,11 +1249,7 @@ impl VcsDownloader for GitDownloader {
}
}
Some("n") => {
- return Err(RuntimeException {
- message: "Update aborted".to_string(),
- code: 0,
- }
- .into());
+ return Err(RuntimeException::new("Update aborted".to_string()).into());
}
Some("v") => {
self.inner
@@ -1362,13 +1322,10 @@ impl VcsDownloader for GitDownloader {
Some(&path),
) != 0
{
- return Err(RuntimeException {
- message: format!(
- "Failed to apply stashed changes:\n\n{}",
- self.inner.process.borrow().get_error_output()
- ),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "Failed to apply stashed changes:\n\n{}",
+ self.inner.process.borrow().get_error_output()
+ ))
.into());
}
}
@@ -1399,14 +1356,11 @@ impl VcsDownloader for GitDownloader {
.execute_args(&command, &mut output, Some(&path))
!= 0
{
- return Err(RuntimeException {
- message: format!(
- "Failed to execute {}\n\n{}",
- implode(" ", &command),
- self.inner.process.borrow().get_error_output(),
- ),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "Failed to execute {}\n\n{}",
+ implode(" ", &command),
+ self.inner.process.borrow().get_error_output(),
+ ))
.into());
}
diff --git a/crates/shirabe/src/downloader/gzip_downloader.rs b/crates/shirabe/src/downloader/gzip_downloader.rs
index b0494479..9473deff 100644
--- a/crates/shirabe/src/downloader/gzip_downloader.rs
+++ b/crates/shirabe/src/downloader/gzip_downloader.rs
@@ -127,10 +127,7 @@ impl ArchiveDownloader for GzipDownloader {
implode(" ", &command),
self.inner.process.borrow().get_error_output(),
);
- return Err(anyhow::anyhow!(RuntimeException {
- message: process_error,
- code: 0
- }));
+ return Err(RuntimeException::new(process_error).into());
}
self.extract_using_ext(file, &target_filepath);
diff --git a/crates/shirabe/src/downloader/hg_downloader.rs b/crates/shirabe/src/downloader/hg_downloader.rs
index e555ccf5..dfd25618 100644
--- a/crates/shirabe/src/downloader/hg_downloader.rs
+++ b/crates/shirabe/src/downloader/hg_downloader.rs
@@ -64,10 +64,9 @@ impl VcsDownloader for HgDownloader {
_prev_package: Option<PackageInterfaceHandle>,
) -> anyhow::Result<Option<PhpMixed>> {
if HgUtils::get_version(&self.inner.process).is_none() {
- return Err(RuntimeException {
- message: "hg was not found in your PATH, skipping source download".to_string(),
- code: 0,
- }
+ return Err(RuntimeException::new(
+ "hg was not found in your PATH, skipping source download".to_string(),
+ )
.into());
}
@@ -111,14 +110,11 @@ impl VcsDownloader for HgDownloader {
shirabe_php_shim::realpath(path).as_deref(),
) != 0
{
- return Err(RuntimeException {
- message: format!(
- "Failed to execute {}\n\n{}",
- command.join(" "),
- self.inner.process.borrow().get_error_output()
- ),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "Failed to execute {}\n\n{}",
+ command.join(" "),
+ self.inner.process.borrow().get_error_output()
+ ))
.into());
}
@@ -145,13 +141,10 @@ impl VcsDownloader for HgDownloader {
));
if !self.has_metadata_repository(path) {
- return Err(RuntimeException {
- message: format!(
- "The .hg directory is missing from {}, see https://getcomposer.org/commit-deps for more information",
- path
- ),
- code: 0,
- }.into());
+ return Err(RuntimeException::new(format!(
+ "The .hg directory is missing from {}, see https://getcomposer.org/commit-deps for more information",
+ path
+ )).into());
}
let pull_command = |url: String| -> Vec<String> {
@@ -195,14 +188,11 @@ impl VcsDownloader for HgDownloader {
shirabe_php_shim::realpath(path).as_deref(),
) != 0
{
- return Err(RuntimeException {
- message: format!(
- "Failed to execute {}\n\n{}",
- command.join(" "),
- self.inner.process.borrow().get_error_output()
- ),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "Failed to execute {}\n\n{}",
+ command.join(" "),
+ self.inner.process.borrow().get_error_output()
+ ))
.into());
}
diff --git a/crates/shirabe/src/downloader/max_file_size_exceeded_exception.rs b/crates/shirabe/src/downloader/max_file_size_exceeded_exception.rs
index ebec74df..7a730ff2 100644
--- a/crates/shirabe/src/downloader/max_file_size_exceeded_exception.rs
+++ b/crates/shirabe/src/downloader/max_file_size_exceeded_exception.rs
@@ -1,6 +1,6 @@
//! ref: composer/src/Composer/Downloader/MaxFileSizeExceededException.php
-use crate::downloader::TransportException;
+use crate::downloader::transport_exception::TransportException;
#[derive(Debug)]
pub struct MaxFileSizeExceededException(pub TransportException);
@@ -11,10 +11,8 @@ impl MaxFileSizeExceededException {
}
}
-impl std::fmt::Display for MaxFileSizeExceededException {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- self.0.fmt(f)
- }
-}
-
-impl std::error::Error for MaxFileSizeExceededException {}
+shirabe_php_shim::impl_php_exception!(
+ MaxFileSizeExceededException,
+ 0,
+ r"Composer\Downloader\MaxFileSizeExceededException"
+);
diff --git a/crates/shirabe/src/downloader/path_downloader.rs b/crates/shirabe/src/downloader/path_downloader.rs
index f10da72a..9449e74a 100644
--- a/crates/shirabe/src/downloader/path_downloader.rs
+++ b/crates/shirabe/src/downloader/path_downloader.rs
@@ -85,17 +85,14 @@ impl PathDownloader {
package: PackageInterfaceHandle,
path: &str,
) -> anyhow::Result<String> {
- let url = package.get_dist_url().ok_or_else(|| RuntimeException {
- message: format!(
+ let url = package.get_dist_url().ok_or_else(|| {
+ RuntimeException::new(format!(
"The package {} has no dist url configured, cannot install.",
package.get_pretty_name()
- ),
- code: 0,
- })?;
- let real_url = realpath(&url).ok_or_else(|| RuntimeException {
- message: format!("Failed to realpath {}", url),
- code: 0,
+ ))
})?;
+ let real_url = realpath(&url)
+ .ok_or_else(|| RuntimeException::new(format!("Failed to realpath {}", url)))?;
if realpath(path).as_deref() == Some(&real_url) {
return Ok(": Source already present".to_string());
@@ -157,10 +154,7 @@ impl PathDownloader {
&& !self.safe_junctions()
{
if !allowed_strategies.contains(&Self::STRATEGY_MIRROR) {
- return Err(RuntimeException {
- message: "You are on an old Windows / old PHP combo which does not allow Composer to use junctions/symlinks and this path repository has symlink:true in its options so copying is not allowed".to_string(),
- code: 0,
- }
+ return Err(RuntimeException::new("You are on an old Windows / old PHP combo which does not allow Composer to use junctions/symlinks and this path repository has symlink:true in its options so copying is not allowed".to_string())
.into());
}
current_strategy = Self::STRATEGY_MIRROR;
@@ -173,10 +167,7 @@ impl PathDownloader {
&& !function_exists("symlink")
{
if !allowed_strategies.contains(&Self::STRATEGY_MIRROR) {
- return Err(RuntimeException {
- message: "Your PHP has the symlink() function disabled which does not allow Composer to use symlinks and this path repository has symlink:true in its options so copying is not allowed".to_string(),
- code: 0,
- }
+ return Err(RuntimeException::new("Your PHP has the symlink() function disabled which does not allow Composer to use symlinks and this path repository has symlink:true in its options so copying is not allowed".to_string())
.into());
}
current_strategy = Self::STRATEGY_MIRROR;
@@ -243,26 +234,22 @@ impl DownloaderInterface for PathDownloader {
output: bool,
) -> anyhow::Result<Option<PhpMixed>> {
let path = Filesystem::trim_trailing_slash(path);
- let url = package.get_dist_url().ok_or_else(|| RuntimeException {
- message: format!(
+ let url = package.get_dist_url().ok_or_else(|| {
+ RuntimeException::new(format!(
"The package {} has no dist url configured, cannot download.",
package.get_pretty_name()
- ),
- code: 0,
+ ))
})?;
let real_url = realpath(&url);
if real_url.is_none()
|| !file_exists(real_url.as_deref().unwrap_or(""))
|| !is_dir(real_url.as_deref().unwrap_or(""))
{
- return Err(RuntimeException {
- message: format!(
- "Source path \"{}\" is not found for package {}",
- url,
- package.get_name()
- ),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "Source path \"{}\" is not found for package {}",
+ url,
+ package.get_name()
+ ))
.into());
}
let real_url = real_url.unwrap();
@@ -282,15 +269,12 @@ impl DownloaderInterface for PathDownloader {
//
// Please see https://github.com/composer/composer/pull/5974 and https://github.com/composer/composer/pull/6174
// for previous attempts that were shut down because they did not work well enough or introduced too many risks.
- return Err(RuntimeException {
- message: format!(
- "Package {} cannot install to \"{}\" inside its source at \"{}\"",
- package.get_name(),
- realpath(&path).unwrap_or_default(),
- real_url
- ),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "Package {} cannot install to \"{}\" inside its source at \"{}\"",
+ package.get_name(),
+ realpath(&path).unwrap_or_default(),
+ real_url
+ ))
.into());
}
@@ -316,17 +300,14 @@ impl DownloaderInterface for PathDownloader {
output: bool,
) -> anyhow::Result<Option<PhpMixed>> {
let path = Filesystem::trim_trailing_slash(path);
- let url = package.get_dist_url().ok_or_else(|| RuntimeException {
- message: format!(
+ let url = package.get_dist_url().ok_or_else(|| {
+ RuntimeException::new(format!(
"The package {} has no dist url configured, cannot install.",
package.get_pretty_name()
- ),
- code: 0,
- })?;
- let real_url = realpath(&url).ok_or_else(|| RuntimeException {
- message: format!("Failed to realpath {}", url),
- code: 0,
+ ))
})?;
+ let real_url = realpath(&url)
+ .ok_or_else(|| RuntimeException::new(format!("Failed to realpath {}", url)))?;
if realpath(&path).as_deref() == Some(&real_url) {
if output {
@@ -442,13 +423,10 @@ impl DownloaderInterface for PathDownloader {
current_strategy = Self::STRATEGY_MIRROR;
is_fallback = true;
} else {
- return Err(RuntimeException {
- message: format!(
- "Symlink from \"{}\" to \"{}\" failed!",
- real_url, path
- ),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "Symlink from \"{}\" to \"{}\" failed!",
+ real_url, path
+ ))
.into());
}
}
@@ -537,25 +515,21 @@ impl DownloaderInterface for PathDownloader {
true,
io_interface::NORMAL,
);
- return Err(RuntimeException {
- message: format!(
- "Could not reliably remove junction for package {}",
- package.get_name()
- ),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "Could not reliably remove junction for package {}",
+ package.get_name()
+ ))
.into());
}
return Ok(None);
}
- let url = package.get_dist_url().ok_or_else(|| RuntimeException {
- message: format!(
+ let url = package.get_dist_url().ok_or_else(|| {
+ RuntimeException::new(format!(
"The package {} has no dist url configured, cannot remove.",
package.get_pretty_name()
- ),
- code: 0,
+ ))
})?;
// ensure that the source path (dist url) is not the same as the install path, which
diff --git a/crates/shirabe/src/downloader/rar_downloader.rs b/crates/shirabe/src/downloader/rar_downloader.rs
index ee0148c7..f4f601bc 100644
--- a/crates/shirabe/src/downloader/rar_downloader.rs
+++ b/crates/shirabe/src/downloader/rar_downloader.rs
@@ -114,39 +114,30 @@ impl ArchiveDownloader for RarDownloader {
process_error.as_deref().unwrap_or(""),
)
};
- return Err(RuntimeException {
- message: error,
- code: 0,
- }
- .into());
+ return Err(RuntimeException::new(error).into());
}
let rar_archive = RarArchive::open(file);
if rar_archive.is_none() {
- return Err(UnexpectedValueException {
- message: format!("Could not open RAR archive: {}", file),
- code: 0,
- }
+ return Err(UnexpectedValueException::new(format!(
+ "Could not open RAR archive: {}",
+ file
+ ))
.into());
}
let rar_archive = rar_archive.unwrap();
let entries = rar_archive.get_entries();
if entries.is_none() {
- return Err(RuntimeException {
- message: "Could not retrieve RAR archive entries".to_string(),
- code: 0,
- }
+ return Err(RuntimeException::new(
+ "Could not retrieve RAR archive entries".to_string(),
+ )
.into());
}
for entry in entries.unwrap() {
if !entry.extract(path) {
- return Err(RuntimeException {
- message: "Could not extract entry".to_string(),
- code: 0,
- }
- .into());
+ return Err(RuntimeException::new("Could not extract entry".to_string()).into());
}
}
diff --git a/crates/shirabe/src/downloader/svn_downloader.rs b/crates/shirabe/src/downloader/svn_downloader.rs
index 6a8bdf0e..cb748a93 100644
--- a/crates/shirabe/src/downloader/svn_downloader.rs
+++ b/crates/shirabe/src/downloader/svn_downloader.rs
@@ -75,13 +75,10 @@ impl SvnDownloader {
Some(path),
) != 0
{
- return Err(RuntimeException {
- message: format!(
- "Could not reset changes\n\n:{}",
- self.inner.process.borrow().get_error_output()
- ),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "Could not reset changes\n\n:{}",
+ self.inner.process.borrow().get_error_output()
+ ))
.into());
}
@@ -96,10 +93,10 @@ impl SvnDownloader {
path: &str,
) -> anyhow::Result<()> {
if self.get_local_changes(package, path)?.is_some() {
- return Err(RuntimeException {
- message: format!("Source directory {} has uncommitted changes.", path),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "Source directory {} has uncommitted changes.",
+ path
+ ))
.into());
}
@@ -143,10 +140,9 @@ impl VcsDownloader for SvnDownloader {
Some(self.inner.process.clone()),
);
if util.binary_version().is_none() {
- return Err(RuntimeException {
- message: "svn was not found in your PATH, skipping source download".to_string(),
- code: 0,
- }
+ return Err(RuntimeException::new(
+ "svn was not found in your PATH, skipping source download".to_string(),
+ )
.into());
}
@@ -206,13 +202,10 @@ impl VcsDownloader for SvnDownloader {
let r#ref = target.get_source_reference();
if !self.has_metadata_repository(path) {
- return Err(RuntimeException {
- message: format!(
- "The .svn directory is missing from {}, see https://getcomposer.org/commit-deps for more information",
- path
- ),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "The .svn directory is missing from {}, see https://getcomposer.org/commit-deps for more information",
+ path
+ ))
.into());
}
@@ -324,11 +317,7 @@ impl VcsDownloader for SvnDownloader {
break;
}
Some("n") => {
- return Err(RuntimeException {
- message: "Update aborted".to_string(),
- code: 0,
- }
- .into());
+ return Err(RuntimeException::new("Update aborted".to_string()).into());
}
Some("v") => {
for line in &changes {
@@ -384,14 +373,11 @@ impl VcsDownloader for SvnDownloader {
.execute_args(&command, &mut output, Some(path))
!= 0
{
- return Err(RuntimeException {
- message: format!(
- "Failed to execute {}\n\n{}",
- command.join(" "),
- self.inner.process.borrow().get_error_output()
- ),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "Failed to execute {}\n\n{}",
+ command.join(" "),
+ self.inner.process.borrow().get_error_output()
+ ))
.into());
}
@@ -403,10 +389,10 @@ impl VcsDownloader for SvnDownloader {
.cloned()
.unwrap_or_default()
} else {
- return Err(RuntimeException {
- message: format!("Unable to determine svn url for path {}", path),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "Unable to determine svn url for path {}",
+ path
+ ))
.into());
};
@@ -431,10 +417,11 @@ impl VcsDownloader for SvnDownloader {
util.set_cache_credentials(self.cache_credentials.get());
util.execute_local(command.clone(), path, None, self.inner.io.is_verbose())
.map_err(|e| {
- RuntimeException {
- message: format!("Failed to execute {}\n\n{}", command.join(" "), e),
- code: 0,
- }
+ RuntimeException::new(format!(
+ "Failed to execute {}\n\n{}",
+ command.join(" "),
+ e
+ ))
.into()
})
} else {
diff --git a/crates/shirabe/src/downloader/transport_exception.rs b/crates/shirabe/src/downloader/transport_exception.rs
index 155a5ce4..da8b4c50 100644
--- a/crates/shirabe/src/downloader/transport_exception.rs
+++ b/crates/shirabe/src/downloader/transport_exception.rs
@@ -1,11 +1,10 @@
//! ref: composer/src/Composer/Downloader/TransportException.php
-use shirabe_php_shim::PhpMixed;
+use shirabe_php_shim::{PhpMixed, RuntimeException};
#[derive(Debug, Clone)]
pub struct TransportException {
- pub message: String,
- pub code: i64,
+ inner: RuntimeException,
pub(crate) headers: Option<Vec<String>>,
pub(crate) response: Option<String>,
pub(crate) status_code: Option<i64>,
@@ -15,8 +14,7 @@ pub struct TransportException {
impl TransportException {
pub fn new(message: String, code: i64) -> Self {
Self {
- message,
- code,
+ inner: RuntimeException::with_code(message, code),
headers: None,
response: None,
status_code: None,
@@ -24,20 +22,6 @@ impl TransportException {
}
}
- /// PHP exposes ($message, $code = 0) — alias of `new` used at call sites where the
- /// status/exception code is provided up-front.
- pub fn new_with_code(message: String, code: i64) -> Self {
- Self::new(message, code)
- }
-
- pub fn get_code(&self) -> i64 {
- self.code
- }
-
- pub fn get_message(&self) -> &str {
- &self.message
- }
-
pub fn set_headers(&mut self, headers: Vec<String>) {
self.headers = Some(headers);
}
@@ -71,10 +55,8 @@ impl TransportException {
}
}
-impl std::fmt::Display for TransportException {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(f, "{}", self.message)
- }
-}
-
-impl std::error::Error for TransportException {}
+shirabe_php_shim::impl_php_exception!(
+ TransportException,
+ inner,
+ r"Composer\Downloader\TransportException"
+);
diff --git a/crates/shirabe/src/downloader/vcs_downloader.rs b/crates/shirabe/src/downloader/vcs_downloader.rs
index 45ca0e3a..56bdea60 100644
--- a/crates/shirabe/src/downloader/vcs_downloader.rs
+++ b/crates/shirabe/src/downloader/vcs_downloader.rs
@@ -18,8 +18,9 @@ use crate::util::Filesystem;
use crate::util::ProcessExecutor;
use indexmap::IndexMap;
use shirabe_php_shim::{
- InvalidArgumentException, PhpMixed, RuntimeException, array_map, array_shift, explode,
- get_class_err, implode, rawurldecode, realpath, str_replace, strlen, strpos, substr, trim,
+ AnyThrowable, InvalidArgumentException, PhpClass as _, PhpMixed, RuntimeException, array_map,
+ array_shift, explode, implode, rawurldecode, realpath, str_replace, strlen, strpos, substr,
+ trim,
};
#[derive(Debug)]
@@ -129,13 +130,10 @@ pub trait VcsDownloader:
prev_package: Option<PackageInterfaceHandle>,
) -> anyhow::Result<Option<PhpMixed>> {
if package.get_source_reference().is_none() {
- return Err(InvalidArgumentException {
- message: format!(
- "Package {} is missing reference information",
- package.get_pretty_name(),
- ),
- code: 0,
- }
+ return Err(InvalidArgumentException::new(format!(
+ "Package {} is missing reference information",
+ package.get_pretty_name(),
+ ))
.into());
}
@@ -157,7 +155,13 @@ pub trait VcsDownloader:
}
if self.io().is_debug() {
self.io().write_error3(
- &format!("Failed: [{}] {}", get_class_err(&e), e),
+ &format!(
+ "Failed: [{}] {}",
+ AnyThrowable::of(e.as_ref())
+ .expect("PHP reaches this only with a caught \\Throwable")
+ .php_class_name(),
+ e
+ ),
true,
io_interface::NORMAL,
);
@@ -232,13 +236,10 @@ pub trait VcsDownloader:
path: &str,
) -> anyhow::Result<Option<PhpMixed>> {
if package.get_source_reference().is_none() {
- return Err(InvalidArgumentException {
- message: format!(
- "Package {} is missing reference information",
- package.get_pretty_name(),
- ),
- code: 0,
- }
+ return Err(InvalidArgumentException::new(format!(
+ "Package {} is missing reference information",
+ package.get_pretty_name(),
+ ))
.into());
}
@@ -264,7 +265,13 @@ pub trait VcsDownloader:
}
if self.io().is_debug() {
self.io().write_error3(
- &format!("Failed: [{}] {}", get_class_err(&e), e),
+ &format!(
+ "Failed: [{}] {}",
+ AnyThrowable::of(e.as_ref())
+ .expect("PHP reaches this only with a caught \\Throwable")
+ .php_class_name(),
+ e
+ ),
true,
io_interface::NORMAL,
);
@@ -292,13 +299,10 @@ pub trait VcsDownloader:
path: &str,
) -> anyhow::Result<Option<PhpMixed>> {
if target.get_source_reference().is_none() {
- return Err(InvalidArgumentException {
- message: format!(
- "Package {} is missing reference information",
- target.get_pretty_name(),
- ),
- code: 0,
- }
+ return Err(InvalidArgumentException::new(format!(
+ "Package {} is missing reference information",
+ target.get_pretty_name(),
+ ))
.into());
}
@@ -333,7 +337,13 @@ pub trait VcsDownloader:
}
if self.io().is_debug() {
self.io().write_error3(
- &format!("Failed: [{}] {}", get_class_err(&e), e),
+ &format!(
+ "Failed: [{}] {}",
+ AnyThrowable::of(e.as_ref())
+ .expect("PHP reaches this only with a caught \\Throwable")
+ .php_class_name(),
+ e
+ ),
true,
io_interface::NORMAL,
);
@@ -400,10 +410,10 @@ pub trait VcsDownloader:
let result = Filesystem::remove_directory_async_via(self.filesystem(), path).await?;
if !result {
- return Err(RuntimeException {
- message: format!("Could not completely delete {}, aborting.", path),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "Could not completely delete {}, aborting.",
+ path
+ ))
.into());
}
@@ -441,10 +451,10 @@ pub trait VcsDownloader:
) -> anyhow::Result<Option<PhpMixed>> {
// the default implementation just fails if there are any changes, override in child classes to provide stash-ability
if self.get_local_changes(package, path)?.is_some() {
- return Err(RuntimeException {
- message: format!("Source directory {} has uncommitted changes.", path),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "Source directory {} has uncommitted changes.",
+ path
+ ))
.into());
}
diff --git a/crates/shirabe/src/downloader/zip_downloader.rs b/crates/shirabe/src/downloader/zip_downloader.rs
index 8870194c..84ed4c9e 100644
--- a/crates/shirabe/src/downloader/zip_downloader.rs
+++ b/crates/shirabe/src/downloader/zip_downloader.rs
@@ -10,6 +10,7 @@ use crate::util::Platform;
use indexmap::IndexMap;
use shirabe_external_packages::composer::pcre::{CaptureKey, Preg};
use shirabe_external_packages::symfony::process::ExecutableFinder;
+use shirabe_php_shim::Catch as _;
use shirabe_php_shim::{
CmpOp, DIRECTORY_SEPARATOR, ErrorException, PhpMixed, RuntimeException,
UnexpectedValueException, ZipArchive, bin2hex, class_exists, file_exists, file_get_contents,
@@ -146,13 +147,10 @@ impl ZipDownloader {
.borrow()
.contains_key(&package.get_name())
{
- return Err(RuntimeException {
- message: format!(
- "Failed to extract {} as the installation was aborted by another package operation.",
- package.get_name()
- ),
- code: 0,
- }
+ return Err(RuntimeException::new(format!(
+ "Failed to extract {} as the installation was aborted by another package operation.",
+ package.get_name()
+ ))
.into());
}
@@ -162,19 +160,16 @@ impl ZipDownloader {
return self
.try_fallback(
- RuntimeException {
- message: format!(
- "Failed to extract {}: ({}) {}\n\n{}",
- package.get_name(),
- process
- .get_exit_code()
- .map(|c| c.to_string())
- .unwrap_or_default(),
- command.join(" "),
- output
- ),
- code: 0,
- }
+ RuntimeException::new(format!(
+ "Failed to extract {}: ({}) {}\n\n{}",
+ package.get_name(),
+ process
+ .get_exit_code()
+ .map(|c| c.to_string())
+ .unwrap_or_default(),
+ command.join(" "),
+ output
+ ))
.into(),
is_last_chance,
file,
@@ -337,13 +332,10 @@ impl ZipDownloader {
&& total_size > archive_sz * 100
&& total_size > 50 * 1024 * 1024
{
- return Err(RuntimeException {
- message: format!(
- "Invalid zip file for \"{}\" with compression ratio >99% (possible zip bomb)",
- package.get_name(),
- ),
- code: 0,
- }.into());
+ return Err(RuntimeException::new(format!(
+ "Invalid zip file for \"{}\" with compression ratio >99% (possible zip bomb)",
+ package.get_name(),
+ )).into());
}
}
@@ -354,32 +346,26 @@ impl ZipDownloader {
return Ok(None);
}
- Err(RuntimeException {
- message: format!(
- "There was an error extracting the ZIP file for \"{}\", it is either corrupted or using an invalid format.",
- package.get_name(),
- ),
- code: 0,
- }.into())
+ Err(RuntimeException::new(format!(
+ "There was an error extracting the ZIP file for \"{}\", it is either corrupted or using an invalid format.",
+ package.get_name(),
+ )).into())
}
- Err(code) => Err(UnexpectedValueException {
- message: self.get_error_message(code, file).trim_end().to_string(),
+ Err(code) => Err(UnexpectedValueException::with_code(
+ self.get_error_message(code, file).trim_end().to_string(),
code,
- }
+ )
.into()),
}
})();
result.map_err(|e| {
- if let Some(err) = e.downcast_ref::<ErrorException>() {
- RuntimeException {
- message: format!(
- "The archive for \"{}\" may contain identical file names with different capitalization (which fails on case insensitive filesystems): {}",
- package.get_name(),
- err.message,
- ),
- code: 0,
- }.into()
+ if let Some(err) = e.catch::<ErrorException>() {
+ RuntimeException::new(format!(
+ "The archive for \"{}\" may contain identical file names with different capitalization (which fails on case insensitive filesystems): {}",
+ package.get_name(),
+ err.get_message(),
+ )).into()
} else {
e
}
@@ -578,11 +564,7 @@ impl crate::downloader::DownloaderInterface for ZipDownloader {
ini_message
)
};
- return Err(RuntimeException {
- message: error,
- code: 0,
- }
- .into());
+ return Err(RuntimeException::new(error).into());
}
{