aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/src/dependency_resolver
diff options
context:
space:
mode:
Diffstat (limited to 'crates/shirabe/src/dependency_resolver')
-rw-r--r--crates/shirabe/src/dependency_resolver/default_policy.rs18
-rw-r--r--crates/shirabe/src/dependency_resolver/generic_rule.rs17
-rw-r--r--crates/shirabe/src/dependency_resolver/lock_transaction.rs20
-rw-r--r--crates/shirabe/src/dependency_resolver/multi_conflict_rule.rs2
-rw-r--r--crates/shirabe/src/dependency_resolver/operation/install_operation.rs8
-rw-r--r--crates/shirabe/src/dependency_resolver/operation/mark_alias_installed_operation.rs4
-rw-r--r--crates/shirabe/src/dependency_resolver/operation/mark_alias_uninstalled_operation.rs4
-rw-r--r--crates/shirabe/src/dependency_resolver/operation/operation_interface.rs18
-rw-r--r--crates/shirabe/src/dependency_resolver/operation/uninstall_operation.rs8
-rw-r--r--crates/shirabe/src/dependency_resolver/operation/update_operation.rs8
-rw-r--r--crates/shirabe/src/dependency_resolver/policy_interface.rs2
-rw-r--r--crates/shirabe/src/dependency_resolver/pool.rs6
-rw-r--r--crates/shirabe/src/dependency_resolver/pool_builder.rs54
-rw-r--r--crates/shirabe/src/dependency_resolver/pool_optimizer.rs56
-rw-r--r--crates/shirabe/src/dependency_resolver/problem.rs49
-rw-r--r--crates/shirabe/src/dependency_resolver/rule.rs114
-rw-r--r--crates/shirabe/src/dependency_resolver/rule2_literals.rs2
-rw-r--r--crates/shirabe/src/dependency_resolver/rule_set.rs4
-rw-r--r--crates/shirabe/src/dependency_resolver/rule_set_generator.rs68
-rw-r--r--crates/shirabe/src/dependency_resolver/rule_watch_graph.rs10
-rw-r--r--crates/shirabe/src/dependency_resolver/rule_watch_node.rs6
-rw-r--r--crates/shirabe/src/dependency_resolver/solver.rs56
-rw-r--r--crates/shirabe/src/dependency_resolver/transaction.rs45
23 files changed, 345 insertions, 234 deletions
diff --git a/crates/shirabe/src/dependency_resolver/default_policy.rs b/crates/shirabe/src/dependency_resolver/default_policy.rs
index 9d8f96c..5d37855 100644
--- a/crates/shirabe/src/dependency_resolver/default_policy.rs
+++ b/crates/shirabe/src/dependency_resolver/default_policy.rs
@@ -51,12 +51,8 @@ impl DefaultPolicy {
ignore_replace: bool,
) -> i64 {
if PackageInterface::get_name(a) == PackageInterface::get_name(b) {
- let a_aliased = (a.as_any() as &dyn Any)
- .downcast_ref::<AliasPackage>()
- .is_some();
- let b_aliased = (b.as_any() as &dyn Any)
- .downcast_ref::<AliasPackage>()
- .is_some();
+ let a_aliased = a.as_any().downcast_ref::<AliasPackage>().is_some();
+ let b_aliased = b.as_any().downcast_ref::<AliasPackage>().is_some();
if a_aliased && !b_aliased {
return -1;
}
@@ -87,11 +83,11 @@ impl DefaultPolicy {
}
}
- if a.id == b.id {
+ if a.id() == b.id() {
return 0;
}
- if a.id < b.id { -1 } else { 1 }
+ if a.id() < b.id() { -1 } else { 1 }
}
pub(crate) fn group_literals_by_name(
@@ -147,7 +143,7 @@ impl DefaultPolicy {
for &literal in &literals {
let package = pool.literal_to_package(literal);
- if let Some(alias_pkg) = (package.as_any() as &dyn Any).downcast_ref::<AliasPackage>() {
+ if let Some(alias_pkg) = package.as_any().downcast_ref::<AliasPackage>() {
if alias_pkg.is_root_package_alias() {
has_local_alias = true;
break;
@@ -162,7 +158,7 @@ impl DefaultPolicy {
let mut selected = vec![];
for &literal in &literals {
let package = pool.literal_to_package(literal);
- if let Some(alias_pkg) = (package.as_any() as &dyn Any).downcast_ref::<AliasPackage>() {
+ if let Some(alias_pkg) = package.as_any().downcast_ref::<AliasPackage>() {
if alias_pkg.is_root_package_alias() {
selected.push(literal);
}
@@ -221,7 +217,7 @@ impl PolicyInterface for DefaultPolicy {
CompilingMatcher::r#match(
&Constraint::new(operator, b.get_version()),
Constraint::OP_EQ,
- a.get_version(),
+ a.get_version().to_string(),
)
}
diff --git a/crates/shirabe/src/dependency_resolver/generic_rule.rs b/crates/shirabe/src/dependency_resolver/generic_rule.rs
index 19974b6..c0381ef 100644
--- a/crates/shirabe/src/dependency_resolver/generic_rule.rs
+++ b/crates/shirabe/src/dependency_resolver/generic_rule.rs
@@ -6,6 +6,7 @@ use shirabe_php_shim::{PHP_VERSION_ID, PhpMixed, RuntimeException, hash_raw, imp
use super::{request::Request, rule::ReasonData};
+#[derive(Debug)]
pub struct GenericRule {
inner: RuleBase,
pub(crate) literals: Vec<i64>,
@@ -13,7 +14,7 @@ pub struct GenericRule {
impl GenericRule {
pub fn new(mut literals: Vec<i64>, reason: PhpMixed, reason_data: PhpMixed) -> Self {
- let inner = RuleBase::new(reason, reason_data);
+ let inner = RuleBase::new(reason.as_int().unwrap_or(0), ReasonData::from(reason_data));
literals.sort();
Self { inner, literals }
}
@@ -70,6 +71,20 @@ pub trait RuleLiterals {
fn is_multi_conflict_rule(&self) -> bool {
false
}
+ fn is_assertion(&self) -> bool {
+ false
+ }
+ fn is_disabled(&self) -> bool {
+ false
+ }
+ fn as_any(&self) -> &dyn std::any::Any {
+ todo!()
+ }
+ /// Clone this rule into an owned `Box<dyn Rule>` so callers like
+ /// `RuleWatchGraph::propagate_literal` can hand it to `Decisions::decide`.
+ fn clone_rule_box(&self) -> Box<dyn Rule> {
+ todo!()
+ }
}
impl RuleLiterals for GenericRule {
diff --git a/crates/shirabe/src/dependency_resolver/lock_transaction.rs b/crates/shirabe/src/dependency_resolver/lock_transaction.rs
index db9eb90..aa49d17 100644
--- a/crates/shirabe/src/dependency_resolver/lock_transaction.rs
+++ b/crates/shirabe/src/dependency_resolver/lock_transaction.rs
@@ -116,10 +116,7 @@ impl LockTransaction {
.map(|v| v.as_slice())
.unwrap_or_default();
for package in source {
- if (package.as_any() as &dyn Any)
- .downcast_ref::<AliasPackage>()
- .is_some()
- {
+ if package.as_any().downcast_ref::<AliasPackage>().is_some() {
continue;
}
@@ -152,9 +149,7 @@ impl LockTransaction {
continue;
}
- if let Some(concrete_pkg) =
- (present_package.as_any() as &dyn Any).downcast_ref::<Package>()
- {
+ if let Some(concrete_pkg) = present_package.as_any().downcast_ref::<Package>() {
concrete_pkg.set_source_url(package.get_source_url());
concrete_pkg.set_source_mirrors(package.get_source_mirrors());
}
@@ -171,9 +166,9 @@ impl LockTransaction {
r"{(?<=/|sha=)[a-f0-9]{40}(?=/|$)}i",
present_package.get_dist_reference().unwrap(),
package.get_dist_url().unwrap(),
- -1,
- ).unwrap_or_else(|_| package.get_dist_url().unwrap().to_string());
- present_package.set_dist_url(&new_dist_url);
+ )
+ .unwrap_or_else(|_| package.get_dist_url().unwrap().to_string());
+ present_package.set_dist_url(Some(new_dist_url));
}
present_package.set_dist_mirrors(package.get_dist_mirrors());
@@ -192,10 +187,7 @@ impl LockTransaction {
if let Some(all_packages) = self.result_packages.get("all") {
for package in all_packages {
- if (package.as_any() as &dyn Any)
- .downcast_ref::<AliasPackage>()
- .is_some()
- {
+ if package.as_any().downcast_ref::<AliasPackage>().is_some() {
let mut i = 0;
while i < remaining_aliases.len() {
if remaining_aliases[i].get("package").map(|s| s.as_str())
diff --git a/crates/shirabe/src/dependency_resolver/multi_conflict_rule.rs b/crates/shirabe/src/dependency_resolver/multi_conflict_rule.rs
index d198a27..14ece50 100644
--- a/crates/shirabe/src/dependency_resolver/multi_conflict_rule.rs
+++ b/crates/shirabe/src/dependency_resolver/multi_conflict_rule.rs
@@ -32,7 +32,7 @@ impl MultiConflictRule {
literals.sort();
Ok(Self {
- inner: RuleBase::new(reason, reason_data),
+ inner: RuleBase::new(reason.as_int().unwrap_or(0), ReasonData::from(reason_data)),
literals,
})
}
diff --git a/crates/shirabe/src/dependency_resolver/operation/install_operation.rs b/crates/shirabe/src/dependency_resolver/operation/install_operation.rs
index 1835636..53b5f99 100644
--- a/crates/shirabe/src/dependency_resolver/operation/install_operation.rs
+++ b/crates/shirabe/src/dependency_resolver/operation/install_operation.rs
@@ -34,6 +34,10 @@ impl SolverOperation for InstallOperation {
}
impl OperationInterface for InstallOperation {
+ fn as_any(&self) -> &dyn std::any::Any {
+ self
+ }
+
fn get_operation_type(&self) -> String {
Self::TYPE.to_string()
}
@@ -45,4 +49,8 @@ impl OperationInterface for InstallOperation {
fn to_string(&self) -> String {
self.show(true)
}
+
+ fn as_install_operation(&self) -> Option<&InstallOperation> {
+ Some(self)
+ }
}
diff --git a/crates/shirabe/src/dependency_resolver/operation/mark_alias_installed_operation.rs b/crates/shirabe/src/dependency_resolver/operation/mark_alias_installed_operation.rs
index e5a7df9..fa6f13d 100644
--- a/crates/shirabe/src/dependency_resolver/operation/mark_alias_installed_operation.rs
+++ b/crates/shirabe/src/dependency_resolver/operation/mark_alias_installed_operation.rs
@@ -25,6 +25,10 @@ impl SolverOperation for MarkAliasInstalledOperation {
}
impl OperationInterface for MarkAliasInstalledOperation {
+ fn as_any(&self) -> &dyn std::any::Any {
+ self
+ }
+
fn get_operation_type(&self) -> String {
Self::TYPE.to_string()
}
diff --git a/crates/shirabe/src/dependency_resolver/operation/mark_alias_uninstalled_operation.rs b/crates/shirabe/src/dependency_resolver/operation/mark_alias_uninstalled_operation.rs
index 21e257d..b9d5d26 100644
--- a/crates/shirabe/src/dependency_resolver/operation/mark_alias_uninstalled_operation.rs
+++ b/crates/shirabe/src/dependency_resolver/operation/mark_alias_uninstalled_operation.rs
@@ -25,6 +25,10 @@ impl SolverOperation for MarkAliasUninstalledOperation {
}
impl OperationInterface for MarkAliasUninstalledOperation {
+ fn as_any(&self) -> &dyn std::any::Any {
+ self
+ }
+
fn get_operation_type(&self) -> String {
Self::TYPE.to_string()
}
diff --git a/crates/shirabe/src/dependency_resolver/operation/operation_interface.rs b/crates/shirabe/src/dependency_resolver/operation/operation_interface.rs
index d93bd0f..f90649d 100644
--- a/crates/shirabe/src/dependency_resolver/operation/operation_interface.rs
+++ b/crates/shirabe/src/dependency_resolver/operation/operation_interface.rs
@@ -1,6 +1,12 @@
//! ref: composer/src/Composer/DependencyResolver/Operation/OperationInterface.php
+use crate::dependency_resolver::operation::install_operation::InstallOperation;
+use crate::dependency_resolver::operation::uninstall_operation::UninstallOperation;
+use crate::dependency_resolver::operation::update_operation::UpdateOperation;
+
pub trait OperationInterface: std::fmt::Debug {
+ fn as_any(&self) -> &dyn std::any::Any;
+
fn get_operation_type(&self) -> String;
fn show(&self, lock: bool) -> String;
@@ -10,4 +16,16 @@ pub trait OperationInterface: std::fmt::Debug {
fn clone_box(&self) -> Box<dyn OperationInterface> {
todo!()
}
+
+ fn as_install_operation(&self) -> Option<&InstallOperation> {
+ None
+ }
+
+ fn as_update_operation(&self) -> Option<&UpdateOperation> {
+ None
+ }
+
+ fn as_uninstall_operation(&self) -> Option<&UninstallOperation> {
+ None
+ }
}
diff --git a/crates/shirabe/src/dependency_resolver/operation/uninstall_operation.rs b/crates/shirabe/src/dependency_resolver/operation/uninstall_operation.rs
index 138a8c8..be7f6f1 100644
--- a/crates/shirabe/src/dependency_resolver/operation/uninstall_operation.rs
+++ b/crates/shirabe/src/dependency_resolver/operation/uninstall_operation.rs
@@ -33,6 +33,10 @@ impl SolverOperation for UninstallOperation {
}
impl OperationInterface for UninstallOperation {
+ fn as_any(&self) -> &dyn std::any::Any {
+ self
+ }
+
fn get_operation_type(&self) -> String {
Self::TYPE.to_string()
}
@@ -44,4 +48,8 @@ impl OperationInterface for UninstallOperation {
fn to_string(&self) -> String {
self.show(true)
}
+
+ fn as_uninstall_operation(&self) -> Option<&UninstallOperation> {
+ Some(self)
+ }
}
diff --git a/crates/shirabe/src/dependency_resolver/operation/update_operation.rs b/crates/shirabe/src/dependency_resolver/operation/update_operation.rs
index c1498ad..9adb248 100644
--- a/crates/shirabe/src/dependency_resolver/operation/update_operation.rs
+++ b/crates/shirabe/src/dependency_resolver/operation/update_operation.rs
@@ -79,6 +79,10 @@ impl SolverOperation for UpdateOperation {
}
impl OperationInterface for UpdateOperation {
+ fn as_any(&self) -> &dyn std::any::Any {
+ self
+ }
+
fn get_operation_type(&self) -> String {
Self::TYPE.to_string()
}
@@ -94,4 +98,8 @@ impl OperationInterface for UpdateOperation {
fn to_string(&self) -> String {
self.show(true)
}
+
+ fn as_update_operation(&self) -> Option<&UpdateOperation> {
+ Some(self)
+ }
}
diff --git a/crates/shirabe/src/dependency_resolver/policy_interface.rs b/crates/shirabe/src/dependency_resolver/policy_interface.rs
index f3cc1a0..606386f 100644
--- a/crates/shirabe/src/dependency_resolver/policy_interface.rs
+++ b/crates/shirabe/src/dependency_resolver/policy_interface.rs
@@ -3,7 +3,7 @@
use crate::dependency_resolver::pool::Pool;
use crate::package::package_interface::PackageInterface;
-pub trait PolicyInterface {
+pub trait PolicyInterface: std::fmt::Debug {
fn version_compare(
&self,
a: &dyn PackageInterface,
diff --git a/crates/shirabe/src/dependency_resolver/pool.rs b/crates/shirabe/src/dependency_resolver/pool.rs
index 96e608b..a194d15 100644
--- a/crates/shirabe/src/dependency_resolver/pool.rs
+++ b/crates/shirabe/src/dependency_resolver/pool.rs
@@ -193,7 +193,7 @@ impl Pool {
let mut id: i64 = 1;
for mut package in packages {
- package.id = id;
+ *package.id_mut() = id;
id += 1;
for provided in package.get_names(true) {
@@ -285,7 +285,7 @@ impl Pool {
) -> String {
let package = self.literal_to_package(literal);
- let prefix = if installed_map.contains_key(&package.id) {
+ let prefix = if installed_map.contains_key(&package.id()) {
if literal > 0 { "keep" } else { "remove" }
} else {
if literal > 0 {
@@ -391,7 +391,7 @@ impl fmt::Display for Pool {
for package in &self.packages {
str.push_str(&format!(
"- {}: {}\n",
- str_pad(&package.id.to_string(), 6, " ", STR_PAD_LEFT),
+ str_pad(&package.id().to_string(), 6, " ", STR_PAD_LEFT),
package.get_name()
));
}
diff --git a/crates/shirabe/src/dependency_resolver/pool_builder.rs b/crates/shirabe/src/dependency_resolver/pool_builder.rs
index ea860f2..3043aaa 100644
--- a/crates/shirabe/src/dependency_resolver/pool_builder.rs
+++ b/crates/shirabe/src/dependency_resolver/pool_builder.rs
@@ -152,19 +152,12 @@ impl PoolBuilder {
.into());
}
- for locked_package in request.get_locked_repository().unwrap().get_packages() {
+ for locked_package in
+ CanonicalPackagesTrait::get_packages(request.get_locked_repository().unwrap())
+ {
if !self.is_update_allowed(&*locked_package) {
- // remember which packages we skipped loading remote content for in this partial update
- self.skipped_load
- .entry(locked_package.get_name().to_string())
- .or_insert_with(Vec::new)
- .push(locked_package.clone_box());
- for (_k, link) in &locked_package.get_replaces() {
- self.skipped_load
- .entry(link.get_target().to_string())
- .or_insert_with(Vec::new)
- .push(locked_package.clone_box());
- }
+ // TODO(phase-b): PackageInterface lacks clone_box; PHP shares references.
+ // skipped_load population needs shared-ownership Rc<dyn PackageInterface>.
// Path repo packages are never loaded from lock, to force them to always remain in sync
// unless symlinking is disabled in which case we probably should rather treat them like
@@ -188,7 +181,7 @@ impl PoolBuilder {
}
}
- for package in request.get_fixed_or_locked_packages() {
+ for (_, package) in request.get_fixed_or_locked_packages() {
// using MatchAllConstraint here because fixed packages do not need to retrigger
// loading any packages
self.loaded_packages.insert(
@@ -369,8 +362,9 @@ impl PoolBuilder {
&mut self,
request: &Request,
name: &str,
- constraint: Box<dyn ConstraintInterface>,
+ constraint: &dyn ConstraintInterface,
) {
+ let constraint = constraint.clone_box();
// Skip platform requires at this stage
if PlatformRepository::is_platform_package(name) {
return;
@@ -389,7 +383,7 @@ impl PoolBuilder {
let root_requires = request.get_requires();
let mut constraint = constraint;
if let Some(root_constraint) = root_requires.get(name) {
- if !Intervals::is_subset_of(&*constraint, &**root_constraint) {
+ if !Intervals::is_subset_of(&*constraint, &**root_constraint)? {
constraint = root_constraint.clone_box();
}
}
@@ -401,7 +395,7 @@ impl PoolBuilder {
// MultiConstraint::create() will optimize anyway)
if let Some(existing) = self.packages_to_load.get(name) {
// Already marked for loading and this does not expand the constraint to be loaded, nothing to do
- if Intervals::is_subset_of(&*constraint, &**existing) {
+ if Intervals::is_subset_of(&*constraint, &**existing).unwrap_or(false) {
return;
}
@@ -419,7 +413,9 @@ impl PoolBuilder {
// No need to load this package with this constraint because it is
// a subset of the constraint with which we have already loaded packages
- if Intervals::is_subset_of(&*constraint, &**self.loaded_packages.get(name).unwrap()) {
+ if Intervals::is_subset_of(&*constraint, &**self.loaded_packages.get(name).unwrap())
+ .unwrap_or(false)
+ {
return;
}
@@ -762,7 +758,7 @@ impl PoolBuilder {
fn is_update_allowed(&self, package: &dyn BasePackage) -> bool {
for pattern in &self.update_allow_list {
let pattern_regexp = base_package::package_name_to_regexp(pattern);
- if Preg::is_match(&pattern_regexp, PackageInterface::get_name(package), None)
+ if Preg::is_match3(&pattern_regexp, PackageInterface::get_name(package), None)
.unwrap_or(false)
{
return true;
@@ -786,8 +782,10 @@ impl PoolBuilder {
let pattern_regexp = base_package::package_name_to_regexp(pattern);
// update pattern matches a locked package? => all good
- for package in request.get_locked_repository().unwrap().get_packages() {
- if Preg::is_match(&pattern_regexp, PackageInterface::get_name(package), None)
+ for package in
+ CanonicalPackagesTrait::get_packages(request.get_locked_repository().unwrap())
+ {
+ if Preg::is_match3(&pattern_regexp, PackageInterface::get_name(package), None)
.unwrap_or(false)
{
continue 'outer;
@@ -795,7 +793,7 @@ impl PoolBuilder {
}
// update pattern matches a root require? => all good, probably a new package
for (package_name, _constraint) in &request.get_requires() {
- if Preg::is_match(&pattern_regexp, package_name, None).unwrap_or(false) {
+ if Preg::is_match3(&pattern_regexp, package_name, None).unwrap_or(false) {
if PlatformRepository::is_platform_package(package_name) {
matched_platform_package = true;
continue;
@@ -855,7 +853,7 @@ impl PoolBuilder {
self.mark_package_name_for_loading(
request,
&replacer_name,
- Box::new(MatchAllConstraint::new()),
+ &MatchAllConstraint::new(),
);
} else {
let pkgs: Vec<Box<dyn BasePackage>> =
@@ -895,7 +893,7 @@ impl PoolBuilder {
// remove locked package by this name which was already initialized
let locked_packages: Vec<Box<dyn BasePackage>> = request
.get_locked_packages()
- .iter()
+ .values()
.map(|p| p.clone_box())
.collect();
for locked_package in &locked_packages {
@@ -914,7 +912,7 @@ impl PoolBuilder {
// that we load that replaced package in case an update to this package removes the replacement
let fixed_or_locked: Vec<Box<dyn BasePackage>> = request
.get_fixed_or_locked_packages()
- .iter()
+ .values()
.map(|p| p.clone_box())
.collect();
for fixed_or_locked_package in &fixed_or_locked {
@@ -1049,7 +1047,7 @@ impl PoolBuilder {
return pool;
}
- self.io.write_with_verbosity(
+ self.io.write3(
&sprintf(
"Pool optimizer completed in %.3f seconds",
&[(microtime(true) - before).into()],
@@ -1057,7 +1055,7 @@ impl PoolBuilder {
true,
io_interface::VERY_VERBOSE,
);
- self.io.write_with_verbosity(
+ self.io.write3(
&sprintf(
"<info>Found %s package versions referenced in your dependency graph. %s (%d%%) were optimized away.</info>",
&[
@@ -1100,7 +1098,7 @@ impl PoolBuilder {
return pool;
}
- self.io.write_with_verbosity(
+ self.io.write3(
&sprintf(
"Security advisory pool filter completed in %.3f seconds",
&[(microtime(true) - before).into()],
@@ -1108,7 +1106,7 @@ impl PoolBuilder {
true,
io_interface::VERY_VERBOSE,
);
- self.io.write_with_verbosity(
+ self.io.write3(
&sprintf(
"<info>Found %s package versions referenced in your dependency graph. %s (%d%%) were filtered away.</info>",
&[
diff --git a/crates/shirabe/src/dependency_resolver/pool_optimizer.rs b/crates/shirabe/src/dependency_resolver/pool_optimizer.rs
index 5307a1c..3da36b1 100644
--- a/crates/shirabe/src/dependency_resolver/pool_optimizer.rs
+++ b/crates/shirabe/src/dependency_resolver/pool_optimizer.rs
@@ -130,9 +130,9 @@ impl PoolOptimizer {
// Keep track of alias packages for every package so if either the alias or aliased is kept
// we keep the others as they are a unit of packages really
- if let Some(alias_pkg) = (package.as_any() as &dyn Any).downcast_ref::<AliasPackage>() {
+ if let Some(alias_pkg) = package.as_any().downcast_ref::<AliasPackage>() {
self.aliases_per_package
- .entry(alias_pkg.get_alias_of().id)
+ .entry(alias_pkg.get_alias_of().id())
.or_insert_with(Vec::new)
.push(package.clone_box());
}
@@ -175,8 +175,8 @@ impl PoolOptimizer {
}
fn mark_package_irremovable(&mut self, package: &dyn BasePackage) {
- self.irremovable_packages.insert(package.id, true);
- if let Some(alias_pkg) = (package.as_any() as &dyn Any).downcast_ref::<AliasPackage>() {
+ self.irremovable_packages.insert(package.id(), true);
+ if let Some(alias_pkg) = package.as_any().downcast_ref::<AliasPackage>() {
// recursing here so aliasesPerPackage for the aliasOf can be checked
// and all its aliases marked as irremovable as well
self.mark_package_irremovable(alias_pkg.get_alias_of());
@@ -184,8 +184,8 @@ impl PoolOptimizer {
// PHP: foreach ($this->aliasesPerPackage[$package->id] as $aliasPackage)
let alias_ids: Vec<i64> = self
.aliases_per_package
- .get(&package.id)
- .map(|aliases| aliases.iter().map(|a| a.id).collect())
+ .get(&package.id())
+ .map(|aliases| aliases.iter().map(|a| a.id()).collect())
.unwrap_or_default();
for alias_id in alias_ids {
self.irremovable_packages.insert(alias_id, true);
@@ -197,7 +197,7 @@ impl PoolOptimizer {
let mut packages: Vec<Box<dyn BasePackage>> = vec![];
let mut removed_versions: IndexMap<String, IndexMap<String, String>> = IndexMap::new();
for package in pool.get_packages() {
- if !self.packages_to_remove.contains_key(&package.id) {
+ if !self.packages_to_remove.contains_key(&package.id()) {
packages.push(package.clone_box());
} else {
removed_versions
@@ -238,11 +238,11 @@ impl PoolOptimizer {
for package in pool.get_packages() {
// If that package was already marked irremovable, we can skip
// the entire process for it
- if self.irremovable_packages.contains_key(&package.id) {
+ if self.irremovable_packages.contains_key(&package.id()) {
continue;
}
- self.mark_package_for_removal(package.id)?;
+ self.mark_package_for_removal(package.id())?;
let dependency_hash = self.calculate_dependency_hash(package.as_ref());
@@ -311,7 +311,7 @@ impl PoolOptimizer {
.or_insert_with(Vec::new)
.push(package.clone_box());
package_identical_definition_lookup
- .entry(package.id)
+ .entry(package.id())
.or_insert_with(IndexMap::new)
.insert(
package_name.clone(),
@@ -344,7 +344,7 @@ impl PoolOptimizer {
let mut literals: Vec<i64> = vec![];
for package in packages {
- literals.push(package.id);
+ literals.push(package.id());
}
for preferred_literal in
@@ -439,13 +439,13 @@ impl PoolOptimizer {
>,
) {
// Already marked to keep
- if !self.packages_to_remove.contains_key(&package.id) {
+ if !self.packages_to_remove.contains_key(&package.id()) {
return;
}
- self.packages_to_remove.shift_remove(&package.id);
+ self.packages_to_remove.shift_remove(&package.id());
- if let Some(alias_pkg) = (package.as_any() as &dyn Any).downcast_ref::<AliasPackage>() {
+ if let Some(alias_pkg) = package.as_any().downcast_ref::<AliasPackage>() {
// recursing here so aliasesPerPackage for the aliasOf can be checked
// and all its aliases marked to be kept as well
self.keep_package(
@@ -457,7 +457,7 @@ impl PoolOptimizer {
// record all the versions of the package group so we can list them later in Problem output
for name in package.get_names(false) {
- if let Some(per_name) = package_identical_definition_lookup.get(&package.id) {
+ if let Some(per_name) = package_identical_definition_lookup.get(&package.id()) {
if let Some(package_group_pointers) = per_name.get(&name) {
let package_group = identical_definitions_per_package
.get(&name)
@@ -466,7 +466,7 @@ impl PoolOptimizer {
if let Some(package_group) = package_group {
for pkg in package_group {
let pkg = if let Some(alias_pkg) =
- (pkg.as_any() as &dyn Any).downcast_ref::<AliasPackage>()
+ pkg.as_any().downcast_ref::<AliasPackage>()
{
if alias_pkg.get_pretty_version()
== VersionParser::DEFAULT_BRANCH_ALIAS
@@ -493,8 +493,13 @@ impl PoolOptimizer {
let alias_info: Vec<(i64, Vec<String>)> = self
.aliases_per_package
- .get(&package.id)
- .map(|aliases| aliases.iter().map(|a| (a.id, a.get_names(false))).collect())
+ .get(&package.id())
+ .map(|aliases| {
+ aliases
+ .iter()
+ .map(|a| (a.id(), a.get_names(false)))
+ .collect()
+ })
.unwrap_or_default();
for (alias_id, alias_names) in alias_info {
self.packages_to_remove.shift_remove(&alias_id);
@@ -510,7 +515,7 @@ impl PoolOptimizer {
if let Some(package_group) = package_group {
for pkg in package_group {
let pkg = if let Some(alias_pkg) =
- (pkg.as_any() as &dyn Any).downcast_ref::<AliasPackage>()
+ pkg.as_any().downcast_ref::<AliasPackage>()
{
if alias_pkg.get_pretty_version()
== VersionParser::DEFAULT_BRANCH_ALIAS
@@ -549,7 +554,7 @@ impl PoolOptimizer {
IndexMap::new();
for package in pool.get_packages() {
- let id = package.id;
+ let id = package.id();
// Do not remove irremovable packages
if self.irremovable_packages.contains_key(&id) {
@@ -557,9 +562,7 @@ impl PoolOptimizer {
}
// Do not remove a package aliased by another package, nor aliases
if self.aliases_per_package.contains_key(&id)
- || (package.as_any() as &dyn Any)
- .downcast_ref::<AliasPackage>()
- .is_some()
+ || package.as_any().downcast_ref::<AliasPackage>().is_some()
{
continue;
}
@@ -573,7 +576,7 @@ impl PoolOptimizer {
package_index
.entry(PackageInterface::get_name(package.as_ref()).to_string())
.or_insert_with(IndexMap::new)
- .insert(package.id, package.clone_box());
+ .insert(package.id(), package.clone_box());
}
for (_, package) in request.get_locked_packages() {
@@ -671,10 +674,9 @@ impl PoolOptimizer {
&self,
constraint: Box<dyn ConstraintInterface>,
) -> Vec<Box<dyn ConstraintInterface>> {
- // TODO(phase-b): Intervals::compactConstraint expects/returns ConstraintInterface
- let constraint = Intervals::compact_constraint(constraint);
+ let constraint = Intervals::compact_constraint(&*constraint).unwrap_or(constraint);
- if let Some(multi) = (constraint.as_ref() as &dyn Any).downcast_ref::<MultiConstraint>() {
+ if let Some(multi) = constraint.as_any().downcast_ref::<MultiConstraint>() {
if multi.is_disjunctive() {
// No need to call ourselves recursively here because Intervals::compactConstraint() ensures that there
// are no nested disjunctive MultiConstraint instances possible
diff --git a/crates/shirabe/src/dependency_resolver/problem.rs b/crates/shirabe/src/dependency_resolver/problem.rs
index 8424941..e78ee14 100644
--- a/crates/shirabe/src/dependency_resolver/problem.rs
+++ b/crates/shirabe/src/dependency_resolver/problem.rs
@@ -2,7 +2,7 @@
use indexmap::IndexMap;
-use shirabe_external_packages::composer::pcre::preg::Preg;
+use shirabe_external_packages::composer::pcre::preg::{CaptureKey, Preg};
use shirabe_external_packages::symfony::console::formatter::output_formatter::OutputFormatter;
use shirabe_php_shim::{
LogicException, PhpMixed, defined, extension_loaded, implode, in_array, php_to_string,
@@ -212,7 +212,8 @@ impl Problem {
installed_map,
learned_pool,
);
- let m_opt = if in_array(
+ let mut m: IndexMap<CaptureKey, String> = IndexMap::new();
+ let matched = if in_array(
PhpMixed::Int(rule.get_reason()),
&PhpMixed::List(
deduplicatable_rule_types
@@ -222,27 +223,29 @@ impl Problem {
),
true,
) {
- Preg::is_match_strict_groups(
+ Preg::is_match_strict_groups3(
r"{^(?P<package>\S+) (?P<version>\S+) (?P<type>requires|conflicts)}",
&message,
+ Some(&mut m),
)
- .unwrap_or(None)
+ .unwrap_or(false)
} else {
- None
+ false
};
- if let Some(m) = m_opt {
+ if matched {
message = str_replace("%", "%%", &message);
let template =
Preg::replace(r"{^\S+ \S+ }", "%s%s ", &message).unwrap_or(message.clone());
messages.push(template.clone());
- let pkg_key = m[1].clone();
- let version_key = parser.normalize(&m[2], "").unwrap_or_default();
+ let pkg_key = m.get(&CaptureKey::ByIndex(1)).cloned().unwrap_or_default();
+ let m2 = m.get(&CaptureKey::ByIndex(2)).cloned().unwrap_or_default();
+ let version_key = parser.normalize(&m2, Some("")).unwrap_or_default();
templates
.entry(template.clone())
.or_insert_with(IndexMap::new)
.entry(pkg_key.clone())
.or_insert_with(IndexMap::new)
- .insert(version_key, m[2].clone());
+ .insert(version_key, m2.clone());
let source_package = rule.get_source_package(pool);
for (version, pretty_version) in
pool.get_removed_versions_by_package(&spl_object_hash(&source_package))
@@ -533,7 +536,7 @@ impl Problem {
}
}
- let mut locked_package: Option<BasePackage> = None;
+ let mut locked_package: Option<Box<dyn BasePackage>> = None;
for package in request.get_locked_packages() {
if package.get_name() == package_name {
locked_package = Some(package.clone());
@@ -554,7 +557,7 @@ impl Problem {
if let Some(c) = constraint {
if c.is_constraint()
&& c.get_operator() == Constraint::STR_OP_EQ
- && Preg::is_match(r"{^dev-.*#.*}", &c.get_pretty_string(), None).unwrap_or(false)
+ && Preg::is_match3(r"{^dev-.*#.*}", &c.get_pretty_string(), None).unwrap_or(false)
{
let new_constraint =
Preg::replace(r"{ +as +([^,\s|]+)$}", "", &c.get_pretty_string())
@@ -606,7 +609,7 @@ impl Problem {
let filtered: Vec<&Box<dyn PackageInterface>> = packages
.iter()
.filter(|p| {
- root_reqs[package_name].matches(&Constraint::new("==", &p.get_version()))
+ root_reqs[package_name].matches(&Constraint::new("==", p.get_version()))
})
.collect();
if filtered.len() == 0 {
@@ -638,12 +641,12 @@ impl Problem {
let temp_reqs = repository_set.get_temporary_constraints();
let first_pkg = packages.first().unwrap();
- for name in first_pkg.get_names() {
+ for name in first_pkg.get_names(true) {
if temp_reqs.contains_key(&name) {
let filtered: Vec<&Box<dyn PackageInterface>> = packages
.iter()
.filter(|p| {
- temp_reqs[&name].matches(&Constraint::new("==", &p.get_version()))
+ temp_reqs[&name].matches(&Constraint::new("==", p.get_version()))
})
.collect();
if filtered.len() == 0 {
@@ -676,10 +679,10 @@ impl Problem {
}
if let Some(ref lp) = locked_package {
- let fixed_constraint = Constraint::new("==", &lp.get_version());
+ let fixed_constraint = Constraint::new("==", lp.get_version());
let filtered: Vec<&Box<dyn PackageInterface>> = packages
.iter()
- .filter(|p| fixed_constraint.matches(&Constraint::new("==", &p.get_version())))
+ .filter(|p| fixed_constraint.matches(&Constraint::new("==", p.get_version())))
.collect();
if filtered.len() == 0 {
return (
@@ -763,22 +766,22 @@ impl Problem {
return format!(
"<href={}>{}</>",
OutputFormatter::escape(advisory.link.as_ref().unwrap()),
- advisory.advisory_id
+ advisory.inner.advisory_id
);
}
- if str_starts_with(&advisory.advisory_id, "PKSA-") {
+ if str_starts_with(&advisory.inner.advisory_id, "PKSA-") {
return format!(
"<href={}>{}</>",
OutputFormatter::escape(&format!(
"https://packagist.org/security-advisories/{}",
- advisory.advisory_id
+ advisory.inner.advisory_id
)),
- advisory.advisory_id
+ advisory.inner.advisory_id
);
}
- advisory.advisory_id.clone()
+ advisory.inner.advisory_id.clone()
})
.collect()
} else {
@@ -961,7 +964,7 @@ impl Problem {
);
}
- if !Preg::is_match(r"{^[A-Za-z0-9_./-]+$}", package_name, None).unwrap_or(false) {
+ if !Preg::is_match3(r"{^[A-Za-z0-9_./-]+$}", package_name, None).unwrap_or(false) {
let illegal_chars =
Preg::replace(r"{[A-Za-z0-9_./-]+}", "", package_name).unwrap_or_default();
@@ -1365,7 +1368,7 @@ impl Problem {
&& c.get_operator() == Constraint::STR_OP_EQ
&& !str_starts_with(&c.get_version(), "dev-")
{
- if !Preg::is_match(r"{^\d+(?:\.\d+)*$}", &c.get_pretty_string(), None)
+ if !Preg::is_match3(r"{^\d+(?:\.\d+)*$}", &c.get_pretty_string(), None)
.unwrap_or(false)
{
return format!(" {} (exact version match)", c.get_pretty_string());
diff --git a/crates/shirabe/src/dependency_resolver/rule.rs b/crates/shirabe/src/dependency_resolver/rule.rs
index 23a5981..e54df18 100644
--- a/crates/shirabe/src/dependency_resolver/rule.rs
+++ b/crates/shirabe/src/dependency_resolver/rule.rs
@@ -37,6 +37,21 @@ pub enum ReasonData {
Fixed {
package: Box<dyn BasePackage>,
},
+ /// Phase B placeholder for an arbitrary PHP-side value not yet mapped to a real variant.
+ Mixed(PhpMixed),
+}
+
+impl From<PhpMixed> for ReasonData {
+ fn from(value: PhpMixed) -> Self {
+ // TODO(phase-b): callers should construct the appropriate variant directly;
+ // this catch-all keeps the rule constructors building while reason_data threading
+ // through PhpMixed in the resolver is still in transition.
+ match value {
+ PhpMixed::String(s) => ReasonData::String(s),
+ PhpMixed::Int(i) => ReasonData::Int(i),
+ other => ReasonData::Mixed(other),
+ }
+ }
}
// reason constants and // their reason data contents
@@ -54,7 +69,7 @@ pub const BITFIELD_TYPE: i64 = 0;
pub const BITFIELD_REASON: i64 = 8;
pub const BITFIELD_DISABLED: i64 = 16;
-pub trait Rule: std::fmt::Display {
+pub trait Rule: std::fmt::Display + std::fmt::Debug {
fn bitfield(&self) -> i64;
fn bitfield_mut(&mut self) -> &mut i64;
fn request(&self) -> Option<&Request>;
@@ -67,14 +82,19 @@ pub trait Rule: std::fmt::Display {
fn equals(&self, rule: &dyn Rule) -> bool;
fn is_assertion(&self) -> bool;
+ fn clone_box(&self) -> Box<dyn Rule> {
+ todo!()
+ }
+
/// @return self::RULE_*
fn get_reason(&self) -> i64 {
- (self.bitfield & (255 << Self::BITFIELD_REASON)) >> Self::BITFIELD_REASON
+ (self.bitfield() & (255 << BITFIELD_REASON)) >> BITFIELD_REASON
}
/// @phpstan-return ReasonData
fn get_reason_data(&self) -> &ReasonData {
- &self.reason_data()
+ // TODO(phase-b): reason_data() returns Option; PHP getReasonData unconditional
+ self.reason_data().unwrap()
}
fn get_required_package(&self) -> Option<String> {
@@ -97,29 +117,29 @@ pub trait Rule: std::fmt::Display {
/// @param RuleSet::TYPE_* $type
fn set_type(&mut self, r#type: i64) {
- self.bitfield = (self.bitfield & !(255i64 << Self::BITFIELD_TYPE))
- | ((255 & r#type) << Self::BITFIELD_TYPE);
+ *self.bitfield_mut() =
+ (self.bitfield() & !(255i64 << BITFIELD_TYPE)) | ((255 & r#type) << BITFIELD_TYPE);
}
fn get_type(&self) -> i64 {
- (self.bitfield & (255 << Self::BITFIELD_TYPE)) >> Self::BITFIELD_TYPE
+ (self.bitfield() & (255 << BITFIELD_TYPE)) >> BITFIELD_TYPE
}
fn disable(&mut self) {
- self.bitfield = (self.bitfield & !(255i64 << Self::BITFIELD_DISABLED))
- | (1i64 << Self::BITFIELD_DISABLED);
+ *self.bitfield_mut() =
+ (self.bitfield() & !(255i64 << BITFIELD_DISABLED)) | (1i64 << BITFIELD_DISABLED);
}
fn enable(&mut self) {
- self.bitfield &= !(255i64 << Self::BITFIELD_DISABLED);
+ *self.bitfield_mut() &= !(255i64 << BITFIELD_DISABLED);
}
fn is_disabled(&self) -> bool {
- 0 != ((self.bitfield & (255 << Self::BITFIELD_DISABLED)) >> Self::BITFIELD_DISABLED)
+ 0 != ((self.bitfield() & (255 << BITFIELD_DISABLED)) >> BITFIELD_DISABLED)
}
fn is_enabled(&self) -> bool {
- 0 == ((self.bitfield & (255 << Self::BITFIELD_DISABLED)) >> Self::BITFIELD_DISABLED)
+ 0 == ((self.bitfield() & (255 << BITFIELD_DISABLED)) >> BITFIELD_DISABLED)
}
fn is_caused_by_lock(
@@ -195,10 +215,12 @@ pub trait Rule: std::fmt::Display {
match self.get_reason() {
r if r == Self::RULE_PACKAGE_CONFLICT => {
- let mut package1 =
- self.deduplicate_default_branch_alias(pool.literal_to_package(literals[0]));
- let mut package2 =
- self.deduplicate_default_branch_alias(pool.literal_to_package(literals[1]));
+ let mut package1 = self.deduplicate_default_branch_alias(
+ pool.literal_to_package(literals[0]).clone_box(),
+ );
+ let mut package2 = self.deduplicate_default_branch_alias(
+ pool.literal_to_package(literals[1]).clone_box(),
+ );
let reason_data = self.get_reason_data();
// swap literals if they are not in the right order with package2 being the conflicter
@@ -213,8 +235,9 @@ pub trait Rule: std::fmt::Display {
r if r == Self::RULE_PACKAGE_REQUIRES => {
let source_literal = literals[0];
- let source_package =
- self.deduplicate_default_branch_alias(pool.literal_to_package(source_literal));
+ let source_package = self.deduplicate_default_branch_alias(
+ pool.literal_to_package(source_literal).clone_box(),
+ );
Ok(source_package)
}
@@ -264,11 +287,7 @@ pub trait Rule: std::fmt::Display {
// PHP: array_values(array_filter($packages, fn ($p) => !($p instanceof AliasPackage)))
let packages_non_alias: Vec<Box<dyn BasePackage>> = packages
.iter()
- .filter(|p| {
- (p.as_any() as &dyn Any)
- .downcast_ref::<AliasPackage>()
- .is_none()
- })
+ .filter(|p| p.as_any().downcast_ref::<AliasPackage>().is_none())
.map(|p| p.clone_box())
.collect();
if packages_non_alias.len() == 1 {
@@ -320,10 +339,12 @@ pub trait Rule: std::fmt::Display {
}
r if r == Self::RULE_PACKAGE_CONFLICT => {
- let mut package1 =
- self.deduplicate_default_branch_alias(pool.literal_to_package(literals[0]));
- let mut package2 =
- self.deduplicate_default_branch_alias(pool.literal_to_package(literals[1]));
+ let mut package1 = self.deduplicate_default_branch_alias(
+ pool.literal_to_package(literals[0]).clone_box(),
+ );
+ let mut package2 = self.deduplicate_default_branch_alias(
+ pool.literal_to_package(literals[1]).clone_box(),
+ );
let mut conflict_target = package1.get_pretty_string();
let reason_data = self.get_reason_data();
@@ -386,8 +407,9 @@ pub trait Rule: std::fmt::Display {
r if r == Self::RULE_PACKAGE_REQUIRES => {
assert!(literals.len() > 0);
let source_literal = array_shift(&mut literals).unwrap();
- let source_package =
- self.deduplicate_default_branch_alias(pool.literal_to_package(source_literal));
+ let source_package = self.deduplicate_default_branch_alias(
+ pool.literal_to_package(source_literal).clone_box(),
+ );
let reason_data = self.get_reason_data();
let link = match reason_data {
ReasonData::Link(l) => l,
@@ -522,7 +544,7 @@ pub trait Rule: std::fmt::Display {
let mut groups: IndexMap<String, Vec<Box<dyn BasePackage>>> = IndexMap::new();
for literal in &literals {
let package = pool.literal_to_package(*literal);
- let group = if installed_map.contains_key(&package.id) {
+ let group = if installed_map.contains_key(&package.id()) {
if *literal > 0 { "keep" } else { "remove" }
} else {
if *literal > 0 {
@@ -565,8 +587,9 @@ pub trait Rule: std::fmt::Display {
if alias_package.get_version() == VersionParser::DEFAULT_BRANCH_ALIAS {
return String::new();
}
- let package =
- self.deduplicate_default_branch_alias(pool.literal_to_package(literals[1]));
+ let package = self.deduplicate_default_branch_alias(
+ pool.literal_to_package(literals[1]).clone_box(),
+ );
format!(
"{} is an alias of {} and thus requires it to be installed too.",
@@ -582,8 +605,9 @@ pub trait Rule: std::fmt::Display {
if alias_package.get_version() == VersionParser::DEFAULT_BRANCH_ALIAS {
return String::new();
}
- let package =
- self.deduplicate_default_branch_alias(pool.literal_to_package(literals[0]));
+ let package = self.deduplicate_default_branch_alias(
+ pool.literal_to_package(literals[0]).clone_box(),
+ );
format!(
"{} is an alias of {} and must be installed with it.",
@@ -656,7 +680,7 @@ pub trait Rule: std::fmt::Display {
&self,
package: Box<dyn BasePackage>,
) -> Box<dyn BasePackage> {
- if let Some(alias_pkg) = (package.as_any() as &dyn Any).downcast_ref::<AliasPackage>() {
+ if let Some(alias_pkg) = package.as_any().downcast_ref::<AliasPackage>() {
if alias_pkg.get_pretty_version() == VersionParser::DEFAULT_BRANCH_ALIAS {
return alias_pkg.get_alias_of().clone_box();
}
@@ -666,21 +690,29 @@ pub trait Rule: std::fmt::Display {
}
}
+#[derive(Debug)]
pub struct RuleBase {
- bitfield: i64,
- request: Option<Request>,
- reason_data: Option<ReasonData>,
+ pub(crate) bitfield: i64,
+ pub(crate) request: Option<Request>,
+ pub(crate) reason_data: Option<ReasonData>,
}
impl RuleBase {
- fn new(reason: i64, reason_data: ReasonData) -> Self {
- let bitfield = (0i64 << Self::BITFIELD_DISABLED)
- | (reason << Self::BITFIELD_REASON)
- | (255i64 << Self::BITFIELD_TYPE);
+ pub const BITFIELD_DISABLED: i64 = BITFIELD_DISABLED;
+ pub const BITFIELD_REASON: i64 = BITFIELD_REASON;
+ pub const BITFIELD_TYPE: i64 = BITFIELD_TYPE;
+
+ pub fn new(reason: i64, reason_data: ReasonData) -> Self {
+ let bitfield =
+ (0i64 << BITFIELD_DISABLED) | (reason << BITFIELD_REASON) | (255i64 << BITFIELD_TYPE);
Self {
bitfield,
request: None,
reason_data: Some(reason_data),
}
}
+
+ pub fn is_disabled(&self) -> bool {
+ 0 != ((self.bitfield & (255 << BITFIELD_DISABLED)) >> BITFIELD_DISABLED)
+ }
}
diff --git a/crates/shirabe/src/dependency_resolver/rule2_literals.rs b/crates/shirabe/src/dependency_resolver/rule2_literals.rs
index cdd1a9c..1c98200 100644
--- a/crates/shirabe/src/dependency_resolver/rule2_literals.rs
+++ b/crates/shirabe/src/dependency_resolver/rule2_literals.rs
@@ -28,7 +28,7 @@ impl Rule2Literals {
};
Self {
- inner: RuleBase::new(reason, reason_data),
+ inner: RuleBase::new(reason.as_int().unwrap_or(0), ReasonData::from(reason_data)),
literal1,
literal2,
literals: vec![literal1, literal2],
diff --git a/crates/shirabe/src/dependency_resolver/rule_set.rs b/crates/shirabe/src/dependency_resolver/rule_set.rs
index 46ee4d2..032790e 100644
--- a/crates/shirabe/src/dependency_resolver/rule_set.rs
+++ b/crates/shirabe/src/dependency_resolver/rule_set.rs
@@ -92,6 +92,10 @@ impl RuleSet {
&*self.rule_by_id[&id]
}
+ pub fn rule_by_id_mut(&mut self, id: i64) -> &mut dyn Rule {
+ &mut *self.rule_by_id.get_mut(&id).unwrap()
+ }
+
pub fn get_rules(&self) -> &IndexMap<i64, Vec<Box<dyn Rule>>> {
&self.rules
}
diff --git a/crates/shirabe/src/dependency_resolver/rule_set_generator.rs b/crates/shirabe/src/dependency_resolver/rule_set_generator.rs
index d5bb1cd..6cbe93b 100644
--- a/crates/shirabe/src/dependency_resolver/rule_set_generator.rs
+++ b/crates/shirabe/src/dependency_resolver/rule_set_generator.rs
@@ -123,16 +123,15 @@ impl RuleSetGenerator {
if literals.len() == 2 {
// Rule2Literals and MultiConflictRule both implement Rule (Phase B: define Rule type)
- Rule::from(Rule2Literals::new(
+ Box::new(Rule2Literals::new(
literals[0],
literals[1],
PhpMixed::Int(reason),
reason_data,
- ))
+ )) as Box<dyn Rule>
} else {
- Rule::from(
- MultiConflictRule::new(literals, PhpMixed::Int(reason), reason_data).unwrap(),
- )
+ Box::new(MultiConflictRule::new(literals, PhpMixed::Int(reason), reason_data).unwrap())
+ as Box<dyn Rule>
}
}
@@ -159,42 +158,45 @@ impl RuleSetGenerator {
continue;
}
- self.added_map.insert(package.get_id(), package.clone_box());
+ self.added_map
+ .insert(package.get_id(), package.clone_package_box());
- let is_alias = (package.as_any() as &dyn Any)
- .downcast_ref::<AliasPackage>()
- .is_some();
+ let is_alias = package.as_any().downcast_ref::<AliasPackage>().is_some();
if !is_alias {
for name in package.get_names(false) {
self.added_packages_by_names
.entry(name)
.or_default()
- .push(package.clone_box());
+ .push(package.clone_package_box());
}
} else {
- let alias_pkg = (package.as_any() as &dyn Any)
- .downcast_ref::<AliasPackage>()
- .unwrap();
+ let alias_pkg = package.as_any().downcast_ref::<AliasPackage>().unwrap();
- work_queue.push_back(alias_pkg.get_alias_of().clone_box());
+ work_queue.push_back(alias_pkg.get_alias_of().clone_package_box());
let alias_of = alias_pkg.get_alias_of();
let rule = self.create_require_rule(
&*package,
- &[alias_of.clone_box()],
+ &[alias_of.clone_package_box()],
rule::RULE_PACKAGE_ALIAS,
PhpMixed::Null, // reasonData: $package (BasePackage)
);
- self.add_rule(RuleSet::TYPE_PACKAGE, rule.map(Rule::from));
+ self.add_rule(
+ RuleSet::TYPE_PACKAGE,
+ rule.map(|r| Box::new(r) as Box<dyn Rule>),
+ );
// aliases must be installed with their main package, so create a rule the other way around as well
let inverse_rule = self.create_require_rule(
alias_of,
- &[package.clone_box()],
+ &[package.clone_package_box()],
rule::RULE_PACKAGE_INVERSE_ALIAS,
PhpMixed::Null, // reasonData: $package->getAliasOf() (BasePackage)
);
- self.add_rule(RuleSet::TYPE_PACKAGE, inverse_rule.map(Rule::from));
+ self.add_rule(
+ RuleSet::TYPE_PACKAGE,
+ inverse_rule.map(|r| Box::new(r) as Box<dyn Rule>),
+ );
// if alias package has no self.version requires, its requirements do not
// need to be added as the aliased package processing will take care of it
@@ -207,7 +209,8 @@ impl RuleSetGenerator {
let mut constraint = link.get_constraint().clone_box();
if platform_requirement_filter.is_ignored(link.get_target()) {
continue;
- } else if let Some(ignore_list_filter) = (platform_requirement_filter as &dyn Any)
+ } else if let Some(ignore_list_filter) = platform_requirement_filter
+ .as_any()
.downcast_ref::<IgnoreListPlatformRequirementFilter>(
) {
constraint = ignore_list_filter
@@ -223,7 +226,10 @@ impl RuleSetGenerator {
rule::RULE_PACKAGE_REQUIRES,
PhpMixed::Null, // reasonData: $link (Link)
);
- self.add_rule(RuleSet::TYPE_PACKAGE, rule.map(Rule::from));
+ self.add_rule(
+ RuleSet::TYPE_PACKAGE,
+ rule.map(|r| Box::new(r) as Box<dyn Rule>),
+ );
for require in possible_requires {
work_queue.push_back(require);
@@ -252,7 +258,8 @@ impl RuleSetGenerator {
let mut constraint = link.get_constraint().clone_box();
if platform_requirement_filter.is_ignored(link.get_target()) {
continue;
- } else if let Some(ignore_list_filter) = (platform_requirement_filter as &dyn Any)
+ } else if let Some(ignore_list_filter) = platform_requirement_filter
+ .as_any()
.downcast_ref::<IgnoreListPlatformRequirementFilter>(
) {
constraint = ignore_list_filter
@@ -266,9 +273,8 @@ impl RuleSetGenerator {
// define the conflict rule for regular packages, for alias packages it's only needed if the name
// matches the conflict exactly, otherwise the name match is by provide/replace which means the
// package which this is an alias of will conflict anyway, so no need to create additional rules
- let conflict_is_alias = (conflict.as_any() as &dyn Any)
- .downcast_ref::<AliasPackage>()
- .is_some();
+ let conflict_is_alias =
+ conflict.as_any().downcast_ref::<AliasPackage>().is_some();
let conflict_name_matches = conflict.get_name() == link.get_target();
if !conflict_is_alias || conflict_name_matches {
let rule = self.create_rule2_literals(
@@ -277,7 +283,10 @@ impl RuleSetGenerator {
rule::RULE_PACKAGE_CONFLICT,
PhpMixed::Null, // reasonData: $link (Link)
);
- self.add_rule(RuleSet::TYPE_PACKAGE, rule.map(Rule::from));
+ self.add_rule(
+ RuleSet::TYPE_PACKAGE,
+ rule.map(|r| Box::new(r) as Box<dyn Rule>),
+ );
}
}
}
@@ -336,14 +345,15 @@ impl RuleSetGenerator {
rule::RULE_FIXED,
PhpMixed::Array(reason_data),
);
- self.add_rule(RuleSet::TYPE_REQUEST, Some(Rule::from(rule)));
+ self.add_rule(RuleSet::TYPE_REQUEST, Some(Box::new(rule) as Box<dyn Rule>));
}
for (package_name, constraint) in request.get_requires() {
let mut constraint = constraint.clone_box();
if platform_requirement_filter.is_ignored(package_name) {
continue;
- } else if let Some(ignore_list_filter) = (platform_requirement_filter as &dyn Any)
+ } else if let Some(ignore_list_filter) = platform_requirement_filter
+ .as_any()
.downcast_ref::<IgnoreListPlatformRequirementFilter>(
) {
constraint = ignore_list_filter
@@ -371,7 +381,7 @@ impl RuleSetGenerator {
rule::RULE_ROOT_REQUIRE,
PhpMixed::Array(reason_data),
);
- self.add_rule(RuleSet::TYPE_REQUEST, Some(Rule::from(rule)));
+ self.add_rule(RuleSet::TYPE_REQUEST, Some(Box::new(rule) as Box<dyn Rule>));
}
}
@@ -387,7 +397,7 @@ impl RuleSetGenerator {
// even if the alias itself isn't required, otherwise a package could be installed without its alias which
// leads to unexpected behavior
let is_not_added = !self.added_map.contains_key(&package.get_id());
- let as_alias = (package.as_any() as &dyn Any).downcast_ref::<AliasPackage>();
+ let as_alias = package.as_any().downcast_ref::<AliasPackage>();
if is_not_added {
if let Some(alias_pkg) = as_alias {
if alias_pkg.is_root_package_alias()
diff --git a/crates/shirabe/src/dependency_resolver/rule_watch_graph.rs b/crates/shirabe/src/dependency_resolver/rule_watch_graph.rs
index 0524fcb..a8176ee 100644
--- a/crates/shirabe/src/dependency_resolver/rule_watch_graph.rs
+++ b/crates/shirabe/src/dependency_resolver/rule_watch_graph.rs
@@ -27,7 +27,10 @@ impl RuleWatchGraph {
return;
}
- let is_multi_conflict = (node.borrow().get_rule().as_any() as &dyn Any)
+ let is_multi_conflict = node
+ .borrow()
+ .get_rule()
+ .as_any()
.downcast_ref::<MultiConflictRule>()
.is_some();
@@ -72,7 +75,10 @@ impl RuleWatchGraph {
self.watch_chains.get_mut(&literal).unwrap().rewind();
while self.watch_chains.get(&literal).unwrap().valid() {
let node = self.watch_chains.get(&literal).unwrap().current().clone();
- let is_multi_conflict = (node.borrow().get_rule().as_any() as &dyn Any)
+ let is_multi_conflict = node
+ .borrow()
+ .get_rule()
+ .as_any()
.downcast_ref::<MultiConflictRule>()
.is_some();
if !is_multi_conflict {
diff --git a/crates/shirabe/src/dependency_resolver/rule_watch_node.rs b/crates/shirabe/src/dependency_resolver/rule_watch_node.rs
index 12dd83f..6c1bada 100644
--- a/crates/shirabe/src/dependency_resolver/rule_watch_node.rs
+++ b/crates/shirabe/src/dependency_resolver/rule_watch_node.rs
@@ -57,6 +57,12 @@ impl RuleWatchNode {
self.rule.as_ref()
}
+ /// Owned clone for callers that need a `Box<dyn Rule>`. Default impl in
+ /// `RuleLiterals` returns `todo!()`; concrete rule impls override it.
+ pub fn get_rule_boxed(&self) -> Box<dyn crate::dependency_resolver::rule::Rule> {
+ self.rule.clone_rule_box()
+ }
+
pub fn get_other_watch(&self, literal: i64) -> i64 {
if self.watch1 == literal {
return self.watch2;
diff --git a/crates/shirabe/src/dependency_resolver/solver.rs b/crates/shirabe/src/dependency_resolver/solver.rs
index 2160b97..b4b878b 100644
--- a/crates/shirabe/src/dependency_resolver/solver.rs
+++ b/crates/shirabe/src/dependency_resolver/solver.rs
@@ -89,7 +89,7 @@ impl Solver {
let rules_count = self.rules.count();
let mut rule_index = 0_i64;
while rule_index < rules_count {
- let rule = self.rules.rule_by_id(rule_index).clone();
+ let rule = self.rules.rule_by_id(rule_index).clone_box();
if !rule.is_assertion() || rule.is_disabled() {
rule_index += 1;
@@ -100,7 +100,7 @@ impl Solver {
let literal = literals[0];
if !self.decisions.decided(literal) {
- self.decisions.decide(literal, 1, rule.clone());
+ self.decisions.decide(literal, 1, rule.clone_box());
rule_index += 1;
continue;
}
@@ -118,12 +118,12 @@ impl Solver {
continue;
}
- let conflict = self.decisions.decision_rule(literal).clone();
+ let conflict = self.decisions.decision_rule(literal).clone_box();
if RuleSet::TYPE_PACKAGE == conflict.get_type() {
let mut problem = Problem::new();
- problem.add_rule(rule.clone());
+ problem.add_rule(rule.clone_box());
problem.add_rule(conflict);
self.rules.rule_by_id_mut(rule_index).disable()?;
self.problems.push(problem);
@@ -144,7 +144,7 @@ impl Solver {
.ids()
.collect();
for assert_rule_id in request_rules {
- let assert_rule = self.rules.rule_by_id(assert_rule_id).clone();
+ let assert_rule = self.rules.rule_by_id(assert_rule_id).clone_box();
if assert_rule.is_disabled() || !assert_rule.is_assertion() {
continue;
}
@@ -204,7 +204,7 @@ impl Solver {
// TODO(phase-b): store the constraint inside reason_data; PhpMixed needs to
// accept a `dyn ConstraintInterface` wrapper.
reason_data.insert("constraint".to_string(), PhpMixed::Null);
- problem.add_rule(Rule::generic(GenericRule::new(
+ problem.add_rule(Box::new(GenericRule::new(
Vec::new(),
PhpMixed::Int(rule::RULE_ROOT_REQUIRE),
PhpMixed::Array(
@@ -213,7 +213,7 @@ impl Solver {
.map(|(k, v)| (k, Box::new(v)))
.collect(),
),
- )));
+ )) as Box<dyn Rule>);
self.problems.push(problem);
}
}
@@ -229,11 +229,8 @@ impl Solver {
self.setup_fixed_map(request);
- self.io.write_error(
- PhpMixed::String("Generating rules".to_string()),
- true,
- crate::io::io_interface::DEBUG,
- );
+ self.io
+ .write_error3("Generating rules", true, crate::io::io_interface::DEBUG);
let mut rule_set_generator =
RuleSetGenerator::new(self.policy.clone_box(), self.pool.clone());
self.rules =
@@ -253,23 +250,20 @@ impl Solver {
// make decisions based on root require/fix assertions
self.make_assertion_rule_decisions()?;
- self.io.write_error(
- PhpMixed::String("Resolving dependencies through SAT".to_string()),
+ self.io.write_error3(
+ "Resolving dependencies through SAT",
true,
crate::io::io_interface::DEBUG,
);
let before = microtime(true);
self.run_sat()?;
- self.io.write_error(
- PhpMixed::String("".to_string()),
- true,
- crate::io::io_interface::DEBUG,
- );
- self.io.write_error(
- PhpMixed::String(sprintf(
+ self.io
+ .write_error3("", true, crate::io::io_interface::DEBUG);
+ self.io.write_error3(
+ &sprintf(
"Dependency resolution completed in %.3f seconds",
&[PhpMixed::Float(microtime(true) - before)],
- )),
+ ),
true,
crate::io::io_interface::VERBOSE,
);
@@ -767,8 +761,8 @@ impl Solver {
let mut rules_count = self.rules.count();
let mut pass = 1_i64;
- self.io.write_error(
- PhpMixed::String("Looking at all rules.".to_string()),
+ self.io.write_error3(
+ "Looking at all rules.",
true,
crate::io::io_interface::DEBUG,
);
@@ -777,20 +771,20 @@ impl Solver {
while n < rules_count {
if i == rules_count {
if 1 == pass {
- self.io.write_error(
- PhpMixed::String(format!(
+ self.io.write_error3(
+ &format!(
"Something's changed, looking at all rules again (pass #{})",
pass
- )),
+ ),
false,
crate::io::io_interface::DEBUG,
);
} else {
- self.io.overwrite_error(
- PhpMixed::String(format!(
+ self.io.overwrite_error4(
+ &format!(
"Something's changed, looking at all rules again (pass #{})",
pass
- )),
+ ),
false,
None,
crate::io::io_interface::DEBUG,
@@ -801,7 +795,7 @@ impl Solver {
pass += 1;
}
- let rule = self.rules.rule_by_id(i).clone();
+ let rule = self.rules.rule_by_id(i).clone_box();
let literals = rule.get_literals().clone();
if rule.is_disabled() {
diff --git a/crates/shirabe/src/dependency_resolver/transaction.rs b/crates/shirabe/src/dependency_resolver/transaction.rs
index 4ab5c6b..8c4595f 100644
--- a/crates/shirabe/src/dependency_resolver/transaction.rs
+++ b/crates/shirabe/src/dependency_resolver/transaction.rs
@@ -37,6 +37,17 @@ pub struct Transaction {
pub(crate) result_packages_by_name: IndexMap<String, Vec<Box<dyn PackageInterface>>>,
}
+impl Default for Transaction {
+ fn default() -> Self {
+ Self {
+ operations: vec![],
+ present_packages: vec![],
+ result_package_map: IndexMap::new(),
+ result_packages_by_name: IndexMap::new(),
+ }
+ }
+}
+
impl Transaction {
/// @param PackageInterface[] $presentPackages
/// @param PackageInterface[] $resultPackages
@@ -67,12 +78,8 @@ impl Transaction {
let _package_sort = |a: &dyn PackageInterface, b: &dyn PackageInterface| -> i64 {
// sort alias packages by the same name behind their non alias version
if a.get_name() == b.get_name() {
- let a_is_alias = (a.as_any() as &dyn Any)
- .downcast_ref::<AliasPackage>()
- .is_some();
- let b_is_alias = (b.as_any() as &dyn Any)
- .downcast_ref::<AliasPackage>()
- .is_some();
+ let a_is_alias = a.as_any().downcast_ref::<AliasPackage>().is_some();
+ let b_is_alias = b.as_any().downcast_ref::<AliasPackage>().is_some();
if a_is_alias != b_is_alias {
return if a_is_alias { -1 } else { 1 };
}
@@ -119,10 +126,7 @@ impl Transaction {
let mut present_alias_map: IndexMap<String, Box<dyn PackageInterface>> = IndexMap::new();
let mut remove_alias_map: IndexMap<String, Box<dyn PackageInterface>> = IndexMap::new();
for package in &self.present_packages {
- if (package.as_any() as &dyn Any)
- .downcast_ref::<AliasPackage>()
- .is_some()
- {
+ if package.as_any().downcast_ref::<AliasPackage>().is_some() {
let key = format!("{}::{}", package.get_name(), package.get_version());
present_alias_map.insert(key.clone(), package.clone_package_box());
remove_alias_map.insert(key, package.clone_package_box());
@@ -151,7 +155,7 @@ impl Transaction {
visited.insert(spl_object_hash(package.as_ref()), true);
stack.push(package.clone_package_box());
- if let Some(alias) = (package.as_any() as &dyn Any).downcast_ref::<AliasPackage>() {
+ if let Some(alias) = package.as_any().downcast_ref::<AliasPackage>() {
stack.push(alias.get_alias_of().clone_package_box());
} else {
for link in package.get_requires().values() {
@@ -165,10 +169,7 @@ impl Transaction {
} else if !processed.contains_key(&spl_object_hash(package.as_ref())) {
processed.insert(spl_object_hash(package.as_ref()), true);
- if (package.as_any() as &dyn Any)
- .downcast_ref::<AliasPackage>()
- .is_some()
- {
+ if package.as_any().downcast_ref::<AliasPackage>().is_some() {
let alias_key = format!("{}::{}", package.get_name(), package.get_version());
if present_alias_map.contains_key(&alias_key) {
remove_alias_map.shift_remove(&alias_key);
@@ -308,12 +309,10 @@ impl Transaction {
let op = &operations[idx];
let package: Box<dyn PackageInterface> = if let Some(install_op) =
- (op.as_ref() as &dyn Any).downcast_ref::<InstallOperation>()
+ op.as_ref().as_any().downcast_ref::<InstallOperation>()
{
install_op.get_package().clone_package_box()
- } else if let Some(update_op) =
- (op.as_ref() as &dyn Any).downcast_ref::<UpdateOperation>()
- {
+ } else if let Some(update_op) = op.as_ref().as_any().downcast_ref::<UpdateOperation>() {
update_op.get_target_package().clone_package_box()
} else {
continue;
@@ -415,10 +414,14 @@ impl Transaction {
let mut uninst_ops: Vec<Box<dyn OperationInterface>> = vec![];
let mut to_remove: Vec<usize> = vec![];
for (idx, op) in operations.iter().enumerate() {
- let is_uninstall = (op.as_ref() as &dyn Any)
+ let is_uninstall = op
+ .as_ref()
+ .as_any()
.downcast_ref::<UninstallOperation>()
.is_some()
- || (op.as_ref() as &dyn Any)
+ || op
+ .as_ref()
+ .as_any()
.downcast_ref::<MarkAliasUninstalledOperation>()
.is_some();
if is_uninstall {