aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-06-27 08:44:57 +0900
committernsfisis <nsfisis@gmail.com>2026-06-27 08:44:57 +0900
commit901878ee3f2bee6605b02d321cc4c92bc32fd5b0 (patch)
tree83d8c8c9a24cb95c0656866d328b87c2d4c5127f /crates/shirabe
parent5c2c72223cb6b4d77a332eeeeff7ee4e82e3f239 (diff)
downloadphp-shirabe-901878ee3f2bee6605b02d321cc4c92bc32fd5b0.tar.gz
php-shirabe-901878ee3f2bee6605b02d321cc4c92bc32fd5b0.tar.zst
php-shirabe-901878ee3f2bee6605b02d321cc4c92bc32fd5b0.zip
refactor(composer): hold managers behind *Interface traits
Composer/PartialComposer exposed its RepositoryManager, InstallationManager, EventDispatcher, Locker, DownloadManager, AutoloadGenerator and ArchiveManager as concrete types, but Composer's public setters (setDownloadManager() etc.) let plugins swap in subclasses. Introduce a *Interface trait per manager and store each as Rc<RefCell<dyn ...Interface>> so a replacement is honored. Only Composer's slots and the sinks fed from its accessors become trait objects; managers injected concretely at construction keep their concrete references, matching PHP semantics. Fluent setters on the affected classes now return () and Locker::update_hash is de-generified to a boxed FnOnce so the traits stay object-safe. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe')
-rw-r--r--crates/shirabe/src/autoload/autoload_generator.rs136
-rw-r--r--crates/shirabe/src/command/archive_command.rs53
-rw-r--r--crates/shirabe/src/command/base_dependency_command.rs2
-rw-r--r--crates/shirabe/src/command/bump_command.rs2
-rw-r--r--crates/shirabe/src/command/create_project_command.rs7
-rw-r--r--crates/shirabe/src/command/diagnose_command.rs6
-rw-r--r--crates/shirabe/src/command/dump_autoload_command.rs2
-rw-r--r--crates/shirabe/src/composer.rs102
-rw-r--r--crates/shirabe/src/console/application.rs2
-rw-r--r--crates/shirabe/src/dependency_resolver/pool_builder.rs6
-rw-r--r--crates/shirabe/src/downloader/download_manager.rs139
-rw-r--r--crates/shirabe/src/event_dispatcher/event_dispatcher.rs71
-rw-r--r--crates/shirabe/src/installer.rs44
-rw-r--r--crates/shirabe/src/installer/installation_manager.rs75
-rw-r--r--crates/shirabe/src/installer/library_installer.rs9
-rw-r--r--crates/shirabe/src/installer/project_installer.rs6
-rw-r--r--crates/shirabe/src/package/archiver/archive_manager.rs29
-rw-r--r--crates/shirabe/src/package/locker.rs164
-rw-r--r--crates/shirabe/src/plugin/plugin_manager.rs4
-rw-r--r--crates/shirabe/src/repository/repository_factory.rs9
-rw-r--r--crates/shirabe/src/repository/repository_manager.rs43
-rw-r--r--crates/shirabe/src/repository/repository_set.rs4
-rw-r--r--crates/shirabe/src/util/sync_helper.rs4
-rw-r--r--crates/shirabe/tests/composer_test.rs22
24 files changed, 785 insertions, 156 deletions
diff --git a/crates/shirabe/src/autoload/autoload_generator.rs b/crates/shirabe/src/autoload/autoload_generator.rs
index 1bdea07..1d0960d 100644
--- a/crates/shirabe/src/autoload/autoload_generator.rs
+++ b/crates/shirabe/src/autoload/autoload_generator.rs
@@ -21,12 +21,12 @@ use crate::event_dispatcher::EventDispatcher;
use crate::filter::platform_requirement_filter::IgnoreAllPlatformRequirementFilter;
use crate::filter::platform_requirement_filter::PlatformRequirementFilterFactory;
use crate::filter::platform_requirement_filter::PlatformRequirementFilterInterface;
-use crate::installer::InstallationManager;
+use crate::installer::InstallationManagerInterface;
use crate::io::IOInterface;
use crate::io::IOInterfaceImmutable;
use crate::io::NullIO;
use crate::json::JsonFile;
-use crate::package::Locker;
+use crate::package::LockerInterface;
use crate::package::PackageInterfaceHandle;
use crate::package::RootPackageInterfaceHandle;
use crate::repository::InstalledRepositoryInterface;
@@ -107,11 +107,11 @@ impl AutoloadGenerator {
config: &Config,
local_repo: &mut dyn InstalledRepositoryInterface,
root_package: RootPackageInterfaceHandle,
- installation_manager: &mut InstallationManager,
+ installation_manager: &mut dyn InstallationManagerInterface,
target_dir: &str,
scan_psr_packages: bool,
suffix: Option<String>,
- locker: Option<&mut Locker>,
+ locker: Option<&mut dyn LockerInterface>,
strict_ambiguous: bool,
) -> anyhow::Result<ClassMap> {
let mut scan_psr_packages = scan_psr_packages;
@@ -732,7 +732,7 @@ impl AutoloadGenerator {
pub fn build_package_map(
&self,
- installation_manager: &mut InstallationManager,
+ installation_manager: &mut dyn InstallationManagerInterface,
root_package: RootPackageInterfaceHandle,
packages: Vec<PackageInterfaceHandle>,
) -> anyhow::Result<Vec<(PackageInterfaceHandle, Option<String>)>> {
@@ -1930,6 +1930,132 @@ impl AutoloadGenerator {
}
}
+// Composer's Composer::setAutoloadGenerator() accepts any AutoloadGenerator subclass, so plugins
+// may swap in a replacement. The interface captures the methods reached through Composer's accessor
+// and through the `Rc<RefCell<dyn AutoloadGeneratorInterface>>` references fed from it.
+pub trait AutoloadGeneratorInterface: std::fmt::Debug {
+ fn set_dev_mode(&mut self, dev_mode: bool);
+ fn set_class_map_authoritative(&mut self, class_map_authoritative: bool);
+ fn set_apcu(&mut self, apcu: bool, apcu_prefix: Option<String>);
+ fn set_run_scripts(&mut self, run_scripts: bool);
+ fn set_dry_run(&mut self, dry_run: bool);
+ fn set_platform_requirement_filter(
+ &mut self,
+ platform_requirement_filter: std::rc::Rc<dyn PlatformRequirementFilterInterface>,
+ );
+ #[allow(clippy::too_many_arguments, reason = "to keep PHP signature")]
+ fn dump(
+ &mut self,
+ config: &Config,
+ local_repo: &mut dyn InstalledRepositoryInterface,
+ root_package: RootPackageInterfaceHandle,
+ installation_manager: &mut dyn InstallationManagerInterface,
+ target_dir: &str,
+ scan_psr_packages: bool,
+ suffix: Option<String>,
+ locker: Option<&mut dyn LockerInterface>,
+ strict_ambiguous: bool,
+ ) -> anyhow::Result<ClassMap>;
+ fn build_package_map(
+ &self,
+ installation_manager: &mut dyn InstallationManagerInterface,
+ root_package: RootPackageInterfaceHandle,
+ packages: Vec<PackageInterfaceHandle>,
+ ) -> anyhow::Result<Vec<(PackageInterfaceHandle, Option<String>)>>;
+ fn parse_autoloads(
+ &self,
+ package_map: Vec<(PackageInterfaceHandle, Option<String>)>,
+ root_package: RootPackageInterfaceHandle,
+ filtered_dev_packages: PhpMixed,
+ ) -> IndexMap<String, PhpMixed>;
+ fn create_loader(
+ &self,
+ autoloads: &IndexMap<String, PhpMixed>,
+ vendor_dir: Option<String>,
+ ) -> ClassLoader;
+}
+
+impl AutoloadGeneratorInterface for AutoloadGenerator {
+ fn set_dev_mode(&mut self, dev_mode: bool) {
+ self.set_dev_mode(dev_mode);
+ }
+
+ fn set_class_map_authoritative(&mut self, class_map_authoritative: bool) {
+ self.set_class_map_authoritative(class_map_authoritative);
+ }
+
+ fn set_apcu(&mut self, apcu: bool, apcu_prefix: Option<String>) {
+ self.set_apcu(apcu, apcu_prefix);
+ }
+
+ fn set_run_scripts(&mut self, run_scripts: bool) {
+ self.set_run_scripts(run_scripts);
+ }
+
+ fn set_dry_run(&mut self, dry_run: bool) {
+ self.set_dry_run(dry_run);
+ }
+
+ fn set_platform_requirement_filter(
+ &mut self,
+ platform_requirement_filter: std::rc::Rc<dyn PlatformRequirementFilterInterface>,
+ ) {
+ self.set_platform_requirement_filter(platform_requirement_filter);
+ }
+
+ #[allow(clippy::too_many_arguments, reason = "to keep PHP signature")]
+ fn dump(
+ &mut self,
+ config: &Config,
+ local_repo: &mut dyn InstalledRepositoryInterface,
+ root_package: RootPackageInterfaceHandle,
+ installation_manager: &mut dyn InstallationManagerInterface,
+ target_dir: &str,
+ scan_psr_packages: bool,
+ suffix: Option<String>,
+ locker: Option<&mut dyn LockerInterface>,
+ strict_ambiguous: bool,
+ ) -> anyhow::Result<ClassMap> {
+ self.dump(
+ config,
+ local_repo,
+ root_package,
+ installation_manager,
+ target_dir,
+ scan_psr_packages,
+ suffix,
+ locker,
+ strict_ambiguous,
+ )
+ }
+
+ fn build_package_map(
+ &self,
+ installation_manager: &mut dyn InstallationManagerInterface,
+ root_package: RootPackageInterfaceHandle,
+ packages: Vec<PackageInterfaceHandle>,
+ ) -> anyhow::Result<Vec<(PackageInterfaceHandle, Option<String>)>> {
+ self.build_package_map(installation_manager, root_package, packages)
+ }
+
+ fn parse_autoloads(
+ &self,
+ package_map: Vec<(PackageInterfaceHandle, Option<String>)>,
+ root_package: RootPackageInterfaceHandle,
+ filtered_dev_packages: PhpMixed,
+ ) -> IndexMap<String, PhpMixed> {
+ self.parse_autoloads(package_map, root_package, filtered_dev_packages)
+ }
+
+ fn create_loader(
+ &self,
+ autoloads: &IndexMap<String, PhpMixed>,
+ vendor_dir: Option<String>,
+ ) -> ClassLoader {
+ self.create_loader(autoloads, vendor_dir)
+ }
+}
+
/// Evaluates one of the `autoload_namespaces.php` / `autoload_psr4.php` / `autoload_classmap.php`
/// files that `dump` just generated, returning the `return array(...)` payload with every path
/// expression resolved to an absolute string. This stands in for PHP's `require $file` (there is no
diff --git a/crates/shirabe/src/command/archive_command.rs b/crates/shirabe/src/command/archive_command.rs
index c2e9070..9aae885 100644
--- a/crates/shirabe/src/command/archive_command.rs
+++ b/crates/shirabe/src/command/archive_command.rs
@@ -19,7 +19,7 @@ use crate::console::input::InputOption;
use crate::factory::Factory;
use crate::io::IOInterface;
use crate::io::IOInterfaceImmutable;
-use crate::package::archiver::ArchiveManager;
+use crate::package::archiver::ArchiveManagerInterface;
use crate::package::version::VersionParser;
use crate::package::version::VersionSelector;
use crate::plugin::CommandEvent;
@@ -222,31 +222,32 @@ impl ArchiveCommand {
let mut owned_archive_manager;
let composer_archive_manager;
let mut composer_archive_manager_ref;
- let archive_manager: &mut ArchiveManager = if let Some(composer) = &composer_guard {
- composer_archive_manager = composer.get_archive_manager().clone();
- composer_archive_manager_ref = composer_archive_manager.borrow_mut();
- &mut composer_archive_manager_ref
- } else {
- let factory = Factory;
- let process = std::rc::Rc::new(std::cell::RefCell::new(ProcessExecutor::new(None)));
- let http_downloader = std::rc::Rc::new(std::cell::RefCell::new(
- Factory::create_http_downloader(io.clone(), config, indexmap::IndexMap::new())?,
- ));
- let download_manager = factory.create_download_manager(
- io.clone(),
- config,
- &http_downloader,
- &process,
- None,
- )?;
- let loop_ = std::rc::Rc::new(std::cell::RefCell::new(Loop::new(
- http_downloader.clone(),
- Some(process),
- )));
- owned_archive_manager =
- factory.create_archive_manager(&config.borrow(), &download_manager, &loop_)?;
- &mut owned_archive_manager
- };
+ let archive_manager: &mut dyn ArchiveManagerInterface =
+ if let Some(composer) = &composer_guard {
+ composer_archive_manager = composer.get_archive_manager().clone();
+ composer_archive_manager_ref = composer_archive_manager.borrow_mut();
+ &mut *composer_archive_manager_ref
+ } else {
+ let factory = Factory;
+ let process = std::rc::Rc::new(std::cell::RefCell::new(ProcessExecutor::new(None)));
+ let http_downloader = std::rc::Rc::new(std::cell::RefCell::new(
+ Factory::create_http_downloader(io.clone(), config, indexmap::IndexMap::new())?,
+ ));
+ let download_manager = factory.create_download_manager(
+ io.clone(),
+ config,
+ &http_downloader,
+ &process,
+ None,
+ )?;
+ let loop_ = std::rc::Rc::new(std::cell::RefCell::new(Loop::new(
+ http_downloader.clone(),
+ Some(process),
+ )));
+ owned_archive_manager =
+ factory.create_archive_manager(&config.borrow(), &download_manager, &loop_)?;
+ &mut owned_archive_manager
+ };
let package: crate::package::CompletePackageInterfaceHandle =
if let Some(name) = package_name {
diff --git a/crates/shirabe/src/command/base_dependency_command.rs b/crates/shirabe/src/command/base_dependency_command.rs
index 8404dec..1c48a06 100644
--- a/crates/shirabe/src/command/base_dependency_command.rs
+++ b/crates/shirabe/src/command/base_dependency_command.rs
@@ -152,7 +152,7 @@ pub trait BaseDependencyCommand: BaseCommand {
RepositoryFactory::default_repos(
Some(self.get_io()),
Some(composer.get_config()),
- Some(&mut rm.borrow_mut()),
+ Some(&mut *rm.borrow_mut()),
)?
.into_values()
.collect(),
diff --git a/crates/shirabe/src/command/bump_command.rs b/crates/shirabe/src/command/bump_command.rs
index f86b29a..3964300 100644
--- a/crates/shirabe/src/command/bump_command.rs
+++ b/crates/shirabe/src/command/bump_command.rs
@@ -285,7 +285,7 @@ impl BumpCommand {
composer
.get_locker()
.borrow_mut()
- .update_hash(&composer_json, None::<fn(_) -> _>)?;
+ .update_hash(&composer_json, None)?;
}
if dry_run && change_count > 0 {
diff --git a/crates/shirabe/src/command/create_project_command.rs b/crates/shirabe/src/command/create_project_command.rs
index ab45400..abbf37a 100644
--- a/crates/shirabe/src/command/create_project_command.rs
+++ b/crates/shirabe/src/command/create_project_command.rs
@@ -865,7 +865,7 @@ impl CreateProjectCommand {
RepositoryFactory::default_repos(
Some(io.clone()),
Some(config.clone()),
- Some(&mut rm.borrow_mut()),
+ Some(&mut *rm.borrow_mut()),
)?
.into_iter()
.map(|(_, v)| v)
@@ -998,9 +998,8 @@ impl CreateProjectCommand {
}
let dm = composer.get_download_manager();
- dm.borrow_mut()
- .set_prefer_source(prefer_source)
- .set_prefer_dist(prefer_dist);
+ dm.borrow_mut().set_prefer_source(prefer_source);
+ dm.borrow_mut().set_prefer_dist(prefer_dist);
let project_installer = ProjectInstaller::new(&directory, dm.clone(), fs.clone());
let installation_manager = composer.get_installation_manager().clone();
diff --git a/crates/shirabe/src/command/diagnose_command.rs b/crates/shirabe/src/command/diagnose_command.rs
index 37009fb..68aec20 100644
--- a/crates/shirabe/src/command/diagnose_command.rs
+++ b/crates/shirabe/src/command/diagnose_command.rs
@@ -34,7 +34,7 @@ use crate::io::IOInterfaceImmutable;
use crate::io::NullIO;
use crate::json::JsonFile;
use crate::json::JsonValidationException;
-use crate::package::Locker;
+use crate::package::LockerInterface;
use crate::package::RootPackage;
use crate::package::version::VersionParser;
use crate::plugin::CommandEvent;
@@ -284,7 +284,7 @@ impl Command for DiagnoseCommand {
io.write_no_newline("Checking composer.lock: ");
let locker = c.get_locker().clone();
let locker = locker.borrow();
- let r = self.check_composer_lock_schema(&locker)?;
+ let r = self.check_composer_lock_schema(&*locker)?;
self.output_result(r);
}
}
@@ -487,7 +487,7 @@ impl DiagnoseCommand {
Ok(PhpMixed::Bool(true))
}
- fn check_composer_lock_schema(&self, locker: &Locker) -> anyhow::Result<PhpMixed> {
+ fn check_composer_lock_schema(&self, locker: &dyn LockerInterface) -> anyhow::Result<PhpMixed> {
let json = locker.get_json_file();
match json.validate_schema(JsonFile::LOCK_SCHEMA, None) {
diff --git a/crates/shirabe/src/command/dump_autoload_command.rs b/crates/shirabe/src/command/dump_autoload_command.rs
index d9e9973..b0bb755 100644
--- a/crates/shirabe/src/command/dump_autoload_command.rs
+++ b/crates/shirabe/src/command/dump_autoload_command.rs
@@ -269,7 +269,7 @@ impl Command for DumpAutoloadCommand {
&config_ref,
local_repo,
package,
- &mut installation_manager_ref,
+ &mut *installation_manager_ref,
"composer",
optimize,
None,
diff --git a/crates/shirabe/src/composer.rs b/crates/shirabe/src/composer.rs
index 57b4c6c..d6c41e2 100644
--- a/crates/shirabe/src/composer.rs
+++ b/crates/shirabe/src/composer.rs
@@ -3,15 +3,15 @@
use shirabe_external_packages::composer::pcre::Preg;
-use crate::autoload::AutoloadGenerator;
+use crate::autoload::AutoloadGeneratorInterface;
use crate::config::Config;
-use crate::downloader::DownloadManager;
-use crate::event_dispatcher::EventDispatcher;
-use crate::installer::InstallationManager;
-use crate::package::archiver::ArchiveManager;
-use crate::package::{Locker, RootPackageInterfaceHandle};
+use crate::downloader::DownloadManagerInterface;
+use crate::event_dispatcher::EventDispatcherInterface;
+use crate::installer::InstallationManagerInterface;
+use crate::package::archiver::ArchiveManagerInterface;
+use crate::package::{LockerInterface, RootPackageInterfaceHandle};
use crate::plugin::PluginManager;
-use crate::repository::RepositoryManager;
+use crate::repository::RepositoryManagerInterface;
use crate::util::r#loop::Loop;
// TODO: change this information to Shirabe version.
@@ -37,10 +37,10 @@ pub struct PartialComposer {
global: bool,
package: Option<RootPackageInterfaceHandle>,
r#loop: Option<std::rc::Rc<std::cell::RefCell<Loop>>>,
- repository_manager: Option<std::rc::Rc<std::cell::RefCell<RepositoryManager>>>,
- installation_manager: Option<std::rc::Rc<std::cell::RefCell<InstallationManager>>>,
+ repository_manager: Option<std::rc::Rc<std::cell::RefCell<dyn RepositoryManagerInterface>>>,
+ installation_manager: Option<std::rc::Rc<std::cell::RefCell<dyn InstallationManagerInterface>>>,
config: Option<std::rc::Rc<std::cell::RefCell<Config>>>,
- event_dispatcher: Option<std::rc::Rc<std::cell::RefCell<EventDispatcher>>>,
+ event_dispatcher: Option<std::rc::Rc<std::cell::RefCell<dyn EventDispatcherInterface>>>,
}
impl PartialComposer {
@@ -70,34 +70,40 @@ impl PartialComposer {
pub fn set_repository_manager(
&mut self,
- manager: std::rc::Rc<std::cell::RefCell<RepositoryManager>>,
+ manager: std::rc::Rc<std::cell::RefCell<dyn RepositoryManagerInterface>>,
) {
self.repository_manager = Some(manager);
}
- pub fn get_repository_manager(&self) -> std::rc::Rc<std::cell::RefCell<RepositoryManager>> {
+ pub fn get_repository_manager(
+ &self,
+ ) -> std::rc::Rc<std::cell::RefCell<dyn RepositoryManagerInterface>> {
self.repository_manager.as_ref().unwrap().clone()
}
pub fn set_installation_manager(
&mut self,
- manager: std::rc::Rc<std::cell::RefCell<InstallationManager>>,
+ manager: std::rc::Rc<std::cell::RefCell<dyn InstallationManagerInterface>>,
) {
self.installation_manager = Some(manager);
}
- pub fn get_installation_manager(&self) -> std::rc::Rc<std::cell::RefCell<InstallationManager>> {
+ pub fn get_installation_manager(
+ &self,
+ ) -> std::rc::Rc<std::cell::RefCell<dyn InstallationManagerInterface>> {
self.installation_manager.as_ref().unwrap().clone()
}
pub fn set_event_dispatcher(
&mut self,
- event_dispatcher: std::rc::Rc<std::cell::RefCell<EventDispatcher>>,
+ event_dispatcher: std::rc::Rc<std::cell::RefCell<dyn EventDispatcherInterface>>,
) {
self.event_dispatcher = Some(event_dispatcher);
}
- pub fn get_event_dispatcher(&self) -> std::rc::Rc<std::cell::RefCell<EventDispatcher>> {
+ pub fn get_event_dispatcher(
+ &self,
+ ) -> std::rc::Rc<std::cell::RefCell<dyn EventDispatcherInterface>> {
self.event_dispatcher.as_ref().unwrap().clone()
}
@@ -114,12 +120,12 @@ impl PartialComposer {
#[derive(Debug)]
pub struct Composer {
partial: PartialComposer,
- locker: Option<std::rc::Rc<std::cell::RefCell<Locker>>>,
- download_manager: Option<std::rc::Rc<std::cell::RefCell<DownloadManager>>>,
+ locker: Option<std::rc::Rc<std::cell::RefCell<dyn LockerInterface>>>,
+ download_manager: Option<std::rc::Rc<std::cell::RefCell<dyn DownloadManagerInterface>>>,
// TODO(plugin): plugin_manager is part of the plugin API
plugin_manager: Option<std::rc::Rc<std::cell::RefCell<PluginManager>>>,
- autoload_generator: Option<std::rc::Rc<std::cell::RefCell<AutoloadGenerator>>>,
- archive_manager: Option<std::rc::Rc<std::cell::RefCell<ArchiveManager>>>,
+ autoload_generator: Option<std::rc::Rc<std::cell::RefCell<dyn AutoloadGeneratorInterface>>>,
+ archive_manager: Option<std::rc::Rc<std::cell::RefCell<dyn ArchiveManagerInterface>>>,
}
impl Default for Composer {
@@ -140,33 +146,37 @@ impl Composer {
}
}
- pub fn set_locker(&mut self, locker: std::rc::Rc<std::cell::RefCell<Locker>>) {
+ pub fn set_locker(&mut self, locker: std::rc::Rc<std::cell::RefCell<dyn LockerInterface>>) {
self.locker = Some(locker);
}
- pub fn get_locker(&self) -> std::rc::Rc<std::cell::RefCell<Locker>> {
+ pub fn get_locker(&self) -> std::rc::Rc<std::cell::RefCell<dyn LockerInterface>> {
self.locker.as_ref().unwrap().clone()
}
pub fn set_download_manager(
&mut self,
- manager: std::rc::Rc<std::cell::RefCell<DownloadManager>>,
+ manager: std::rc::Rc<std::cell::RefCell<dyn DownloadManagerInterface>>,
) {
self.download_manager = Some(manager);
}
- pub fn get_download_manager(&self) -> std::rc::Rc<std::cell::RefCell<DownloadManager>> {
+ pub fn get_download_manager(
+ &self,
+ ) -> std::rc::Rc<std::cell::RefCell<dyn DownloadManagerInterface>> {
self.download_manager.as_ref().unwrap().clone()
}
pub fn set_archive_manager(
&mut self,
- manager: std::rc::Rc<std::cell::RefCell<ArchiveManager>>,
+ manager: std::rc::Rc<std::cell::RefCell<dyn ArchiveManagerInterface>>,
) {
self.archive_manager = Some(manager);
}
- pub fn get_archive_manager(&self) -> std::rc::Rc<std::cell::RefCell<ArchiveManager>> {
+ pub fn get_archive_manager(
+ &self,
+ ) -> std::rc::Rc<std::cell::RefCell<dyn ArchiveManagerInterface>> {
self.archive_manager.as_ref().unwrap().clone()
}
@@ -182,12 +192,14 @@ impl Composer {
pub fn set_autoload_generator(
&mut self,
- autoload_generator: std::rc::Rc<std::cell::RefCell<AutoloadGenerator>>,
+ autoload_generator: std::rc::Rc<std::cell::RefCell<dyn AutoloadGeneratorInterface>>,
) {
self.autoload_generator = Some(autoload_generator);
}
- pub fn get_autoload_generator(&self) -> std::rc::Rc<std::cell::RefCell<AutoloadGenerator>> {
+ pub fn get_autoload_generator(
+ &self,
+ ) -> std::rc::Rc<std::cell::RefCell<dyn AutoloadGeneratorInterface>> {
self.autoload_generator.as_ref().unwrap().clone()
}
@@ -225,40 +237,45 @@ impl Composer {
pub fn set_repository_manager(
&mut self,
- manager: std::rc::Rc<std::cell::RefCell<crate::repository::RepositoryManager>>,
+ manager: std::rc::Rc<std::cell::RefCell<dyn crate::repository::RepositoryManagerInterface>>,
) {
self.partial.set_repository_manager(manager);
}
pub fn get_repository_manager(
&self,
- ) -> std::rc::Rc<std::cell::RefCell<crate::repository::RepositoryManager>> {
+ ) -> std::rc::Rc<std::cell::RefCell<dyn crate::repository::RepositoryManagerInterface>> {
self.partial.get_repository_manager()
}
pub fn set_installation_manager(
&mut self,
- manager: std::rc::Rc<std::cell::RefCell<crate::installer::InstallationManager>>,
+ manager: std::rc::Rc<
+ std::cell::RefCell<dyn crate::installer::InstallationManagerInterface>,
+ >,
) {
self.partial.set_installation_manager(manager);
}
pub fn get_installation_manager(
&self,
- ) -> std::rc::Rc<std::cell::RefCell<crate::installer::InstallationManager>> {
+ ) -> std::rc::Rc<std::cell::RefCell<dyn crate::installer::InstallationManagerInterface>> {
self.partial.get_installation_manager()
}
pub fn set_event_dispatcher(
&mut self,
- dispatcher: std::rc::Rc<std::cell::RefCell<crate::event_dispatcher::EventDispatcher>>,
+ dispatcher: std::rc::Rc<
+ std::cell::RefCell<dyn crate::event_dispatcher::EventDispatcherInterface>,
+ >,
) {
self.partial.set_event_dispatcher(dispatcher);
}
pub fn get_event_dispatcher(
&self,
- ) -> std::rc::Rc<std::cell::RefCell<crate::event_dispatcher::EventDispatcher>> {
+ ) -> std::rc::Rc<std::cell::RefCell<dyn crate::event_dispatcher::EventDispatcherInterface>>
+ {
self.partial.get_event_dispatcher()
}
@@ -366,7 +383,7 @@ impl PartialOrFullComposer {
pub fn set_repository_manager(
&mut self,
- manager: std::rc::Rc<std::cell::RefCell<crate::repository::RepositoryManager>>,
+ manager: std::rc::Rc<std::cell::RefCell<dyn crate::repository::RepositoryManagerInterface>>,
) {
match self {
Self::Full(full) => full.set_repository_manager(manager),
@@ -376,7 +393,7 @@ impl PartialOrFullComposer {
pub fn get_repository_manager(
&self,
- ) -> std::rc::Rc<std::cell::RefCell<crate::repository::RepositoryManager>> {
+ ) -> std::rc::Rc<std::cell::RefCell<dyn crate::repository::RepositoryManagerInterface>> {
match self {
Self::Full(full) => full.get_repository_manager(),
Self::Partial(partial) => partial.get_repository_manager(),
@@ -385,7 +402,9 @@ impl PartialOrFullComposer {
pub fn set_installation_manager(
&mut self,
- manager: std::rc::Rc<std::cell::RefCell<crate::installer::InstallationManager>>,
+ manager: std::rc::Rc<
+ std::cell::RefCell<dyn crate::installer::InstallationManagerInterface>,
+ >,
) {
match self {
Self::Full(full) => full.set_installation_manager(manager),
@@ -395,7 +414,7 @@ impl PartialOrFullComposer {
pub fn get_installation_manager(
&self,
- ) -> std::rc::Rc<std::cell::RefCell<crate::installer::InstallationManager>> {
+ ) -> std::rc::Rc<std::cell::RefCell<dyn crate::installer::InstallationManagerInterface>> {
match self {
Self::Full(full) => full.get_installation_manager(),
Self::Partial(partial) => partial.get_installation_manager(),
@@ -404,7 +423,9 @@ impl PartialOrFullComposer {
pub fn set_event_dispatcher(
&mut self,
- dispatcher: std::rc::Rc<std::cell::RefCell<crate::event_dispatcher::EventDispatcher>>,
+ dispatcher: std::rc::Rc<
+ std::cell::RefCell<dyn crate::event_dispatcher::EventDispatcherInterface>,
+ >,
) {
match self {
Self::Full(full) => full.set_event_dispatcher(dispatcher),
@@ -414,7 +435,8 @@ impl PartialOrFullComposer {
pub fn get_event_dispatcher(
&self,
- ) -> std::rc::Rc<std::cell::RefCell<crate::event_dispatcher::EventDispatcher>> {
+ ) -> std::rc::Rc<std::cell::RefCell<dyn crate::event_dispatcher::EventDispatcherInterface>>
+ {
match self {
Self::Full(full) => full.get_event_dispatcher(),
Self::Partial(partial) => partial.get_event_dispatcher(),
diff --git a/crates/shirabe/src/console/application.rs b/crates/shirabe/src/console/application.rs
index de1ecfc..f3e4292 100644
--- a/crates/shirabe/src/console/application.rs
+++ b/crates/shirabe/src/console/application.rs
@@ -2383,7 +2383,7 @@ impl ApplicationHandle {
let installation_manager = composer.get_installation_manager();
let package_map = generator.build_package_map(
- &mut installation_manager.borrow_mut(),
+ &mut *installation_manager.borrow_mut(),
root_package.clone(),
vec![],
)?;
diff --git a/crates/shirabe/src/dependency_resolver/pool_builder.rs b/crates/shirabe/src/dependency_resolver/pool_builder.rs
index e2c5b11..843818f 100644
--- a/crates/shirabe/src/dependency_resolver/pool_builder.rs
+++ b/crates/shirabe/src/dependency_resolver/pool_builder.rs
@@ -19,7 +19,7 @@ use crate::dependency_resolver::Pool;
use crate::dependency_resolver::PoolOptimizer;
use crate::dependency_resolver::Request;
use crate::dependency_resolver::SecurityAdvisoryPoolFilter;
-use crate::event_dispatcher::EventDispatcher;
+use crate::event_dispatcher::EventDispatcherInterface;
use crate::io::IOInterface;
use crate::io::IOInterfaceImmutable;
use crate::package::AliasPackageHandle;
@@ -40,7 +40,7 @@ pub struct PoolBuilder {
root_aliases: IndexMap<String, IndexMap<String, IndexMap<String, String>>>,
root_references: IndexMap<String, String>,
temporary_constraints: IndexMap<String, AnyConstraint>,
- event_dispatcher: Option<std::rc::Rc<std::cell::RefCell<EventDispatcher>>>,
+ event_dispatcher: Option<std::rc::Rc<std::cell::RefCell<dyn EventDispatcherInterface>>>,
pool_optimizer: Option<PoolOptimizer>,
io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
alias_map: IndexMap<String, IndexMap<i64, AliasPackageHandle>>,
@@ -85,7 +85,7 @@ impl PoolBuilder {
root_aliases: IndexMap<String, IndexMap<String, IndexMap<String, String>>>,
root_references: IndexMap<String, String>,
io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
- event_dispatcher: Option<std::rc::Rc<std::cell::RefCell<EventDispatcher>>>,
+ event_dispatcher: Option<std::rc::Rc<std::cell::RefCell<dyn EventDispatcherInterface>>>,
pool_optimizer: Option<PoolOptimizer>,
temporary_constraints: IndexMap<String, AnyConstraint>,
security_advisory_pool_filter: Option<SecurityAdvisoryPoolFilter>,
diff --git a/crates/shirabe/src/downloader/download_manager.rs b/crates/shirabe/src/downloader/download_manager.rs
index 183813d..a5a83a6 100644
--- a/crates/shirabe/src/downloader/download_manager.rs
+++ b/crates/shirabe/src/downloader/download_manager.rs
@@ -60,28 +60,22 @@ impl DownloadManager {
/// Makes downloader prefer source installation over the dist.
///
/// @param bool $preferSource prefer downloading from source
- pub fn set_prefer_source(&mut self, prefer_source: bool) -> &mut Self {
+ pub fn set_prefer_source(&mut self, prefer_source: bool) {
self.prefer_source = prefer_source;
-
- self
}
/// Makes downloader prefer dist installation over the source.
///
/// @param bool $preferDist prefer downloading from dist
- pub fn set_prefer_dist(&mut self, prefer_dist: bool) -> &mut Self {
+ pub fn set_prefer_dist(&mut self, prefer_dist: bool) {
self.prefer_dist = prefer_dist;
-
- self
}
/// Sets fine tuned preference settings for package level source/dist selection.
///
/// @param array<string, string> $preferences array of preferences by package patterns
- pub fn set_preferences(&mut self, preferences: IndexMap<String, String>) -> &mut Self {
+ pub fn set_preferences(&mut self, preferences: IndexMap<String, String>) {
self.package_preferences = preferences;
-
- self
}
/// Sets installer downloader for a specific installation type.
@@ -92,11 +86,9 @@ impl DownloadManager {
&mut self,
r#type: &str,
downloader: std::rc::Rc<std::cell::RefCell<dyn DownloaderInterface>>,
- ) -> &mut Self {
+ ) {
let r#type = strtolower(r#type);
self.downloaders.insert(r#type, downloader);
-
- self
}
/// Returns downloader for a specific installation type.
@@ -551,3 +543,126 @@ impl DownloadManager {
rtrim(dir, Some("\\/"))
}
}
+
+// Composer's Composer::setDownloadManager() accepts any DownloadManager subclass, so plugins may
+// swap in a replacement. The interface captures the methods reached through Composer's accessor and
+// through the `Rc<RefCell<dyn DownloadManagerInterface>>` references fed from it.
+#[async_trait::async_trait(?Send)]
+pub trait DownloadManagerInterface: std::fmt::Debug {
+ fn set_prefer_source(&mut self, prefer_source: bool);
+ fn set_prefer_dist(&mut self, prefer_dist: bool);
+ fn get_downloader_for_package(
+ &self,
+ package: PackageInterfaceHandle,
+ ) -> Result<Option<std::rc::Rc<std::cell::RefCell<dyn DownloaderInterface>>>>;
+ async fn download(
+ &self,
+ package: PackageInterfaceHandle,
+ target_dir: &str,
+ prev_package: Option<PackageInterfaceHandle>,
+ ) -> Result<Option<PhpMixed>>;
+ async fn prepare(
+ &self,
+ r#type: &str,
+ package: PackageInterfaceHandle,
+ target_dir: &str,
+ prev_package: Option<PackageInterfaceHandle>,
+ ) -> Result<Option<PhpMixed>>;
+ async fn install(
+ &self,
+ package: PackageInterfaceHandle,
+ target_dir: &str,
+ ) -> Result<Option<PhpMixed>>;
+ async fn update(
+ &self,
+ initial: PackageInterfaceHandle,
+ target: PackageInterfaceHandle,
+ target_dir: &str,
+ ) -> Result<Option<PhpMixed>>;
+ async fn remove(
+ &self,
+ package: PackageInterfaceHandle,
+ target_dir: &str,
+ ) -> Result<Option<PhpMixed>>;
+ async fn cleanup(
+ &self,
+ r#type: &str,
+ package: PackageInterfaceHandle,
+ target_dir: &str,
+ prev_package: Option<PackageInterfaceHandle>,
+ ) -> Result<Option<PhpMixed>>;
+}
+
+#[async_trait::async_trait(?Send)]
+impl DownloadManagerInterface for DownloadManager {
+ fn set_prefer_source(&mut self, prefer_source: bool) {
+ self.set_prefer_source(prefer_source);
+ }
+
+ fn set_prefer_dist(&mut self, prefer_dist: bool) {
+ self.set_prefer_dist(prefer_dist);
+ }
+
+ fn get_downloader_for_package(
+ &self,
+ package: PackageInterfaceHandle,
+ ) -> Result<Option<std::rc::Rc<std::cell::RefCell<dyn DownloaderInterface>>>> {
+ self.get_downloader_for_package(package)
+ }
+
+ async fn download(
+ &self,
+ package: PackageInterfaceHandle,
+ target_dir: &str,
+ prev_package: Option<PackageInterfaceHandle>,
+ ) -> Result<Option<PhpMixed>> {
+ self.download(package, target_dir, prev_package).await
+ }
+
+ async fn prepare(
+ &self,
+ r#type: &str,
+ package: PackageInterfaceHandle,
+ target_dir: &str,
+ prev_package: Option<PackageInterfaceHandle>,
+ ) -> Result<Option<PhpMixed>> {
+ self.prepare(r#type, package, target_dir, prev_package)
+ .await
+ }
+
+ async fn install(
+ &self,
+ package: PackageInterfaceHandle,
+ target_dir: &str,
+ ) -> Result<Option<PhpMixed>> {
+ self.install(package, target_dir).await
+ }
+
+ async fn update(
+ &self,
+ initial: PackageInterfaceHandle,
+ target: PackageInterfaceHandle,
+ target_dir: &str,
+ ) -> Result<Option<PhpMixed>> {
+ self.update(initial, target, target_dir).await
+ }
+
+ async fn remove(
+ &self,
+ package: PackageInterfaceHandle,
+ target_dir: &str,
+ ) -> Result<Option<PhpMixed>> {
+ self.remove(package, target_dir).await
+ }
+
+ async fn cleanup(
+ &self,
+ r#type: &str,
+ package: PackageInterfaceHandle,
+ target_dir: &str,
+ prev_package: Option<PackageInterfaceHandle>,
+ ) -> Result<Option<PhpMixed>> {
+ self.cleanup(r#type, package, target_dir, prev_package)
+ .await
+ }
+}
diff --git a/crates/shirabe/src/event_dispatcher/event_dispatcher.rs b/crates/shirabe/src/event_dispatcher/event_dispatcher.rs
index f74b4a2..091160e 100644
--- a/crates/shirabe/src/event_dispatcher/event_dispatcher.rs
+++ b/crates/shirabe/src/event_dispatcher/event_dispatcher.rs
@@ -125,10 +125,8 @@ impl EventDispatcher {
}
/// Set whether script handlers are active or not
- pub fn set_run_scripts(&mut self, run_scripts: bool) -> &mut Self {
+ pub fn set_run_scripts(&mut self, run_scripts: bool) {
self.run_scripts = run_scripts;
-
- self
}
/// Dispatch an event
@@ -1193,7 +1191,7 @@ impl EventDispatcher {
let installation_manager = composer.get_installation_manager();
let package_map = generator.build_package_map(
- &mut installation_manager.borrow_mut(),
+ &mut *installation_manager.borrow_mut(),
package.clone(),
packages,
)?;
@@ -1245,3 +1243,68 @@ impl EventDispatcher {
}
}
}
+
+// Composer's PartialComposer::setEventDispatcher() accepts any EventDispatcher subclass, so plugins
+// may swap in a replacement. The interface captures the methods reached through Composer's accessor
+// and through the `Rc<RefCell<dyn EventDispatcherInterface>>` references fed from it.
+pub trait EventDispatcherInterface: std::fmt::Debug {
+ fn dispatch(
+ &mut self,
+ event_name: Option<&str>,
+ event: Option<&mut dyn EventInterface>,
+ ) -> anyhow::Result<i64>;
+ fn dispatch_script(
+ &mut self,
+ event_name: &str,
+ dev_mode: bool,
+ additional_args: Vec<String>,
+ flags: IndexMap<String, PhpMixed>,
+ ) -> anyhow::Result<i64>;
+ fn dispatch_installer_event(
+ &mut self,
+ event_name: &str,
+ dev_mode: bool,
+ execute_operations: bool,
+ transaction: Transaction,
+ ) -> anyhow::Result<i64>;
+ fn add_listener(&mut self, event_name: &str, listener: Callable, priority: i64);
+ fn has_event_listeners(&mut self, event: &dyn EventInterface) -> bool;
+}
+
+impl EventDispatcherInterface for EventDispatcher {
+ fn dispatch(
+ &mut self,
+ event_name: Option<&str>,
+ event: Option<&mut dyn EventInterface>,
+ ) -> anyhow::Result<i64> {
+ self.dispatch(event_name, event)
+ }
+
+ fn dispatch_script(
+ &mut self,
+ event_name: &str,
+ dev_mode: bool,
+ additional_args: Vec<String>,
+ flags: IndexMap<String, PhpMixed>,
+ ) -> anyhow::Result<i64> {
+ self.dispatch_script(event_name, dev_mode, additional_args, flags)
+ }
+
+ fn dispatch_installer_event(
+ &mut self,
+ event_name: &str,
+ dev_mode: bool,
+ execute_operations: bool,
+ transaction: Transaction,
+ ) -> anyhow::Result<i64> {
+ self.dispatch_installer_event(event_name, dev_mode, execute_operations, transaction)
+ }
+
+ fn add_listener(&mut self, event_name: &str, listener: Callable, priority: i64) {
+ self.add_listener(event_name, listener, priority);
+ }
+
+ fn has_event_listeners(&mut self, event: &dyn EventInterface) -> bool {
+ self.has_event_listeners(event)
+ }
+}
diff --git a/crates/shirabe/src/installer.rs b/crates/shirabe/src/installer.rs
index 2590b49..f051563 100644
--- a/crates/shirabe/src/installer.rs
+++ b/crates/shirabe/src/installer.rs
@@ -42,7 +42,7 @@ use shirabe_semver;
use crate::advisory::AuditConfig;
use crate::advisory::Auditor;
-use crate::autoload::AutoloadGenerator;
+use crate::autoload::AutoloadGeneratorInterface;
use crate::composer::PartialComposerHandle;
use crate::config::Config;
use crate::console::GithubActionError;
@@ -56,9 +56,9 @@ use crate::dependency_resolver::SecurityAdvisoryPoolFilter;
use crate::dependency_resolver::Solver;
use crate::dependency_resolver::UpdateAllowTransitiveDeps;
use crate::dependency_resolver::operation::OperationInterface;
-use crate::downloader::DownloadManager;
+use crate::downloader::DownloadManagerInterface;
use crate::downloader::TransportException;
-use crate::event_dispatcher::EventDispatcher;
+use crate::event_dispatcher::EventDispatcherInterface;
use crate::filter::platform_requirement_filter::IgnoreListPlatformRequirementFilter;
use crate::filter::platform_requirement_filter::PlatformRequirementFilterFactory;
use crate::filter::platform_requirement_filter::PlatformRequirementFilterInterface;
@@ -67,7 +67,7 @@ use crate::io::IOInterfaceImmutable;
use crate::package::AliasPackageHandle;
use crate::package::CompleteAliasPackageHandle;
use crate::package::Link;
-use crate::package::Locker;
+use crate::package::LockerInterface;
use crate::package::PackageInterfaceHandle;
use crate::package::RootPackageInterfaceHandle;
use crate::package::base_package;
@@ -83,7 +83,7 @@ use crate::repository::InstalledRepository;
use crate::repository::PlatformRepository;
use crate::repository::PlatformRepositoryHandle;
use crate::repository::RepositoryInterface;
-use crate::repository::RepositoryManager;
+use crate::repository::RepositoryManagerInterface;
use crate::repository::RepositorySet;
use crate::repository::RootPackageRepository;
use crate::script::ScriptEvents;
@@ -98,12 +98,13 @@ pub struct Installer {
pub(crate) package: RootPackageInterfaceHandle,
// TODO can we get rid of the below and just use the package itself?
pub(crate) fixed_root_package: RootPackageInterfaceHandle,
- pub(crate) download_manager: std::rc::Rc<std::cell::RefCell<DownloadManager>>,
- pub(crate) repository_manager: std::rc::Rc<std::cell::RefCell<RepositoryManager>>,
- pub(crate) locker: std::rc::Rc<std::cell::RefCell<Locker>>,
- pub(crate) installation_manager: std::rc::Rc<std::cell::RefCell<InstallationManager>>,
- pub(crate) event_dispatcher: std::rc::Rc<std::cell::RefCell<EventDispatcher>>,
- pub(crate) autoload_generator: std::rc::Rc<std::cell::RefCell<AutoloadGenerator>>,
+ pub(crate) download_manager: std::rc::Rc<std::cell::RefCell<dyn DownloadManagerInterface>>,
+ pub(crate) repository_manager: std::rc::Rc<std::cell::RefCell<dyn RepositoryManagerInterface>>,
+ pub(crate) locker: std::rc::Rc<std::cell::RefCell<dyn LockerInterface>>,
+ pub(crate) installation_manager:
+ std::rc::Rc<std::cell::RefCell<dyn InstallationManagerInterface>>,
+ pub(crate) event_dispatcher: std::rc::Rc<std::cell::RefCell<dyn EventDispatcherInterface>>,
+ pub(crate) autoload_generator: std::rc::Rc<std::cell::RefCell<dyn AutoloadGeneratorInterface>>,
pub(crate) prefer_source: bool,
pub(crate) prefer_dist: bool,
pub(crate) optimize_autoloader: bool,
@@ -155,12 +156,12 @@ impl Installer {
io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: std::rc::Rc<std::cell::RefCell<Config>>,
package: RootPackageInterfaceHandle,
- download_manager: std::rc::Rc<std::cell::RefCell<DownloadManager>>,
- repository_manager: std::rc::Rc<std::cell::RefCell<RepositoryManager>>,
- locker: std::rc::Rc<std::cell::RefCell<Locker>>,
- installation_manager: std::rc::Rc<std::cell::RefCell<InstallationManager>>,
- event_dispatcher: std::rc::Rc<std::cell::RefCell<EventDispatcher>>,
- autoload_generator: std::rc::Rc<std::cell::RefCell<AutoloadGenerator>>,
+ download_manager: std::rc::Rc<std::cell::RefCell<dyn DownloadManagerInterface>>,
+ repository_manager: std::rc::Rc<std::cell::RefCell<dyn RepositoryManagerInterface>>,
+ locker: std::rc::Rc<std::cell::RefCell<dyn LockerInterface>>,
+ installation_manager: std::rc::Rc<std::cell::RefCell<dyn InstallationManagerInterface>>,
+ event_dispatcher: std::rc::Rc<std::cell::RefCell<dyn EventDispatcherInterface>>,
+ autoload_generator: std::rc::Rc<std::cell::RefCell<dyn AutoloadGeneratorInterface>>,
) -> Self {
let suggested_packages_reporter = std::rc::Rc::new(std::cell::RefCell::new(
SuggestedPackagesReporter::new(io.clone()),
@@ -249,7 +250,7 @@ impl Installer {
self.write_lock = false;
self.dump_autoloader = false;
let repository_manager = self.repository_manager.clone();
- self.mock_local_repositories(&mut repository_manager.borrow_mut())?;
+ self.mock_local_repositories(&mut *repository_manager.borrow_mut())?;
}
if self.download_only {
@@ -409,7 +410,7 @@ impl Installer {
.as_installed_repository_interface_mut()
.unwrap(),
self.package.clone(),
- &mut self.installation_manager.borrow_mut(),
+ &mut *self.installation_manager.borrow_mut(),
"composer",
self.optimize_autoloader,
None,
@@ -1651,7 +1652,10 @@ impl Installer {
/// Replace local repositories with InstalledArrayRepository instances
///
/// This is to prevent any accidental modification of the existing repos on disk
- fn mock_local_repositories(&self, rm: &mut RepositoryManager) -> anyhow::Result<()> {
+ fn mock_local_repositories(
+ &self,
+ rm: &mut dyn RepositoryManagerInterface,
+ ) -> anyhow::Result<()> {
let mut packages: IndexMap<String, PackageInterfaceHandle> = IndexMap::new();
for package in rm.get_local_repository().get_packages()? {
packages.insert(package.to_string(), PackageInterfaceHandle::dup(&package));
diff --git a/crates/shirabe/src/installer/installation_manager.rs b/crates/shirabe/src/installer/installation_manager.rs
index ac5f8e4..bee14cc 100644
--- a/crates/shirabe/src/installer/installation_manager.rs
+++ b/crates/shirabe/src/installer/installation_manager.rs
@@ -791,3 +791,78 @@ impl InstallationManager {
}
}
}
+
+// Composer's PartialComposer::setInstallationManager() accepts any InstallationManager subclass, so
+// plugins may swap in a replacement. The interface captures the methods reached through Composer's
+// accessor and through the `&mut dyn InstallationManagerInterface` references fed from it.
+pub trait InstallationManagerInterface: std::fmt::Debug {
+ fn add_installer(&mut self, installer: Box<dyn InstallerInterface>);
+ fn remove_installer(&mut self, installer: &dyn InstallerInterface);
+ fn disable_plugins(&mut self);
+ fn is_package_installed(
+ &mut self,
+ repo: &dyn InstalledRepositoryInterface,
+ package: PackageInterfaceHandle,
+ ) -> Result<bool>;
+ fn ensure_binaries_presence(&mut self, package: PackageInterfaceHandle);
+ fn execute(
+ &mut self,
+ repo: &mut dyn InstalledRepositoryInterface,
+ operations: Vec<std::rc::Rc<dyn OperationInterface>>,
+ dev_mode: bool,
+ run_scripts: bool,
+ download_only: bool,
+ ) -> Result<()>;
+ fn get_install_path(&mut self, package: PackageInterfaceHandle) -> Option<String>;
+ fn set_output_progress(&mut self, output_progress: bool);
+ fn notify_installs(&mut self, io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>);
+}
+
+impl InstallationManagerInterface for InstallationManager {
+ fn add_installer(&mut self, installer: Box<dyn InstallerInterface>) {
+ self.add_installer(installer);
+ }
+
+ fn remove_installer(&mut self, installer: &dyn InstallerInterface) {
+ self.remove_installer(installer);
+ }
+
+ fn disable_plugins(&mut self) {
+ self.disable_plugins();
+ }
+
+ fn is_package_installed(
+ &mut self,
+ repo: &dyn InstalledRepositoryInterface,
+ package: PackageInterfaceHandle,
+ ) -> Result<bool> {
+ self.is_package_installed(repo, package)
+ }
+
+ fn ensure_binaries_presence(&mut self, package: PackageInterfaceHandle) {
+ self.ensure_binaries_presence(package);
+ }
+
+ fn execute(
+ &mut self,
+ repo: &mut dyn InstalledRepositoryInterface,
+ operations: Vec<std::rc::Rc<dyn OperationInterface>>,
+ dev_mode: bool,
+ run_scripts: bool,
+ download_only: bool,
+ ) -> Result<()> {
+ self.execute(repo, operations, dev_mode, run_scripts, download_only)
+ }
+
+ fn get_install_path(&mut self, package: PackageInterfaceHandle) -> Option<String> {
+ self.get_install_path(package)
+ }
+
+ fn set_output_progress(&mut self, output_progress: bool) {
+ self.set_output_progress(output_progress);
+ }
+
+ fn notify_installs(&mut self, io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>) {
+ self.notify_installs(io);
+ }
+}
diff --git a/crates/shirabe/src/installer/library_installer.rs b/crates/shirabe/src/installer/library_installer.rs
index e2c6c0c..e1c3aec 100644
--- a/crates/shirabe/src/installer/library_installer.rs
+++ b/crates/shirabe/src/installer/library_installer.rs
@@ -8,7 +8,7 @@ use shirabe_php_shim::{
};
use crate::composer::PartialComposerWeakHandle;
-use crate::downloader::DownloadManager;
+use crate::downloader::DownloadManagerInterface;
use crate::installer::BinaryInstaller;
use crate::installer::BinaryPresenceInterface;
use crate::installer::InstallerInterface;
@@ -24,7 +24,8 @@ use crate::util::Silencer;
pub struct LibraryInstaller {
pub(crate) composer: PartialComposerWeakHandle,
pub(crate) vendor_dir: String,
- pub(crate) download_manager: Option<std::rc::Rc<std::cell::RefCell<DownloadManager>>>,
+ pub(crate) download_manager:
+ Option<std::rc::Rc<std::cell::RefCell<dyn DownloadManagerInterface>>>,
pub(crate) io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
pub(crate) r#type: Option<String>,
pub(crate) filesystem: std::rc::Rc<std::cell::RefCell<Filesystem>>,
@@ -192,7 +193,9 @@ impl LibraryInstaller {
self.vendor_dir = realpath(&self.vendor_dir).unwrap_or_default();
}
- pub(crate) fn get_download_manager(&self) -> &std::rc::Rc<std::cell::RefCell<DownloadManager>> {
+ pub(crate) fn get_download_manager(
+ &self,
+ ) -> &std::rc::Rc<std::cell::RefCell<dyn DownloadManagerInterface>> {
// PHP: assert($this->downloadManager instanceof DownloadManager, new \LogicException(...))
assert!(
self.download_manager.is_some(),
diff --git a/crates/shirabe/src/installer/project_installer.rs b/crates/shirabe/src/installer/project_installer.rs
index 351fd35..83ffbb2 100644
--- a/crates/shirabe/src/installer/project_installer.rs
+++ b/crates/shirabe/src/installer/project_installer.rs
@@ -1,6 +1,6 @@
//! ref: composer/src/Composer/Installer/ProjectInstaller.php
-use crate::downloader::DownloadManager;
+use crate::downloader::DownloadManagerInterface;
use crate::installer::InstallerInterface;
use crate::package::PackageInterfaceHandle;
use crate::repository::InstalledRepositoryInterface;
@@ -10,14 +10,14 @@ use shirabe_php_shim::{InvalidArgumentException, PhpMixed};
#[derive(Debug)]
pub struct ProjectInstaller {
install_path: String,
- download_manager: std::rc::Rc<std::cell::RefCell<DownloadManager>>,
+ download_manager: std::rc::Rc<std::cell::RefCell<dyn DownloadManagerInterface>>,
filesystem: std::rc::Rc<std::cell::RefCell<Filesystem>>,
}
impl ProjectInstaller {
pub fn new(
install_path: &str,
- dm: std::rc::Rc<std::cell::RefCell<DownloadManager>>,
+ dm: std::rc::Rc<std::cell::RefCell<dyn DownloadManagerInterface>>,
fs: std::rc::Rc<std::cell::RefCell<Filesystem>>,
) -> Self {
let install_path = format!("{}/", install_path.replace('\\', "/").trim_end_matches('/'));
diff --git a/crates/shirabe/src/package/archiver/archive_manager.rs b/crates/shirabe/src/package/archiver/archive_manager.rs
index 139eb9a..be911d6 100644
--- a/crates/shirabe/src/package/archiver/archive_manager.rs
+++ b/crates/shirabe/src/package/archiver/archive_manager.rs
@@ -49,9 +49,8 @@ impl ArchiveManager {
self.archivers.push(archiver);
}
- pub fn set_overwrite_files(&mut self, overwrite_files: bool) -> &mut Self {
+ pub fn set_overwrite_files(&mut self, overwrite_files: bool) {
self.overwrite_files = overwrite_files;
- self
}
pub fn get_package_filename_parts(
@@ -314,3 +313,29 @@ impl ArchiveManager {
formats
}
}
+
+// Composer's Composer::setArchiveManager() accepts any ArchiveManager subclass, so plugins may
+// swap in a replacement. The interface captures the methods reached through Composer's accessor.
+pub trait ArchiveManagerInterface: std::fmt::Debug {
+ fn archive(
+ &mut self,
+ package: CompletePackageInterfaceHandle,
+ format: String,
+ target_dir: String,
+ file_name: Option<String>,
+ ignore_filters: bool,
+ ) -> anyhow::Result<String>;
+}
+
+impl ArchiveManagerInterface for ArchiveManager {
+ fn archive(
+ &mut self,
+ package: CompletePackageInterfaceHandle,
+ format: String,
+ target_dir: String,
+ file_name: Option<String>,
+ ignore_filters: bool,
+ ) -> anyhow::Result<String> {
+ self.archive(package, format, target_dir, file_name, ignore_filters)
+ }
+}
diff --git a/crates/shirabe/src/package/locker.rs b/crates/shirabe/src/package/locker.rs
index 3a87061..df5e1de 100644
--- a/crates/shirabe/src/package/locker.rs
+++ b/crates/shirabe/src/package/locker.rs
@@ -642,14 +642,13 @@ impl Locker {
}
/// Updates the lock file's hash in-place from a given composer.json's JsonFile
- pub fn update_hash<F>(
+ pub fn update_hash(
&mut self,
composer_json: &JsonFile,
- data_processor: Option<F>,
- ) -> Result<()>
- where
- F: FnOnce(IndexMap<String, PhpMixed>) -> IndexMap<String, PhpMixed>,
- {
+ data_processor: Option<
+ Box<dyn FnOnce(IndexMap<String, PhpMixed>) -> IndexMap<String, PhpMixed>>,
+ >,
+ ) -> Result<()> {
let contents = file_get_contents(composer_json.get_path());
let contents = match contents {
Some(s) => s,
@@ -1002,6 +1001,159 @@ impl Locker {
}
}
+// Composer's Composer::setLocker() accepts any Locker subclass, so plugins may swap in a
+// replacement. The interface captures the methods reached through Composer's accessor and through
+// the `&mut dyn LockerInterface` / `&dyn LockerInterface` references fed from it.
+pub trait LockerInterface: std::fmt::Debug {
+ fn get_json_file(&self) -> &JsonFile;
+ fn is_locked(&mut self) -> bool;
+ fn is_fresh(&mut self) -> Result<bool>;
+ fn get_locked_repository(&mut self, with_dev_reqs: bool) -> Result<LockArrayRepositoryHandle>;
+ fn get_dev_package_names(&mut self) -> Result<Vec<String>>;
+ fn get_platform_requirements(&mut self, with_dev_reqs: bool) -> Result<Vec<Link>>;
+ fn get_minimum_stability(&mut self) -> Result<String>;
+ fn get_stability_flags(&mut self) -> Result<IndexMap<String, String>>;
+ fn get_prefer_stable(&mut self) -> Result<Option<bool>>;
+ fn get_prefer_lowest(&mut self) -> Result<Option<bool>>;
+ fn get_platform_overrides(&mut self) -> Result<IndexMap<String, String>>;
+ fn get_aliases(&mut self) -> Result<Vec<IndexMap<String, String>>>;
+ fn get_plugin_api(&mut self) -> Result<String>;
+ fn get_lock_data(&mut self) -> Result<IndexMap<String, PhpMixed>>;
+ #[allow(clippy::too_many_arguments, reason = "to keep PHP signature")]
+ fn set_lock_data(
+ &mut self,
+ packages: Vec<PackageInterfaceHandle>,
+ dev_packages: Option<Vec<PackageInterfaceHandle>>,
+ platform_reqs: IndexMap<String, String>,
+ platform_dev_reqs: IndexMap<String, String>,
+ aliases: Vec<IndexMap<String, PhpMixed>>,
+ minimum_stability: &str,
+ stability_flags: IndexMap<String, i64>,
+ prefer_stable: bool,
+ prefer_lowest: bool,
+ platform_overrides: IndexMap<String, PhpMixed>,
+ write: bool,
+ ) -> Result<bool>;
+ fn update_hash(
+ &mut self,
+ composer_json: &JsonFile,
+ data_processor: Option<
+ Box<dyn FnOnce(IndexMap<String, PhpMixed>) -> IndexMap<String, PhpMixed>>,
+ >,
+ ) -> Result<()>;
+ fn get_missing_requirement_info(
+ &mut self,
+ package: RootPackageInterfaceHandle,
+ include_dev: bool,
+ ) -> Result<Vec<String>>;
+}
+
+impl LockerInterface for Locker {
+ fn get_json_file(&self) -> &JsonFile {
+ self.get_json_file()
+ }
+
+ fn is_locked(&mut self) -> bool {
+ self.is_locked()
+ }
+
+ fn is_fresh(&mut self) -> Result<bool> {
+ self.is_fresh()
+ }
+
+ fn get_locked_repository(&mut self, with_dev_reqs: bool) -> Result<LockArrayRepositoryHandle> {
+ self.get_locked_repository(with_dev_reqs)
+ }
+
+ fn get_dev_package_names(&mut self) -> Result<Vec<String>> {
+ self.get_dev_package_names()
+ }
+
+ fn get_platform_requirements(&mut self, with_dev_reqs: bool) -> Result<Vec<Link>> {
+ self.get_platform_requirements(with_dev_reqs)
+ }
+
+ fn get_minimum_stability(&mut self) -> Result<String> {
+ self.get_minimum_stability()
+ }
+
+ fn get_stability_flags(&mut self) -> Result<IndexMap<String, String>> {
+ self.get_stability_flags()
+ }
+
+ fn get_prefer_stable(&mut self) -> Result<Option<bool>> {
+ self.get_prefer_stable()
+ }
+
+ fn get_prefer_lowest(&mut self) -> Result<Option<bool>> {
+ self.get_prefer_lowest()
+ }
+
+ fn get_platform_overrides(&mut self) -> Result<IndexMap<String, String>> {
+ self.get_platform_overrides()
+ }
+
+ fn get_aliases(&mut self) -> Result<Vec<IndexMap<String, String>>> {
+ self.get_aliases()
+ }
+
+ fn get_plugin_api(&mut self) -> Result<String> {
+ self.get_plugin_api()
+ }
+
+ fn get_lock_data(&mut self) -> Result<IndexMap<String, PhpMixed>> {
+ self.get_lock_data()
+ }
+
+ #[allow(clippy::too_many_arguments, reason = "to keep PHP signature")]
+ fn set_lock_data(
+ &mut self,
+ packages: Vec<PackageInterfaceHandle>,
+ dev_packages: Option<Vec<PackageInterfaceHandle>>,
+ platform_reqs: IndexMap<String, String>,
+ platform_dev_reqs: IndexMap<String, String>,
+ aliases: Vec<IndexMap<String, PhpMixed>>,
+ minimum_stability: &str,
+ stability_flags: IndexMap<String, i64>,
+ prefer_stable: bool,
+ prefer_lowest: bool,
+ platform_overrides: IndexMap<String, PhpMixed>,
+ write: bool,
+ ) -> Result<bool> {
+ self.set_lock_data(
+ packages,
+ dev_packages,
+ platform_reqs,
+ platform_dev_reqs,
+ aliases,
+ minimum_stability,
+ stability_flags,
+ prefer_stable,
+ prefer_lowest,
+ platform_overrides,
+ write,
+ )
+ }
+
+ fn update_hash(
+ &mut self,
+ composer_json: &JsonFile,
+ data_processor: Option<
+ Box<dyn FnOnce(IndexMap<String, PhpMixed>) -> IndexMap<String, PhpMixed>>,
+ >,
+ ) -> Result<()> {
+ self.update_hash(composer_json, data_processor)
+ }
+
+ fn get_missing_requirement_info(
+ &mut self,
+ package: RootPackageInterfaceHandle,
+ include_dev: bool,
+ ) -> Result<Vec<String>> {
+ self.get_missing_requirement_info(package, include_dev)
+ }
+}
+
struct SetEntry {
repo: LockArrayRepositoryHandle,
method: String,
diff --git a/crates/shirabe/src/plugin/plugin_manager.rs b/crates/shirabe/src/plugin/plugin_manager.rs
index c1cd38e..a949c03 100644
--- a/crates/shirabe/src/plugin/plugin_manager.rs
+++ b/crates/shirabe/src/plugin/plugin_manager.rs
@@ -19,7 +19,7 @@ use crate::factory::DisablePlugins;
use crate::installer::InstallerInterface;
use crate::io::IOInterface;
use crate::io::IOInterfaceImmutable;
-use crate::package::Locker;
+use crate::package::LockerInterface;
use crate::package::PackageInterfaceHandle;
use crate::package::RootPackageInterfaceHandle;
use crate::package::base_package::{self};
@@ -738,7 +738,7 @@ impl PluginManager {
fn parse_allowed_plugins(
allow_plugins_config: PhpMixed,
- mut locker: Option<&mut Locker>,
+ mut locker: Option<&mut dyn LockerInterface>,
) -> Option<IndexMap<String, bool>> {
// PHP: [] === $allowPluginsConfig && $locker !== null && $locker->isLocked() && version_compare($locker->getPluginApi(), '2.2.0', '<')
let is_empty_array = allow_plugins_config
diff --git a/crates/shirabe/src/repository/repository_factory.rs b/crates/shirabe/src/repository/repository_factory.rs
index db8185e..bc08589 100644
--- a/crates/shirabe/src/repository/repository_factory.rs
+++ b/crates/shirabe/src/repository/repository_factory.rs
@@ -15,6 +15,7 @@ use crate::json::JsonFile;
use crate::repository::FilesystemRepository;
use crate::repository::RepositoryInterfaceHandle;
use crate::repository::RepositoryManager;
+use crate::repository::RepositoryManagerInterface;
use crate::util::HttpDownloader;
use crate::util::ProcessExecutor;
@@ -98,7 +99,7 @@ impl RepositoryFactory {
config: &std::rc::Rc<std::cell::RefCell<Config>>,
repository: &str,
allow_filesystem: bool,
- rm: Option<&mut RepositoryManager>,
+ rm: Option<&mut dyn RepositoryManagerInterface>,
) -> anyhow::Result<RepositoryInterfaceHandle> {
let repo_config =
Self::config_from_string(io.clone(), config, repository, allow_filesystem)?;
@@ -109,7 +110,7 @@ impl RepositoryFactory {
io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: &std::rc::Rc<std::cell::RefCell<Config>>,
repo_config: IndexMap<String, PhpMixed>,
- rm: Option<&mut RepositoryManager>,
+ rm: Option<&mut dyn RepositoryManagerInterface>,
) -> anyhow::Result<RepositoryInterfaceHandle> {
let mut owned_rm;
let rm = if let Some(rm) = rm {
@@ -134,7 +135,7 @@ impl RepositoryFactory {
pub fn default_repos(
io: Option<std::rc::Rc<std::cell::RefCell<dyn IOInterface>>>,
config: Option<std::rc::Rc<std::cell::RefCell<Config>>>,
- rm: Option<&mut RepositoryManager>,
+ rm: Option<&mut dyn RepositoryManagerInterface>,
) -> anyhow::Result<IndexMap<String, RepositoryInterfaceHandle>> {
let config = match config {
Some(c) => c,
@@ -235,7 +236,7 @@ impl RepositoryFactory {
}
fn create_repos(
- rm: &mut RepositoryManager,
+ rm: &mut dyn RepositoryManagerInterface,
repo_configs: Vec<PhpMixed>,
) -> anyhow::Result<IndexMap<String, RepositoryInterfaceHandle>> {
let mut repo_map: IndexMap<String, RepositoryInterfaceHandle> = IndexMap::new();
diff --git a/crates/shirabe/src/repository/repository_manager.rs b/crates/shirabe/src/repository/repository_manager.rs
index 247236c..41f4e7d 100644
--- a/crates/shirabe/src/repository/repository_manager.rs
+++ b/crates/shirabe/src/repository/repository_manager.rs
@@ -196,3 +196,46 @@ impl RepositoryManager {
self.local_repository.clone().unwrap()
}
}
+
+// Composer's PartialComposer::setRepositoryManager() accepts any RepositoryManager subclass, so
+// plugins may swap in a replacement. The interface captures the methods reached through Composer's
+// accessor and through the `&mut RepositoryManager` parameters fed from it.
+pub trait RepositoryManagerInterface: std::fmt::Debug {
+ fn get_local_repository(&self) -> RepositoryInterfaceHandle;
+ fn get_repositories(&self) -> &Vec<RepositoryInterfaceHandle>;
+ fn create_repository(
+ &self,
+ r#type: &str,
+ config: IndexMap<String, PhpMixed>,
+ name: Option<&str>,
+ ) -> anyhow::Result<RepositoryInterfaceHandle>;
+ fn add_repository(&mut self, repository: RepositoryInterfaceHandle);
+ fn set_local_repository(&mut self, repository: RepositoryInterfaceHandle);
+}
+
+impl RepositoryManagerInterface for RepositoryManager {
+ fn get_local_repository(&self) -> RepositoryInterfaceHandle {
+ self.get_local_repository()
+ }
+
+ fn get_repositories(&self) -> &Vec<RepositoryInterfaceHandle> {
+ self.get_repositories()
+ }
+
+ fn create_repository(
+ &self,
+ r#type: &str,
+ config: IndexMap<String, PhpMixed>,
+ name: Option<&str>,
+ ) -> anyhow::Result<RepositoryInterfaceHandle> {
+ self.create_repository(r#type, config, name)
+ }
+
+ fn add_repository(&mut self, repository: RepositoryInterfaceHandle) {
+ self.add_repository(repository);
+ }
+
+ fn set_local_repository(&mut self, repository: RepositoryInterfaceHandle) {
+ self.set_local_repository(repository);
+ }
+}
diff --git a/crates/shirabe/src/repository/repository_set.rs b/crates/shirabe/src/repository/repository_set.rs
index ba6373a..393639f 100644
--- a/crates/shirabe/src/repository/repository_set.rs
+++ b/crates/shirabe/src/repository/repository_set.rs
@@ -15,7 +15,7 @@ use crate::dependency_resolver::PoolOptimizer;
use crate::dependency_resolver::Request;
use crate::dependency_resolver::SecurityAdvisoryPoolFilter;
use crate::downloader::TransportException;
-use crate::event_dispatcher::EventDispatcher;
+use crate::event_dispatcher::EventDispatcherInterface;
use crate::io::IOInterface;
use crate::io::NullIO;
use crate::package::AliasPackageHandle;
@@ -451,7 +451,7 @@ impl RepositorySet {
&mut self,
request: &mut Request,
io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
- event_dispatcher: Option<std::rc::Rc<std::cell::RefCell<EventDispatcher>>>,
+ event_dispatcher: Option<std::rc::Rc<std::cell::RefCell<dyn EventDispatcherInterface>>>,
pool_optimizer: Option<PoolOptimizer>,
ignored_types: Vec<String>,
allowed_types: Option<Vec<String>>,
diff --git a/crates/shirabe/src/util/sync_helper.rs b/crates/shirabe/src/util/sync_helper.rs
index 6220f5c..8988795 100644
--- a/crates/shirabe/src/util/sync_helper.rs
+++ b/crates/shirabe/src/util/sync_helper.rs
@@ -1,6 +1,6 @@
//! ref: composer/src/Composer/Util/SyncHelper.php
-use crate::downloader::DownloadManager;
+use crate::downloader::DownloadManagerInterface;
use crate::downloader::DownloaderInterface;
use crate::package::PackageInterfaceHandle;
use crate::util::r#loop::Loop;
@@ -9,7 +9,7 @@ use shirabe_php_shim::PhpMixed;
pub enum DownloaderOrManager<'a> {
Interface(&'a std::rc::Rc<std::cell::RefCell<dyn DownloaderInterface>>),
- Manager(&'a std::rc::Rc<std::cell::RefCell<DownloadManager>>),
+ Manager(&'a std::rc::Rc<std::cell::RefCell<dyn DownloadManagerInterface>>),
}
impl<'a> DownloaderOrManager<'a> {
diff --git a/crates/shirabe/tests/composer_test.rs b/crates/shirabe/tests/composer_test.rs
index 908e813..bffe4ce 100644
--- a/crates/shirabe/tests/composer_test.rs
+++ b/crates/shirabe/tests/composer_test.rs
@@ -7,12 +7,15 @@ use indexmap::IndexMap;
use shirabe::composer::Composer;
use shirabe::config::Config;
use shirabe::downloader::DownloadManager;
+use shirabe::downloader::DownloadManagerInterface;
use shirabe::installer::InstallationManager;
+use shirabe::installer::InstallationManagerInterface;
use shirabe::io::IOInterface;
use shirabe::io::null_io::NullIO;
use shirabe::json::JsonFile;
-use shirabe::package::{Locker, RootPackageHandle, RootPackageInterfaceHandle};
+use shirabe::package::{Locker, LockerInterface, RootPackageHandle, RootPackageInterfaceHandle};
use shirabe::repository::RepositoryManager;
+use shirabe::repository::RepositoryManagerInterface;
use shirabe::util::http_downloader::HttpDownloader;
use shirabe::util::r#loop::Loop;
use shirabe::util::process_executor::ProcessExecutor;
@@ -60,7 +63,7 @@ fn test_set_get_locker() {
let io = null_io();
let json_file = JsonFile::new("composer.lock".to_string(), None, None).unwrap();
let process = Rc::new(RefCell::new(ProcessExecutor::new(Some(io.clone()))));
- let locker = Rc::new(RefCell::new(Locker::new(
+ let locker: Rc<RefCell<dyn LockerInterface>> = Rc::new(RefCell::new(Locker::new(
io.clone(),
json_file,
installation_manager(&io),
@@ -77,13 +80,9 @@ fn test_set_get_repository_manager() {
let mut composer = Composer::new();
let io = null_io();
let config = Rc::new(RefCell::new(Config::new(false, None)));
- let manager = Rc::new(RefCell::new(RepositoryManager::new(
- io.clone(),
- config,
- http_downloader(&io),
- None,
- None,
- )));
+ let manager: Rc<RefCell<dyn RepositoryManagerInterface>> = Rc::new(RefCell::new(
+ RepositoryManager::new(io.clone(), config, http_downloader(&io), None, None),
+ ));
composer.set_repository_manager(manager.clone());
assert!(Rc::ptr_eq(&composer.get_repository_manager(), &manager));
@@ -92,7 +91,8 @@ fn test_set_get_repository_manager() {
#[test]
fn test_set_get_download_manager() {
let mut composer = Composer::new();
- let manager = Rc::new(RefCell::new(DownloadManager::new(null_io(), false, None)));
+ let manager: Rc<RefCell<dyn DownloadManagerInterface>> =
+ Rc::new(RefCell::new(DownloadManager::new(null_io(), false, None)));
composer.set_download_manager(manager.clone());
assert!(Rc::ptr_eq(&composer.get_download_manager(), &manager));
@@ -102,7 +102,7 @@ fn test_set_get_download_manager() {
fn test_set_get_installation_manager() {
let mut composer = Composer::new();
let io = null_io();
- let manager = installation_manager(&io);
+ let manager: Rc<RefCell<dyn InstallationManagerInterface>> = installation_manager(&io);
composer.set_installation_manager(manager.clone());
assert!(Rc::ptr_eq(&composer.get_installation_manager(), &manager));