diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-05-19 21:46:01 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-05-19 21:46:08 +0900 |
| commit | 5e31fa33c3b5cf726a57a063b8e7a070869250fe (patch) | |
| tree | 98522466966fa7df483cad174ab5fc03db39bc09 /crates/shirabe/src/downloader | |
| parent | c839244d8d09f3036ebfee8eef7eb6b147e593ab (diff) | |
| download | php-shirabe-5e31fa33c3b5cf726a57a063b8e7a070869250fe.tar.gz php-shirabe-5e31fa33c3b5cf726a57a063b8e7a070869250fe.tar.zst php-shirabe-5e31fa33c3b5cf726a57a063b8e7a070869250fe.zip | |
fix(compile): fix more random compile errors
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe/src/downloader')
18 files changed, 564 insertions, 401 deletions
diff --git a/crates/shirabe/src/downloader/archive_downloader.rs b/crates/shirabe/src/downloader/archive_downloader.rs index 02cd8a9..937add0 100644 --- a/crates/shirabe/src/downloader/archive_downloader.rs +++ b/crates/shirabe/src/downloader/archive_downloader.rs @@ -69,7 +69,7 @@ pub trait ArchiveDownloader { )); } - let vendor_dir = self.inner().config.get("vendor-dir"); + let vendor_dir = self.inner().config.borrow_mut().get("vendor-dir"); // clean up the target directory, unless it contains the vendor dir, as the vendor dir contains // the archive to be extracted. This is the case when installing with create-project in the current directory @@ -77,15 +77,20 @@ pub trait ArchiveDownloader { if !self .inner() .filesystem + .borrow() .normalize_path(&vendor_dir) .contains( &self .inner() .filesystem + .borrow() .normalize_path(&format!("{}{}", path, DIRECTORY_SEPARATOR)), ) { - self.inner_mut().filesystem.empty_directory(path); + self.inner_mut() + .filesystem + .borrow_mut() + .empty_directory(path); } let temporary_dir; @@ -105,6 +110,7 @@ pub trait ArchiveDownloader { self.inner_mut() .filesystem + .borrow_mut() .ensure_directory_exists(&temporary_dir); let file_name = self.inner().get_file_name(package, path); @@ -115,9 +121,9 @@ pub trait ArchiveDownloader { self.inner_mut().clear_last_cache_write(package); // clean up - filesystem.remove_directory(&temporary_dir); + filesystem.borrow_mut().remove_directory(&temporary_dir); if is_dir(path) && realpath(path) != Platform::get_cwd(false).unwrap_or_default() { - filesystem.remove_directory(path); + filesystem.borrow_mut().remove_directory(path); } self.inner_mut() .remove_cleanup_path(package, &temporary_dir); @@ -138,7 +144,7 @@ pub trait ArchiveDownloader { Ok(promise.then( Box::new(move || -> Result<Box<dyn PromiseInterface>> { if file_exists(&file_name) { - filesystem.unlink(&file_name); + filesystem.borrow_mut().unlink(&file_name); } let get_folder_content = |dir: &str| -> Vec<std::path::PathBuf> { @@ -177,7 +183,7 @@ pub trait ArchiveDownloader { &format!("{}/{}", to, file_basename), )?; } else { - filesystem.rename(&file, &format!("{}/{}", to, file_basename)); + filesystem.borrow_mut().rename(&file, &format!("{}/{}", to, file_basename)); } } @@ -187,8 +193,8 @@ pub trait ArchiveDownloader { let mut rename_as_one = false; if !file_exists(path) { rename_as_one = true; - } else if filesystem.is_dir_empty(path) { - match filesystem.remove_directory_php(path) { + } else if filesystem.borrow().is_dir_empty(path) { + match filesystem.borrow_mut().remove_directory_php(path) { Ok(true) => { rename_as_one = true; } @@ -210,7 +216,7 @@ pub trait ArchiveDownloader { } else { temporary_dir.clone() }; - filesystem.rename(&extracted_dir, path); + filesystem.borrow_mut().rename(&extracted_dir, path); } else { // only one dir in the archive, extract its contents out of it let from = if single_dir_at_top_level { @@ -222,7 +228,7 @@ pub trait ArchiveDownloader { rename_recursively.as_ref().unwrap()(&from, path)?; } - let promise = filesystem.remove_directory_async(&temporary_dir); + let promise = filesystem.borrow_mut().remove_directory_async(&temporary_dir); Ok(promise.then( Box::new(move || -> Result<()> { diff --git a/crates/shirabe/src/downloader/download_manager.rs b/crates/shirabe/src/downloader/download_manager.rs index db3484e..ea2ee1e 100644 --- a/crates/shirabe/src/downloader/download_manager.rs +++ b/crates/shirabe/src/downloader/download_manager.rs @@ -29,7 +29,7 @@ pub struct DownloadManager { /// @var array<string, string> package_preferences: IndexMap<String, String>, /// @var Filesystem - filesystem: Filesystem, + filesystem: std::rc::Rc<std::cell::RefCell<Filesystem>>, /// @var array<string, DownloaderInterface> downloaders: IndexMap<String, Box<dyn DownloaderInterface>>, } @@ -43,9 +43,10 @@ impl DownloadManager { pub fn new( io: Box<dyn IOInterface>, prefer_source: bool, - filesystem: Option<Filesystem>, + filesystem: Option<std::rc::Rc<std::cell::RefCell<Filesystem>>>, ) -> Self { - let filesystem = filesystem.unwrap_or_else(|| Filesystem::new(None)); + let filesystem = filesystem + .unwrap_or_else(|| std::rc::Rc::new(std::cell::RefCell::new(Filesystem::new(None)))); Self { io, prefer_source, @@ -202,6 +203,7 @@ impl DownloadManager { ) -> Result<Box<dyn PromiseInterface>> { let target_dir = self.normalize_target_dir(target_dir); self.filesystem + .borrow_mut() .ensure_directory_exists(&dirname(&target_dir)); let mut sources = self.get_available_sources(package, prev_package)?; @@ -217,11 +219,11 @@ impl DownloadManager { } }; if retry_state { - self.io.write_error( - PhpMixed::String(format!( + self.io.write_error3( + &format!( " <warning>Now trying to download from {}</warning>", source, - )), + ), true, io_interface::NORMAL, ); @@ -237,7 +239,7 @@ impl DownloadManager { }; // TODO(phase-b): use anyhow::Result<Result<T, E>> to model PHP try/catch - let result = match downloader.download(package, &target_dir, prev_package) { + let result = match downloader.download3(package, &target_dir, prev_package) { Ok(r) => r, Err(e) => { // PHP closure handleError: rethrow if not RuntimeException or if IrrecoverableDownloadException @@ -250,13 +252,13 @@ impl DownloadManager { return Err(e); } - self.io.write_error( - PhpMixed::String(format!( + self.io.write_error3( + &format!( " <warning>Failed to download {} from {}: {}</warning>", package.get_pretty_name(), source, e, - )), + ), true, io_interface::NORMAL, ); @@ -316,7 +318,7 @@ impl DownloadManager { ) -> Result<Box<dyn PromiseInterface>> { let target_dir = self.normalize_target_dir(target_dir); if let Some(downloader) = self.get_downloader_for_package(package)? { - return downloader.install(package, &target_dir); + return downloader.install2(package, &target_dir); } Ok(shirabe_external_packages::react::promise::resolve(None)) @@ -347,7 +349,7 @@ impl DownloadManager { // if we have a downloader present before, but not after, the package became a metapackage and its files should be removed if downloader.is_none() { - return initial_downloader.unwrap().remove(initial, &target_dir); + return initial_downloader.unwrap().remove2(initial, &target_dir); } let initial_type = self.get_downloader_type(initial_downloader.unwrap()); @@ -362,8 +364,8 @@ impl DownloadManager { if !self.io.is_interactive() { return Err(e); } - self.io.write_error( - PhpMixed::String(format!("<error> Update failed ({})</error>", e,)), + self.io.write_error3( + &format!("<error> Update failed ({})</error>", e,), true, io_interface::NORMAL, ); @@ -379,7 +381,7 @@ impl DownloadManager { // if downloader type changed, or update failed and user asks for reinstall, // we wipe the dir and do a new install instead of updating it - let promise = initial_downloader.unwrap().remove(initial, &target_dir)?; + let promise = initial_downloader.unwrap().remove2(initial, &target_dir)?; let target_dir_owned = target_dir.clone(); // TODO(phase-b): capture self and target into the closure @@ -402,7 +404,7 @@ impl DownloadManager { ) -> Result<Box<dyn PromiseInterface>> { let target_dir = self.normalize_target_dir(target_dir); if let Some(downloader) = self.get_downloader_for_package(package)? { - return downloader.remove(package, &target_dir); + return downloader.remove2(package, &target_dir); } Ok(shirabe_external_packages::react::promise::resolve(None)) @@ -442,7 +444,7 @@ impl DownloadManager { "{{^{}$}}i", str_replace("\\*", ".*", &preg_quote(pattern, None)), ); - if Preg::is_match(&pattern_regex, package.get_name()) { + if Preg::is_match(&pattern_regex, package.get_name()).unwrap_or(false) { if "dist" == preference || (!package.is_dev() && "auto" == preference) { return "dist".to_string(); } diff --git a/crates/shirabe/src/downloader/downloader_interface.rs b/crates/shirabe/src/downloader/downloader_interface.rs index 6662799..b72d80e 100644 --- a/crates/shirabe/src/downloader/downloader_interface.rs +++ b/crates/shirabe/src/downloader/downloader_interface.rs @@ -4,7 +4,7 @@ use shirabe_external_packages::react::promise::promise_interface::PromiseInterfa use crate::package::package_interface::PackageInterface; -pub trait DownloaderInterface { +pub trait DownloaderInterface: std::fmt::Debug { fn get_installation_source(&self) -> String; fn download( @@ -15,6 +15,16 @@ pub trait DownloaderInterface { output: bool, ) -> anyhow::Result<Box<dyn PromiseInterface>>; + /// Convenience for the PHP default `$output = true` overload. + fn download3( + &self, + package: &dyn PackageInterface, + path: &str, + prev_package: Option<&dyn PackageInterface>, + ) -> anyhow::Result<Box<dyn PromiseInterface>> { + self.download(package, path, prev_package, true) + } + fn prepare( &self, r#type: &str, @@ -30,6 +40,15 @@ pub trait DownloaderInterface { output: bool, ) -> anyhow::Result<Box<dyn PromiseInterface>>; + /// Convenience for the PHP default `$output = true` overload. + fn install2( + &self, + package: &dyn PackageInterface, + path: &str, + ) -> anyhow::Result<Box<dyn PromiseInterface>> { + self.install(package, path, true) + } + fn update( &self, initial: &dyn PackageInterface, @@ -44,6 +63,15 @@ pub trait DownloaderInterface { output: bool, ) -> anyhow::Result<Box<dyn PromiseInterface>>; + /// Convenience for the PHP default `$output = true` overload. + fn remove2( + &self, + package: &dyn PackageInterface, + path: &str, + ) -> anyhow::Result<Box<dyn PromiseInterface>> { + self.remove(package, path, true) + } + fn cleanup( &self, r#type: &str, diff --git a/crates/shirabe/src/downloader/file_downloader.rs b/crates/shirabe/src/downloader/file_downloader.rs index 85e43fc..c814baa 100644 --- a/crates/shirabe/src/downloader/file_downloader.rs +++ b/crates/shirabe/src/downloader/file_downloader.rs @@ -59,17 +59,17 @@ pub struct FileDownloader { /// @var IOInterface pub(crate) io: Box<dyn IOInterface>, /// @var Config - pub(crate) config: Config, + pub(crate) config: std::rc::Rc<std::cell::RefCell<Config>>, /// @var HttpDownloader - pub(crate) http_downloader: HttpDownloader, + pub(crate) http_downloader: std::rc::Rc<std::cell::RefCell<HttpDownloader>>, /// @var Filesystem - pub(crate) filesystem: Filesystem, + pub(crate) filesystem: std::rc::Rc<std::cell::RefCell<Filesystem>>, /// @var ?Cache pub(crate) cache: Option<Cache>, /// @var ?EventDispatcher pub(crate) event_dispatcher: Option<EventDispatcher>, /// @var ProcessExecutor - pub(crate) process: ProcessExecutor, + pub(crate) process: std::rc::Rc<std::cell::RefCell<ProcessExecutor>>, /// @var array<string, string> Map of package name to cache key last_cache_writes: IndexMap<String, String>, /// @var array<string, string[]> Map of package name to list of paths @@ -80,15 +80,23 @@ impl FileDownloader { /// Constructor. pub fn new( io: Box<dyn IOInterface>, - config: Config, - http_downloader: HttpDownloader, + config: std::rc::Rc<std::cell::RefCell<Config>>, + http_downloader: std::rc::Rc<std::cell::RefCell<HttpDownloader>>, event_dispatcher: Option<EventDispatcher>, cache: Option<Cache>, - filesystem: Option<Filesystem>, - process: Option<ProcessExecutor>, + filesystem: Option<std::rc::Rc<std::cell::RefCell<Filesystem>>>, + process: Option<std::rc::Rc<std::cell::RefCell<ProcessExecutor>>>, ) -> Self { - let process = process.unwrap_or_else(|| ProcessExecutor::new(Some(Box::new(&*io)), None)); - let filesystem = filesystem.unwrap_or_else(|| Filesystem::new(Some(process.clone()))); + let process = process.unwrap_or_else(|| { + std::rc::Rc::new(std::cell::RefCell::new(ProcessExecutor::new(Some( + Box::new(&*io), + )))) + }); + let filesystem = filesystem.unwrap_or_else(|| { + std::rc::Rc::new(std::cell::RefCell::new(Filesystem::new(Some( + std::rc::Rc::clone(&process), + )))) + }); let mut this = Self { io, @@ -106,8 +114,16 @@ impl FileDownloader { // PHP: writeError('Running cache garbage collection', true, io_interface::VERY_VERBOSE) this.io.write_error("Running cache garbage collection"); this.cache.as_mut().unwrap().gc( - this.config.get("cache-files-ttl").as_int().unwrap_or(0), - this.config.get("cache-files-maxsize").as_int().unwrap_or(0), + this.config + .borrow_mut() + .get("cache-files-ttl") + .as_int() + .unwrap_or(0), + this.config + .borrow_mut() + .get("cache-files-maxsize") + .as_int() + .unwrap_or(0), ); } @@ -168,9 +184,11 @@ impl DownloaderInterface for FileDownloader { debug_assert!(urls.len() > 0); let file_name = self.get_file_name(package, path); - self.filesystem.ensure_directory_exists(path)?; + self.filesystem.borrow_mut().ensure_directory_exists(path)?; let dir_of_file = shirabe_php_shim::dirname(&file_name, 1); - self.filesystem.ensure_directory_exists(&dir_of_file)?; + self.filesystem + .borrow_mut() + .ensure_directory_exists(&dir_of_file)?; // TODO(plugin): inline closures rely on captured $accept/$reject/$urls/$retries. In Rust // we'd need a struct holding shared state — left as a phase-b refactor. @@ -204,11 +222,12 @@ impl DownloaderInterface for FileDownloader { ) -> Result<Box<dyn PromiseInterface>> { let file_name = self.get_file_name(package, path); if file_exists(&file_name) { - self.filesystem.unlink(&file_name)?; + self.filesystem.borrow_mut().unlink(&file_name)?; } let vendor_dir = self .config + .borrow_mut() .get("vendor-dir") .as_string() .unwrap_or("") @@ -232,16 +251,16 @@ impl DownloaderInterface for FileDownloader { .cloned() { for path_to_clean in &paths { - self.filesystem.remove(path_to_clean)?; + self.filesystem.borrow_mut().remove(path_to_clean)?; } } for dir in &dirs_to_clean_up { if is_dir(dir) - && self.filesystem.is_dir_empty(dir)? + && self.filesystem.borrow_mut().is_dir_empty(dir)? && realpath(dir).as_deref() != Some(&Platform::get_cwd(false).unwrap_or_default()) { - self.filesystem.remove_directory_php(dir)?; + self.filesystem.borrow_mut().remove_directory_php(dir)?; } } @@ -262,6 +281,7 @@ impl DownloaderInterface for FileDownloader { let vendor_dir = self .config + .borrow_mut() .get("vendor-dir") .as_string() .unwrap_or("") @@ -271,16 +291,17 @@ impl DownloaderInterface for FileDownloader { // the file to be installed. This is the case when installing with create-project in the current directory // but in that case we ensure the directory is empty already in ProjectInstaller so no need to empty it here. if false == { - let normalized_vendor = self.filesystem.normalize_path(&vendor_dir); + let normalized_vendor = self.filesystem.borrow_mut().normalize_path(&vendor_dir); let normalized_path = self .filesystem + .borrow() .normalize_path(&format!("{}{}", path, DIRECTORY_SEPARATOR)); strpos(&normalized_vendor, &normalized_path).is_some() } { - self.filesystem.empty_directory(path, true)?; + self.filesystem.borrow_mut().empty_directory(path, true)?; } - self.filesystem.ensure_directory_exists(path)?; - self.filesystem.rename( + self.filesystem.borrow_mut().ensure_directory_exists(path)?; + self.filesystem.borrow_mut().rename( &self.get_file_name(package, path), &format!( "{}/{}", @@ -338,7 +359,7 @@ impl DownloaderInterface for FileDownloader { UninstallOperation::format(package, false) )); } - let _promise = self.filesystem.remove_directory_async(path)?; + let _promise = self.filesystem.borrow_mut().remove_directory_async(path)?; // TODO(phase-b): chain `.then(|result| if !result { throw RuntimeException })` let _ = path; @@ -357,7 +378,7 @@ impl ChangeReportInterface for FileDownloader { // TODO(phase-b): swap self.io to NullIO and restore — needs a take/swap helper let mut null_io = NullIO::new(); - null_io.load_configuration(&self.config); + null_io.load_configuration(&mut *self.config.borrow_mut())?; let mut e: Option<anyhow::Error> = None; let mut output: String = String::new(); @@ -365,7 +386,8 @@ impl ChangeReportInterface for FileDownloader { let result: Result<()> = (|| -> Result<()> { if is_dir(&format!("{}_compare", target_dir)) { self.filesystem - .remove_directory(&format!("{}_compare", target_dir), false)?; + .borrow_mut() + .remove_directory(&format!("{}_compare", target_dir))?; } let promise = @@ -377,7 +399,7 @@ impl ChangeReportInterface for FileDownloader { PhpMixed::Null })), ); - self.http_downloader.wait()?; + self.http_downloader.borrow_mut().wait()?; if e.is_some() { return Err(e.unwrap()); } @@ -389,7 +411,7 @@ impl ChangeReportInterface for FileDownloader { PhpMixed::Null })), ); - self.process.wait()?; + self.process.borrow_mut().wait()?; if e.is_some() { return Err(e.unwrap()); } @@ -400,6 +422,7 @@ impl ChangeReportInterface for FileDownloader { comparer.do_compare(); output = comparer.get_changed_as_string(true, false); self.filesystem + .borrow_mut() .remove_directory(&format!("{}_compare", target_dir))?; Ok(()) })(); @@ -491,7 +514,11 @@ impl FileDownloader { rtrim( &format!( "{}/composer/tmp-{}.{}", - self.config.get("vendor-dir").as_string().unwrap_or(""), + self.config + .borrow_mut() + .get("vendor-dir") + .as_string() + .unwrap_or(""), hash( "md5", &format!("{}{}", package, spl_object_hash(&PhpMixed::Null)) @@ -525,10 +552,10 @@ impl FileDownloader { let mut url = url.to_string(); if package.get_dist_reference().is_some() { url = UrlUtil::update_dist_reference( - &self.config, + &*self.config.borrow(), &url, package.get_dist_reference().unwrap(), - )?; + ); } Ok(url) diff --git a/crates/shirabe/src/downloader/fossil_downloader.rs b/crates/shirabe/src/downloader/fossil_downloader.rs index 5314e10..53b4315 100644 --- a/crates/shirabe/src/downloader/fossil_downloader.rs +++ b/crates/shirabe/src/downloader/fossil_downloader.rs @@ -29,9 +29,11 @@ impl FossilDownloader { path: String, url: String, ) -> Result<Box<dyn PromiseInterface>> { - self.inner - .config - .prohibit_url_by_config(&url, &self.inner.io)?; + self.inner.config.borrow_mut().prohibit_url_by_config( + &url, + Some(&self.inner.io), + &indexmap::IndexMap::new(), + )?; let repo_file = format!("{}.fossil", path); let real_path = shirabe_php_shim::realpath(&path); @@ -85,9 +87,11 @@ impl FossilDownloader { path: String, url: String, ) -> Result<Box<dyn PromiseInterface>> { - self.inner - .config - .prohibit_url_by_config(&url, &self.inner.io)?; + self.inner.config.borrow_mut().prohibit_url_by_config( + &url, + Some(&self.inner.io), + &indexmap::IndexMap::new(), + )?; self.inner.io.write_error(&format!( " Updating to {}", @@ -135,7 +139,7 @@ impl FossilDownloader { } let mut output = String::new(); - self.inner.process.execute( + self.inner.process.borrow_mut().execute_args( &["fossil".to_string(), "changes".to_string()], &mut output, shirabe_php_shim::realpath(&path), @@ -196,12 +200,18 @@ impl FossilDownloader { cwd: Option<String>, output: &mut String, ) -> Result<()> { - if self.inner.process.execute(&command, output, cwd) != 0 { + if self + .inner + .process + .borrow_mut() + .execute(&command, output, cwd) + != 0 + { return Err(RuntimeException { message: format!( "Failed to execute {}\n\n{}", command.join(" "), - self.inner.process.get_error_output() + self.inner.process.borrow().get_error_output() ), code: 0, } diff --git a/crates/shirabe/src/downloader/git_downloader.rs b/crates/shirabe/src/downloader/git_downloader.rs index fb41b0c..d451727 100644 --- a/crates/shirabe/src/downloader/git_downloader.rs +++ b/crates/shirabe/src/downloader/git_downloader.rs @@ -3,7 +3,7 @@ use crate::io::io_interface; use anyhow::Result; use indexmap::IndexMap; -use shirabe_external_packages::composer::pcre::preg::Preg; +use shirabe_external_packages::composer::pcre::preg::{CaptureKey, Preg}; use shirabe_external_packages::react::promise; use shirabe_external_packages::react::promise::promise_interface::PromiseInterface; use shirabe_php_shim::{ @@ -38,12 +38,17 @@ pub struct GitDownloader { impl GitDownloader { pub fn new( io: Box<dyn IOInterface>, - config: Config, - process: Option<ProcessExecutor>, - fs: Option<Filesystem>, + config: std::rc::Rc<std::cell::RefCell<Config>>, + process: Option<std::rc::Rc<std::cell::RefCell<ProcessExecutor>>>, + fs: Option<std::rc::Rc<std::cell::RefCell<Filesystem>>>, ) -> Self { let inner = VcsDownloaderBase::new(io, config, process, fs); - let git_util = GitUtil::new(&*inner.io, &inner.config, &inner.process, &inner.filesystem); + let git_util = GitUtil::new( + inner.io.clone_box(), + std::rc::Rc::clone(&inner.config), + std::rc::Rc::clone(&inner.process), + std::rc::Rc::clone(&inner.filesystem), + ); Self { inner, has_stashed_changes: IndexMap::new(), @@ -71,10 +76,11 @@ impl GitDownloader { "{}/{}/", self.inner .config + .borrow_mut() .get("cache-vcs-dir") .as_string() .unwrap_or(""), - Preg::replace(r"{[^a-z0-9.]}i", "-", Url::sanitize(url.to_string())), + Preg::replace(r"{[^a-z0-9.]}i", "-", &Url::sanitize(url.to_string()))?, ); let git_version = GitUtil::get_version(&self.inner.process); @@ -83,20 +89,20 @@ impl GitDownloader { && version_compare(git_version.as_deref().unwrap_or(""), "2.3.0-rc0", ">=") && Cache::is_usable(&cache_path) { - self.inner.io.write_error( - PhpMixed::String(format!( + self.inner.io.write_error3( + &format!( " - Syncing <info>{}</info> (<comment>{}</comment>) into cache", package.get_name(), package.get_full_pretty_version(), - )), + ), true, io_interface::NORMAL, ); - self.inner.io.write_error( - PhpMixed::String(sprintf( + self.inner.io.write_error3( + &sprintf( " Cloning to cache at %s", &[PhpMixed::String(cache_path.clone())], - )), + ), true, io_interface::DEBUG, ); @@ -136,10 +142,11 @@ impl GitDownloader { "{}/{}/", self.inner .config + .borrow_mut() .get("cache-vcs-dir") .as_string() .unwrap_or(""), - Preg::replace(r"{[^a-z0-9.]}i", "-", Url::sanitize(url.to_string())), + Preg::replace(r"{[^a-z0-9.]}i", "-", &Url::sanitize(url.to_string()))?, ); let r#ref = package.get_source_reference().unwrap_or("").to_string(); @@ -252,7 +259,8 @@ impl GitDownloader { self.inner.io.write_error3(&msg, true, io_interface::NORMAL); - self.git_util.run_commands(commands, url, &path, true); + self.git_util + .run_commands(commands, url, Some(&path), true, None)?; let source_url = package.get_source_url(); if url != source_url.unwrap_or("") && source_url.is_some() { @@ -299,10 +307,11 @@ impl GitDownloader { "{}/{}/", self.inner .config + .borrow_mut() .get("cache-vcs-dir") .as_string() .unwrap_or(""), - Preg::replace(r"{[^a-z0-9.]}i", "-", Url::sanitize(url.to_string())), + Preg::replace(r"{[^a-z0-9.]}i", "-", &Url::sanitize(url.to_string()))?, ); let r#ref = target.get_source_reference().unwrap_or("").to_string(); @@ -335,7 +344,7 @@ impl GitDownloader { self.inner.io.write_error3(&msg, true, io_interface::NORMAL); let mut output = String::new(); - if self.inner.process.execute( + if self.inner.process.borrow_mut().execute_args( &vec![ "git".to_string(), "rev-parse".to_string(), @@ -369,7 +378,8 @@ impl GitDownloader { ], ]; - self.git_util.run_commands(commands, url, &path, false); + self.git_util + .run_commands(commands, url, Some(&path), false, None)?; } let command = vec![ @@ -380,7 +390,8 @@ impl GitDownloader { "--".to_string(), "%sanitizedUrl%".to_string(), ]; - self.git_util.run_commands(vec![command], url, &path, false); + self.git_util + .run_commands(vec![command], url, Some(&path), false, None)?; if let Some(new_ref) = self.update_to_commit(target, &path, &r#ref, target.get_pretty_version())? @@ -395,18 +406,35 @@ impl GitDownloader { let mut update_origin_url = false; let mut output = String::new(); - if self.inner.process.execute( + if self.inner.process.borrow_mut().execute_args( &vec!["git".to_string(), "remote".to_string(), "-v".to_string()], &mut output, Some(path.clone()), ) == 0 { - let origin_match = Preg::is_match_strict_groups(r"{^origin\s+(?P<url>\S+)}m", &output); - let composer_match = - Preg::is_match_strict_groups(r"{^composer\s+(?P<url>\S+)}m", &output); - if let (Some(origin_match), Some(composer_match)) = (origin_match, composer_match) { - let origin_url = origin_match.get("url").cloned().unwrap_or_default(); - let composer_url = composer_match.get("url").cloned().unwrap_or_default(); + let mut origin_match: IndexMap<CaptureKey, String> = IndexMap::new(); + let mut composer_match: IndexMap<CaptureKey, String> = IndexMap::new(); + if Preg::is_match3( + r"{^origin\s+(?P<url>\S+)}m", + &output, + Some(&mut origin_match), + ) + .unwrap_or(false) + && Preg::is_match3( + r"{^composer\s+(?P<url>\S+)}m", + &output, + Some(&mut composer_match), + ) + .unwrap_or(false) + { + let origin_url = origin_match + .get(&CaptureKey::ByName("url".to_string())) + .cloned() + .unwrap_or_default(); + let composer_url = composer_match + .get(&CaptureKey::ByName("url".to_string())) + .cloned() + .unwrap_or_default(); if origin_url == composer_url && Some(composer_url.as_str()) != target.get_source_url() { @@ -434,11 +462,11 @@ impl GitDownloader { "--untracked-files=no".to_string(), ]; let mut output = String::new(); - if self - .inner - .process - .execute(&command, &mut output, Some(path.to_string())) - != 0 + if self.inner.process.borrow_mut().execute_args( + &command, + &mut output, + Some(path.to_string()), + ) != 0 { // TODO(phase-b): cannot throw from &self / non-Result fn; bubble error via Result later panic!( @@ -446,7 +474,7 @@ impl GitDownloader { format!( "Failed to execute {}\n\n{}", implode(" ", &command), - self.inner.process.get_error_output(), + self.inner.process.borrow().get_error_output(), ) ); } @@ -481,7 +509,8 @@ impl GitDownloader { if self .inner .process - .execute(&command, &mut output, Some(path.clone())) + .borrow_mut() + .execute_args(&command, &mut output, Some(path.clone())) != 0 { // TODO(phase-b): bubble error via Result later @@ -490,26 +519,39 @@ impl GitDownloader { format!( "Failed to execute {}\n\n{}", implode(" ", &command), - self.inner.process.get_error_output(), + self.inner.process.borrow().get_error_output(), ) ); } let mut refs = trim(&output, None); - let head_ref = match Preg::is_match_strict_groups(r"{^([a-f0-9]+) HEAD$}mi", &refs) { - Some(m) => m.get(1).cloned().unwrap_or_default(), + let mut head_match: IndexMap<CaptureKey, String> = IndexMap::new(); + if !Preg::is_match_strict_groups3(r"{^([a-f0-9]+) HEAD$}mi", &refs, Some(&mut head_match)) + .unwrap_or(false) + { // could not match the HEAD for some reason - None => return None, - }; + return None; + } + let head_ref = head_match + .get(&CaptureKey::ByIndex(1)) + .cloned() + .unwrap_or_default(); - let candidate_branches: Vec<String> = match Preg::is_match_all_strict_groups( + let mut branches_match: IndexMap<CaptureKey, Vec<String>> = IndexMap::new(); + if !Preg::is_match_all_strict_groups3( &format!("{{^{} refs/heads/(.+)$}}mi", preg_quote(&head_ref, None)), &refs, - ) { - Some(m) => m.get(1).cloned().unwrap_or_default(), + Some(&mut branches_match), + ) + .unwrap_or(false) + { // not on a branch, we are either on a not-modified tag or some sort of detached head, so skip this - None => return None, - }; + return None; + } + let candidate_branches: Vec<String> = branches_match + .get(&CaptureKey::ByIndex(1)) + .cloned() + .unwrap_or_default(); // use the first match as branch name for now let mut branch = candidate_branches[0].clone(); @@ -522,14 +564,19 @@ impl GitDownloader { // try to find matching branch names in remote repos for candidate in &candidate_branches { - if let Some(m) = Preg::is_match_all_strict_groups( + let mut m: IndexMap<CaptureKey, Vec<String>> = IndexMap::new(); + if Preg::is_match_all_strict_groups3( &format!( "{{^[a-f0-9]+ refs/remotes/((?:[^/]+)/{})$}}mi", preg_quote(candidate, None) ), &refs, - ) { - let matches: Vec<String> = m.get(1).cloned().unwrap_or_default(); + Some(&mut m), + ) + .unwrap_or(false) + { + let matches: Vec<String> = + m.get(&CaptureKey::ByIndex(1)).cloned().unwrap_or_default(); for match_ in matches { branch = candidate.clone(); remote_branches.push(match_); @@ -562,11 +609,11 @@ impl GitDownloader { "--".to_string(), ]; let mut output = String::new(); - if self - .inner - .process - .execute(&command, &mut output, Some(path.clone())) - != 0 + if self.inner.process.borrow_mut().execute_args( + &command, + &mut output, + Some(path.clone()), + ) != 0 { // TODO(phase-b): bubble error via Result later panic!( @@ -574,7 +621,7 @@ impl GitDownloader { format!( "Failed to execute {}\n\n{}", implode(" ", &command), - self.inner.process.get_error_output(), + self.inner.process.borrow().get_error_output(), ) ); } @@ -593,7 +640,7 @@ impl GitDownloader { // remotes and then try again as outdated remotes can sometimes cause false-positives if unpushed_changes.is_some() && i == 0 { let mut output = String::new(); - self.inner.process.execute( + self.inner.process.borrow_mut().execute_args( &vec!["git".to_string(), "fetch".to_string(), "--all".to_string()], &mut output, Some(path.clone()), @@ -607,11 +654,11 @@ impl GitDownloader { "-d".to_string(), ]; let mut output = String::new(); - if self - .inner - .process - .execute(&command, &mut output, Some(path.clone())) - != 0 + if self.inner.process.borrow_mut().execute_args( + &command, + &mut output, + Some(path.clone()), + ) != 0 { // TODO(phase-b): bubble error via Result later panic!( @@ -619,7 +666,7 @@ impl GitDownloader { format!( "Failed to execute {}\n\n{}", implode(" ", &command), - self.inner.process.get_error_output(), + self.inner.process.borrow().get_error_output(), ) ); } @@ -647,7 +694,13 @@ impl GitDownloader { let unpushed = self.get_unpushed_changes(package, &path); if let Some(unpushed) = unpushed.as_deref() { if self.inner.io.is_interactive() - || self.inner.config.get("discard-changes").as_bool() != Some(true) + || self + .inner + .config + .borrow_mut() + .get("discard-changes") + .as_bool() + != Some(true) { return Err(RuntimeException { message: format!( @@ -666,7 +719,7 @@ impl GitDownloader { }; if !self.inner.io.is_interactive() { - let discard_changes = self.inner.config.get("discard-changes"); + let discard_changes = self.inner.config.borrow_mut().get("discard-changes"); if discard_changes.as_bool() == Some(true) { return self.discard_changes(&path); } @@ -685,16 +738,16 @@ impl GitDownloader { |elem: &String| format!(" {}", elem), &Preg::split(r"{\s*\r?\n\s*}", &changes), ); - self.inner.io.write_error( - PhpMixed::String(format!( + self.inner.io.write_error3( + &format!( " <error>{} has modified files:</error>", package.get_pretty_name() - )), + ), true, io_interface::NORMAL, ); let slice_end = 10_usize.min(changes.len()); - self.inner.io.write_error( + self.inner.io.write_error3( PhpMixed::List( changes[..slice_end] .iter() @@ -705,11 +758,11 @@ impl GitDownloader { io_interface::NORMAL, ); if (changes.len() as i64) > 10 { - self.inner.io.write_error( - PhpMixed::String(format!( + self.inner.io.write_error3( + &format!( " <info>{} more files modified, choose \"v\" to view the full list</info>", changes.len() as i64 - 10 - )), + ), true, io_interface::NORMAL, ); @@ -751,7 +804,7 @@ impl GitDownloader { .into()); } Some("v") => { - self.inner.io.write_error( + self.inner.io.write_error3( PhpMixed::List( changes .iter() @@ -773,7 +826,7 @@ impl GitDownloader { if do_help { // help: - self.inner.io.write_error( + self.inner.io.write_error3( PhpMixed::List(vec![ Box::new(PhpMixed::String(format!( " y - discard changes and apply the {}", @@ -792,20 +845,15 @@ impl GitDownloader { io_interface::NORMAL, ); if update { - self.inner.io.write_error( - PhpMixed::String( - " s - stash changes and try to reapply them after the update" - .to_string(), - ), + self.inner.io.write_error3( + " s - stash changes and try to reapply them after the update", true, io_interface::NORMAL, ); } - self.inner.io.write_error( - PhpMixed::String(" ? - print help".to_string()), - true, - io_interface::NORMAL, - ); + self.inner + .io + .write_error3(" ? - print help", true, io_interface::NORMAL); } } @@ -821,13 +869,13 @@ impl GitDownloader { .unwrap_or(false) { self.has_stashed_changes.shift_remove(&path); - self.inner.io.write_error( - PhpMixed::String(" <info>Re-applying stashed changes</info>".to_string()), + self.inner.io.write_error3( + " <info>Re-applying stashed changes</info>", true, io_interface::NORMAL, ); let mut output = String::new(); - if self.inner.process.execute( + if self.inner.process.borrow_mut().execute_args( &vec!["git".to_string(), "stash".to_string(), "pop".to_string()], &mut output, Some(path.clone()), @@ -836,7 +884,7 @@ impl GitDownloader { return Err(RuntimeException { message: format!( "Failed to apply stashed changes:\n\n{}", - self.inner.process.get_error_output() + self.inner.process.borrow().get_error_output() ), code: 0, } @@ -877,11 +925,7 @@ impl GitDownloader { // If the non-existent branch is actually the name of a file, the file // is checked out. - let mut branch = Preg::replace( - r"{(?:^dev-|(?:\.x)?-dev$)}i", - "", - pretty_version.to_string(), - ); + let mut branch = Preg::replace(r"{(?:^dev-|(?:\.x)?-dev$)}i", "", &pretty_version); // Closure equivalent: $execute = function(array $command) use (&$output, $path) { ... }; // Inlined below at each call site. @@ -889,7 +933,7 @@ impl GitDownloader { let mut branches: Option<String> = None; { let mut output = String::new(); - if self.inner.process.execute( + if self.inner.process.borrow_mut().execute_args( &vec!["git".to_string(), "branch".to_string(), "-r".to_string()], &mut output, Some(path.to_string()), @@ -926,17 +970,18 @@ impl GitDownloader { ]; let mut output = String::new(); - let ok1 = self - .inner - .process - .execute(&command1, &mut output, Some(path.to_string())) - == 0; + let ok1 = self.inner.process.borrow_mut().execute_args( + &command1, + &mut output, + Some(path.to_string()), + ) == 0; let ok2 = if ok1 { let mut output = String::new(); - self.inner - .process - .execute(&command2, &mut output, Some(path.to_string())) - == 0 + self.inner.process.borrow_mut().execute_args( + &command2, + &mut output, + Some(path.to_string()), + ) == 0 } else { false }; @@ -986,26 +1031,28 @@ impl GitDownloader { ]; let mut output = String::new(); - let ok_command = - self.inner - .process - .execute(&command, &mut output, Some(path.to_string())) - == 0; + let ok_command = self.inner.process.borrow_mut().execute_args( + &command, + &mut output, + Some(path.to_string()), + ) == 0; let ok_fallback = if !ok_command { let mut output = String::new(); - self.inner - .process - .execute(&fallback_command, &mut output, Some(path.to_string())) - == 0 + self.inner.process.borrow_mut().execute_args( + &fallback_command, + &mut output, + Some(path.to_string()), + ) == 0 } else { false }; let ok_reset = if ok_command || ok_fallback { let mut output = String::new(); - self.inner - .process - .execute(&reset_command, &mut output, Some(path.to_string())) - == 0 + self.inner.process.borrow_mut().execute_args( + &reset_command, + &mut output, + Some(path.to_string()), + ) == 0 } else { false }; @@ -1026,17 +1073,18 @@ impl GitDownloader { ]; { let mut output = String::new(); - let ok1 = self - .inner - .process - .execute(&command1, &mut output, Some(path.to_string())) - == 0; + let ok1 = self.inner.process.borrow_mut().execute_args( + &command1, + &mut output, + Some(path.to_string()), + ) == 0; let ok2 = if ok1 { let mut output = String::new(); - self.inner - .process - .execute(&command2, &mut output, Some(path.to_string())) - == 0 + self.inner.process.borrow_mut().execute_args( + &command2, + &mut output, + Some(path.to_string()), + ) == 0 } else { false }; @@ -1048,12 +1096,12 @@ impl GitDownloader { let mut exception_extra = String::new(); // reference was not found (prints "fatal: reference is not a tree: $ref") - if strpos(self.inner.process.get_error_output(), reference).is_some() { - self.inner.io.write_error( - PhpMixed::String(format!( + if strpos(self.inner.process.borrow().get_error_output(), reference).is_some() { + self.inner.io.write_error3( + &format!( " <warning>{} is gone (history was rewritten?)</warning>", reference - )), + ), true, io_interface::NORMAL, ); @@ -1074,7 +1122,7 @@ impl GitDownloader { message: Url::sanitize(format!( "Failed to execute {}\n\n{}{}", command, - self.inner.process.get_error_output(), + self.inner.process.borrow().get_error_output(), exception_extra, )), code: 0, @@ -1084,7 +1132,7 @@ impl GitDownloader { pub(crate) fn update_origin_url(&mut self, path: &str, url: &str) { let mut output = String::new(); - self.inner.process.execute( + self.inner.process.borrow_mut().execute_args( &vec![ "git".to_string(), "remote".to_string(), @@ -1101,17 +1149,30 @@ impl GitDownloader { pub(crate) fn set_push_url(&mut self, path: &str, url: &str) { // set push url for github projects - if let Some(match_) = Preg::is_match_strict_groups( + let mut match_: IndexMap<CaptureKey, String> = IndexMap::new(); + if Preg::is_match3( &format!( "{{^(?:https?|git)://{}/([^/]+)/([^/]+?)(?:\\.git)?$}}", - GitUtil::get_github_domains_regex(&self.inner.config) + GitUtil::get_github_domains_regex(&*self.inner.config.borrow()) ), url, - ) { - let protocols = self.inner.config.get("github-protocols"); - let m1 = match_.get(1).cloned().unwrap_or_default(); - let m2 = match_.get(2).cloned().unwrap_or_default(); - let m3 = match_.get(3).cloned().unwrap_or_default(); + Some(&mut match_), + ) + .unwrap_or(false) + { + let protocols = self.inner.config.borrow_mut().get("github-protocols"); + let m1 = match_ + .get(&CaptureKey::ByIndex(1)) + .cloned() + .unwrap_or_default(); + let m2 = match_ + .get(&CaptureKey::ByIndex(2)) + .cloned() + .unwrap_or_default(); + let m3 = match_ + .get(&CaptureKey::ByIndex(3)) + .cloned() + .unwrap_or_default(); let mut push_url = format!("git@{}:{}/{}.git", m1, m2, m3); if !in_array(PhpMixed::String("ssh".to_string()), &protocols, true) { push_url = format!("https://{}/{}/{}.git", m1, m2, m3); @@ -1126,9 +1187,11 @@ impl GitDownloader { push_url, ]; let mut ignored_output = String::new(); - self.inner - .process - .execute(&cmd, &mut ignored_output, Some(path.to_string())); + self.inner.process.borrow_mut().execute_args( + &cmd, + &mut ignored_output, + Some(path.to_string()), + ); } } @@ -1150,14 +1213,15 @@ impl GitDownloader { if self .inner .process - .execute(&command, &mut output, Some(path.clone())) + .borrow_mut() + .execute_args(&command, &mut output, Some(path.clone())) != 0 { return Err(RuntimeException { message: format!( "Failed to execute {}\n\n{}", implode(" ", &command), - self.inner.process.get_error_output(), + self.inner.process.borrow().get_error_output(), ), code: 0, } @@ -1172,7 +1236,7 @@ impl GitDownloader { pub(crate) fn discard_changes(&mut self, path: &str) -> Result<Box<dyn PromiseInterface>> { let path = self.normalize_path(path); let mut output = String::new(); - if self.inner.process.execute( + if self.inner.process.borrow_mut().execute_args( &vec!["git".to_string(), "clean".to_string(), "-df".to_string()], &mut output, Some(path.clone()), @@ -1185,7 +1249,7 @@ impl GitDownloader { .into()); } let mut output = String::new(); - if self.inner.process.execute( + if self.inner.process.borrow_mut().execute_args( &vec!["git".to_string(), "reset".to_string(), "--hard".to_string()], &mut output, Some(path.clone()), @@ -1208,7 +1272,7 @@ impl GitDownloader { pub(crate) fn stash_changes(&mut self, path: &str) -> Result<Box<dyn PromiseInterface>> { let path = self.normalize_path(path); let mut output = String::new(); - if self.inner.process.execute( + if self.inner.process.borrow_mut().execute_args( &vec![ "git".to_string(), "stash".to_string(), @@ -1234,7 +1298,7 @@ impl GitDownloader { pub(crate) fn view_diff(&mut self, path: &str) { let path = self.normalize_path(path); let mut output = String::new(); - if self.inner.process.execute( + if self.inner.process.borrow_mut().execute_args( &vec!["git".to_string(), "diff".to_string(), "HEAD".to_string()], &mut output, Some(path.clone()), diff --git a/crates/shirabe/src/downloader/gzip_downloader.rs b/crates/shirabe/src/downloader/gzip_downloader.rs index 2a485de..4ee9d33 100644 --- a/crates/shirabe/src/downloader/gzip_downloader.rs +++ b/crates/shirabe/src/downloader/gzip_downloader.rs @@ -29,12 +29,12 @@ pub struct GzipDownloader { impl GzipDownloader { pub fn new( io: Box<dyn IOInterface>, - config: Config, - http_downloader: HttpDownloader, + config: std::rc::Rc<std::cell::RefCell<Config>>, + http_downloader: std::rc::Rc<std::cell::RefCell<HttpDownloader>>, event_dispatcher: Option<EventDispatcher>, cache: Option<Cache>, - filesystem: Filesystem, - process: ProcessExecutor, + filesystem: std::rc::Rc<std::cell::RefCell<Filesystem>>, + process: std::rc::Rc<std::cell::RefCell<ProcessExecutor>>, ) -> Self { Self { inner: FileDownloader::new( @@ -80,7 +80,7 @@ impl GzipDownloader { ]; let mut process_output = PhpMixed::Null; - if self.inner.process.execute( + if self.inner.process.borrow_mut().execute( PhpMixed::List( command .iter() @@ -102,7 +102,7 @@ impl GzipDownloader { let process_error = format!( "Failed to execute {}\n\n{}", implode(" ", &command), - self.inner.process.get_error_output(), + self.inner.process.borrow().get_error_output(), ); return Err(anyhow::anyhow!(RuntimeException { message: process_error, diff --git a/crates/shirabe/src/downloader/hg_downloader.rs b/crates/shirabe/src/downloader/hg_downloader.rs index 1b4204f..161eb7e 100644 --- a/crates/shirabe/src/downloader/hg_downloader.rs +++ b/crates/shirabe/src/downloader/hg_downloader.rs @@ -37,7 +37,11 @@ impl HgDownloader { path: String, url: String, ) -> Result<Box<dyn PromiseInterface>> { - let hg_utils = HgUtils::new(&self.inner.io, &self.inner.config, &self.inner.process); + let hg_utils = HgUtils::new( + &*self.inner.io, + &*self.inner.config.borrow(), + &self.inner.process, + ); let path_clone = path.clone(); let clone_command = move |url: String| -> Vec<String> { @@ -58,7 +62,7 @@ impl HgDownloader { package.get_source_reference().unwrap_or_default(), ]; let mut ignored_output = String::new(); - if self.inner.process.execute( + if self.inner.process.borrow_mut().execute_args( &command, &mut ignored_output, shirabe_php_shim::realpath(&path), @@ -68,7 +72,7 @@ impl HgDownloader { message: format!( "Failed to execute {}\n\n{}", command.join(" "), - self.inner.process.get_error_output() + self.inner.process.borrow().get_error_output() ), code: 0, } @@ -85,7 +89,11 @@ impl HgDownloader { path: String, url: String, ) -> Result<Box<dyn PromiseInterface>> { - let hg_utils = HgUtils::new(&self.inner.io, &self.inner.config, &self.inner.process); + let hg_utils = HgUtils::new( + &*self.inner.io, + &*self.inner.config.borrow(), + &self.inner.process, + ); let ref_ = target.get_source_reference().unwrap_or_default(); self.inner.io.write_error(&format!( @@ -132,7 +140,7 @@ impl HgDownloader { } let mut output = String::new(); - self.inner.process.execute( + self.inner.process.borrow_mut().execute_args( &["hg".to_string(), "st".to_string()], &mut output, shirabe_php_shim::realpath(&path), @@ -163,17 +171,17 @@ impl HgDownloader { ]; let mut output = String::new(); - if self - .inner - .process - .execute(&command, &mut output, shirabe_php_shim::realpath(&path)) - != 0 + if self.inner.process.borrow_mut().execute_args( + &command, + &mut output, + shirabe_php_shim::realpath(&path), + ) != 0 { return Err(RuntimeException { message: format!( "Failed to execute {}\n\n{}", command.join(" "), - self.inner.process.get_error_output() + self.inner.process.borrow().get_error_output() ), code: 0, } diff --git a/crates/shirabe/src/downloader/path_downloader.rs b/crates/shirabe/src/downloader/path_downloader.rs index a525df0..26795f3 100644 --- a/crates/shirabe/src/downloader/path_downloader.rs +++ b/crates/shirabe/src/downloader/path_downloader.rs @@ -117,12 +117,12 @@ impl PathDownloader { if realpath(&path).as_deref() == Some(&real_url) { if output { let appendix = self.get_install_operation_appendix(package, &path)?; - self.inner.io.write_error( - PhpMixed::String(format!( + self.inner.io.write_error3( + &format!( " - {}{}", InstallOperation::format(package, false), appendix - )), + ), true, io_interface::NORMAL, ); @@ -141,14 +141,11 @@ impl PathDownloader { self.compute_allowed_strategies(&transport_options)?; let symfony_filesystem = SymfonyFilesystem::new(None); - self.inner.filesystem.remove_directory(&path); + self.inner.filesystem.borrow_mut().remove_directory(&path); if output { - self.inner.io.write_error( - PhpMixed::String(format!( - " - {}: ", - InstallOperation::format(package, false) - )), + self.inner.io.write_error3( + &format!(" - {}: ", InstallOperation::format(package, false)), false, io_interface::NORMAL, ); @@ -160,18 +157,22 @@ impl PathDownloader { if Platform::is_windows() { // Implement symlinks as NTFS junctions on Windows if output { - self.inner.io.write_error( - PhpMixed::String(format!("Junctioning from {}", url)), + self.inner.io.write_error3( + &format!("Junctioning from {}", url), false, io_interface::NORMAL, ); } - Ok(self.inner.filesystem.junction(&real_url, &path)) + Ok(self + .inner + .filesystem + .borrow_mut() + .junction(&real_url, &path)) } else { let path = path.trim_end_matches('/').to_string(); if output { - self.inner.io.write_error( - PhpMixed::String(format!("Symlinking from {}", url)), + self.inner.io.write_error3( + &format!("Symlinking from {}", url), false, io_interface::NORMAL, ); @@ -181,17 +182,18 @@ impl PathDownloader { .and_then(|v| v.as_bool()) .unwrap_or(false) { - let absolute_path = if !self.inner.filesystem.is_absolute_path(&path) { - format!( - "{}{}{}", - Platform::get_cwd(false), - DIRECTORY_SEPARATOR, - path - ) - } else { - path.clone() - }; - let shortest_path = self.inner.filesystem.find_shortest_path( + let absolute_path = + if !self.inner.filesystem.borrow_mut().is_absolute_path(&path) { + format!( + "{}{}{}", + Platform::get_cwd(false), + DIRECTORY_SEPARATOR, + path + ) + } else { + path.clone() + }; + let shortest_path = self.inner.filesystem.borrow_mut().find_shortest_path( &absolute_path, &real_url, false, @@ -209,16 +211,9 @@ impl PathDownloader { Err(_e) => { if allowed_strategies.contains(&Self::STRATEGY_MIRROR) { if output { - self.inner.io.write_error( - PhpMixed::String("".to_string()), - true, - io_interface::NORMAL, - ); - self.inner.io.write_error( - PhpMixed::String( - " <error>Symlink failed, fallback to use mirroring!</error>" - .to_string(), - ), + self.inner.io.write_error3("", true, io_interface::NORMAL); + self.inner.io.write_error3( + " <error>Symlink failed, fallback to use mirroring!</error>", true, io_interface::NORMAL, ); @@ -241,15 +236,15 @@ impl PathDownloader { // Fallback if symlink failed or if symlink is not allowed for the package if Self::STRATEGY_MIRROR == current_strategy { - let real_url = self.inner.filesystem.normalize_path(&real_url); + let real_url = self.inner.filesystem.borrow_mut().normalize_path(&real_url); if output { - self.inner.io.write_error( - PhpMixed::String(format!( + self.inner.io.write_error3( + &format!( "{}Mirroring from {}", if is_fallback { " " } else { "" }, url - )), + ), false, io_interface::NORMAL, ); @@ -280,24 +275,24 @@ impl PathDownloader { // process inadvertently locks the file the removal will fail, but it would fall back to recursive // delete which is disastrous within a junction. So in that case we have no other real choice but // to fail hard. - if Platform::is_windows() && self.inner.filesystem.is_junction(&path) { + if Platform::is_windows() && self.inner.filesystem.borrow_mut().is_junction(&path) { if output { - self.inner.io.write_error( - PhpMixed::String(format!( + self.inner.io.write_error3( + &format!( " - {}, source is still present in {}", UninstallOperation::format(package, false), path - )), + ), true, io_interface::NORMAL, ); } - if !self.inner.filesystem.remove_junction(&path) { - self.inner.io.write_error( - PhpMixed::String(format!( + if !self.inner.filesystem.borrow_mut().remove_junction(&path)? { + self.inner.io.write_error3( + &format!( " <warning>Could not remove junction at {} - is another process locking it?</warning>", path - )), + ), true, io_interface::NORMAL, ); @@ -339,12 +334,12 @@ impl PathDownloader { }; if fs.normalize_path(&abs_path) == fs.normalize_path(&abs_dist_url) { if output { - self.inner.io.write_error( - PhpMixed::String(format!( + self.inner.io.write_error3( + &format!( " - {}, source is still present in {}", UninstallOperation::format(package, false), path - )), + ), true, io_interface::NORMAL, ); @@ -360,10 +355,10 @@ impl PathDownloader { let path = Filesystem::trim_trailing_slash(path); let parser = VersionParser::new(); let guesser = VersionGuesser::new( - &self.inner.config, - &self.inner.process, - &parser, - Some(&*self.inner.io), + std::rc::Rc::clone(&self.inner.config), + std::rc::Rc::clone(&self.inner.process), + parser.clone(), + Some(self.inner.io.clone_box()), ); let dumper = ArrayDumper::new(); diff --git a/crates/shirabe/src/downloader/perforce_downloader.rs b/crates/shirabe/src/downloader/perforce_downloader.rs index b10e27f..fe5e9e5 100644 --- a/crates/shirabe/src/downloader/perforce_downloader.rs +++ b/crates/shirabe/src/downloader/perforce_downloader.rs @@ -74,7 +74,7 @@ impl PerforceDownloader { let repository = package.get_repository(); let repo_config: Option<IndexMap<String, PhpMixed>> = if let Some(repo) = repository { - if let Some(vcs_repo) = (repo.as_any() as &dyn Any).downcast_ref::<VcsRepository>() { + if let Some(vcs_repo) = repo.as_any().downcast_ref::<VcsRepository>() { Some(self.get_repo_config(vcs_repo)) } else { None diff --git a/crates/shirabe/src/downloader/phar_downloader.rs b/crates/shirabe/src/downloader/phar_downloader.rs index 649841d..19777fb 100644 --- a/crates/shirabe/src/downloader/phar_downloader.rs +++ b/crates/shirabe/src/downloader/phar_downloader.rs @@ -25,12 +25,12 @@ pub struct PharDownloader { impl PharDownloader { pub fn new( io: Box<dyn IOInterface>, - config: Config, - http_downloader: HttpDownloader, + config: std::rc::Rc<std::cell::RefCell<Config>>, + http_downloader: std::rc::Rc<std::cell::RefCell<HttpDownloader>>, event_dispatcher: Option<EventDispatcher>, cache: Option<Cache>, - filesystem: Filesystem, - process: ProcessExecutor, + filesystem: std::rc::Rc<std::cell::RefCell<Filesystem>>, + process: std::rc::Rc<std::cell::RefCell<ProcessExecutor>>, ) -> Self { Self { inner: FileDownloader::new( diff --git a/crates/shirabe/src/downloader/rar_downloader.rs b/crates/shirabe/src/downloader/rar_downloader.rs index 51feadb..afc2f12 100644 --- a/crates/shirabe/src/downloader/rar_downloader.rs +++ b/crates/shirabe/src/downloader/rar_downloader.rs @@ -28,12 +28,12 @@ pub struct RarDownloader { impl RarDownloader { pub fn new( io: Box<dyn IOInterface>, - config: Config, - http_downloader: HttpDownloader, + config: std::rc::Rc<std::cell::RefCell<Config>>, + http_downloader: std::rc::Rc<std::cell::RefCell<HttpDownloader>>, event_dispatcher: Option<EventDispatcher>, cache: Option<Cache>, - filesystem: Filesystem, - process: ProcessExecutor, + filesystem: std::rc::Rc<std::cell::RefCell<Filesystem>>, + process: std::rc::Rc<std::cell::RefCell<ProcessExecutor>>, ) -> Self { Self { inner: FileDownloader::new( @@ -67,7 +67,7 @@ impl RarDownloader { ]; let mut process_output = PhpMixed::Null; - if self.inner.process.execute( + if self.inner.process.borrow_mut().execute( PhpMixed::List( command .iter() @@ -84,7 +84,7 @@ impl RarDownloader { process_error = Some(format!( "Failed to execute {}\n\n{}", implode(" ", &command), - self.inner.process.get_error_output(), + self.inner.process.borrow().get_error_output(), )); } diff --git a/crates/shirabe/src/downloader/svn_downloader.rs b/crates/shirabe/src/downloader/svn_downloader.rs index eb4de65..c228379 100644 --- a/crates/shirabe/src/downloader/svn_downloader.rs +++ b/crates/shirabe/src/downloader/svn_downloader.rs @@ -1,7 +1,8 @@ //! ref: composer/src/Composer/Downloader/SvnDownloader.php use crate::io::io_interface; -use shirabe_external_packages::composer::pcre::preg::Preg; +use indexmap::IndexMap; +use shirabe_external_packages::composer::pcre::preg::{CaptureKey, Preg}; use shirabe_external_packages::react::promise; use shirabe_external_packages::react::promise::promise_interface::PromiseInterface; use shirabe_php_shim::{PhpMixed, RuntimeException, is_dir, version_compare}; @@ -29,9 +30,9 @@ impl SvnDownloader { SvnUtil::clean_env(); let util = SvnUtil::new( url, - &*self.inner.io, - &self.inner.config, - &self.inner.process, + self.inner.io.clone_box(), + std::rc::Rc::clone(&self.inner.config), + Some(std::rc::Rc::clone(&self.inner.process)), ); if util.binary_version().is_none() { return Err(RuntimeException { @@ -68,8 +69,8 @@ impl SvnDownloader { } } - self.inner.io.write_error( - PhpMixed::String(format!(" Checking out {}", package.get_source_reference())), + self.inner.io.write_error3( + &format!(" Checking out {}", package.get_source_reference()), true, io_interface::NORMAL, ); @@ -108,17 +109,17 @@ impl SvnDownloader { let util = SvnUtil::new( url, - &*self.inner.io, - &self.inner.config, - &self.inner.process, + self.inner.io.clone_box(), + std::rc::Rc::clone(&self.inner.config), + Some(std::rc::Rc::clone(&self.inner.process)), ); let mut flags: Vec<String> = vec![]; if version_compare(&util.binary_version().unwrap_or_default(), "1.7.0", ">=") { flags.push("--ignore-ancestry".to_string()); } - self.inner.io.write_error( - PhpMixed::String(format!(" Checking out {}", r#ref)), + self.inner.io.write_error3( + &format!(" Checking out {}", r#ref), true, io_interface::NORMAL, ); @@ -142,7 +143,7 @@ impl SvnDownloader { } let mut output = String::new(); - self.inner.process.execute( + self.inner.process.borrow_mut().execute_args( &["svn", "status", "--ignore-externals"] .map(|s| s.to_string()) .to_vec(), @@ -168,9 +169,9 @@ impl SvnDownloader { ) -> anyhow::Result<String> { let mut util = SvnUtil::new( base_url, - &*self.inner.io, - &self.inner.config, - &self.inner.process, + self.inner.io.clone_box(), + std::rc::Rc::clone(&self.inner.config), + Some(std::rc::Rc::clone(&self.inner.process)), ); util.set_cache_credentials(self.cache_credentials); util.execute(command, url, cwd, path, self.inner.io.is_verbose()) @@ -195,7 +196,14 @@ impl SvnDownloader { } if !self.inner.io.is_interactive() { - if self.inner.config.get("discard-changes").as_bool() == Some(true) { + if self + .inner + .config + .borrow_mut() + .get("discard-changes") + .as_bool() + == Some(true) + { return self.discard_changes(path); } @@ -208,17 +216,17 @@ impl SvnDownloader { .map(|elem| format!(" {}", elem)) .collect(); let count_changes = changes.len() as i64; - self.inner.io.write_error( - PhpMixed::String(format!( + self.inner.io.write_error3( + &format!( " <error>{} has modified file{}:</error>", package.get_pretty_name(), if count_changes == 1 { "" } else { "s" } - )), + ), true, io_interface::NORMAL, ); let slice_end = 10_usize.min(changes.len()); - self.inner.io.write_error( + self.inner.io.write_error3( PhpMixed::List( changes[..slice_end] .iter() @@ -230,12 +238,12 @@ impl SvnDownloader { ); if count_changes > 10 { let remaining_changes = count_changes - 10; - self.inner.io.write_error( - PhpMixed::String(format!( + self.inner.io.write_error3( + &format!( " <info>{} more file{} modified, choose \"v\" to view the full list</info>", remaining_changes, if remaining_changes == 1 { "" } else { "s" } - )), + ), true, io_interface::NORMAL, ); @@ -263,7 +271,7 @@ impl SvnDownloader { .into()); } Some("v") => { - self.inner.io.write_error( + self.inner.io.write_error3( PhpMixed::List( changes .iter() @@ -275,7 +283,7 @@ impl SvnDownloader { ); } _ => { - self.inner.io.write_error( + self.inner.io.write_error3( PhpMixed::List(vec![ Box::new(PhpMixed::String(format!( " y - discard changes and apply the {}", @@ -317,17 +325,17 @@ impl SvnDownloader { path.to_string(), ]; let mut output = String::new(); - if self - .inner - .process - .execute(&command, &mut output, Some(path.to_string())) - != 0 + if self.inner.process.borrow_mut().execute_args( + &command, + &mut output, + Some(path.to_string()), + ) != 0 { return Err(RuntimeException { message: format!( "Failed to execute {}\n\n{}", command.join(" "), - self.inner.process.get_error_output() + self.inner.process.borrow().get_error_output() ), code: 0, } @@ -335,8 +343,14 @@ impl SvnDownloader { } let url_pattern = "#<url>(.*)</url>#"; - let base_url = if let Some(matches) = Preg::match_strict_groups(url_pattern, &output) { - matches.get("1").cloned().unwrap_or_default() + let mut matches: IndexMap<CaptureKey, String> = IndexMap::new(); + let base_url = if Preg::match_strict_groups3(url_pattern, &output, Some(&mut matches)) + .unwrap_or(false) + { + matches + .get(&CaptureKey::ByIndex(1)) + .cloned() + .unwrap_or_default() } else { return Err(RuntimeException { message: format!("Unable to determine svn url for path {}", path), @@ -346,8 +360,10 @@ impl SvnDownloader { }; // strip paths from references and only keep the actual revision - let from_revision = Preg::replace(r"{.*@(\d+)$}", "$1", from_reference.to_string()); - let to_revision = Preg::replace(r"{.*@(\d+)$}", "$1", to_reference.to_string()); + let from_revision = + Preg::replace(r"{.*@(\d+)$}", "$1", &from_reference).unwrap_or_default(); + let to_revision = + Preg::replace(r"{.*@(\d+)$}", "$1", &to_reference).unwrap_or_default(); let command = vec![ "svn".to_string(), @@ -359,9 +375,9 @@ impl SvnDownloader { let mut util = SvnUtil::new( &base_url, - &*self.inner.io, - &self.inner.config, - &self.inner.process, + self.inner.io.clone_box(), + std::rc::Rc::clone(&self.inner.config), + Some(std::rc::Rc::clone(&self.inner.process)), ); util.set_cache_credentials(self.cache_credentials); util.execute_local(command.clone(), path, None, self.inner.io.is_verbose()) @@ -382,7 +398,7 @@ impl SvnDownloader { pub(crate) fn discard_changes(&self, path: &str) -> anyhow::Result<Box<dyn PromiseInterface>> { let mut output = String::new(); - if self.inner.process.execute( + if self.inner.process.borrow_mut().execute_args( &["svn", "revert", "-R", "."].map(|s| s.to_string()).to_vec(), &mut output, Some(path.to_string()), @@ -391,7 +407,7 @@ impl SvnDownloader { return Err(RuntimeException { message: format!( "Could not reset changes\n\n:{}", - self.inner.process.get_error_output() + self.inner.process.borrow().get_error_output() ), code: 0, } diff --git a/crates/shirabe/src/downloader/tar_downloader.rs b/crates/shirabe/src/downloader/tar_downloader.rs index aaa7153..8fcf339 100644 --- a/crates/shirabe/src/downloader/tar_downloader.rs +++ b/crates/shirabe/src/downloader/tar_downloader.rs @@ -25,12 +25,12 @@ pub struct TarDownloader { impl TarDownloader { pub fn new( io: Box<dyn IOInterface>, - config: Config, - http_downloader: HttpDownloader, + config: std::rc::Rc<std::cell::RefCell<Config>>, + http_downloader: std::rc::Rc<std::cell::RefCell<HttpDownloader>>, event_dispatcher: Option<EventDispatcher>, cache: Option<Cache>, - filesystem: Filesystem, - process: ProcessExecutor, + filesystem: std::rc::Rc<std::cell::RefCell<Filesystem>>, + process: std::rc::Rc<std::cell::RefCell<ProcessExecutor>>, ) -> Self { Self { inner: FileDownloader::new( diff --git a/crates/shirabe/src/downloader/transport_exception.rs b/crates/shirabe/src/downloader/transport_exception.rs index 382da01..9d5b352 100644 --- a/crates/shirabe/src/downloader/transport_exception.rs +++ b/crates/shirabe/src/downloader/transport_exception.rs @@ -24,6 +24,12 @@ 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 } diff --git a/crates/shirabe/src/downloader/vcs_downloader.rs b/crates/shirabe/src/downloader/vcs_downloader.rs index 346603a..39518e3 100644 --- a/crates/shirabe/src/downloader/vcs_downloader.rs +++ b/crates/shirabe/src/downloader/vcs_downloader.rs @@ -27,21 +27,24 @@ use crate::util::process_executor::ProcessExecutor; #[derive(Debug)] pub struct VcsDownloaderBase { pub io: Box<dyn IOInterface>, - pub config: Config, - pub process: ProcessExecutor, - pub filesystem: Filesystem, + pub config: std::rc::Rc<std::cell::RefCell<Config>>, + pub process: std::rc::Rc<std::cell::RefCell<ProcessExecutor>>, + pub filesystem: std::rc::Rc<std::cell::RefCell<Filesystem>>, pub has_cleaned_changes: IndexMap<String, bool>, } impl VcsDownloaderBase { pub fn new( io: Box<dyn IOInterface>, - config: Config, - process: Option<ProcessExecutor>, - fs: Option<Filesystem>, + config: std::rc::Rc<std::cell::RefCell<Config>>, + process: Option<std::rc::Rc<std::cell::RefCell<ProcessExecutor>>>, + fs: Option<std::rc::Rc<std::cell::RefCell<Filesystem>>>, ) -> Self { - let process = process.unwrap_or_else(|| ProcessExecutor::new(None, None)); - let filesystem = fs.unwrap_or_else(|| Filesystem::new(None)); + let process = process.unwrap_or_else(|| { + std::rc::Rc::new(std::cell::RefCell::new(ProcessExecutor::new(None))) + }); + let filesystem = + fs.unwrap_or_else(|| std::rc::Rc::new(std::cell::RefCell::new(Filesystem::new(None)))); Self { io, config, @@ -57,12 +60,12 @@ pub trait VcsDownloader: { fn io(&self) -> &dyn IOInterface; fn io_mut(&mut self) -> &mut dyn IOInterface; - fn config(&self) -> &Config; - fn config_mut(&mut self) -> &mut Config; - fn process(&self) -> &ProcessExecutor; - fn process_mut(&mut self) -> &mut ProcessExecutor; - fn filesystem(&self) -> &Filesystem; - fn filesystem_mut(&mut self) -> &mut Filesystem; + fn config(&self) -> &std::rc::Rc<std::cell::RefCell<Config>>; + fn config_mut(&mut self) -> &mut std::rc::Rc<std::cell::RefCell<Config>>; + fn process(&self) -> &std::rc::Rc<std::cell::RefCell<ProcessExecutor>>; + fn process_mut(&mut self) -> &mut std::rc::Rc<std::cell::RefCell<ProcessExecutor>>; + fn filesystem(&self) -> &std::rc::Rc<std::cell::RefCell<Filesystem>>; + fn filesystem_mut(&mut self) -> &mut std::rc::Rc<std::cell::RefCell<Filesystem>>; fn has_cleaned_changes(&self) -> &IndexMap<String, bool>; fn has_cleaned_changes_mut(&mut self) -> &mut IndexMap<String, bool>; @@ -136,8 +139,8 @@ pub trait VcsDownloader: return Err(e); } if self.io().is_debug() { - self.io_mut().write_error( - PhpMixed::String(format!("Failed: [{}] {}", get_class(&e), e,)), + self.io_mut().write_error3( + &format!("Failed: [{}] {}", get_class(&e), e,), true, io_interface::NORMAL, ); @@ -147,8 +150,8 @@ pub trait VcsDownloader: .collect(), )) > 0 { - self.io_mut().write_error( - PhpMixed::String(" Failed, trying the next URL".to_string()), + self.io_mut().write_error3( + " Failed, trying the next URL", true, io_interface::NORMAL, ); @@ -180,7 +183,7 @@ pub trait VcsDownloader: self.has_cleaned_changes_mut() .insert(prev_package.unwrap().get_unique_name(), true); } else if r#type == "install" { - self.filesystem_mut().empty_directory(path); + self.filesystem_mut().borrow_mut().empty_directory(path); } else if r#type == "uninstall" { self.clean_changes(package, path, false)?; } @@ -227,11 +230,8 @@ pub trait VcsDownloader: .into()); } - self.io_mut().write_error( - PhpMixed::String(format!( - " - {}: ", - InstallOperation::format(package, false) - )), + self.io_mut().write_error3( + &format!(" - {}: ", InstallOperation::format(package, false)), false, io_interface::NORMAL, ); @@ -250,8 +250,8 @@ pub trait VcsDownloader: return Err(e); } if self.io().is_debug() { - self.io_mut().write_error( - PhpMixed::String(format!("Failed: [{}] {}", get_class(&e), e,)), + self.io_mut().write_error3( + &format!("Failed: [{}] {}", get_class(&e), e,), true, io_interface::NORMAL, ); @@ -261,8 +261,8 @@ pub trait VcsDownloader: .collect(), )) > 0 { - self.io_mut().write_error( - PhpMixed::String(" Failed, trying the next URL".to_string()), + self.io_mut().write_error3( + " Failed, trying the next URL", true, io_interface::NORMAL, ); @@ -299,11 +299,8 @@ pub trait VcsDownloader: .into()); } - self.io_mut().write_error( - PhpMixed::String(format!( - " - {}: ", - UpdateOperation::format(initial, target, false), - )), + self.io_mut().write_error3( + &format!(" - {}: ", UpdateOperation::format(initial, target, false),), false, io_interface::NORMAL, ); @@ -328,8 +325,8 @@ pub trait VcsDownloader: return Err(e); } if self.io().is_debug() { - self.io_mut().write_error( - PhpMixed::String(format!("Failed: [{}] {}", get_class(&e), e,)), + self.io_mut().write_error3( + &format!("Failed: [{}] {}", get_class(&e), e,), true, io_interface::NORMAL, ); @@ -339,8 +336,8 @@ pub trait VcsDownloader: .collect(), )) > 0 { - self.io_mut().write_error( - PhpMixed::String(" Failed, trying the next URL".to_string()), + self.io_mut().write_error3( + " Failed, trying the next URL", true, io_interface::NORMAL, ); @@ -379,11 +376,8 @@ pub trait VcsDownloader: // escape angle brackets for proper output in the console logs = str_replace("<", "\\<", &logs); - self.io_mut().write_error( - PhpMixed::String(format!(" {}", message)), - true, - io_interface::NORMAL, - ); + self.io_mut() + .write_error3(&format!(" {}", message), true, io_interface::NORMAL); self.io_mut() .write_error3(&logs, true, io_interface::NORMAL); } @@ -403,16 +397,16 @@ pub trait VcsDownloader: package: &dyn PackageInterface, path: &str, ) -> Result<Box<dyn PromiseInterface>> { - self.io_mut().write_error( - PhpMixed::String(format!( - " - {}", - UninstallOperation::format(package, false) - )), + self.io_mut().write_error3( + &format!(" - {}", UninstallOperation::format(package, false)), true, io_interface::NORMAL, ); - let promise = self.filesystem_mut().remove_directory_async(path); + let promise = self + .filesystem_mut() + .borrow_mut() + .remove_directory_async(path); let path = path.to_string(); Ok( @@ -432,7 +426,12 @@ pub trait VcsDownloader: fn get_vcs_reference(&self, package: &dyn PackageInterface, path: &str) -> Option<String> { let parser = VersionParser::new(); - let guesser = VersionGuesser::new(self.config(), self.process(), &parser, self.io()); + let guesser = VersionGuesser::new( + std::rc::Rc::clone(self.config()), + std::rc::Rc::clone(self.process()), + parser.clone(), + Some(self.io().clone_box()), + ); let dumper = ArrayDumper::new(); let package_config = dumper.dump(package); diff --git a/crates/shirabe/src/downloader/xz_downloader.rs b/crates/shirabe/src/downloader/xz_downloader.rs index 61a7f14..99c29d3 100644 --- a/crates/shirabe/src/downloader/xz_downloader.rs +++ b/crates/shirabe/src/downloader/xz_downloader.rs @@ -24,12 +24,12 @@ pub struct XzDownloader { impl XzDownloader { pub fn new( io: Box<dyn IOInterface>, - config: Config, - http_downloader: HttpDownloader, + config: std::rc::Rc<std::cell::RefCell<Config>>, + http_downloader: std::rc::Rc<std::cell::RefCell<HttpDownloader>>, event_dispatcher: Option<EventDispatcher>, cache: Option<Cache>, - filesystem: Filesystem, - process: ProcessExecutor, + filesystem: std::rc::Rc<std::cell::RefCell<Filesystem>>, + process: std::rc::Rc<std::cell::RefCell<ProcessExecutor>>, ) -> Self { Self { inner: FileDownloader::new( @@ -54,7 +54,7 @@ impl XzDownloader { let command = vec!["tar", "-xJf", file, "-C", path]; let mut ignored_output = PhpMixed::Null; - if self.inner.process.execute( + if self.inner.process.borrow_mut().execute( PhpMixed::List( command .iter() @@ -71,7 +71,7 @@ impl XzDownloader { let process_error = format!( "Failed to execute {}\n\n{}", command.join(" "), - self.inner.process.get_error_output() + self.inner.process.borrow().get_error_output() ); bail!(process_error); diff --git a/crates/shirabe/src/downloader/zip_downloader.rs b/crates/shirabe/src/downloader/zip_downloader.rs index 7f779c8..bfaf180 100644 --- a/crates/shirabe/src/downloader/zip_downloader.rs +++ b/crates/shirabe/src/downloader/zip_downloader.rs @@ -7,7 +7,7 @@ use crate::util::ini_helper::IniHelper; use crate::util::platform::Platform; use anyhow::Result; use indexmap::IndexMap; -use shirabe_external_packages::composer::pcre::preg::Preg; +use shirabe_external_packages::composer::pcre::preg::{CaptureKey, Preg}; use shirabe_external_packages::react::promise::promise_interface::PromiseInterface; use shirabe_external_packages::symfony::component::process::executable_finder::ExecutableFinder; use shirabe_external_packages::symfony::component::process::process::Process; @@ -164,9 +164,7 @@ impl ZipDownloader { } } - self.inner - .inner - .download(package, path, prev_package, output) + self.inner.download(package, path, prev_package, output) } fn extract_with_system_unzip( @@ -217,18 +215,23 @@ impl ZipDownloader { let mut output = String::new(); if self .inner - .inner .process .execute(&[command_spec[1].as_str()], &mut output) == 0 { - if let Some(m) = - Preg::is_match_strict_groups(r"^\s*7-Zip(?:\s\[64\])?\s([0-9.]+)", &output) + let mut m: IndexMap<CaptureKey, String> = IndexMap::new(); + if Preg::is_match_strict_groups3( + r"^\s*7-Zip(?:\s\[64\])?\s([0-9.]+)", + &output, + Some(&mut m), + ) + .unwrap_or(false) { - if version_compare(&m[1], "21.01", "<") { + let m1 = m.get(&CaptureKey::ByIndex(1)).cloned().unwrap_or_default(); + if version_compare(&m1, "21.01", "<") { self.inner.io.write_error(&format!( " <warning>Unzipping using {} {} may result in incorrect file permissions. Install {} 21.01+ or unzip to ensure you get correct permissions.</warning>", - executable, m[1], executable, + executable, m1, executable, )); } } @@ -281,7 +284,6 @@ impl ZipDownloader { io.write_error(&format!( "Origin URL: {}", self.inner - .inner .process_url(package, &package.get_dist_url().unwrap_or_default()) )); let headers = FileDownloader::response_headers.lock().unwrap(); @@ -297,7 +299,7 @@ impl ZipDownloader { self.extract_with_zip_archive(package, file, path) }; - match self.inner.process.execute_async(&command) { + match self.inner.process.borrow_mut().execute_async(&command) { Ok(promise) => Ok(promise.then( Box::new(move |process: Process| -> Result<()> { if !process.is_successful() { |
