diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-08-04 02:25:28 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-08-04 05:43:18 +0900 |
| commit | a02fc7d728a9973a3275a0f47604081c4439b424 (patch) | |
| tree | b1a73d2eb6b17bb6c204318b58d75ae6cf46cc7a /crates/shirabe/src/installer/installation_manager.rs | |
| parent | 20f7a7826ae048d249e0d837ca6393a5f09c9ba6 (diff) | |
| download | php-shirabe-a02fc7d728a9973a3275a0f47604081c4439b424.tar.gz php-shirabe-a02fc7d728a9973a3275a0f47604081c4439b424.tar.zst php-shirabe-a02fc7d728a9973a3275a0f47604081c4439b424.zip | |
feat(plugin): activate plugins through the PHP RPC worker
Implement the remainder of PluginManager::registerPackage: the plugin
autoload map is built by the ported createLoader/parseAutoloads and
served to the worker over the existing reverse-RPC autoloader, files
entries go through a composerRequire-equivalent glue call, and
already-defined classes take the upstream _composer_tmp rename/eval
path. Instantiation uses the new NewObject/CallPhpMethod lanes backed
by a P table in the worker; PhpPluginProxy adapts the resulting handle
to PluginInterface, with $composer/$io exposed to plugin callbacks via
an R table (unsupported methods stay explicit errors). Hand-written
proxy stubs cover Composer, PartialComposer and the IO hierarchy, and
the stub autoloader is re-prepended after loading the Composer PHP
runtime so its vendor autoloader cannot shadow proxied FQCNs.
FilesystemRepository::write now mirrors InstalledVersions::reload into
a running worker (class_exists-guarded, so an unloaded class keeps its
upstream lazy-load behavior), removing the previously undefined
observation window.
The installer pipeline passes the installed repository as a shared
handle instead of a long-lived `&mut dyn`: plugin registration runs
inside InstallationManager::execute and re-enters the same local
repository through the RepositoryManager, which would panic on the
RefCell re-borrow under the old shape.
PluginInterface lifecycle methods now take an owned ComposerHandle
(plugins retain $composer past the call) and return anyhow::Result
(PHP plugin code may throw); the plugin list uses shared ownership so
the identity comparison of removePlugin survives the dual storage in
registeredPlugins, matching PHP reference semantics.
Ports the activate/upgrade/uninstall tests of PluginInstallerTest,
serialized across the shared worker process whose persistent class
table is exactly what exercises the rename path.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe/src/installer/installation_manager.rs')
| -rw-r--r-- | crates/shirabe/src/installer/installation_manager.rs | 42 |
1 files changed, 20 insertions, 22 deletions
diff --git a/crates/shirabe/src/installer/installation_manager.rs b/crates/shirabe/src/installer/installation_manager.rs index cf75469c..8d248a76 100644 --- a/crates/shirabe/src/installer/installation_manager.rs +++ b/crates/shirabe/src/installer/installation_manager.rs @@ -16,6 +16,7 @@ use crate::io::IOInterfaceImmutable; use crate::io::io_interface; use crate::package::PackageInterfaceHandle; use crate::repository::InstalledRepositoryInterface; +use crate::repository::InstalledRepositoryInterfaceHandle; use crate::util::Platform; use crate::util::r#loop::Loop; use crate::util::sync_executor; @@ -198,17 +199,18 @@ impl InstallationManager { /// Checks whether provided package is installed in one of the registered installers. pub fn is_package_installed( &self, - repo: &mut dyn InstalledRepositoryInterface, + repo: &InstalledRepositoryInterfaceHandle, package: PackageInterfaceHandle, ) -> anyhow::Result<bool> { // For testing only (ref InstallationManagerMock::isPackageInstalled). if self.mock.is_some() { - return repo.has_package(package); + return repo.borrow_mut().has_package(package); } if let Some(alias) = package.as_alias() { let alias_of: PackageInterfaceHandle = alias.get_alias_of().into(); - return Ok(repo.has_package(package)? && self.is_package_installed(repo, alias_of)?); + return Ok(repo.borrow_mut().has_package(package)? + && self.is_package_installed(repo, alias_of)?); } self.get_installer(&package.get_type())? @@ -236,7 +238,7 @@ impl InstallationManager { /// Executes solver operation. pub fn execute( &mut self, - repo: &mut dyn InstalledRepositoryInterface, + repo: &InstalledRepositoryInterfaceHandle, operations: Vec<AnyOperation>, dev_mode: bool, run_scripts: bool, @@ -248,6 +250,7 @@ impl InstallationManager { // borrowed across the loop without also borrowing `&self`. if let Some(mock) = self.mock.as_mut() { let _ = (dev_mode, run_scripts, download_only); + let mut repo = repo.borrow_mut(); for operation in operations { let trace = shirabe_php_shim::strip_tags(&operation.to_string()); match operation { @@ -318,11 +321,6 @@ impl InstallationManager { let all_operations: Vec<AnyOperation> = operations.clone(); - // The concurrent operation chains share the repository; each chain borrows it only in - // synchronous sections, never across an await. - let repo_cell: std::cell::RefCell<&mut dyn InstalledRepositoryInterface> = - std::cell::RefCell::new(repo); - let result: anyhow::Result<()> = (|| -> anyhow::Result<()> { // execute operations in batches to make sure download-modifying-plugins are installed // before the other packages get downloaded @@ -363,7 +361,7 @@ impl InstallationManager { for batch_to_execute in batches { sync_executor::block_on(self.download_and_execute_batch( - &repo_cell, + repo, batch_to_execute, &mut cleanup_promises, dev_mode, @@ -394,7 +392,7 @@ impl InstallationManager { // do a last write so that we write the repository even if nothing changed // as that can trigger an update of some files like InstalledVersions.php if // running a new composer version - repo_cell.into_inner().write(dev_mode, self); + repo.borrow_mut().write(dev_mode, self); Ok(()) } @@ -402,7 +400,7 @@ impl InstallationManager { #[allow(clippy::too_many_arguments, reason = "to keep PHP signature")] async fn download_and_execute_batch( &self, - repo: &std::cell::RefCell<&mut dyn InstalledRepositoryInterface>, + repo: &InstalledRepositoryInterfaceHandle, operations: IndexMap<i64, AnyOperation>, cleanup_promises: &mut IndexMap< i64, @@ -544,7 +542,7 @@ impl InstallationManager { async fn execute_batch( &self, - repo: &std::cell::RefCell<&mut dyn InstalledRepositoryInterface>, + repo: &InstalledRepositoryInterfaceHandle, operations: IndexMap<i64, AnyOperation>, cleanup_promises: &IndexMap< i64, @@ -577,10 +575,10 @@ impl InstallationManager { } match &operation { AnyOperation::MarkAliasInstalled(op) => { - self.mark_alias_installed(&mut **repo.borrow_mut(), op)?; + self.mark_alias_installed(&mut *repo.borrow_mut(), op)?; } AnyOperation::MarkAliasUninstalled(op) => { - self.mark_alias_uninstalled(&mut **repo.borrow_mut(), op); + self.mark_alias_uninstalled(&mut *repo.borrow_mut(), op); } _ => {} } @@ -701,7 +699,7 @@ impl InstallationManager { /// Executes install operation. pub async fn install( &self, - repo: &std::cell::RefCell<&mut dyn InstalledRepositoryInterface>, + repo: &InstalledRepositoryInterfaceHandle, operation: &InstallOperation, ) -> anyhow::Result<Option<PhpMixed>> { let package = operation.get_package(); @@ -716,7 +714,7 @@ impl InstallationManager { /// Executes update operation. pub async fn update( &self, - repo: &std::cell::RefCell<&mut dyn InstalledRepositoryInterface>, + repo: &InstalledRepositoryInterfaceHandle, operation: &UpdateOperation, ) -> anyhow::Result<Option<PhpMixed>> { let initial = operation.get_initial_package().clone(); @@ -744,7 +742,7 @@ impl InstallationManager { /// Uninstalls package. pub async fn uninstall( &self, - repo: &std::cell::RefCell<&mut dyn InstalledRepositoryInterface>, + repo: &InstalledRepositoryInterfaceHandle, operation: &UninstallOperation, ) -> anyhow::Result<Option<PhpMixed>> { let package = operation.get_package(); @@ -1017,13 +1015,13 @@ pub trait InstallationManagerInterface: std::fmt::Debug { fn disable_plugins(&mut self); fn is_package_installed( &mut self, - repo: &mut dyn InstalledRepositoryInterface, + repo: &InstalledRepositoryInterfaceHandle, package: PackageInterfaceHandle, ) -> anyhow::Result<bool>; fn ensure_binaries_presence(&mut self, package: PackageInterfaceHandle); fn execute( &mut self, - repo: &mut dyn InstalledRepositoryInterface, + repo: &InstalledRepositoryInterfaceHandle, operations: Vec<AnyOperation>, dev_mode: bool, run_scripts: bool, @@ -1053,7 +1051,7 @@ impl InstallationManagerInterface for InstallationManager { fn is_package_installed( &mut self, - repo: &mut dyn InstalledRepositoryInterface, + repo: &InstalledRepositoryInterfaceHandle, package: PackageInterfaceHandle, ) -> anyhow::Result<bool> { InstallationManager::is_package_installed(self, repo, package) @@ -1065,7 +1063,7 @@ impl InstallationManagerInterface for InstallationManager { fn execute( &mut self, - repo: &mut dyn InstalledRepositoryInterface, + repo: &InstalledRepositoryInterfaceHandle, operations: Vec<AnyOperation>, dev_mode: bool, run_scripts: bool, |
