diff options
Diffstat (limited to 'crates/shirabe/src/installer')
7 files changed, 89 insertions, 59 deletions
diff --git a/crates/shirabe/src/installer/binary_installer.rs b/crates/shirabe/src/installer/binary_installer.rs index e6677ed..c7b880b 100644 --- a/crates/shirabe/src/installer/binary_installer.rs +++ b/crates/shirabe/src/installer/binary_installer.rs @@ -1,7 +1,8 @@ //! ref: composer/src/Composer/Installer/BinaryInstaller.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_php_shim::{ PhpMixed, basename, basename_with_suffix, chmod, dirname, fclose, fgets, file_exists, file_get_contents, file_put_contents, fopen, is_dir, is_file, is_link, realpath, rmdir, substr, @@ -21,7 +22,7 @@ pub struct BinaryInstaller { pub(crate) bin_dir: String, pub(crate) bin_compat: String, pub(crate) io: Box<dyn IOInterface>, - pub(crate) filesystem: Filesystem, + pub(crate) filesystem: std::rc::Rc<std::cell::RefCell<Filesystem>>, vendor_dir: Option<String>, } @@ -30,10 +31,11 @@ impl BinaryInstaller { io: Box<dyn IOInterface>, bin_dir: String, bin_compat: String, - filesystem: Option<Filesystem>, + filesystem: Option<std::rc::Rc<std::cell::RefCell<Filesystem>>>, vendor_dir: Option<String>, ) -> 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 { bin_dir, bin_compat, @@ -59,30 +61,30 @@ impl BinaryInstaller { for bin in &binaries { let mut bin_path = format!("{}/{}", install_path, bin); if !file_exists(&bin_path) { - self.io.write_error( - PhpMixed::String(format!( + self.io.write_error3( + &format!( " <warning>Skipped installation of bin {} for package {}: file not found in package</warning>", bin, package.get_name(), - )), + ), true, io_interface::NORMAL, ); continue; } if is_dir(&bin_path) { - self.io.write_error( - PhpMixed::String(format!( + self.io.write_error3( + &format!( " <warning>Skipped installation of bin {} for package {}: found a directory at that path</warning>", bin, package.get_name(), - )), + ), true, io_interface::NORMAL, ); continue; } - if !self.filesystem.is_absolute_path(&bin_path) { + if !self.filesystem.borrow_mut().is_absolute_path(&bin_path) { // in case a custom installer returned a relative path for the // $package, we can now safely turn it into a absolute path (as we // already checked the binary's existence). The following helpers @@ -94,12 +96,12 @@ impl BinaryInstaller { if file_exists(&link) { if !is_link(&link) { if warn_on_overwrite { - self.io.write_error( - PhpMixed::String(format!( + self.io.write_error3( + &format!( " Skipped installation of bin {} for package {}: name conflicts with an existing file", bin, package.get_name(), - )), + ), true, io_interface::NORMAL, ); @@ -108,7 +110,7 @@ impl BinaryInstaller { } if realpath(&link) == realpath(&bin_path) { // It is a linked binary from a previous installation, which can be replaced with a proxy file - self.filesystem.unlink(&link); + self.filesystem.borrow_mut().unlink(&link); } } @@ -142,15 +144,17 @@ impl BinaryInstaller { let link = format!("{}/{}", self.bin_dir, basename(bin)); if is_link(&link) || file_exists(&link) { // still checking for symlinks here for legacy support - self.filesystem.unlink(&link); + self.filesystem.borrow_mut().unlink(&link); } if is_file(&format!("{}.bat", link)) { - self.filesystem.unlink(&format!("{}.bat", link)); + self.filesystem + .borrow_mut() + .unlink(&format!("{}.bat", link)); } } // attempt removing the bin dir in case it is left empty - if is_dir(&self.bin_dir) && self.filesystem.is_dir_empty(&self.bin_dir) { + if is_dir(&self.bin_dir) && self.filesystem.borrow_mut().is_dir_empty(&self.bin_dir) { let bin_dir = self.bin_dir.clone(); let _ = Silencer::call(|| { rmdir(&bin_dir); @@ -167,10 +171,20 @@ impl BinaryInstaller { let handle = fopen(bin, "r"); let line = fgets(handle.clone()).unwrap_or_default(); fclose(handle); - if let Some(m) = - Preg::is_match_strict_groups(r"{^#!/(?:usr/bin/env )?(?:[^/]+/)*(.+)$}m", &line) + let mut m: IndexMap<CaptureKey, String> = IndexMap::new(); + if Preg::is_match_strict_groups3( + r"{^#!/(?:usr/bin/env )?(?:[^/]+/)*(.+)$}m", + &line, + Some(&mut m), + ) + .unwrap_or(false) { - return trim(m.get(1).map(|s| s.as_str()).unwrap_or(""), None); + return trim( + m.get(&CaptureKey::ByIndex(1)) + .map(|s| s.as_str()) + .unwrap_or(""), + None, + ); } "php".to_string() @@ -194,12 +208,12 @@ impl BinaryInstaller { self.install_unixy_proxy_binaries(bin_path, &link); link.push_str(".bat"); if file_exists(&link) { - self.io.write_error( - PhpMixed::String(format!( + self.io.write_error3( + &format!( " Skipped installation of bin {}.bat proxy for package {}: a .bat proxy was already installed", bin, package.get_name(), - )), + ), true, io_interface::NORMAL, ); @@ -227,13 +241,18 @@ impl BinaryInstaller { } pub(crate) fn initialize_bin_dir(&mut self) { - self.filesystem.ensure_directory_exists(&self.bin_dir); + self.filesystem + .borrow_mut() + .ensure_directory_exists(&self.bin_dir); // TODO(phase-b): PHP assigns realpath(...) even when realpath returns false self.bin_dir = realpath(&self.bin_dir).unwrap_or_default(); } pub(crate) fn generate_windows_proxy_code(&self, bin: &str, link: &str) -> String { - let bin_path = self.filesystem.find_shortest_path(link, bin, false); + let bin_path = self + .filesystem + .borrow_mut() + .find_shortest_path(link, bin, false); let caller = Self::determine_binary_caller(bin); // if the target is a php file, we run the unixy proxy file @@ -266,7 +285,10 @@ impl BinaryInstaller { } pub(crate) fn generate_unixy_proxy_code(&self, bin: &str, link: &str) -> String { - let bin_path = self.filesystem.find_shortest_path(link, bin, false); + let bin_path = self + .filesystem + .borrow_mut() + .find_shortest_path(link, bin, false); let bin_dir = ProcessExecutor::escape(&dirname(&bin_path)); let bin_file = basename(&bin_path); @@ -289,6 +311,7 @@ impl BinaryInstaller { }; let bin_path_exported = self .filesystem + .borrow() .find_shortest_path_code(link, bin, false, true); let mut stream_proxy_code = String::new(); let mut stream_hint = String::new(); @@ -301,7 +324,7 @@ impl BinaryInstaller { let vendor_dir_real = realpath(vendor_dir).unwrap_or_else(|| vendor_dir.clone()); globals_code.push_str(&format!( "$GLOBALS['_composer_autoload_path'] = {};\n", - self.filesystem.find_shortest_path_code( + self.filesystem.borrow_mut().find_shortest_path_code( link, &format!("{}/autoload.php", vendor_dir_real), false, @@ -311,9 +334,10 @@ impl BinaryInstaller { } // Add workaround for PHPUnit process isolation if let Some(vendor_dir) = &self.vendor_dir { - if self.filesystem.normalize_path(bin) + if self.filesystem.borrow().normalize_path(bin) == self .filesystem + .borrow() .normalize_path(&format!("{}/phpunit/phpunit/phpunit", vendor_dir)) { // workaround issue on PHPUnit 6.5+ running on PHP 8+ diff --git a/crates/shirabe/src/installer/installation_manager.rs b/crates/shirabe/src/installer/installation_manager.rs index 59e029a..3789729 100644 --- a/crates/shirabe/src/installer/installation_manager.rs +++ b/crates/shirabe/src/installer/installation_manager.rs @@ -412,8 +412,8 @@ impl InstallationManager { if !["update", "install", "uninstall"].contains(&op_type.as_str()) { // output alias ops in debug verbosity as they have no output otherwise if self.io.is_debug() { - self.io.write_error( - PhpMixed::String(format!(" - {}", operation.show(false))), + self.io.write_error3( + &format!(" - {}", operation.show(false)), true, io_interface::NORMAL, ); @@ -696,12 +696,12 @@ impl InstallationManager { ), ); - promises.push(self.loop_.borrow().get_http_downloader().add( + promises.push(self.loop_.borrow().get_http_downloader().borrow_mut().add( &url, &PhpMixed::Array( opts.into_iter().map(|(k, v)| (k, Box::new(v))).collect(), ), - )); + )?); } continue; @@ -767,10 +767,10 @@ impl InstallationManager { PhpMixed::Array(http.into_iter().map(|(k, v)| (k, Box::new(v))).collect()), ); - promises.push(self.loop_.borrow().get_http_downloader().add( + promises.push(self.loop_.borrow().get_http_downloader().borrow_mut().add( repo_url, &PhpMixed::Array(opts.into_iter().map(|(k, v)| (k, Box::new(v))).collect()), - )); + )?); } let _ = self.loop_.borrow_mut().wait(promises, None); diff --git a/crates/shirabe/src/installer/installer_interface.rs b/crates/shirabe/src/installer/installer_interface.rs index cf700be..a9e8d9b 100644 --- a/crates/shirabe/src/installer/installer_interface.rs +++ b/crates/shirabe/src/installer/installer_interface.rs @@ -4,7 +4,7 @@ use crate::package::package_interface::PackageInterface; use crate::repository::installed_repository_interface::InstalledRepositoryInterface; use shirabe_external_packages::react::promise::promise_interface::PromiseInterface; -pub trait InstallerInterface { +pub trait InstallerInterface: std::fmt::Debug { fn supports(&self, package_type: &str) -> bool; fn is_installed( diff --git a/crates/shirabe/src/installer/library_installer.rs b/crates/shirabe/src/installer/library_installer.rs index 17404e2..0bc87f9 100644 --- a/crates/shirabe/src/installer/library_installer.rs +++ b/crates/shirabe/src/installer/library_installer.rs @@ -30,7 +30,7 @@ pub struct LibraryInstaller { pub(crate) download_manager: Option<std::rc::Rc<std::cell::RefCell<DownloadManager>>>, pub(crate) io: Box<dyn IOInterface>, pub(crate) r#type: Option<String>, - pub(crate) filesystem: Filesystem, + pub(crate) filesystem: std::rc::Rc<std::cell::RefCell<Filesystem>>, pub(crate) binary_installer: BinaryInstaller, } @@ -40,31 +40,34 @@ impl LibraryInstaller { io: Box<dyn IOInterface>, composer: PartialComposer, r#type: Option<String>, - filesystem: Option<Filesystem>, + filesystem: Option<std::rc::Rc<std::cell::RefCell<Filesystem>>>, binary_installer: Option<BinaryInstaller>, ) -> Self { // PHP: $this->downloadManager = $composer instanceof Composer ? $composer->getDownloadManager() : null; - let download_manager = if let Some(full_composer) = - (composer.as_any() as &dyn Any).downcast_ref::<Composer>() - { - // TODO(phase-b): clone or borrow the DownloadManager from the full Composer - Some(todo!("composer.get_download_manager() as DownloadManager")) - } else { - None - }; + let download_manager = + if let Some(full_composer) = composer.as_any().downcast_ref::<Composer>() { + // TODO(phase-b): clone or borrow the DownloadManager from the full Composer + Some(todo!("composer.get_download_manager() as DownloadManager")) + } else { + None + }; - 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)))); let vendor_dir = rtrim( - // TODO(phase-b): composer.get_config().get("vendor-dir") returns a PhpMixed/String - &composer.get_config().get("vendor-dir"), + // TODO(phase-b): composer.get_config().borrow_mut().get("vendor-dir") returns a PhpMixed/String + &composer.get_config().borrow_mut().get("vendor-dir"), Some("/"), ); let binary_installer = binary_installer.unwrap_or_else(|| { BinaryInstaller::new( // TODO(phase-b): pass io by reference/clone todo!("io reference"), - rtrim(&composer.get_config().get("bin-dir"), Some("/")), - composer.get_config().get("bin-compat"), + rtrim( + &composer.get_config().borrow_mut().get("bin-dir"), + Some("/"), + ), + composer.get_config().borrow_mut().get("bin-compat"), // TODO(phase-b): pass filesystem reference todo!("filesystem reference"), vendor_dir.clone(), @@ -163,6 +166,7 @@ impl LibraryInstaller { } self.filesystem + .borrow_mut() .rename(&initial_download_path, &target_download_path); } @@ -185,7 +189,9 @@ impl LibraryInstaller { } pub(crate) fn initialize_vendor_dir(&mut self) { - self.filesystem.ensure_directory_exists(&self.vendor_dir); + self.filesystem + .borrow_mut() + .ensure_directory_exists(&self.vendor_dir); // TODO(phase-b): realpath returns Option<String>; PHP assigns to vendorDir even when false self.vendor_dir = realpath(&self.vendor_dir).unwrap(); } @@ -232,7 +238,7 @@ impl InstallerInterface for LibraryInstaller { return true; } - if Platform::is_windows() && self.filesystem.is_junction(&install_path) { + if Platform::is_windows() && self.filesystem.borrow_mut().is_junction(&install_path) { return true; } @@ -393,7 +399,7 @@ impl InstallerInterface for LibraryInstaller { if strpos(package.get_name(), "/").is_some() { let package_vendor_dir = shirabe_php_shim::dirname(&download_path); if shirabe_php_shim::is_dir(&package_vendor_dir) - && filesystem.is_dir_empty(&package_vendor_dir) + && filesystem.borrow().is_dir_empty(&package_vendor_dir) { Silencer::call(|| { rmdir(&package_vendor_dir); diff --git a/crates/shirabe/src/installer/plugin_installer.rs b/crates/shirabe/src/installer/plugin_installer.rs index 77bd669..bb04947 100644 --- a/crates/shirabe/src/installer/plugin_installer.rs +++ b/crates/shirabe/src/installer/plugin_installer.rs @@ -23,7 +23,7 @@ impl PluginInstaller { pub fn new( io: Box<dyn IOInterface>, composer: PartialComposer, - fs: Option<Filesystem>, + fs: Option<std::rc::Rc<std::cell::RefCell<Filesystem>>>, binary_installer: Option<BinaryInstaller>, ) -> Self { Self { diff --git a/crates/shirabe/src/installer/project_installer.rs b/crates/shirabe/src/installer/project_installer.rs index f8b0bba..906e2c0 100644 --- a/crates/shirabe/src/installer/project_installer.rs +++ b/crates/shirabe/src/installer/project_installer.rs @@ -12,14 +12,14 @@ use shirabe_php_shim::InvalidArgumentException; pub struct ProjectInstaller { install_path: String, download_manager: std::rc::Rc<std::cell::RefCell<DownloadManager>>, - filesystem: Filesystem, + filesystem: std::rc::Rc<std::cell::RefCell<Filesystem>>, } impl ProjectInstaller { pub fn new( install_path: &str, dm: std::rc::Rc<std::cell::RefCell<DownloadManager>>, - fs: Filesystem, + fs: std::rc::Rc<std::cell::RefCell<Filesystem>>, ) -> Self { let install_path = format!("{}/", install_path.replace('\\', "/").trim_end_matches('/')); Self { @@ -50,7 +50,7 @@ impl InstallerInterface for ProjectInstaller { ) -> anyhow::Result<Option<Box<dyn PromiseInterface>>> { let install_path = &self.install_path; if std::path::Path::new(install_path).exists() - && !self.filesystem.is_dir_empty(install_path) + && !self.filesystem.borrow().is_dir_empty(install_path) { return Err(InvalidArgumentException { message: format!("Project directory {} is not empty.", install_path), diff --git a/crates/shirabe/src/installer/suggested_packages_reporter.rs b/crates/shirabe/src/installer/suggested_packages_reporter.rs index 31a34d8..c820009 100644 --- a/crates/shirabe/src/installer/suggested_packages_reporter.rs +++ b/crates/shirabe/src/installer/suggested_packages_reporter.rs @@ -161,7 +161,7 @@ impl SuggestedPackagesReporter { let mut installed_names: Vec<String> = Vec::new(); if installed_repo.is_some() && !suggested_packages.is_empty() { for package in installed_repo.unwrap().get_packages() { - installed_names.extend(package.get_names()); + installed_names.extend(package.get_names(true)); } } |
