From eee660c46a6b919ff5db6d447c3a500140306991 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Fri, 15 May 2026 23:50:58 +0900 Subject: feat(port): port RepositoryManager.php --- .../shirabe/src/repository/repository_manager.rs | 119 +++++++++++++++++++++ 1 file changed, 119 insertions(+) (limited to 'crates/shirabe/src/repository') diff --git a/crates/shirabe/src/repository/repository_manager.rs b/crates/shirabe/src/repository/repository_manager.rs index 8afb92e..fd60e7b 100644 --- a/crates/shirabe/src/repository/repository_manager.rs +++ b/crates/shirabe/src/repository/repository_manager.rs @@ -1 +1,120 @@ //! ref: composer/src/Composer/Repository/RepositoryManager.php + +use indexmap::IndexMap; +use shirabe_php_shim::{json_encode, InvalidArgumentException, PhpMixed}; +use shirabe_semver::constraint::constraint_interface::ConstraintInterface; + +use crate::config::Config; +use crate::event_dispatcher::event_dispatcher::EventDispatcher; +use crate::io::io_interface::IOInterface; +use crate::package::package_interface::PackageInterface; +use crate::repository::filter_repository::FilterRepository; +use crate::repository::installed_repository_interface::InstalledRepositoryInterface; +use crate::repository::repository_interface::RepositoryInterface; +use crate::util::http_downloader::HttpDownloader; +use crate::util::process_executor::ProcessExecutor; + +pub struct RepositoryManager { + local_repository: Option>, + repositories: Vec>, + repository_classes: IndexMap, + io: Box, + config: Config, + http_downloader: HttpDownloader, + event_dispatcher: Option, + process: ProcessExecutor, +} + +impl RepositoryManager { + pub fn new(io: &dyn IOInterface, config: &Config, http_downloader: HttpDownloader, event_dispatcher: Option, process: Option) -> Self { + let process = process.unwrap_or_else(|| ProcessExecutor::new(io)); + Self { + local_repository: None, + repositories: vec![], + repository_classes: IndexMap::new(), + io: io.clone_box(), + config: config.clone(), + http_downloader, + event_dispatcher, + process, + } + } + + pub fn find_package(&self, name: &str, constraint: &dyn ConstraintInterface) -> Option> { + for repository in &self.repositories { + if let Some(package) = repository.find_package(name, constraint) { + return Some(package); + } + } + None + } + + pub fn find_packages(&self, name: &str, constraint: &dyn ConstraintInterface) -> Vec> { + let mut packages: Vec> = vec![]; + for repository in self.get_repositories() { + packages.extend(repository.find_packages(name, constraint)); + } + packages + } + + pub fn add_repository(&mut self, repository: Box) { + self.repositories.push(repository); + } + + pub fn prepend_repository(&mut self, repository: Box) { + self.repositories.insert(0, repository); + } + + pub fn create_repository(&self, r#type: &str, config: IndexMap, name: Option<&str>) -> anyhow::Result> { + if !self.repository_classes.contains_key(r#type) { + return Err(InvalidArgumentException { + message: format!("Repository type is not registered: {}", r#type), + code: 0, + }.into()); + } + + if config.get("packagist").and_then(|v| v.as_bool()) == Some(false) { + let config_json = json_encode(&PhpMixed::Array(config.iter().map(|(k, v)| (k.clone(), Box::new(v.clone()))).collect())).unwrap_or_default(); + self.io.write_error(&format!("Repository \"{}\" ({}) has a packagist key which should be in its own repository definition", name.unwrap_or(""), config_json)); + } + + let class = self.repository_classes[r#type].clone(); + + let has_filter = config.contains_key("only") || config.contains_key("exclude") || config.contains_key("canonical"); + let filter_config = if has_filter { Some(config.clone()) } else { None }; + + let mut cleaned_config = config; + cleaned_config.remove("only"); + cleaned_config.remove("exclude"); + cleaned_config.remove("canonical"); + + // Phase B: implement dynamic class instantiation by class name + let repository = self.create_repository_by_class(&class, cleaned_config)?; + + if let Some(filter_config) = filter_config { + return Ok(Box::new(FilterRepository::new(repository, filter_config))); + } + + Ok(repository) + } + + fn create_repository_by_class(&self, _class: &str, _config: IndexMap) -> anyhow::Result> { + todo!("Phase B: dynamic class instantiation by class name") + } + + pub fn set_repository_class(&mut self, r#type: &str, class: &str) { + self.repository_classes.insert(r#type.to_string(), class.to_string()); + } + + pub fn get_repositories(&self) -> &Vec> { + &self.repositories + } + + pub fn set_local_repository(&mut self, repository: Box) { + self.local_repository = Some(repository); + } + + pub fn get_local_repository(&self) -> &dyn InstalledRepositoryInterface { + self.local_repository.as_ref().unwrap().as_ref() + } +} -- cgit v1.3.1