diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-05-20 08:33:49 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-05-20 08:33:57 +0900 |
| commit | f31b101ce1e921a026ba234b1f0a83b0392bc118 (patch) | |
| tree | b7ac2aa84d71ebd162cc21aeab0240e7e0544988 /crates/shirabe/src/package | |
| parent | 5e31fa33c3b5cf726a57a063b8e7a070869250fe (diff) | |
| download | php-shirabe-f31b101ce1e921a026ba234b1f0a83b0392bc118.tar.gz php-shirabe-f31b101ce1e921a026ba234b1f0a83b0392bc118.tar.zst php-shirabe-f31b101ce1e921a026ba234b1f0a83b0392bc118.zip | |
fix(compile): fix all remaining compile errors
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe/src/package')
17 files changed, 313 insertions, 202 deletions
diff --git a/crates/shirabe/src/package/alias_package.rs b/crates/shirabe/src/package/alias_package.rs index 3f4b1d8..0049d89 100644 --- a/crates/shirabe/src/package/alias_package.rs +++ b/crates/shirabe/src/package/alias_package.rs @@ -130,7 +130,11 @@ impl AliasPackage { } pub fn get_alias_of(&self) -> &dyn BasePackage { - &self.alias_of + self.alias_of.as_ref() + } + + pub fn get_alias_of_mut(&mut self) -> &mut dyn BasePackage { + &mut *self.alias_of } /// Stores whether this is an alias created by an aliasing in the requirements of the root package or not @@ -181,7 +185,7 @@ impl AliasPackage { Some(link_type.to_string()), Some(pretty_version.clone()), ); - constraint.set_pretty_string(&pretty_version); + shirabe_semver::constraint::constraint_interface::ConstraintInterface::set_pretty_string(&mut constraint, Some(pretty_version.clone())); new_links.push(new_link); } } @@ -201,7 +205,7 @@ impl AliasPackage { Some(link_type.to_string()), Some(pretty_version.clone()), ); - constraint.set_pretty_string(&pretty_version); + shirabe_semver::constraint::constraint_interface::ConstraintInterface::set_pretty_string(&mut constraint, Some(pretty_version.clone())); links[index] = new_link; } } @@ -479,7 +483,7 @@ impl BasePackage for AliasPackage { } fn repository_opt(&self) -> Option<&dyn RepositoryInterface> { - self.repository.as_ref() + self.repository.as_deref() } fn set_repository_box(&mut self, repository: Box<dyn RepositoryInterface>) { diff --git a/crates/shirabe/src/package/archiver/archive_manager.rs b/crates/shirabe/src/package/archiver/archive_manager.rs index 374e16c..094ddc3 100644 --- a/crates/shirabe/src/package/archiver/archive_manager.rs +++ b/crates/shirabe/src/package/archiver/archive_manager.rs @@ -58,10 +58,10 @@ impl ArchiveManager { pub fn get_package_filename_parts( &self, package: &dyn CompletePackageInterface, - ) -> IndexMap<String, String> { + ) -> anyhow::Result<IndexMap<String, String>> { let base_name = match package.get_archive_name() { Some(name) => name.to_string(), - None => Preg::replace("#[^a-z0-9-_]#i", "-", package.get_name()), + None => Preg::replace("#[^a-z0-9-_]#i", "-", package.get_name())?, }; let mut parts: IndexMap<String, String> = IndexMap::new(); @@ -70,7 +70,7 @@ impl ArchiveManager { let dist_reference = package.get_dist_reference(); if let Some(ref dist_ref) = dist_reference { if Preg::is_match("{^[a-f0-9]{40}$}", dist_ref).unwrap_or(false) { - parts.insert("dist_reference".to_string(), dist_ref.clone()); + parts.insert("dist_reference".to_string(), dist_ref.to_string()); if let Some(dist_type) = package.get_dist_type() { parts.insert("dist_type".to_string(), dist_type.to_string()); } @@ -79,7 +79,7 @@ impl ArchiveManager { "version".to_string(), package.get_pretty_version().to_string(), ); - parts.insert("dist_reference".to_string(), dist_ref.clone()); + parts.insert("dist_reference".to_string(), dist_ref.to_string()); } } else { parts.insert( @@ -95,10 +95,10 @@ impl ArchiveManager { // array_filter removed null values; replace '/' with '-' in each value for val in parts.values_mut() { - *val = val.replace('/', '-'); + *val = val.replace('/', "-"); } - parts + Ok(parts) } pub fn get_package_filename_from_parts(&self, parts: &IndexMap<String, String>) -> String { @@ -106,9 +106,12 @@ impl ArchiveManager { values.join("-") } - pub fn get_package_filename(&self, package: &dyn CompletePackageInterface) -> String { - let parts = self.get_package_filename_parts(package); - self.get_package_filename_from_parts(&parts) + pub fn get_package_filename( + &self, + package: &dyn CompletePackageInterface, + ) -> anyhow::Result<String> { + let parts = self.get_package_filename_parts(package)?; + Ok(self.get_package_filename_from_parts(&parts)) } pub fn archive( @@ -147,9 +150,9 @@ impl ArchiveManager { } }; - let filesystem = Filesystem::new(None); + let mut filesystem = Filesystem::new(None); - let is_root = package.as_any().is::<dyn RootPackageInterface>(); + let is_root = package.as_root_package_interface().is_some(); let source_path: String; if is_root { @@ -181,7 +184,7 @@ impl ArchiveManager { let composer_json_path = format!("{}/composer.json", source_path); if file_exists(&composer_json_path) { - let json_file = JsonFile::new(composer_json_path, None, None)?; + let mut json_file = JsonFile::new(composer_json_path, None, None)?; let json_data = json_file.read()?; if let Some(archive) = json_data.get("archive") { if let Some(name) = archive.get("name").and_then(|v| v.as_string()) { @@ -206,7 +209,7 @@ impl ArchiveManager { let supported_formats = self.get_supported_formats(); let package_name_parts = match file_name { - None => self.get_package_filename_parts(package), + None => self.get_package_filename_parts(package)?, Some(f) => { let mut parts = IndexMap::new(); parts.insert("base".to_string(), f); diff --git a/crates/shirabe/src/package/archiver/archiver_interface.rs b/crates/shirabe/src/package/archiver/archiver_interface.rs index 82e976d..54121b5 100644 --- a/crates/shirabe/src/package/archiver/archiver_interface.rs +++ b/crates/shirabe/src/package/archiver/archiver_interface.rs @@ -1,5 +1,7 @@ //! ref: composer/src/Composer/Package/Archiver/ArchiverInterface.php +use std::any::Any; + pub trait ArchiverInterface { fn archive( &self, @@ -11,4 +13,7 @@ pub trait ArchiverInterface { ) -> anyhow::Result<String>; fn supports(&self, format: String, source_type: Option<String>) -> bool; + + /// PHP `$archiver instanceof X` checks; allow downcasting from `dyn ArchiverInterface`. + fn as_any(&self) -> &dyn Any; } diff --git a/crates/shirabe/src/package/archiver/phar_archiver.rs b/crates/shirabe/src/package/archiver/phar_archiver.rs index 7b5142b..17bc05b 100644 --- a/crates/shirabe/src/package/archiver/phar_archiver.rs +++ b/crates/shirabe/src/package/archiver/phar_archiver.rs @@ -156,4 +156,8 @@ impl ArchiverInterface for PharArchiver { fn supports(&self, format: String, _source_type: Option<String>) -> bool { formats().contains_key(format.as_str()) } + + fn as_any(&self) -> &dyn std::any::Any { + self + } } diff --git a/crates/shirabe/src/package/archiver/zip_archiver.rs b/crates/shirabe/src/package/archiver/zip_archiver.rs index 471352f..a5dd4f4 100644 --- a/crates/shirabe/src/package/archiver/zip_archiver.rs +++ b/crates/shirabe/src/package/archiver/zip_archiver.rs @@ -107,4 +107,8 @@ impl ArchiverInterface for ZipArchiver { fn supports(&self, format: String, _source_type: Option<String>) -> bool { Self::formats().contains_key(&format) && self.compression_available() } + + fn as_any(&self) -> &dyn std::any::Any { + self + } } diff --git a/crates/shirabe/src/package/base_package.rs b/crates/shirabe/src/package/base_package.rs index 052a480..109fdb4 100644 --- a/crates/shirabe/src/package/base_package.rs +++ b/crates/shirabe/src/package/base_package.rs @@ -83,6 +83,12 @@ pub trait BasePackage: PackageInterface + std::fmt::Display { fn set_repository_box(&mut self, repository: Box<dyn RepositoryInterface>); fn take_repository(&mut self) -> Option<Box<dyn RepositoryInterface>>; + /// PHP `setRepository($this)` from the containing repository — Rust port marker until + /// the borrow story for repository-package back-references is finalized in phase B. + fn set_repository_self(&mut self) { + // TODO(phase-b): wire up a back-reference to the containing repository when needed. + } + fn clone_box(&self) -> Box<dyn BasePackage>; // as_alias_package / as_complete_package_interface inherited from PackageInterface. diff --git a/crates/shirabe/src/package/complete_package.rs b/crates/shirabe/src/package/complete_package.rs index 27c49c6..f6ee7ae 100644 --- a/crates/shirabe/src/package/complete_package.rs +++ b/crates/shirabe/src/package/complete_package.rs @@ -23,6 +23,26 @@ pub struct CompletePackage { pub(crate) archive_excludes: Vec<String>, } +impl CompletePackage { + pub fn new(name: String, version: String, pretty_version: String) -> Self { + Self { + inner: crate::package::package::Package::new(name, version, pretty_version), + repositories: Vec::new(), + license: Vec::new(), + keywords: Vec::new(), + authors: Vec::new(), + description: None, + homepage: None, + scripts: IndexMap::new(), + support: IndexMap::new(), + funding: Vec::new(), + abandoned: PhpMixed::Bool(false), + archive_name: None, + archive_excludes: Vec::new(), + } + } +} + impl CompletePackageInterface for CompletePackage { fn set_scripts(&mut self, scripts: IndexMap<String, Vec<String>>) { self.scripts = scripts; diff --git a/crates/shirabe/src/package/dumper/array_dumper.rs b/crates/shirabe/src/package/dumper/array_dumper.rs index 0b57070..cbff605 100644 --- a/crates/shirabe/src/package/dumper/array_dumper.rs +++ b/crates/shirabe/src/package/dumper/array_dumper.rs @@ -1,14 +1,14 @@ //! ref: composer/src/Composer/Package/Dumper/ArrayDumper.php -use std::any::Any; - use indexmap::IndexMap; use shirabe_php_shim::PhpMixed; -use crate::package::base_package::BasePackage; +use crate::package::base_package::SUPPORTED_LINK_TYPES; use crate::package::complete_package::CompletePackage; +use crate::package::complete_package_interface::CompletePackageInterface; use crate::package::package_interface::PackageInterface; use crate::package::root_package::RootPackage; +use crate::package::root_package_interface::RootPackageInterface; #[derive(Debug)] pub struct ArrayDumper; @@ -131,10 +131,10 @@ impl ArrayDumper { } // corresponds to: foreach (BasePackage::$supportedLinkTypes as $type => $opts) { $links = $package->{'get'.ucfirst($opts['method'])}(); ... } - for (type_name, method_name) in <dyn BasePackage>::supported_link_types() { + for (type_name, opts) in SUPPORTED_LINK_TYPES.iter() { // TODO(phase-b): PackageInterface needs get_links_by_method to mimic PHP magic call let links: Vec<crate::package::link::Link> = Vec::new(); - let _ = (&method_name, package); + let _ = (&opts.method, package); if links.is_empty() { continue; } @@ -142,11 +142,13 @@ impl ArrayDumper { for link in &links { link_map.insert( link.get_target().to_string(), - Box::new(PhpMixed::String(link.get_pretty_constraint().to_string())), + Box::new(PhpMixed::String( + link.get_pretty_constraint().unwrap_or_default().to_string(), + )), ); } link_map.sort_keys(); - data.insert(type_name, PhpMixed::Array(link_map)); + data.insert(type_name.to_string(), PhpMixed::Array(link_map)); } let suggests = package.get_suggests(); @@ -265,7 +267,7 @@ impl ArrayDumper { let entry = data .entry("archive".to_string()) .or_insert_with(|| PhpMixed::Array(IndexMap::new())); - if let PhpMixed::Array(ref mut archive) = entry { + if let PhpMixed::Array(archive) = entry { archive.insert( "name".to_string(), Box::new(PhpMixed::String(archive_name.to_string())), @@ -277,7 +279,7 @@ impl ArrayDumper { let entry = data .entry("archive".to_string()) .or_insert_with(|| PhpMixed::Array(IndexMap::new())); - if let PhpMixed::Array(ref mut archive) = entry { + if let PhpMixed::Array(archive) = entry { archive.insert( "exclude".to_string(), Box::new(PhpMixed::List( diff --git a/crates/shirabe/src/package/loader/array_loader.rs b/crates/shirabe/src/package/loader/array_loader.rs index 3ece5c7..82b2ef7 100644 --- a/crates/shirabe/src/package/loader/array_loader.rs +++ b/crates/shirabe/src/package/loader/array_loader.rs @@ -860,7 +860,7 @@ impl ArrayLoader { && default_branch_is_true && self .version_parser - .parse_numeric_alias_prefix(&Preg::replace(r"{^v}", "", &version_str)) + .parse_numeric_alias_prefix(&Preg::replace(r"{^v}", "", &version_str)?) .is_none() { return Ok(Some(VersionParser::DEFAULT_BRANCH_ALIAS.to_string())); diff --git a/crates/shirabe/src/package/loader/root_package_loader.rs b/crates/shirabe/src/package/loader/root_package_loader.rs index d2e2a7a..15f1114 100644 --- a/crates/shirabe/src/package/loader/root_package_loader.rs +++ b/crates/shirabe/src/package/loader/root_package_loader.rs @@ -9,12 +9,14 @@ use shirabe_php_shim::{ use crate::config::Config; use crate::io::io_interface::IOInterface; use crate::package::base_package::{BasePackage, STABILITIES, SUPPORTED_LINK_TYPES}; +use crate::package::complete_package_interface::CompletePackageInterface; use crate::package::loader::array_loader::ArrayLoader; use crate::package::loader::loader_interface::LoaderInterface; use crate::package::loader::validating_array_loader::ValidatingArrayLoader; use crate::package::package_interface::PackageInterface; use crate::package::root_alias_package::RootAliasPackage; use crate::package::root_package::RootPackage; +use crate::package::root_package_interface::RootPackageInterface; use crate::package::version::version_guesser::VersionGuesser; use crate::package::version::version_parser::VersionParser; use crate::repository::repository_factory::RepositoryFactory; @@ -39,9 +41,9 @@ impl RootPackageLoader { version_guesser: Option<VersionGuesser>, io: Option<Box<dyn IOInterface>>, ) -> Self { - let inner = ArrayLoader::new(parser); + let inner = ArrayLoader::new(parser, true); let version_guesser = version_guesser.unwrap_or_else(|| { - let mut process_executor = ProcessExecutor::new(io.as_deref()); + let mut process_executor = ProcessExecutor::new(io.as_deref().map(|i| i.clone_box())); process_executor.enable_async(); VersionGuesser::new( std::rc::Rc::clone(&config), @@ -94,7 +96,7 @@ impl RootPackageLoader { let mut commit: Option<String> = None; if Platform::get_env("COMPOSER_ROOT_VERSION").is_some() { - let version = self.version_guesser.get_root_version_from_env(); + let version = self.version_guesser.get_root_version_from_env()?; config.insert( "version".to_string(), Box::new(shirabe_php_shim::PhpMixed::String(version)), @@ -102,18 +104,25 @@ impl RootPackageLoader { } else { let cwd_str = cwd .map(|s| s.to_string()) - .unwrap_or_else(|| Platform::get_cwd(true)); - let version_data = self.version_guesser.guess_version(&config, &cwd_str); + .unwrap_or_else(|| Platform::get_cwd(true).unwrap_or_default()); + // TODO(phase-b): config here is IndexMap<String, Box<PhpMixed>> but guess_version + // expects IndexMap<String, PhpMixed>; pass an empty map as placeholder. + let unboxed_config: IndexMap<String, shirabe_php_shim::PhpMixed> = IndexMap::new(); + let version_data = self + .version_guesser + .guess_version(&unboxed_config, &cwd_str)?; if let Some(data) = version_data { config.insert( "version".to_string(), Box::new(shirabe_php_shim::PhpMixed::String( - data.pretty_version.clone(), + data.pretty_version.clone().unwrap_or_default(), )), ); config.insert( "version_normalized".to_string(), - Box::new(shirabe_php_shim::PhpMixed::String(data.version.clone())), + Box::new(shirabe_php_shim::PhpMixed::String( + data.version.clone().unwrap_or_default(), + )), ); commit = data.commit; } @@ -127,7 +136,7 @@ impl RootPackageLoader { io.warning(&format!( "Composer could not detect the root package ({}) version, defaulting to '1.0.0'. See https://getcomposer.org/root-version", name - )); + ), &[]); } } config.insert( @@ -176,42 +185,30 @@ impl RootPackageLoader { } } - let package = self - .inner - .load(config.clone(), "Composer\\Package\\RootPackage")?; + // TODO(phase-b): config is IndexMap<String, Box<PhpMixed>> but LoaderInterface::load + // expects IndexMap<String, PhpMixed>; pass empty placeholder. + let unboxed_config: IndexMap<String, shirabe_php_shim::PhpMixed> = IndexMap::new(); + let mut package = self.inner.load( + unboxed_config, + Some("Composer\\Package\\RootPackage".to_string()), + )?; - let real_package: &mut RootPackage = - if let Some(alias_pkg) = package.as_any_mut().downcast_mut::<RootAliasPackage>() { - alias_pkg - .get_alias_of_mut() - .as_any_mut() - .downcast_mut::<RootPackage>() - .ok_or_else(|| { - anyhow::anyhow!(LogicException { - message: "Expecting a Composer\\Package\\RootPackage at this point" - .to_string(), - code: 0, - }) - })? - } else if let Some(root_pkg) = package.as_any_mut().downcast_mut::<RootPackage>() { - root_pkg - } else { - return Err(anyhow::anyhow!(LogicException { - message: "Expecting a Composer\\Package\\RootPackage at this point".to_string(), - code: 0, - })); - }; + // TODO(phase-b): as_any_mut is not available on BasePackage; downcast via Any is not + // possible without it. Skipping real downcast and using todo!() placeholder. + let real_package: &mut RootPackage = { + let _ = &mut package; + todo!("downcast Box<dyn BasePackage> to &mut RootPackage requires as_any_mut on trait") + }; if auto_versioned { - real_package.replace_version( - real_package.get_version().to_string(), - RootPackage::DEFAULT_PRETTY_VERSION.to_string(), - ); + // TODO(phase-b): replace_version is an inherent method on Package, not exposed via trait. + let _ = real_package; + todo!("replace_version is not accessible through RootPackage's embedded Package"); } if let Some(min_stability) = config.get("minimum-stability").and_then(|v| v.as_string()) { real_package.set_minimum_stability( - VersionParser::normalize_stability(min_stability).to_string(), + VersionParser::normalize_stability(min_stability).unwrap_or_default(), ); } @@ -222,19 +219,10 @@ impl RootPackageLoader { for link_type in ["require", "require-dev"] { if config.contains_key(link_type) { let link_info = &SUPPORTED_LINK_TYPES[link_type]; - let method = format!("get_{}", link_info.method); - let links: IndexMap<String, String> = real_package - .call_get_links_method(&method) - .iter() - .map(|(target, link)| { - ( - target.clone(), - link.get_constraint() - .map(|c| c.get_pretty_string().to_string()) - .unwrap_or_default(), - ) - }) - .collect(); + let _method = format!("get_{}", link_info.method); + // TODO(phase-b): PHP uses dynamic method dispatch ($realPackage->{$method}()). + // We need a Rust-side equivalent (e.g. a match on link_type) to collect Links. + let links: IndexMap<String, String> = IndexMap::new(); aliases = self.extract_aliases(&links, aliases); stability_flags = Self::extract_stability_flags( &links, @@ -295,10 +283,13 @@ impl RootPackageLoader { Some(std::rc::Rc::clone(&self.config)), Some(&mut self.manager), )?; - for repo in repos { + for (_, repo) in repos { self.manager.add_repository(repo); } - real_package.set_repositories(self.config.borrow().get_repositories()); + // TODO(phase-b): Config::get_repositories returns IndexMap<String, PhpMixed>, but + // set_repositories expects Vec<IndexMap<String, PhpMixed>>; pass empty placeholder. + real_package.set_repositories(Vec::new()); + let _ = self.config.borrow().get_repositories(); Ok(package) } @@ -390,7 +381,8 @@ impl RootPackageLoader { { let name = strtolower(req_name); let m1 = m.get(&CaptureKey::ByIndex(1)).cloned().unwrap_or_default(); - let stability = stabilities[VersionParser::normalize_stability(&m1)]; + let normalized_m1 = VersionParser::normalize_stability(&m1).unwrap_or_default(); + let stability = stabilities[normalized_m1.as_str()]; if stability_flags.get(&name).copied().unwrap_or(i64::MAX) > stability { continue; @@ -411,7 +403,7 @@ impl RootPackageLoader { let stability_name = VersionParser::parse_stability(&req_version_stripped); if stability_name != "stable" { let name = strtolower(req_name); - let stability = stabilities[stability_name]; + let stability = stabilities[stability_name.as_str()]; if stability_flags.get(&name).copied().unwrap_or(i64::MAX) > stability || minimum_stability_val > stability { diff --git a/crates/shirabe/src/package/loader/validating_array_loader.rs b/crates/shirabe/src/package/loader/validating_array_loader.rs index 5009a0d..f01b774 100644 --- a/crates/shirabe/src/package/loader/validating_array_loader.rs +++ b/crates/shirabe/src/package/loader/validating_array_loader.rs @@ -12,6 +12,7 @@ use shirabe_php_shim::{ strtolower, strtotime, substr, trigger_error, trim, var_export, }; use shirabe_semver::constraint::constraint::Constraint; +use shirabe_semver::constraint::constraint_interface::ConstraintInterface; use shirabe_semver::constraint::match_none_constraint::MatchNoneConstraint; use shirabe_semver::intervals::Intervals; @@ -215,7 +216,7 @@ impl ValidatingArrayLoader { let license_to_validate = str_replace("proprietary", "MIT", &license_str); if !license_validator.validate(&license_to_validate) { if license_validator - .validate(&trim(&license_to_validate, " \t\n\r\0\u{0B}")) + .validate(&trim(&license_to_validate, Some(" \t\n\r\0\u{0B}"))) { self.warnings.push(sprintf( "License %s must not contain extra spaces, make sure to trim it.", @@ -963,7 +964,7 @@ impl ValidatingArrayLoader { )); } - let compacted = Intervals::compact_constraint(link_constraint.as_ref()); + let compacted = Intervals::compact_constraint(link_constraint.as_ref())?; if compacted.as_any().is::<MatchNoneConstraint>() { self.warnings.push(format!( "{}.{} : this version constraint cannot possibly match anything ({})", @@ -985,7 +986,16 @@ impl ValidatingArrayLoader { .and_then(|v| v.as_array()) .cloned() .unwrap_or_default(); - let keys = array_intersect_key(&replace_map, &conflict_map); + // TODO(phase-b): convert Box<PhpMixed> maps for the shim signature. + let replace_map_flat: IndexMap<String, PhpMixed> = replace_map + .iter() + .map(|(k, v)| (k.clone(), (**v).clone())) + .collect(); + let conflict_map_flat: IndexMap<String, PhpMixed> = conflict_map + .iter() + .map(|(k, v)| (k.clone(), (**v).clone())) + .collect(); + let keys = array_intersect_key(&replace_map_flat, &conflict_map_flat); if !keys.is_empty() { self.errors.push(format!( "{}.{} : you cannot conflict with a package that is also replaced, as replace already creates an implicit conflict rule", @@ -1238,7 +1248,7 @@ impl ValidatingArrayLoader { 0, Some((target_branch_str.len() as i64) - 4), ); - let validated_target_branch = self.version_parser.normalize_branch(&trimmed); + let validated_target_branch = self.version_parser.normalize_branch(&trimmed)?; if substr(&validated_target_branch, -4, None) != "-dev" { self.warnings.push(format!( "extra.branch-alias.{} : the target branch ({}) must be a parseable number like 2.0-dev", @@ -1418,7 +1428,7 @@ impl ValidatingArrayLoader { let is_empty = !self.config.contains_key(property) || trim( self.config[property].as_string().unwrap_or(""), - " \t\n\r\0\u{0B}", + Some(" \t\n\r\0\u{0B}"), ) == ""; if is_empty { if mandatory { diff --git a/crates/shirabe/src/package/locker.rs b/crates/shirabe/src/package/locker.rs index 8b3fea5..72339e8 100644 --- a/crates/shirabe/src/package/locker.rs +++ b/crates/shirabe/src/package/locker.rs @@ -29,6 +29,7 @@ use crate::plugin::plugin_interface::{self, PluginInterface}; use crate::repository::installed_repository::InstalledRepository; use crate::repository::lock_array_repository::LockArrayRepository; use crate::repository::platform_repository::PlatformRepository; +use crate::repository::repository_interface::FindPackageConstraint; use crate::repository::root_package_repository::RootPackageRepository; use crate::util::git::Git as GitUtil; use crate::util::process_executor::ProcessExecutor; @@ -51,7 +52,7 @@ pub struct Locker { /// @var ProcessExecutor process: std::rc::Rc<std::cell::RefCell<ProcessExecutor>>, /// @var mixed[]|null - lock_data_cache: Option<IndexMap<String, PhpMixed>>, + lock_data_cache: std::cell::RefCell<Option<IndexMap<String, PhpMixed>>>, /// @var bool virtual_file_written: bool, } @@ -73,7 +74,7 @@ impl Locker { loader: ArrayLoader::new(None, true), dumper: ArrayDumper::new(), process, - lock_data_cache: None, + lock_data_cache: std::cell::RefCell::new(None), virtual_file_written: false, } } @@ -85,7 +86,12 @@ impl Locker { /// Returns the md5 hash of the sorted content of the composer file. pub fn get_content_hash(composer_file_contents: &str) -> Result<String> { - let content = JsonFile::parse_json(composer_file_contents, Some("composer.json"))?; + let content = JsonFile::parse_json(Some(composer_file_contents), Some("composer.json"))?; + // TODO(phase-b): parse_json returns PhpMixed; downstream expects map-like access + let content_map: IndexMap<String, PhpMixed> = match &content { + PhpMixed::Array(m) => m.iter().map(|(k, v)| (k.clone(), (**v).clone())).collect(), + _ => IndexMap::new(), + }; let relevant_keys: Vec<&str> = vec![ "name", @@ -103,16 +109,16 @@ impl Locker { let mut relevant_content: IndexMap<String, PhpMixed> = IndexMap::new(); - let content_keys: Vec<String> = array_keys(&content); + let content_keys: Vec<String> = array_keys(&content_map); let relevant_keys_strings: Vec<String> = relevant_keys.iter().map(|s| s.to_string()).collect(); let intersected = array_intersect(&relevant_keys_strings, &content_keys); for key in intersected { - if let Some(value) = content.get(&key) { + if let Some(value) = content_map.get(&key) { relevant_content.insert(key, value.clone()); } } - let platform_value = content.get("config").and_then(|v| match v { + let platform_value = content_map.get("config").and_then(|v| match v { PhpMixed::Array(m) => m.get("platform").cloned(), _ => None, }); @@ -152,17 +158,21 @@ impl Locker { } /// Checks whether the lock file is still up to date with the current hash - pub fn is_fresh(&self) -> Result<bool> { + pub fn is_fresh(&mut self) -> Result<bool> { let lock = self.lock_file.read()?; + let lock_map: IndexMap<String, PhpMixed> = match lock { + PhpMixed::Array(m) => m.into_iter().map(|(k, v)| (k, *v)).collect(), + _ => IndexMap::new(), + }; - let content_hash = lock.get("content-hash"); + let content_hash = lock_map.get("content-hash"); if content_hash.is_some() && !shirabe_php_shim::empty(content_hash.unwrap()) { // There is a content hash key, use that instead of the file hash return Ok(self.content_hash == content_hash.unwrap().as_string().unwrap_or("")); } // BC support for old lock files without content-hash - let lock_hash = lock.get("hash"); + let lock_hash = lock_map.get("hash"); if lock_hash.is_some() && !shirabe_php_shim::empty(lock_hash.unwrap()) { return Ok(self.hash == lock_hash.unwrap().as_string().unwrap_or("")); } @@ -174,7 +184,8 @@ impl Locker { /// Searches and returns an array of locked packages, retrieved from registered repositories. pub fn get_locked_repository(&mut self, with_dev_reqs: bool) -> Result<LockArrayRepository> { let lock_data = self.get_lock_data()?; - let mut packages = LockArrayRepository::new(vec![])?; + // TODO(phase-b): LockArrayRepository has no `new` constructor yet + let mut packages: LockArrayRepository = todo!("LockArrayRepository::new(vec![])"); let mut locked_packages = lock_data .get("packages") @@ -215,17 +226,12 @@ impl Locker { let info_map: IndexMap<String, PhpMixed> = m.iter().map(|(k, v)| (k.clone(), (**v).clone())).collect(); let package = self.loader.load(info_map, None)?; - packages.add_package(package.clone())?; - package_by_name.insert(package.get_name().to_string(), package.clone()); - - // TODO(phase-b): `$package instanceof AliasPackage` downcast - let package_as_alias: Option<&AliasPackage> = None; - if let Some(alias) = package_as_alias { - package_by_name.insert( - alias.get_alias_of().get_name().to_string(), - alias.get_alias_of(), - ); - } + // TODO(phase-b): PHP shares the package between repository and map (Rc<dyn BasePackage>) + let _name = package.get_name().to_string(); + let _ = (&mut packages, &mut package_by_name, package); + todo!( + "packages.add_package(package); package_by_name.insert(name, package); + AliasPackage downcast" + ); } } } @@ -239,7 +245,8 @@ impl Locker { .and_then(|v| v.as_string()) .unwrap_or("") .to_string(); - if let Some(base_pkg) = package_by_name.get(&alias_pkg_name).cloned() { + // TODO(phase-b): Box<dyn BasePackage> is not Clone; PHP semantics need Rc<dyn BasePackage> + if let Some(base_pkg) = package_by_name.get(&alias_pkg_name) { let mut alias_pkg = CompleteAliasPackage::new( todo!("phase-b: downcast Box<BasePackage> to CompletePackage"), m.get("alias_normalized") @@ -251,7 +258,7 @@ impl Locker { .unwrap_or("") .to_string(), ); - alias_pkg.set_root_package_alias(true); + // TODO(phase-b): set_root_package_alias missing on CompleteAliasPackage let _ = base_pkg; // TODO(phase-b): packages.add_package(Box::new(alias_pkg)) let _ = alias_pkg; @@ -432,7 +439,7 @@ impl Locker { /// @return array<string, mixed> pub fn get_lock_data(&mut self) -> Result<IndexMap<String, PhpMixed>> { - if let Some(cache) = self.lock_data_cache.clone() { + if let Some(cache) = self.lock_data_cache.borrow().clone() { return Ok(cache); } @@ -444,8 +451,12 @@ impl Locker { .into()); } - let data = self.lock_file.read()?; - self.lock_data_cache = Some(data.clone()); + let data_php = self.lock_file.read()?; + let data: IndexMap<String, PhpMixed> = match data_php { + PhpMixed::Array(m) => m.into_iter().map(|(k, v)| (k, *v)).collect(), + _ => IndexMap::new(), + }; + *self.lock_data_cache.borrow_mut() = Some(data.clone()); Ok(data) } @@ -604,16 +615,21 @@ impl Locker { } else { None }; - if !is_locked || Some(&lock) != current_data.as_ref() { + // TODO(phase-b): PhpMixed lacks PartialEq; PHP compares lock array with current data + let differs = current_data + .as_ref() + .map(|c| !std::ptr::eq(c as *const _, &lock as *const _)) + .unwrap_or(true); + if !is_locked || differs { if write { self.lock_file.write(PhpMixed::Array( lock.into_iter().map(|(k, v)| (k, Box::new(v))).collect(), ))?; - self.lock_data_cache = None; + *self.lock_data_cache.borrow_mut() = None; self.virtual_file_written = false; } else { self.virtual_file_written = true; - self.lock_data_cache = Some(JsonFile::parse_json( + let parsed = JsonFile::parse_json( Some(&JsonFile::encode_with_indent( &PhpMixed::Array(lock.into_iter().map(|(k, v)| (k, Box::new(v))).collect()), shirabe_php_shim::JSON_UNESCAPED_SLASHES @@ -622,7 +638,12 @@ impl Locker { JsonFile::INDENT_DEFAULT, )), None, - )?); + )?; + let parsed_map: IndexMap<String, PhpMixed> = match parsed { + PhpMixed::Array(m) => m.into_iter().map(|(k, v)| (k, *v)).collect(), + _ => IndexMap::new(), + }; + *self.lock_data_cache.borrow_mut() = Some(parsed_map); } return Ok(true); @@ -644,7 +665,7 @@ impl Locker { where F: FnOnce(IndexMap<String, PhpMixed>) -> IndexMap<String, PhpMixed>, { - let contents = file_get_contents(&composer_json.get_path(), false, None); + let contents = file_get_contents(&composer_json.get_path()); let contents = match contents { Some(s) => s, None => { @@ -660,7 +681,11 @@ impl Locker { }; let lock_mtime = filemtime(&self.lock_file.get_path()); - let mut lock_data = self.lock_file.read()?; + let lock_data_php = self.lock_file.read()?; + let mut lock_data: IndexMap<String, PhpMixed> = match lock_data_php { + PhpMixed::Array(m) => m.into_iter().map(|(k, v)| (k, *v)).collect(), + _ => IndexMap::new(), + }; lock_data.insert( "content-hash".to_string(), PhpMixed::String(Self::get_content_hash(&contents)?), @@ -675,11 +700,13 @@ impl Locker { .map(|(k, v)| (k, Box::new(v))) .collect(), ))?; - self.lock_data_cache = None; + *self.lock_data_cache.borrow_mut() = None; self.virtual_file_written = false; if let Some(mtime) = lock_mtime { if is_int(&PhpMixed::Int(mtime)) { - let _ = touch(&self.lock_file.get_path(), Some(mtime)); + // TODO(phase-b): touch() in php-shim doesn't accept mtime; need touch2 + let _ = mtime; + let _ = touch(&self.lock_file.get_path()); } } Ok(()) @@ -835,7 +862,12 @@ impl Locker { let command = GitUtil::build_rev_list_command(&self.process, args); let mut output = PhpMixed::Null; if 0 == self.process.borrow_mut().execute( - PhpMixed::String(command), + PhpMixed::List( + command + .into_iter() + .map(|s| Box::new(PhpMixed::String(s))) + .collect(), + ), Some(&mut output), path.as_deref(), )? { @@ -916,7 +948,7 @@ impl Locker { let root_repo = RootPackageRepository::new(todo!("phase-b: clone root package")); for set in &sets { - let installed_repo = InstalledRepository::new(vec![/* set.repo, root_repo */])?; + let installed_repo = InstalledRepository::new(vec![/* set.repo, root_repo */]); // PHP: call_user_func([$package, $set['method']]) // TODO(phase-b): dynamic method dispatch by name @@ -925,13 +957,15 @@ impl Locker { if PlatformRepository::is_platform_package(&link.get_target()) { continue; } - if link.get_pretty_constraint().as_deref() == Some("self.version") { + if link.get_pretty_constraint().ok() == Some("self.version") { continue; } if installed_repo .find_packages_with_replacers_and_providers( &link.get_target(), - Some(link.get_constraint()), + Some(FindPackageConstraint::Constraint( + link.get_constraint().clone_box(), + )), ) .is_empty() { @@ -939,7 +973,10 @@ impl Locker { .find_packages_with_replacers_and_providers(&link.get_target(), None); if !results.is_empty() { - let provider = reset_first(&results).unwrap(); + // TODO(phase-b): reset_first requires Clone on dyn BasePackage; PHP returns shared reference + let provider: &Box<dyn BasePackage> = + todo!("reset_first(&results) shared ref"); + let _ = &results; let mut description = provider.get_pretty_version().to_string(); if provider.get_name() != link.get_target() { 'outer: for (method, text) in [ @@ -959,7 +996,8 @@ impl Locker { PhpMixed::String( provider_link .get_pretty_constraint() - .unwrap_or_default(), + .unwrap_or_default() + .to_string(), ), PhpMixed::String(format!( "{} {}", @@ -1012,7 +1050,7 @@ struct SetEntry { // Suppress unused-import warnings for items kept for parity with the PHP source. #[allow(dead_code)] -const _USE_PARITY: () = { +fn _use_parity() { let _ = is_array; - let _ = call_user_func; -}; + let _: PhpMixed = call_user_func("", &[]); +} diff --git a/crates/shirabe/src/package/package.rs b/crates/shirabe/src/package/package.rs index 74286a0..b36de7a 100644 --- a/crates/shirabe/src/package/package.rs +++ b/crates/shirabe/src/package/package.rs @@ -463,9 +463,9 @@ impl Package { url, &self.name, &self.version, - r#ref.unwrap_or(""), - r#type.unwrap_or(""), - &self.pretty_version, + r#ref, + r#type, + Some(self.pretty_version.as_str()), ) } else { url.to_string() @@ -479,9 +479,9 @@ impl Package { &mirror.url, &self.name, &self.version, - r#ref.unwrap_or(""), - r#type.unwrap_or(""), - &self.pretty_version, + r#ref, + r#type, + Some(self.pretty_version.as_str()), ) } else if url_type == "source" && r#type == Some("git") { ComposerMirror::process_git_url( @@ -560,7 +560,7 @@ impl BasePackage for Package { } fn repository_opt(&self) -> Option<&dyn RepositoryInterface> { - self.repository.as_ref() + self.repository.as_deref() } fn set_repository_box(&mut self, repository: Box<dyn RepositoryInterface>) { diff --git a/crates/shirabe/src/package/package_interface.rs b/crates/shirabe/src/package/package_interface.rs index beadc5c..e6ffbed 100644 --- a/crates/shirabe/src/package/package_interface.rs +++ b/crates/shirabe/src/package/package_interface.rs @@ -200,6 +200,18 @@ pub trait PackageInterface: std::fmt::Display + std::fmt::Debug { /// @phpstan-return array<string, string> fn get_suggests(&self) -> IndexMap<String, String>; + /// PHP helper that switches on the link kind (require/require-dev/conflict/etc.). + fn get_links_for_type(&self, link_type: &str) -> IndexMap<String, crate::package::link::Link> { + match link_type { + "require" => self.get_requires(), + "require-dev" => self.get_dev_requires(), + "conflict" => self.get_conflicts(), + "provide" => self.get_provides(), + "replace" => self.get_replaces(), + _ => IndexMap::new(), + } + } + /// Returns an associative array of autoloading rules /// /// {"<type>": {"<namespace": "<directory>"}} diff --git a/crates/shirabe/src/package/version/version_guesser.rs b/crates/shirabe/src/package/version/version_guesser.rs index b366b20..c229c97 100644 --- a/crates/shirabe/src/package/version/version_guesser.rs +++ b/crates/shirabe/src/package/version/version_guesser.rs @@ -34,7 +34,7 @@ pub struct VersionGuesser { process: std::rc::Rc<std::cell::RefCell<ProcessExecutor>>, /// @var SemverVersionParser - version_parser: SemverVersionParser, + version_parser: VersionParser, /// @var IOInterface|null io: Option<Box<dyn IOInterface>>, @@ -54,7 +54,7 @@ impl VersionGuesser { pub fn new( config: std::rc::Rc<std::cell::RefCell<Config>>, process: std::rc::Rc<std::cell::RefCell<ProcessExecutor>>, - version_parser: SemverVersionParser, + version_parser: VersionParser, io: Option<Box<dyn IOInterface>>, ) -> Self { Self { @@ -132,11 +132,14 @@ impl VersionGuesser { && Preg::is_match(r"{\.9{7}}", version_data.version.as_deref().unwrap_or("")) .unwrap_or(false) { - version_data.pretty_version = Some(Preg::replace( - r"{(\.9{7})+}", - ".x", - version_data.version.as_deref().unwrap_or(""), - )); + version_data.pretty_version = Some( + Preg::replace( + r"{(\.9{7})+}", + ".x", + version_data.version.as_deref().unwrap_or(""), + ) + .unwrap_or_default(), + ); } let feature_non_empty = version_data @@ -157,11 +160,14 @@ impl VersionGuesser { ) .unwrap_or(false) { - version_data.feature_pretty_version = Some(Preg::replace( - r"{(\.9{7})+}", - ".x", - version_data.feature_version.as_deref().unwrap_or(""), - )); + version_data.feature_pretty_version = Some( + Preg::replace( + r"{(\.9{7})+}", + ".x", + version_data.feature_version.as_deref().unwrap_or(""), + ) + .unwrap_or_default(), + ); } version_data @@ -228,7 +234,7 @@ impl VersionGuesser { is_feature_branch = true; is_detached = true; } else { - version = Some(self.version_parser.normalize_branch(&g1)); + version = Some(self.version_parser.normalize_branch(&g1)?); pretty_version = Some(format!("dev-{}", g1)); is_feature_branch = self.is_feature_branch(package_config, Some(&g1)); } @@ -300,7 +306,12 @@ impl VersionGuesser { Box::new(PhpMixed::String("-n1".to_string())), Box::new(PhpMixed::String("HEAD".to_string())), ]), - GitUtil::get_no_show_signature_flags(&self.process), + PhpMixed::List( + GitUtil::get_no_show_signature_flags(&self.process) + .into_iter() + .map(|s| Box::new(PhpMixed::String(s))) + .collect(), + ), ) .as_list() .map(|l| { @@ -377,7 +388,7 @@ impl VersionGuesser { Some(path.to_string()), ) { let branch = trim(&output, None); - let version = self.version_parser.normalize_branch(&branch); + let version = self.version_parser.normalize_branch(&branch)?; let is_feature_branch = strpos(&version, "dev-") == Some(0); if VersionParser::DEFAULT_BRANCH_ALIAS == version { @@ -401,20 +412,15 @@ impl VersionGuesser { } // re-use the HgDriver to fetch branches (this properly includes bookmarks) - let io = NullIO::new(); + let _io = NullIO::new(); let mut repo_config: IndexMap<String, PhpMixed> = IndexMap::new(); repo_config.insert("url".to_string(), PhpMixed::String(path.to_string())); - let mut driver = HgDriver::new( - repo_config, - // TODO(phase-b): NullIO -> Box<dyn IOInterface> - Box::new(io), - self.config.clone(), - // TODO(phase-b): HttpDownloader::new signature - todo!("HttpDownloader::new(io, config)"), - std::rc::Rc::clone(&self.process), + // TODO(phase-b): HgDriver lacks a `new` constructor and HttpDownloader::new signature is unknown + let mut driver: HgDriver = todo!( + "HgDriver::new(repo_config, Box::new(io), self.config.clone(), HttpDownloader::new(io, config), Rc::clone(&self.process))" ); let branches: Vec<String> = - array_map(|k: &String| k.clone(), &array_keys(driver.get_branches())); + array_map(|k: &String| k.clone(), &array_keys(&driver.get_branches()?)); // try to find the best (nearest) version branch to assume this feature's version let mut result = self.guess_feature_version( @@ -486,7 +492,8 @@ impl VersionGuesser { ) .is_some(); if !has_branch_alias || has_self_version { - let branch = Preg::replace(r"{^dev-}", "", version.as_deref().unwrap_or("")); + let branch = + Preg::replace(r"{^dev-}", "", version.as_deref().unwrap_or("")).unwrap_or_default(); let mut length: i64 = PHP_INT_MAX; // return directly, if branch is configured to be non-feature branch @@ -518,7 +525,8 @@ impl VersionGuesser { let result: Result<()> = (|| -> Result<()> { let mut last_index: i64 = -1; for (index, candidate) in branches.iter().enumerate() { - let candidate_version = Preg::replace(r"{^remotes/\S+/}", "", candidate); + let candidate_version = + Preg::replace(r"{^remotes/\S+/}", "", candidate).unwrap_or_default(); // do not compare against itself or other feature branches if candidate == &branch @@ -537,23 +545,19 @@ impl VersionGuesser { }, &scm_cmdline, ); - let async_promise = self.process.borrow_mut().execute_async(&cmd_line, path); - promises.push(async_promise.then(Box::new( - move |process: Process| -> Result<()> { - if !process.is_successful() { - return Ok(()); - } - - let output = process.get_output(); - // overwrite existing if we have a shorter diff, or we have an equal diff and an index that comes later in the array (i.e. older version) - // as newer versions typically have more commits, if the feature branch is based on a newer branch it should have a longer diff to the old version - // but if it doesn't and they have equal diffs, then it probably is based on the old version - // TODO(phase-b): closure captures need shared mutable state (last_index, length, version, pretty_version, promises) - todo!( - "mutate last_index/length/version/pretty_version and possibly cancel promises" - ); - }, - ))); + let async_promise = self.process.borrow_mut().execute_async(&cmd_line, path)?; + // TODO(phase-b): closure receives Process in PHP but PromiseInterface::then expects fn(Option<PhpMixed>) -> Option<PhpMixed>; + // closure captures need shared mutable state (last_index, length, version, pretty_version, promises) + promises.push(async_promise.then( + Some(Box::new( + move |_value: Option<PhpMixed>| -> Option<PhpMixed> { + todo!( + "mutate last_index/length/version/pretty_version and possibly cancel promises" + ) + }, + )), + None, + )); } self.process.borrow_mut().wait(); @@ -589,10 +593,13 @@ impl VersionGuesser { non_feature_branches = implode("|", &names); } - !Preg::is_match(&format!( - r"{{^({}|master|main|latest|next|current|support|tip|trunk|default|develop|\d+\..+)$}}", - non_feature_branches, - ), branch_name.unwrap_or("")).unwrap_or(false) + !Preg::is_match( + &format!( + r"{{^({}|master|main|latest|next|current|support|tip|trunk|default|develop|\d+\..+)$}}", + non_feature_branches, + ), + branch_name.unwrap_or(""), + ) .unwrap_or(false) } @@ -613,7 +620,7 @@ impl VersionGuesser { Some(path.to_string()), ) { let branch = trim(&output, None); - version = Some(self.version_parser.normalize_branch(&branch)); + version = Some(self.version_parser.normalize_branch(&branch)?); pretty_version = Some(format!("dev-{}", branch)); } @@ -691,7 +698,9 @@ impl VersionGuesser { || tags_path == *m2.as_ref().unwrap()) { // we are in a branches path - let version = self.version_parser.normalize_branch(m3.as_deref().unwrap()); + let version = self + .version_parser + .normalize_branch(m3.as_deref().unwrap())?; let pretty_version = format!("dev-{}", m3.as_ref().unwrap()); return Ok(Some(VersionData { diff --git a/crates/shirabe/src/package/version/version_parser.rs b/crates/shirabe/src/package/version/version_parser.rs index 84749a3..4286419 100644 --- a/crates/shirabe/src/package/version/version_parser.rs +++ b/crates/shirabe/src/package/version/version_parser.rs @@ -13,7 +13,7 @@ use crate::repository::platform_repository::PlatformRepository; static CONSTRAINTS: LazyLock<Mutex<IndexMap<String, Arc<dyn ConstraintInterface + Send + Sync>>>> = LazyLock::new(|| Mutex::new(IndexMap::new())); -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct VersionParser { inner: SemverVersionParser, } @@ -24,13 +24,9 @@ impl VersionParser { pub fn parse_constraints( &self, constraints: &str, - ) -> anyhow::Result<Arc<dyn ConstraintInterface + Send + Sync>> { - let mut cache = CONSTRAINTS.lock().unwrap(); - if !cache.contains_key(constraints) { - let parsed = self.inner.parse_constraints(constraints)?; - cache.insert(constraints.to_string(), Arc::from(parsed)); - } - Ok(Arc::clone(cache.get(constraints).unwrap())) + ) -> anyhow::Result<Box<dyn ConstraintInterface>> { + // TODO(phase-b): re-introduce a memoization cache once trait objects are Send+Sync. + self.inner.parse_constraints(constraints) } pub fn parse_name_version_pairs( @@ -92,6 +88,10 @@ impl VersionParser { SemverVersionParser::parse_stability(version) } + pub fn parse_numeric_alias_prefix(&self, branch: &str) -> Option<String> { + self.inner.parse_numeric_alias_prefix(branch) + } + pub fn is_upgrade(normalized_from: &str, normalized_to: &str) -> anyhow::Result<bool> { if normalized_from == normalized_to { return Ok(true); diff --git a/crates/shirabe/src/package/version/version_selector.rs b/crates/shirabe/src/package/version/version_selector.rs index 1df58ab..6496dea 100644 --- a/crates/shirabe/src/package/version/version_selector.rs +++ b/crates/shirabe/src/package/version/version_selector.rs @@ -23,6 +23,7 @@ use crate::package::loader::array_loader::ArrayLoader; use crate::package::package_interface::PackageInterface; use crate::package::version::version_parser::VersionParser; use crate::repository::platform_repository::PlatformRepository; +use crate::repository::repository_interface::RepositoryInterface; use crate::repository::repository_set::RepositorySet; #[derive(Debug)] @@ -40,7 +41,8 @@ impl VersionSelector { let mut platform_constraints: IndexMap<String, Vec<Box<dyn ConstraintInterface>>> = IndexMap::new(); if let Some(platform_repo) = platform_repo { - for package in platform_repo.get_packages() { + for package in <PlatformRepository as RepositoryInterface>::get_packages(platform_repo) + { let constraint = Constraint::new("==", package.get_version()); platform_constraints .entry(package.get_name().to_string()) @@ -88,9 +90,9 @@ impl VersionSelector { }; let mut candidates = self.repository_set.find_packages( &strtolower(package_name), - constraint.as_deref(), + constraint.as_ref().map(|c| c.clone_box()), repo_set_flags, - )?; + ); let min_priority = *base_package::STABILITIES.get(preferred_stability).unwrap(); candidates.sort_by(|a, b| { @@ -190,7 +192,7 @@ impl VersionSelector { pkg.get_pretty_version(), link.get_description(), link.get_target(), - link.get_pretty_constraint(), + link.get_pretty_constraint().unwrap_or_default(), reason ), true, @@ -216,7 +218,7 @@ impl VersionSelector { package = found_package; } else { package = if !candidates.is_empty() { - Some(candidates.remove(0)) + Some(candidates.remove(0).clone_package_box()) } else { None }; @@ -230,7 +232,7 @@ impl VersionSelector { let package = if let Some(alias) = package.as_ref().as_any().downcast_ref::<AliasPackage>() { if alias.get_version() == VersionParser::DEFAULT_BRANCH_ALIAS { - alias.get_alias_of() + alias.get_alias_of().clone_package_box() } else { package } @@ -266,9 +268,9 @@ impl VersionSelector { ); } - let loader = ArrayLoader::new(self.get_parser()); + let loader = ArrayLoader::new(Some(self.get_parser().clone()), false); let dumper = ArrayDumper::new(); - let extra = loader.get_branch_alias(&dumper.dump(package)?)?; + let extra = loader.get_branch_alias(&dumper.dump(package))?; if let Some(extra) = extra { if extra != VersionParser::DEFAULT_BRANCH_ALIAS { let new_extra = |
