diff options
Diffstat (limited to 'crates/shirabe/src/installer')
| -rw-r--r-- | crates/shirabe/src/installer/installation_manager.rs | 98 | ||||
| -rw-r--r-- | crates/shirabe/src/installer/package_event.rs | 24 |
2 files changed, 72 insertions, 50 deletions
diff --git a/crates/shirabe/src/installer/installation_manager.rs b/crates/shirabe/src/installer/installation_manager.rs index 439026b0..1f1c60a5 100644 --- a/crates/shirabe/src/installer/installation_manager.rs +++ b/crates/shirabe/src/installer/installation_manager.rs @@ -327,16 +327,19 @@ impl InstallationManager { }), ); - let all_operations: Vec<AnyOperation> = operations.clone(); + // Shared rather than owned so that one operation reaches a plugin as one object, both + // through the whole batch pipeline and through its pre- and post-event. + let all_operations: Vec<std::rc::Rc<AnyOperation>> = + operations.into_iter().map(std::rc::Rc::new).collect(); let result: anyhow::Result<()> = (|| -> anyhow::Result<()> { // execute operations in batches to make sure download-modifying-plugins are installed // before the other packages get downloaded - let mut batches: Vec<IndexMap<i64, AnyOperation>> = vec![]; - let mut batch: IndexMap<i64, AnyOperation> = IndexMap::new(); - for (index, operation) in operations.into_iter().enumerate() { + let mut batches: Vec<IndexMap<i64, std::rc::Rc<AnyOperation>>> = vec![]; + let mut batch: IndexMap<i64, std::rc::Rc<AnyOperation>> = IndexMap::new(); + for (index, operation) in all_operations.iter().cloned().enumerate() { let index = index as i64; - let package: Option<PackageInterfaceHandle> = match &operation { + let package: Option<PackageInterfaceHandle> = match &*operation { AnyOperation::Update(update) => Some(update.get_target_package()), AnyOperation::Install(install) => Some(install.get_package()), _ => None, @@ -409,7 +412,7 @@ impl InstallationManager { async fn download_and_execute_batch( &self, repo: &InstalledRepositoryInterfaceHandle, - operations: IndexMap<i64, AnyOperation>, + operations: IndexMap<i64, std::rc::Rc<AnyOperation>>, cleanup_promises: &mut IndexMap< i64, Box< @@ -421,7 +424,7 @@ impl InstallationManager { dev_mode: bool, run_scripts: bool, download_only: bool, - all_operations: Vec<AnyOperation>, + all_operations: Vec<std::rc::Rc<AnyOperation>>, ) -> anyhow::Result<()> { let mut promises: Vec< std::pin::Pin<Box<dyn std::future::Future<Output = anyhow::Result<()>>>>, @@ -436,7 +439,7 @@ impl InstallationManager { } let package = operation.get_target_package(); - let initial_package: Option<PackageInterfaceHandle> = match operation { + let initial_package: Option<PackageInterfaceHandle> = match &**operation { AnyOperation::Update(update_op) => Some(update_op.get_initial_package()), _ => None, }; @@ -505,10 +508,10 @@ impl InstallationManager { // execute operations in batches to make sure every plugin is installed in the // right order and activated before the packages depending on it are installed - let mut batches: Vec<IndexMap<i64, AnyOperation>> = vec![]; - let mut batch: IndexMap<i64, AnyOperation> = IndexMap::new(); + let mut batches: Vec<IndexMap<i64, std::rc::Rc<AnyOperation>>> = vec![]; + let mut batch: IndexMap<i64, std::rc::Rc<AnyOperation>> = IndexMap::new(); for (index, operation) in operations { - let package: Option<PackageInterfaceHandle> = match &operation { + let package: Option<PackageInterfaceHandle> = match &*operation { AnyOperation::Update(update) => Some(update.get_target_package()), AnyOperation::Install(install) => Some(install.get_package()), _ => None, @@ -551,7 +554,7 @@ impl InstallationManager { async fn execute_batch( &self, repo: &InstalledRepositoryInterfaceHandle, - operations: IndexMap<i64, AnyOperation>, + operations: IndexMap<i64, std::rc::Rc<AnyOperation>>, cleanup_promises: &IndexMap< i64, Box< @@ -562,11 +565,13 @@ impl InstallationManager { >, dev_mode: bool, run_scripts: bool, - all_operations: &[AnyOperation], + all_operations: &[std::rc::Rc<AnyOperation>], ) -> anyhow::Result<()> { let mut promises: Vec< std::pin::Pin<Box<dyn std::future::Future<Output = anyhow::Result<()>> + '_>>, > = vec![]; + // @var array<callable(): void> $postExecCallbacks + let mut post_exec_callbacks: Vec<Box<dyn Fn() -> anyhow::Result<()>>> = vec![]; for (index, operation) in operations { let op_type = operation.get_operation_type(); @@ -581,7 +586,7 @@ impl InstallationManager { io_interface::NORMAL, ); } - match &operation { + match &*operation { AnyOperation::MarkAliasInstalled(op) => { self.mark_alias_installed(&mut *repo.borrow_mut(), op)?; } @@ -595,7 +600,7 @@ impl InstallationManager { } let package = operation.get_target_package(); - let initial_package: Option<PackageInterfaceHandle> = match &operation { + let initial_package: Option<PackageInterfaceHandle> = match &*operation { AnyOperation::Update(update_op) => Some(update_op.get_initial_package()), _ => None, }; @@ -607,11 +612,14 @@ impl InstallationManager { _ => "", }; - if run_scripts && self.event_dispatcher.is_some() { - // TODO(phase-c): dispatch_package_event takes Box<dyn RepositoryInterface>/Vec<Box<...>> - // but we hold a RefCell'd &mut dyn here. Needs structural rework (likely shared Rc - // on repo and ops). - let _ = (event_name, dev_mode, &repo, &all_operations, &operation); + if run_scripts && let Some(event_dispatcher) = &self.event_dispatcher { + event_dispatcher.borrow_mut().dispatch_package_event( + event_name, + dev_mode, + repo.clone(), + all_operations.to_vec(), + operation.clone(), + )?; } let installer = self.get_installer(&package.get_type())?; @@ -620,16 +628,16 @@ impl InstallationManager { // ->then(fn() => $this->{$opType}($repo, $operation)) // ->then($cleanupPromises[$index]) // ->then(fn() => $repo->write($devMode, $this), fn($e) => { "<op> of <pkg> - // failed"; throw $e; }) - // ->then(fn() => dispatch POST_PACKAGE_* event); + // failed"; throw $e; }); // each package gets its own chain and the whole batch resolves via waitOnPromises. + let executed_operation = std::rc::Rc::clone(&operation); promises.push(Box::pin(async move { let chain_result: anyhow::Result<()> = async { installer .prepare(op_type, package.clone(), initial_package.clone()) .await?; - match &operation { + match &*executed_operation { AnyOperation::Install(op) => { self.install(repo, op).await?; } @@ -668,24 +676,32 @@ impl InstallationManager { // PHP: ->then(fn() => $repo->write($devMode, $this)) persists the repository after each op. repo.borrow_mut().write(dev_mode, self)?; - let event_name_post = match op_type { - "install" => PackageEvents::POST_PACKAGE_INSTALL, - "update" => PackageEvents::POST_PACKAGE_UPDATE, - "uninstall" => PackageEvents::POST_PACKAGE_UNINSTALL, - _ => "", - }; - - if run_scripts && self.event_dispatcher.is_some() { - // PHP dispatches the POST_PACKAGE_* event at the end of the chain via the event - // dispatcher with repo/all_operations/operation. - // TODO(phase-c): dispatch_package_event takes Box<dyn RepositoryInterface>/ - // Vec<Box<...>> but we hold a RefCell'd &mut dyn here. Needs structural rework - // (likely shared Rc on repo and ops). - let _ = event_name_post; - } - Ok(()) })); + + let event_name = match op_type { + "install" => PackageEvents::POST_PACKAGE_INSTALL, + "update" => PackageEvents::POST_PACKAGE_UPDATE, + "uninstall" => PackageEvents::POST_PACKAGE_UNINSTALL, + _ => "", + }; + + if run_scripts && let Some(event_dispatcher) = &self.event_dispatcher { + let event_dispatcher = event_dispatcher.clone(); + let repo = repo.clone(); + let all_operations = all_operations.to_vec(); + post_exec_callbacks.push(Box::new(move || { + event_dispatcher.borrow_mut().dispatch_package_event( + event_name, + dev_mode, + repo.clone(), + all_operations.clone(), + operation.clone(), + )?; + + Ok(()) + })); + } } if !promises.is_empty() { @@ -694,6 +710,10 @@ impl InstallationManager { Platform::workaround_filesystem_issues(); + for cb in post_exec_callbacks { + cb()?; + } + Ok(()) } diff --git a/crates/shirabe/src/installer/package_event.rs b/crates/shirabe/src/installer/package_event.rs index 9435a581..5e6ddb34 100644 --- a/crates/shirabe/src/installer/package_event.rs +++ b/crates/shirabe/src/installer/package_event.rs @@ -5,19 +5,21 @@ use crate::dependency_resolver::operation::AnyOperation; use crate::event_dispatcher::Event; use crate::event_dispatcher::EventInterface; use crate::io::IOInterface; -use crate::repository::RepositoryInterface; +use crate::repository::InstalledRepositoryInterfaceHandle; use indexmap::IndexMap; use shirabe_php_shim::PhpMixed; +/// The operations are shared rather than owned so that the same operation crosses the plugin +/// boundary as one object for both the pre- and the post-event, as it does in PHP. #[derive(Debug)] pub struct PackageEvent { inner: Event, composer: ComposerWeakHandle, io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>, dev_mode: bool, - local_repo: Box<dyn RepositoryInterface>, - operations: Vec<AnyOperation>, - operation: AnyOperation, + local_repo: InstalledRepositoryInterfaceHandle, + operations: Vec<std::rc::Rc<AnyOperation>>, + operation: std::rc::Rc<AnyOperation>, } impl PackageEvent { @@ -26,9 +28,9 @@ impl PackageEvent { composer: ComposerWeakHandle, io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>, dev_mode: bool, - local_repo: Box<dyn RepositoryInterface>, - operations: Vec<AnyOperation>, - operation: AnyOperation, + local_repo: InstalledRepositoryInterfaceHandle, + operations: Vec<std::rc::Rc<AnyOperation>>, + operation: std::rc::Rc<AnyOperation>, ) -> Self { Self { inner: Event::new(event_name, vec![], IndexMap::new()), @@ -57,15 +59,15 @@ impl PackageEvent { self.dev_mode } - pub fn get_local_repo(&self) -> &dyn RepositoryInterface { - self.local_repo.as_ref() + pub fn get_local_repo(&self) -> InstalledRepositoryInterfaceHandle { + self.local_repo.clone() } - pub fn get_operations(&self) -> &Vec<AnyOperation> { + pub fn get_operations(&self) -> &Vec<std::rc::Rc<AnyOperation>> { &self.operations } - pub fn get_operation(&self) -> &AnyOperation { + pub fn get_operation(&self) -> &std::rc::Rc<AnyOperation> { &self.operation } } |
