aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/src/installer
diff options
context:
space:
mode:
Diffstat (limited to 'crates/shirabe/src/installer')
-rw-r--r--crates/shirabe/src/installer/installation_manager.rs76
-rw-r--r--crates/shirabe/src/installer/installer_interface.rs2
-rw-r--r--crates/shirabe/src/installer/library_installer.rs6
-rw-r--r--crates/shirabe/src/installer/metapackage_installer.rs4
-rw-r--r--crates/shirabe/src/installer/noop_installer.rs4
-rw-r--r--crates/shirabe/src/installer/plugin_installer.rs4
-rw-r--r--crates/shirabe/src/installer/project_installer.rs4
7 files changed, 49 insertions, 51 deletions
diff --git a/crates/shirabe/src/installer/installation_manager.rs b/crates/shirabe/src/installer/installation_manager.rs
index 31bfaa2c..439026b0 100644
--- a/crates/shirabe/src/installer/installation_manager.rs
+++ b/crates/shirabe/src/installer/installation_manager.rs
@@ -33,12 +33,12 @@ pub struct InstallationManager {
/// Rc rather than Box so `get_installer` can hand out shareable handles: the download/cleanup
/// futures collected for Loop::wait must own their installer beyond the loop iteration that
/// created them (PHP closures capture $installer the same way).
- installers: Vec<std::rc::Rc<dyn InstallerInterface>>,
- /// Maps a package type to the index of its installer in `installers`. PHP caches the installer
- /// instance itself; here we store an index instead. The index never dangles because both
- /// `add_installer` and `remove_installer` clear the cache whenever `installers` changes.
+ /// RefCell so a plugin activated from inside `execute` — which holds a shared borrow of this
+ /// manager for the whole run — can still register its own installer.
+ installers: std::cell::RefCell<Vec<std::rc::Rc<dyn InstallerInterface>>>,
+ /// Maps a package type to its installer.
/// RefCell so lookups can populate the cache through `&self` from concurrent operation chains.
- cache: std::cell::RefCell<IndexMap<String, usize>>,
+ cache: std::cell::RefCell<IndexMap<String, std::rc::Rc<dyn InstallerInterface>>>,
/// RefCell so mark_for_notification works through `&self` from concurrent operation chains.
notifiable_packages: std::cell::RefCell<IndexMap<String, Vec<PackageInterfaceHandle>>>,
loop_: std::rc::Rc<std::cell::RefCell<Loop>>,
@@ -69,7 +69,7 @@ impl InstallationManager {
event_dispatcher: Option<std::rc::Rc<std::cell::RefCell<EventDispatcher>>>,
) -> Self {
Self {
- installers: vec![],
+ installers: std::cell::RefCell::new(vec![]),
cache: std::cell::RefCell::new(IndexMap::new()),
notifiable_packages: std::cell::RefCell::new(IndexMap::new()),
loop_,
@@ -133,30 +133,25 @@ impl InstallationManager {
}
/// Adds installer
- pub fn add_installer(&mut self, installer: Box<dyn InstallerInterface>) {
- array_unshift(&mut self.installers, std::rc::Rc::from(installer));
- self.cache = std::cell::RefCell::new(IndexMap::new());
- }
-
- /// For testing only: adds an installer as a pre-built shared handle, so the caller keeps an
- /// identity handle usable for PHP `assertSame`-style comparisons (`Rc::ptr_eq`) and for
- /// `remove_installer`. `add_installer` cannot serve because `Rc::from(Box)` reallocates,
- /// losing the caller's pointer identity.
- pub fn __add_installer(&mut self, installer: std::rc::Rc<dyn InstallerInterface>) {
- array_unshift(&mut self.installers, installer);
- self.cache = std::cell::RefCell::new(IndexMap::new());
+ ///
+ /// The installer is taken as a shared handle: PHP hands over an object reference and both
+ /// sides keep the same identity afterwards, which `removeInstaller` and the plugin
+ /// manager's `registeredPlugins` bookkeeping compare against.
+ pub fn add_installer(&self, installer: std::rc::Rc<dyn InstallerInterface>) {
+ array_unshift(&mut self.installers.borrow_mut(), installer);
+ self.cache.borrow_mut().clear();
}
/// Removes installer
- pub fn remove_installer(&mut self, installer: &dyn InstallerInterface) {
+ pub fn remove_installer(&self, installer: &dyn InstallerInterface) {
let target = installer as *const dyn InstallerInterface as *const ();
- let key = self
- .installers
+ let mut installers = self.installers.borrow_mut();
+ let key = installers
.iter()
.position(|inst| &**inst as *const dyn InstallerInterface as *const () == target);
if let Some(k) = key {
- array_splice(&mut self.installers, k as i64, Some(1), vec![]);
- self.cache = std::cell::RefCell::new(IndexMap::new());
+ array_splice(&mut installers, k as i64, Some(1), vec![]);
+ self.cache.borrow_mut().clear();
}
}
@@ -166,7 +161,9 @@ impl InstallationManager {
/// disabling the PluginManager. This ensures that no third-party
/// code is ever executed.
pub fn disable_plugins(&mut self) {
- for installer in self.installers.iter() {
+ // Cloned out: `disablePlugins` reaches into the plugin manager, which may reach back.
+ let installers = self.installers.borrow().clone();
+ for installer in installers.iter() {
if let Some(plugin_installer) = installer.as_plugin_installer() {
plugin_installer.disable_plugins();
}
@@ -180,17 +177,18 @@ impl InstallationManager {
) -> anyhow::Result<std::rc::Rc<dyn InstallerInterface>> {
let r#type = strtolower(r#type);
- if let Some(&index) = self.cache.borrow().get(&r#type) {
- return Ok(self.installers[index].clone());
+ if let Some(installer) = self.cache.borrow().get(&r#type) {
+ return Ok(installer.clone());
}
- let index = self
- .installers
- .iter()
- .position(|installer| installer.supports(&r#type));
- if let Some(index) = index {
- self.cache.borrow_mut().insert(r#type, index);
- return Ok(self.installers[index].clone());
+ // Cloned out: a PHP-backed installer answers `supports` over RPC, and the plugin behind
+ // it can register a further installer from that call.
+ let installers = self.installers.borrow().clone();
+ for installer in installers {
+ if installer.supports(&r#type)? {
+ self.cache.borrow_mut().insert(r#type, installer.clone());
+ return Ok(installer);
+ }
}
Err(InvalidArgumentException {
@@ -1020,8 +1018,8 @@ pub trait InstallationManagerInterface: std::fmt::Debug {
unimplemented!("as_any is only implemented for the concrete InstallationManager")
}
- fn add_installer(&mut self, installer: Box<dyn InstallerInterface>);
- fn remove_installer(&mut self, installer: &dyn InstallerInterface);
+ fn add_installer(&self, installer: std::rc::Rc<dyn InstallerInterface>);
+ fn remove_installer(&self, installer: &dyn InstallerInterface);
fn disable_plugins(&mut self);
fn is_package_installed(
&mut self,
@@ -1047,12 +1045,12 @@ impl InstallationManagerInterface for InstallationManager {
self
}
- fn add_installer(&mut self, installer: Box<dyn InstallerInterface>) {
- self.add_installer(installer);
+ fn add_installer(&self, installer: std::rc::Rc<dyn InstallerInterface>) {
+ InstallationManager::add_installer(self, installer);
}
- fn remove_installer(&mut self, installer: &dyn InstallerInterface) {
- self.remove_installer(installer);
+ fn remove_installer(&self, installer: &dyn InstallerInterface) {
+ InstallationManager::remove_installer(self, installer);
}
fn disable_plugins(&mut self) {
diff --git a/crates/shirabe/src/installer/installer_interface.rs b/crates/shirabe/src/installer/installer_interface.rs
index bc464735..fc273916 100644
--- a/crates/shirabe/src/installer/installer_interface.rs
+++ b/crates/shirabe/src/installer/installer_interface.rs
@@ -8,7 +8,7 @@ use shirabe_php_shim::PhpMixed;
#[async_trait::async_trait(?Send)]
pub trait InstallerInterface: std::fmt::Debug {
- fn supports(&self, package_type: &str) -> bool;
+ fn supports(&self, package_type: &str) -> anyhow::Result<bool>;
fn is_installed(
&self,
diff --git a/crates/shirabe/src/installer/library_installer.rs b/crates/shirabe/src/installer/library_installer.rs
index c5a9608e..479fc6d5 100644
--- a/crates/shirabe/src/installer/library_installer.rs
+++ b/crates/shirabe/src/installer/library_installer.rs
@@ -232,11 +232,11 @@ impl LibraryInstaller {
#[async_trait::async_trait(?Send)]
impl InstallerInterface for LibraryInstaller {
- fn supports(&self, package_type: &str) -> bool {
- match &self.r#type {
+ fn supports(&self, package_type: &str) -> anyhow::Result<bool> {
+ Ok(match &self.r#type {
Some(t) => package_type == t,
None => true,
- }
+ })
}
fn is_installed(
diff --git a/crates/shirabe/src/installer/metapackage_installer.rs b/crates/shirabe/src/installer/metapackage_installer.rs
index e2821fd3..52c152ea 100644
--- a/crates/shirabe/src/installer/metapackage_installer.rs
+++ b/crates/shirabe/src/installer/metapackage_installer.rs
@@ -24,8 +24,8 @@ impl MetapackageInstaller {
#[async_trait::async_trait(?Send)]
impl InstallerInterface for MetapackageInstaller {
- fn supports(&self, package_type: &str) -> bool {
- package_type == "metapackage"
+ fn supports(&self, package_type: &str) -> anyhow::Result<bool> {
+ Ok(package_type == "metapackage")
}
fn is_installed(
diff --git a/crates/shirabe/src/installer/noop_installer.rs b/crates/shirabe/src/installer/noop_installer.rs
index 68a2b981..95f31f2e 100644
--- a/crates/shirabe/src/installer/noop_installer.rs
+++ b/crates/shirabe/src/installer/noop_installer.rs
@@ -10,8 +10,8 @@ pub struct NoopInstaller;
#[async_trait::async_trait(?Send)]
impl InstallerInterface for NoopInstaller {
- fn supports(&self, _package_type: &str) -> bool {
- true
+ fn supports(&self, _package_type: &str) -> anyhow::Result<bool> {
+ Ok(true)
}
fn is_installed(
diff --git a/crates/shirabe/src/installer/plugin_installer.rs b/crates/shirabe/src/installer/plugin_installer.rs
index 1e7a2636..7683a7d5 100644
--- a/crates/shirabe/src/installer/plugin_installer.rs
+++ b/crates/shirabe/src/installer/plugin_installer.rs
@@ -73,8 +73,8 @@ impl PluginInstaller {
#[async_trait::async_trait(?Send)]
impl InstallerInterface for PluginInstaller {
- fn supports(&self, package_type: &str) -> bool {
- package_type == "composer-plugin" || package_type == "composer-installer"
+ fn supports(&self, package_type: &str) -> anyhow::Result<bool> {
+ Ok(package_type == "composer-plugin" || package_type == "composer-installer")
}
fn is_installed(
diff --git a/crates/shirabe/src/installer/project_installer.rs b/crates/shirabe/src/installer/project_installer.rs
index 6fee682f..59d44410 100644
--- a/crates/shirabe/src/installer/project_installer.rs
+++ b/crates/shirabe/src/installer/project_installer.rs
@@ -31,8 +31,8 @@ impl ProjectInstaller {
#[async_trait::async_trait(?Send)]
impl InstallerInterface for ProjectInstaller {
- fn supports(&self, _package_type: &str) -> bool {
- true
+ fn supports(&self, _package_type: &str) -> anyhow::Result<bool> {
+ Ok(true)
}
fn is_installed(