aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-07-25 12:16:25 +0900
committernsfisis <nsfisis@gmail.com>2026-07-25 12:16:25 +0900
commit42b5f9e321c918cef542c120ad21ba8a7339eb29 (patch)
tree39f2b5a3cb856de9068f72fb670d170c09a2438f /crates/shirabe
parentf93d9b49382c8f79fcea4f03361d50bda534bcc4 (diff)
downloadphp-shirabe-42b5f9e321c918cef542c120ad21ba8a7339eb29.tar.gz
php-shirabe-42b5f9e321c918cef542c120ad21ba8a7339eb29.tar.zst
php-shirabe-42b5f9e321c918cef542c120ad21ba8a7339eb29.zip
refactor(operation): replace OperationInterface with AnyOperation enum
Operations are only ever constructed by the dependency resolver, so a plugin has no way to inject an implementation of its own and the set is closed. Modelling it as an enum, like AnyPackage, removes the OperationInterface trait together with its two parallel downcast mechanisms (as_any() + downcast_ref, and as_*_operation()) and the get_package() default method that panicked on UpdateOperation. The PHP idiom `$op instanceof UpdateOperation ? getTargetPackage() : getPackage()`, written out at six call sites, becomes AnyOperation::get_target_package(). InstallationManager's three blocks that matched on the type string and then recovered the type with expect() collapse into exhaustive matches. SolverOperation keeps only its TYPE constant; the shared getOperationType()/__toString() implementations move to AnyOperation, which also drops the five Self::TYPE.to_string() allocations. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe')
-rw-r--r--crates/shirabe/src/command/create_project_command.rs2
-rw-r--r--crates/shirabe/src/command/reinstall_command.rs11
-rw-r--r--crates/shirabe/src/dependency_resolver/local_repo_transaction.rs4
-rw-r--r--crates/shirabe/src/dependency_resolver/lock_transaction.rs4
-rw-r--r--crates/shirabe/src/dependency_resolver/operation.rs4
-rw-r--r--crates/shirabe/src/dependency_resolver/operation/any_operation.rs92
-rw-r--r--crates/shirabe/src/dependency_resolver/operation/install_operation.rs29
-rw-r--r--crates/shirabe/src/dependency_resolver/operation/mark_alias_installed_operation.rs25
-rw-r--r--crates/shirabe/src/dependency_resolver/operation/mark_alias_uninstalled_operation.rs25
-rw-r--r--crates/shirabe/src/dependency_resolver/operation/operation_interface.rs31
-rw-r--r--crates/shirabe/src/dependency_resolver/operation/solver_operation.rs12
-rw-r--r--crates/shirabe/src/dependency_resolver/operation/uninstall_operation.rs29
-rw-r--r--crates/shirabe/src/dependency_resolver/operation/update_operation.rs33
-rw-r--r--crates/shirabe/src/dependency_resolver/transaction.rs80
-rw-r--r--crates/shirabe/src/event_dispatcher/event_dispatcher.rs6
-rw-r--r--crates/shirabe/src/installer.rs54
-rw-r--r--crates/shirabe/src/installer/installation_manager.rs196
-rw-r--r--crates/shirabe/src/installer/package_event.rs16
-rw-r--r--crates/shirabe/tests/dependency_resolver/solver_test.rs14
-rw-r--r--crates/shirabe/tests/dependency_resolver/transaction_test.rs7
-rw-r--r--crates/shirabe/tests/repository/filesystem_repository_test.rs4
21 files changed, 275 insertions, 403 deletions
diff --git a/crates/shirabe/src/command/create_project_command.rs b/crates/shirabe/src/command/create_project_command.rs
index 8ea4f07f..fdc01391 100644
--- a/crates/shirabe/src/command/create_project_command.rs
+++ b/crates/shirabe/src/command/create_project_command.rs
@@ -1002,7 +1002,7 @@ impl CreateProjectCommand {
let mut installed_repo = InstalledArrayRepository::new()?;
im.execute(
&mut installed_repo,
- vec![std::rc::Rc::new(InstallOperation::new(package.clone()))],
+ vec![InstallOperation::new(package.clone()).into()],
true,
true,
false,
diff --git a/crates/shirabe/src/command/reinstall_command.rs b/crates/shirabe/src/command/reinstall_command.rs
index c2c3ab18..bf10aeed 100644
--- a/crates/shirabe/src/command/reinstall_command.rs
+++ b/crates/shirabe/src/command/reinstall_command.rs
@@ -6,8 +6,7 @@ use crate::command::base_command::base_command_initialize;
use crate::console::input::InputArgument;
use crate::console::input::InputOption;
use crate::dependency_resolver::Transaction;
-use crate::dependency_resolver::operation::InstallOperation;
-use crate::dependency_resolver::operation::OperationInterface;
+use crate::dependency_resolver::operation::AnyOperation;
use crate::dependency_resolver::operation::UninstallOperation;
use crate::io::IOInterfaceImmutable;
use crate::package::base_package;
@@ -175,7 +174,7 @@ impl Command for ReinstallCommand {
let mut install_order = indexmap::IndexMap::new();
for (index, op) in install_operations.iter().enumerate() {
- if let Some(install_op) = op.as_any().downcast_ref::<InstallOperation>()
+ if let AnyOperation::Install(install_op) = op
&& install_op.get_package().as_alias().is_none()
{
install_order.insert(install_op.get_package().get_name(), index);
@@ -241,10 +240,8 @@ impl Command for ReinstallCommand {
indexmap::IndexMap::new(),
);
- let uninstall_operations: Vec<std::rc::Rc<dyn OperationInterface>> = uninstall_operations
- .into_iter()
- .map(|op| std::rc::Rc::new(op) as std::rc::Rc<dyn OperationInterface>)
- .collect();
+ let uninstall_operations: Vec<AnyOperation> =
+ uninstall_operations.into_iter().map(Into::into).collect();
{
let mut local_repo_ref = local_repo.borrow_mut();
let repo = local_repo_ref
diff --git a/crates/shirabe/src/dependency_resolver/local_repo_transaction.rs b/crates/shirabe/src/dependency_resolver/local_repo_transaction.rs
index e592741e..a3443b93 100644
--- a/crates/shirabe/src/dependency_resolver/local_repo_transaction.rs
+++ b/crates/shirabe/src/dependency_resolver/local_repo_transaction.rs
@@ -1,7 +1,7 @@
//! ref: composer/src/Composer/DependencyResolver/LocalRepoTransaction.php
use super::Transaction;
-use crate::dependency_resolver::operation::OperationInterface;
+use crate::dependency_resolver::operation::AnyOperation;
use crate::repository::InstalledRepositoryInterface;
use crate::repository::RepositoryInterface;
@@ -23,7 +23,7 @@ impl LocalRepoTransaction {
})
}
- pub fn get_operations(&self) -> &Vec<std::rc::Rc<dyn OperationInterface>> {
+ pub fn get_operations(&self) -> &Vec<AnyOperation> {
self.inner.get_operations()
}
diff --git a/crates/shirabe/src/dependency_resolver/lock_transaction.rs b/crates/shirabe/src/dependency_resolver/lock_transaction.rs
index d78db851..a9086983 100644
--- a/crates/shirabe/src/dependency_resolver/lock_transaction.rs
+++ b/crates/shirabe/src/dependency_resolver/lock_transaction.rs
@@ -235,9 +235,7 @@ impl LockTransaction {
used_aliases
}
- pub fn get_operations(
- &self,
- ) -> &Vec<std::rc::Rc<dyn crate::dependency_resolver::operation::OperationInterface>> {
+ pub fn get_operations(&self) -> &Vec<crate::dependency_resolver::operation::AnyOperation> {
self.inner.get_operations()
}
}
diff --git a/crates/shirabe/src/dependency_resolver/operation.rs b/crates/shirabe/src/dependency_resolver/operation.rs
index 720c5a0a..b0db094a 100644
--- a/crates/shirabe/src/dependency_resolver/operation.rs
+++ b/crates/shirabe/src/dependency_resolver/operation.rs
@@ -1,15 +1,15 @@
+pub mod any_operation;
pub mod install_operation;
pub mod mark_alias_installed_operation;
pub mod mark_alias_uninstalled_operation;
-pub mod operation_interface;
pub mod solver_operation;
pub mod uninstall_operation;
pub mod update_operation;
+pub use any_operation::*;
pub use install_operation::*;
pub use mark_alias_installed_operation::*;
pub use mark_alias_uninstalled_operation::*;
-pub use operation_interface::*;
pub use solver_operation::*;
pub use uninstall_operation::*;
pub use update_operation::*;
diff --git a/crates/shirabe/src/dependency_resolver/operation/any_operation.rs b/crates/shirabe/src/dependency_resolver/operation/any_operation.rs
new file mode 100644
index 00000000..6675b280
--- /dev/null
+++ b/crates/shirabe/src/dependency_resolver/operation/any_operation.rs
@@ -0,0 +1,92 @@
+//! ref: composer/src/Composer/DependencyResolver/Operation/OperationInterface.php
+//!
+//! PHP's `OperationInterface` is not ported as a trait. Operations are only ever constructed by the
+//! dependency resolver, so a plugin has no way to inject an implementation of its own and the set is
+//! closed. The shared implementations PHP puts on `SolverOperation` (`getOperationType()`,
+//! `__toString()`) live here.
+
+use crate::dependency_resolver::operation::{
+ InstallOperation, MarkAliasInstalledOperation, MarkAliasUninstalledOperation, SolverOperation,
+ UninstallOperation, UpdateOperation,
+};
+use crate::package::PackageInterfaceHandle;
+
+/// Any solver operation.
+#[derive(Debug, Clone)]
+pub enum AnyOperation {
+ Install(InstallOperation),
+ Update(UpdateOperation),
+ Uninstall(UninstallOperation),
+ MarkAliasInstalled(MarkAliasInstalledOperation),
+ MarkAliasUninstalled(MarkAliasUninstalledOperation),
+}
+
+impl AnyOperation {
+ pub fn get_operation_type(&self) -> &'static str {
+ match self {
+ Self::Install(_) => InstallOperation::TYPE,
+ Self::Update(_) => UpdateOperation::TYPE,
+ Self::Uninstall(_) => UninstallOperation::TYPE,
+ Self::MarkAliasInstalled(_) => MarkAliasInstalledOperation::TYPE,
+ Self::MarkAliasUninstalled(_) => MarkAliasUninstalledOperation::TYPE,
+ }
+ }
+
+ pub fn show(&self, lock: bool) -> String {
+ match self {
+ Self::Install(op) => op.show(lock),
+ Self::Update(op) => op.show(lock),
+ Self::Uninstall(op) => op.show(lock),
+ Self::MarkAliasInstalled(op) => op.show(lock),
+ Self::MarkAliasUninstalled(op) => op.show(lock),
+ }
+ }
+
+ /// The package the operation results in. PHP spells this out at every call site as
+ /// `$op instanceof UpdateOperation ? $op->getTargetPackage() : $op->getPackage()`.
+ pub fn get_target_package(&self) -> PackageInterfaceHandle {
+ match self {
+ Self::Install(op) => op.get_package(),
+ Self::Update(op) => op.get_target_package(),
+ Self::Uninstall(op) => op.get_package(),
+ Self::MarkAliasInstalled(op) => op.get_package().into(),
+ Self::MarkAliasUninstalled(op) => op.get_package().into(),
+ }
+ }
+}
+
+impl std::fmt::Display for AnyOperation {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{}", self.show(false))
+ }
+}
+
+impl From<InstallOperation> for AnyOperation {
+ fn from(op: InstallOperation) -> Self {
+ Self::Install(op)
+ }
+}
+
+impl From<UpdateOperation> for AnyOperation {
+ fn from(op: UpdateOperation) -> Self {
+ Self::Update(op)
+ }
+}
+
+impl From<UninstallOperation> for AnyOperation {
+ fn from(op: UninstallOperation) -> Self {
+ Self::Uninstall(op)
+ }
+}
+
+impl From<MarkAliasInstalledOperation> for AnyOperation {
+ fn from(op: MarkAliasInstalledOperation) -> Self {
+ Self::MarkAliasInstalled(op)
+ }
+}
+
+impl From<MarkAliasUninstalledOperation> for AnyOperation {
+ fn from(op: MarkAliasUninstalledOperation) -> Self {
+ Self::MarkAliasUninstalled(op)
+ }
+}
diff --git a/crates/shirabe/src/dependency_resolver/operation/install_operation.rs b/crates/shirabe/src/dependency_resolver/operation/install_operation.rs
index ef492393..05349c2d 100644
--- a/crates/shirabe/src/dependency_resolver/operation/install_operation.rs
+++ b/crates/shirabe/src/dependency_resolver/operation/install_operation.rs
@@ -1,10 +1,9 @@
//! ref: composer/src/Composer/DependencyResolver/Operation/InstallOperation.php
-use crate::dependency_resolver::operation::OperationInterface;
use crate::dependency_resolver::operation::SolverOperation;
use crate::package::PackageInterfaceHandle;
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub struct InstallOperation {
pub(crate) package: PackageInterfaceHandle,
}
@@ -18,6 +17,10 @@ impl InstallOperation {
self.package.clone()
}
+ pub fn show(&self, lock: bool) -> String {
+ Self::format(self.package.clone(), lock)
+ }
+
pub fn format(package: PackageInterfaceHandle, lock: bool) -> String {
format!(
"{}<info>{}</info> (<comment>{}</comment>)",
@@ -32,28 +35,6 @@ impl SolverOperation for InstallOperation {
const TYPE: &'static str = "install";
}
-impl OperationInterface for InstallOperation {
- fn as_any(&self) -> &dyn std::any::Any {
- self
- }
-
- fn get_operation_type(&self) -> String {
- Self::TYPE.to_string()
- }
-
- fn show(&self, lock: bool) -> String {
- Self::format(self.package.clone(), lock)
- }
-
- fn as_install_operation(&self) -> Option<&InstallOperation> {
- Some(self)
- }
-
- fn get_package(&self) -> PackageInterfaceHandle {
- self.package.clone()
- }
-}
-
impl std::fmt::Display for InstallOperation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.show(false))
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 28bf511a..72066204 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
@@ -1,10 +1,9 @@
//! ref: composer/src/Composer/DependencyResolver/Operation/MarkAliasInstalledOperation.php
-use crate::dependency_resolver::operation::OperationInterface;
use crate::dependency_resolver::operation::SolverOperation;
use crate::package::AliasPackageHandle;
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub struct MarkAliasInstalledOperation {
pub(crate) package: AliasPackageHandle,
}
@@ -17,22 +16,8 @@ impl MarkAliasInstalledOperation {
pub fn get_package(&self) -> AliasPackageHandle {
self.package.clone()
}
-}
-
-impl SolverOperation for MarkAliasInstalledOperation {
- const TYPE: &'static str = "markAliasInstalled";
-}
-
-impl OperationInterface for MarkAliasInstalledOperation {
- fn as_any(&self) -> &dyn std::any::Any {
- self
- }
- fn get_operation_type(&self) -> String {
- Self::TYPE.to_string()
- }
-
- fn show(&self, _lock: bool) -> String {
+ pub fn show(&self, _lock: bool) -> String {
format!(
"Marking <info>{}</info> (<comment>{}</comment>) as installed, alias of <info>{}</info> (<comment>{}</comment>)",
self.package.get_pretty_name(),
@@ -44,10 +29,10 @@ impl OperationInterface for MarkAliasInstalledOperation {
.get_full_pretty_version(true, crate::package::DisplayMode::SourceRefIfDev),
)
}
+}
- fn get_package(&self) -> crate::package::PackageInterfaceHandle {
- self.package.clone().into()
- }
+impl SolverOperation for MarkAliasInstalledOperation {
+ const TYPE: &'static str = "markAliasInstalled";
}
impl std::fmt::Display for MarkAliasInstalledOperation {
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 3c0de332..4e4000df 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
@@ -1,10 +1,9 @@
//! ref: composer/src/Composer/DependencyResolver/Operation/MarkAliasUninstalledOperation.php
-use crate::dependency_resolver::operation::OperationInterface;
use crate::dependency_resolver::operation::SolverOperation;
use crate::package::AliasPackageHandle;
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub struct MarkAliasUninstalledOperation {
pub(crate) package: AliasPackageHandle,
}
@@ -17,22 +16,8 @@ impl MarkAliasUninstalledOperation {
pub fn get_package(&self) -> AliasPackageHandle {
self.package.clone()
}
-}
-
-impl SolverOperation for MarkAliasUninstalledOperation {
- const TYPE: &'static str = "markAliasUninstalled";
-}
-
-impl OperationInterface for MarkAliasUninstalledOperation {
- fn as_any(&self) -> &dyn std::any::Any {
- self
- }
- fn get_operation_type(&self) -> String {
- Self::TYPE.to_string()
- }
-
- fn show(&self, _lock: bool) -> String {
+ pub fn show(&self, _lock: bool) -> String {
format!(
"Marking <info>{}</info> (<comment>{}</comment>) as uninstalled, alias of <info>{}</info> (<comment>{}</comment>)",
self.package.get_pretty_name(),
@@ -44,10 +29,10 @@ impl OperationInterface for MarkAliasUninstalledOperation {
.get_full_pretty_version(true, crate::package::DisplayMode::SourceRefIfDev),
)
}
+}
- fn get_package(&self) -> crate::package::PackageInterfaceHandle {
- self.package.clone().into()
- }
+impl SolverOperation for MarkAliasUninstalledOperation {
+ const TYPE: &'static str = "markAliasUninstalled";
}
impl std::fmt::Display for MarkAliasUninstalledOperation {
diff --git a/crates/shirabe/src/dependency_resolver/operation/operation_interface.rs b/crates/shirabe/src/dependency_resolver/operation/operation_interface.rs
deleted file mode 100644
index 30ed8eb5..00000000
--- a/crates/shirabe/src/dependency_resolver/operation/operation_interface.rs
+++ /dev/null
@@ -1,31 +0,0 @@
-//! ref: composer/src/Composer/DependencyResolver/Operation/OperationInterface.php
-
-use crate::dependency_resolver::operation::InstallOperation;
-use crate::dependency_resolver::operation::UninstallOperation;
-use crate::dependency_resolver::operation::UpdateOperation;
-
-pub trait OperationInterface: std::fmt::Display + std::fmt::Debug {
- fn as_any(&self) -> &dyn std::any::Any;
-
- fn get_operation_type(&self) -> String;
-
- fn show(&self, lock: bool) -> String;
-
- fn as_install_operation(&self) -> Option<&InstallOperation> {
- None
- }
-
- fn as_update_operation(&self) -> Option<&UpdateOperation> {
- None
- }
-
- fn as_uninstall_operation(&self) -> Option<&UninstallOperation> {
- None
- }
-
- /// PHP duck-typed accessor. Only InstallOperation/UninstallOperation/MarkAlias*Operation
- /// expose this; UpdateOperation has getInitialPackage()/getTargetPackage() instead.
- fn get_package(&self) -> crate::package::PackageInterfaceHandle {
- todo!("get_package is not available on this operation type")
- }
-}
diff --git a/crates/shirabe/src/dependency_resolver/operation/solver_operation.rs b/crates/shirabe/src/dependency_resolver/operation/solver_operation.rs
index 2710ec50..eb9c6315 100644
--- a/crates/shirabe/src/dependency_resolver/operation/solver_operation.rs
+++ b/crates/shirabe/src/dependency_resolver/operation/solver_operation.rs
@@ -1,11 +1,9 @@
//! ref: composer/src/Composer/DependencyResolver/Operation/SolverOperation.php
-use crate::dependency_resolver::operation::OperationInterface;
-
-pub trait SolverOperation: OperationInterface {
+/// PHP's abstract `SolverOperation` carries the per-class `TYPE` constant and the
+/// `getOperationType()` / `__toString()` implementations shared by every operation. Only the
+/// constant remains here; the shared implementations live on
+/// [`AnyOperation`](crate::dependency_resolver::operation::AnyOperation).
+pub trait SolverOperation {
const TYPE: &'static str;
-
- fn get_operation_type(&self) -> &str {
- Self::TYPE
- }
}
diff --git a/crates/shirabe/src/dependency_resolver/operation/uninstall_operation.rs b/crates/shirabe/src/dependency_resolver/operation/uninstall_operation.rs
index d2dd6651..2fd35af5 100644
--- a/crates/shirabe/src/dependency_resolver/operation/uninstall_operation.rs
+++ b/crates/shirabe/src/dependency_resolver/operation/uninstall_operation.rs
@@ -1,10 +1,9 @@
//! ref: composer/src/Composer/DependencyResolver/Operation/UninstallOperation.php
-use crate::dependency_resolver::operation::OperationInterface;
use crate::dependency_resolver::operation::SolverOperation;
use crate::package::PackageInterfaceHandle;
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub struct UninstallOperation {
pub(crate) package: PackageInterfaceHandle,
}
@@ -18,6 +17,10 @@ impl UninstallOperation {
self.package.clone()
}
+ pub fn show(&self, lock: bool) -> String {
+ Self::format(self.package.clone(), lock)
+ }
+
pub fn format(package: PackageInterfaceHandle, _lock: bool) -> String {
format!(
"Removing <info>{}</info> (<comment>{}</comment>)",
@@ -31,28 +34,6 @@ impl SolverOperation for UninstallOperation {
const TYPE: &'static str = "uninstall";
}
-impl OperationInterface for UninstallOperation {
- fn as_any(&self) -> &dyn std::any::Any {
- self
- }
-
- fn get_operation_type(&self) -> String {
- Self::TYPE.to_string()
- }
-
- fn show(&self, lock: bool) -> String {
- Self::format(self.package.clone(), lock)
- }
-
- fn as_uninstall_operation(&self) -> Option<&UninstallOperation> {
- Some(self)
- }
-
- fn get_package(&self) -> PackageInterfaceHandle {
- self.package.clone()
- }
-}
-
impl std::fmt::Display for UninstallOperation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.show(false))
diff --git a/crates/shirabe/src/dependency_resolver/operation/update_operation.rs b/crates/shirabe/src/dependency_resolver/operation/update_operation.rs
index 76b17189..a06a9cdc 100644
--- a/crates/shirabe/src/dependency_resolver/operation/update_operation.rs
+++ b/crates/shirabe/src/dependency_resolver/operation/update_operation.rs
@@ -1,11 +1,10 @@
//! ref: composer/src/Composer/DependencyResolver/Operation/UpdateOperation.php
-use crate::dependency_resolver::operation::OperationInterface;
use crate::dependency_resolver::operation::SolverOperation;
use crate::package::PackageInterfaceHandle;
use crate::package::version::VersionParser;
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub struct UpdateOperation {
pub(crate) initial_package: PackageInterfaceHandle,
pub(crate) target_package: PackageInterfaceHandle,
@@ -27,6 +26,14 @@ impl UpdateOperation {
self.target_package.clone()
}
+ pub fn show(&self, lock: bool) -> String {
+ Self::format(
+ self.initial_package.clone(),
+ self.target_package.clone(),
+ lock,
+ )
+ }
+
pub fn format(
initial_package: PackageInterfaceHandle,
target_package: PackageInterfaceHandle,
@@ -78,28 +85,6 @@ impl SolverOperation for UpdateOperation {
const TYPE: &'static str = "update";
}
-impl OperationInterface for UpdateOperation {
- fn as_any(&self) -> &dyn std::any::Any {
- self
- }
-
- fn get_operation_type(&self) -> String {
- Self::TYPE.to_string()
- }
-
- fn show(&self, lock: bool) -> String {
- Self::format(
- self.initial_package.clone(),
- self.target_package.clone(),
- lock,
- )
- }
-
- fn as_update_operation(&self) -> Option<&UpdateOperation> {
- Some(self)
- }
-}
-
impl std::fmt::Display for UpdateOperation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.show(false))
diff --git a/crates/shirabe/src/dependency_resolver/transaction.rs b/crates/shirabe/src/dependency_resolver/transaction.rs
index 07564ed0..4abe85d4 100644
--- a/crates/shirabe/src/dependency_resolver/transaction.rs
+++ b/crates/shirabe/src/dependency_resolver/transaction.rs
@@ -1,9 +1,9 @@
//! ref: composer/src/Composer/DependencyResolver/Transaction.php
+use crate::dependency_resolver::operation::AnyOperation;
use crate::dependency_resolver::operation::InstallOperation;
use crate::dependency_resolver::operation::MarkAliasInstalledOperation;
use crate::dependency_resolver::operation::MarkAliasUninstalledOperation;
-use crate::dependency_resolver::operation::OperationInterface;
use crate::dependency_resolver::operation::UninstallOperation;
use crate::dependency_resolver::operation::UpdateOperation;
use crate::package::AliasPackageHandle;
@@ -21,7 +21,7 @@ use shirabe_php_shim::{
#[derive(Debug, Clone)]
pub struct Transaction {
/// @var OperationInterface[]
- pub(crate) operations: Vec<std::rc::Rc<dyn OperationInterface>>,
+ pub(crate) operations: Vec<AnyOperation>,
/// Packages present at the beginning of the transaction
/// @var PackageInterface[]
@@ -64,7 +64,7 @@ impl Transaction {
this
}
- pub fn get_operations(&self) -> &Vec<std::rc::Rc<dyn OperationInterface>> {
+ pub fn get_operations(&self) -> &Vec<AnyOperation> {
&self.operations
}
@@ -108,8 +108,8 @@ impl Transaction {
}
/// @return OperationInterface[]
- pub(crate) fn calculate_operations(&mut self) -> Vec<std::rc::Rc<dyn OperationInterface>> {
- let mut operations: Vec<std::rc::Rc<dyn OperationInterface>> = vec![];
+ pub(crate) fn calculate_operations(&mut self) -> Vec<AnyOperation> {
+ let mut operations: Vec<AnyOperation> = vec![];
let mut present_package_map: IndexMap<String, PackageInterfaceHandle> = IndexMap::new();
let mut remove_map: IndexMap<String, PackageInterfaceHandle> = IndexMap::new();
@@ -163,7 +163,7 @@ impl Transaction {
if present_alias_map.contains(&alias_key) {
remove_alias_map.shift_remove(&alias_key);
} else {
- operations.push(std::rc::Rc::new(MarkAliasInstalledOperation::new(alias)));
+ operations.push(MarkAliasInstalledOperation::new(alias).into());
}
} else if let Some(source) = present_package_map.get(&package.get_name()).cloned() {
// do we need to update?
@@ -187,14 +187,12 @@ impl Transaction {
|| package.get_source_reference() != present.get_source_reference()
|| abandoned_or_replacement_changed
{
- operations.push(std::rc::Rc::new(UpdateOperation::new(
- source.clone(),
- package.clone(),
- )));
+ operations
+ .push(UpdateOperation::new(source.clone(), package.clone()).into());
}
remove_map.shift_remove(&package.get_name());
} else {
- operations.push(std::rc::Rc::new(InstallOperation::new(package.clone())));
+ operations.push(InstallOperation::new(package.clone()).into());
remove_map.shift_remove(&package.get_name());
}
}
@@ -202,16 +200,10 @@ impl Transaction {
for (_name, package) in remove_map {
// PHP: array_unshift($operations, new Operation\UninstallOperation($package));
- array_unshift(
- &mut operations,
- std::rc::Rc::new(UninstallOperation::new(package))
- as std::rc::Rc<dyn OperationInterface>,
- );
+ array_unshift(&mut operations, UninstallOperation::new(package).into());
}
for (_name_version, package) in remove_alias_map {
- operations.push(std::rc::Rc::new(MarkAliasUninstalledOperation::new(
- package,
- )));
+ operations.push(MarkAliasUninstalledOperation::new(package).into());
}
let operations = self.move_plugins_to_front(operations);
@@ -279,29 +271,22 @@ impl Transaction {
///
/// @param OperationInterface[] $operations
/// @return OperationInterface[] reordered operation list
- fn move_plugins_to_front(
- &self,
- mut operations: Vec<std::rc::Rc<dyn OperationInterface>>,
- ) -> Vec<std::rc::Rc<dyn OperationInterface>> {
- let mut dl_modifying_plugins_no_deps: Vec<std::rc::Rc<dyn OperationInterface>> = vec![];
- let mut dl_modifying_plugins_with_deps: Vec<std::rc::Rc<dyn OperationInterface>> = vec![];
+ fn move_plugins_to_front(&self, mut operations: Vec<AnyOperation>) -> Vec<AnyOperation> {
+ let mut dl_modifying_plugins_no_deps: Vec<AnyOperation> = vec![];
+ let mut dl_modifying_plugins_with_deps: Vec<AnyOperation> = vec![];
let mut dl_modifying_plugin_requires: Vec<String> = vec![];
- let mut plugins_no_deps: Vec<std::rc::Rc<dyn OperationInterface>> = vec![];
- let mut plugins_with_deps: Vec<std::rc::Rc<dyn OperationInterface>> = vec![];
+ let mut plugins_no_deps: Vec<AnyOperation> = vec![];
+ let mut plugins_with_deps: Vec<AnyOperation> = vec![];
let mut plugin_requires: Vec<String> = vec![];
let mut to_remove: Vec<usize> = vec![];
for idx in (0..operations.len()).rev() {
let op = &operations[idx];
- let package: PackageInterfaceHandle = if let Some(install_op) =
- op.as_ref().as_any().downcast_ref::<InstallOperation>()
- {
- install_op.get_package().clone()
- } else if let Some(update_op) = op.as_ref().as_any().downcast_ref::<UpdateOperation>() {
- update_op.get_target_package().clone()
- } else {
- continue;
+ let package: PackageInterfaceHandle = match op {
+ AnyOperation::Install(install_op) => install_op.get_package(),
+ AnyOperation::Update(update_op) => update_op.get_target_package(),
+ _ => continue,
};
let extra = package.get_extra();
@@ -373,7 +358,7 @@ impl Transaction {
}
// PHP: array_merge($dlModifyingPluginsNoDeps, $dlModifyingPluginsWithDeps, $pluginsNoDeps, $pluginsWithDeps, $operations)
- let mut result: Vec<std::rc::Rc<dyn OperationInterface>> = vec![];
+ let mut result: Vec<AnyOperation> = vec![];
result.extend(dl_modifying_plugins_no_deps);
result.extend(dl_modifying_plugins_with_deps);
result.extend(plugins_no_deps);
@@ -387,23 +372,14 @@ impl Transaction {
///
/// @param OperationInterface[] $operations
/// @return OperationInterface[] reordered operation list
- fn move_uninstalls_to_front(
- &self,
- mut operations: Vec<std::rc::Rc<dyn OperationInterface>>,
- ) -> Vec<std::rc::Rc<dyn OperationInterface>> {
- let mut uninst_ops: Vec<std::rc::Rc<dyn OperationInterface>> = vec![];
+ fn move_uninstalls_to_front(&self, mut operations: Vec<AnyOperation>) -> Vec<AnyOperation> {
+ let mut uninst_ops: Vec<AnyOperation> = vec![];
let mut to_remove: Vec<usize> = vec![];
for (idx, op) in operations.iter().enumerate() {
- let is_uninstall = op
- .as_ref()
- .as_any()
- .downcast_ref::<UninstallOperation>()
- .is_some()
- || op
- .as_ref()
- .as_any()
- .downcast_ref::<MarkAliasUninstalledOperation>()
- .is_some();
+ let is_uninstall = matches!(
+ op,
+ AnyOperation::Uninstall(_) | AnyOperation::MarkAliasUninstalled(_)
+ );
if is_uninstall {
uninst_ops.push(op.clone());
to_remove.push(idx);
@@ -415,7 +391,7 @@ impl Transaction {
operations.remove(idx);
}
- let mut result: Vec<std::rc::Rc<dyn OperationInterface>> = vec![];
+ let mut result: Vec<AnyOperation> = vec![];
result.extend(uninst_ops);
result.extend(operations);
result
diff --git a/crates/shirabe/src/event_dispatcher/event_dispatcher.rs b/crates/shirabe/src/event_dispatcher/event_dispatcher.rs
index 1f1d9619..abc8aad8 100644
--- a/crates/shirabe/src/event_dispatcher/event_dispatcher.rs
+++ b/crates/shirabe/src/event_dispatcher/event_dispatcher.rs
@@ -4,7 +4,7 @@ use crate::autoload::ClassLoader;
use crate::composer::PartialComposerHandle;
use crate::composer::PartialComposerWeakHandle;
use crate::dependency_resolver::Transaction;
-use crate::dependency_resolver::operation::OperationInterface;
+use crate::dependency_resolver::operation::AnyOperation;
use crate::event_dispatcher::Event;
use crate::event_dispatcher::EventInterface;
use crate::event_dispatcher::EventSubscriberInterface;
@@ -205,8 +205,8 @@ impl EventDispatcher {
event_name: &str,
dev_mode: bool,
local_repo: Box<dyn RepositoryInterface>,
- operations: Vec<std::rc::Rc<dyn OperationInterface>>,
- operation: std::rc::Rc<dyn OperationInterface>,
+ operations: Vec<AnyOperation>,
+ operation: AnyOperation,
) -> anyhow::Result<i64> {
let composer = self.composer();
assert!(
diff --git a/crates/shirabe/src/installer.rs b/crates/shirabe/src/installer.rs
index cfe2432c..3cdb046b 100644
--- a/crates/shirabe/src/installer.rs
+++ b/crates/shirabe/src/installer.rs
@@ -55,7 +55,7 @@ use crate::dependency_resolver::Request;
use crate::dependency_resolver::SecurityAdvisoryPoolFilter;
use crate::dependency_resolver::Solver;
use crate::dependency_resolver::UpdateAllowTransitiveDeps;
-use crate::dependency_resolver::operation::OperationInterface;
+use crate::dependency_resolver::operation::AnyOperation;
use crate::downloader::DownloadManagerInterface;
use crate::downloader::TransportException;
use crate::event_dispatcher::EventDispatcherInterface;
@@ -754,14 +754,14 @@ impl Installer {
let platform_dev_reqs =
self.extract_platform_requirements(&self.package.get_dev_requires());
- let mut installs_updates: Vec<std::rc::Rc<dyn OperationInterface>> = vec![];
- let mut uninstalls: Vec<std::rc::Rc<dyn OperationInterface>> = vec![];
+ let mut installs_updates: Vec<AnyOperation> = vec![];
+ let mut uninstalls: Vec<AnyOperation> = vec![];
if !lock_transaction.get_operations().is_empty() {
let mut install_names: Vec<String> = vec![];
let mut update_names: Vec<String> = vec![];
let mut uninstall_names: Vec<String> = vec![];
for operation in lock_transaction.get_operations() {
- if let Some(io) = operation.as_install_operation() {
+ if let AnyOperation::Install(io) = operation {
installs_updates.push(operation.clone());
install_names.push(format!(
"{}:{}",
@@ -771,7 +771,7 @@ impl Installer {
crate::package::DisplayMode::SourceRefIfDev
)
));
- } else if let Some(uo) = operation.as_update_operation() {
+ } else if let AnyOperation::Update(uo) = operation {
// when mirrors/metadata from a package gets updated we do not want to list it as an
// update in the output as it is only an internal lock file metadata update
if self.update_mirrors
@@ -791,7 +791,7 @@ impl Installer {
crate::package::DisplayMode::SourceRefIfDev
)
));
- } else if let Some(uo) = operation.as_uninstall_operation() {
+ } else if let AnyOperation::Uninstall(uo) = operation {
uninstalls.push(operation.clone());
uninstall_names.push(uo.get_package().get_pretty_name().to_string());
}
@@ -837,29 +837,20 @@ impl Installer {
}
}
- let sort_by_name = |a: &std::rc::Rc<dyn OperationInterface>,
- b: &std::rc::Rc<dyn OperationInterface>|
- -> i64 {
- let a_name: String = if let Some(uo) = a.as_update_operation() {
- uo.get_target_package().get_name().to_string()
- } else {
- a.get_package().get_name().to_string()
- };
- let b_name: String = if let Some(uo) = b.as_update_operation() {
- uo.get_target_package().get_name().to_string()
- } else {
- b.get_package().get_name().to_string()
- };
- strcmp(&a_name, &b_name)
+ let sort_by_name = |a: &AnyOperation, b: &AnyOperation| -> i64 {
+ strcmp(
+ &a.get_target_package().get_name(),
+ &b.get_target_package().get_name(),
+ )
};
usort(&mut uninstalls, &sort_by_name);
usort(&mut installs_updates, &sort_by_name);
- let mut merged: Vec<std::rc::Rc<dyn OperationInterface>> = uninstalls;
+ let mut merged: Vec<AnyOperation> = uninstalls;
merged.extend(installs_updates);
for operation in &merged {
// collect suggestions
- if let Some(io) = operation.as_install_operation() {
+ if let AnyOperation::Install(io) = operation {
self.suggested_packages_reporter
.borrow_mut()
.add_suggestions_from_package(io.get_package());
@@ -872,17 +863,13 @@ impl Installer {
.get("lock")
.as_bool()
.unwrap_or(false)
- && (strpos(&operation.get_operation_type(), "Alias").is_none()
- || self.io.is_debug())
+ && (strpos(operation.get_operation_type(), "Alias").is_none() || self.io.is_debug())
{
let mut source_repo = String::new();
if self.io.is_very_verbose()
- && strpos(&operation.get_operation_type(), "Alias").is_none()
+ && strpos(operation.get_operation_type(), "Alias").is_none()
{
- let operation_pkg = match operation.as_update_operation() {
- Some(uo) => uo.get_target_package(),
- None => operation.get_package(),
- };
+ let operation_pkg = operation.get_target_package();
if let Some(repo) = operation_pkg.get_repository() {
source_repo = format!(" from {}", repo.get_repo_name());
}
@@ -1212,21 +1199,21 @@ impl Installer {
let mut updates: Vec<String> = vec![];
let mut uninstalls: Vec<String> = vec![];
for operation in local_repo_transaction.get_operations() {
- if let Some(io) = operation.as_install_operation() {
+ if let AnyOperation::Install(io) = operation {
installs.push(format!(
"{}:{}",
io.get_package().get_pretty_name(),
io.get_package()
.get_full_pretty_version(true, crate::package::DisplayMode::SourceRefIfDev)
));
- } else if let Some(uo) = operation.as_update_operation() {
+ } else if let AnyOperation::Update(uo) = operation {
updates.push(format!(
"{}:{}",
uo.get_target_package().get_pretty_name(),
uo.get_target_package()
.get_full_pretty_version(true, crate::package::DisplayMode::SourceRefIfDev)
));
- } else if let Some(uo) = operation.as_uninstall_operation() {
+ } else if let AnyOperation::Uninstall(uo) = operation {
uninstalls.push(uo.get_package().get_pretty_name().to_string());
}
}
@@ -1298,8 +1285,7 @@ impl Installer {
} else {
for operation in local_repo_transaction.get_operations() {
// output op, but alias op only in debug verbosity
- if strpos(&operation.get_operation_type(), "Alias").is_none() || self.io.is_debug()
- {
+ if strpos(operation.get_operation_type(), "Alias").is_none() || self.io.is_debug() {
self.io
.write_error(&format!(" - {}", operation.show(false)));
}
diff --git a/crates/shirabe/src/installer/installation_manager.rs b/crates/shirabe/src/installer/installation_manager.rs
index 2d60997c..4eb905ed 100644
--- a/crates/shirabe/src/installer/installation_manager.rs
+++ b/crates/shirabe/src/installer/installation_manager.rs
@@ -1,9 +1,9 @@
//! ref: composer/src/Composer/Installer/InstallationManager.php
+use crate::dependency_resolver::operation::AnyOperation;
use crate::dependency_resolver::operation::InstallOperation;
use crate::dependency_resolver::operation::MarkAliasInstalledOperation;
use crate::dependency_resolver::operation::MarkAliasUninstalledOperation;
-use crate::dependency_resolver::operation::OperationInterface;
use crate::dependency_resolver::operation::UninstallOperation;
use crate::dependency_resolver::operation::UpdateOperation;
use crate::downloader::FileDownloader;
@@ -240,7 +240,7 @@ impl InstallationManager {
pub fn execute(
&mut self,
repo: &mut dyn InstalledRepositoryInterface,
- operations: Vec<std::rc::Rc<dyn OperationInterface>>,
+ operations: Vec<AnyOperation>,
dev_mode: bool,
run_scripts: bool,
download_only: bool,
@@ -253,18 +253,16 @@ impl InstallationManager {
let _ = (dev_mode, run_scripts, download_only);
for operation in operations {
let trace = shirabe_php_shim::strip_tags(&operation.to_string());
- match operation.get_operation_type().as_str() {
- "install" => {
- let op = operation.as_install_operation().expect("install operation");
+ match operation {
+ AnyOperation::Install(op) => {
let package = op.get_package();
mock.installed.push(package.clone());
mock.trace.push(trace);
repo.add_package(PackageInterfaceHandle::dup(&package));
}
- "update" => {
- let op = operation.as_update_operation().expect("update operation");
- let initial = op.get_initial_package().clone();
- let target = op.get_target_package().clone();
+ AnyOperation::Update(op) => {
+ let initial = op.get_initial_package();
+ let target = op.get_target_package();
mock.updated.push((initial.clone(), target.clone()));
mock.trace.push(trace);
repo.remove_package(initial);
@@ -272,38 +270,26 @@ impl InstallationManager {
repo.add_package(PackageInterfaceHandle::dup(&target));
}
}
- "uninstall" => {
- let op = operation
- .as_uninstall_operation()
- .expect("uninstall operation");
+ AnyOperation::Uninstall(op) => {
let package = op.get_package();
mock.uninstalled.push(package.clone());
mock.trace.push(trace);
repo.remove_package(package);
}
- "markAliasInstalled" => {
- let op = operation
- .as_any()
- .downcast_ref::<MarkAliasInstalledOperation>()
- .expect("markAliasInstalled operation");
- let package = op.get_package();
- mock.installed.push(package.clone().into());
+ AnyOperation::MarkAliasInstalled(op) => {
+ let package: PackageInterfaceHandle = op.get_package().into();
+ mock.installed.push(package.clone());
mock.trace.push(trace);
- if !repo.has_package(package.clone().into()) {
- repo.add_package(PackageInterfaceHandle::dup(&package.into()));
+ if !repo.has_package(package.clone()) {
+ repo.add_package(PackageInterfaceHandle::dup(&package));
}
}
- "markAliasUninstalled" => {
- let op = operation
- .as_any()
- .downcast_ref::<MarkAliasUninstalledOperation>()
- .expect("markAliasUninstalled operation");
- let package = op.get_package();
- mock.uninstalled.push(package.clone().into());
+ AnyOperation::MarkAliasUninstalled(op) => {
+ let package: PackageInterfaceHandle = op.get_package().into();
+ mock.uninstalled.push(package.clone());
mock.trace.push(trace);
- repo.remove_package(package.into());
+ repo.remove_package(package);
}
- other => panic!("unknown operation type: {}", other),
}
}
return Ok(());
@@ -333,7 +319,7 @@ impl InstallationManager {
}),
);
- let all_operations: Vec<std::rc::Rc<dyn OperationInterface>> = operations.clone();
+ let all_operations: Vec<AnyOperation> = operations.clone();
// The concurrent operation chains share the repository; each chain borrows it only in
// synchronous sections, never across an await.
@@ -343,18 +329,15 @@ impl InstallationManager {
let result: anyhow::Result<()> = (|| -> anyhow::Result<()> {
// execute operations in batches to make sure download-modifying-plugins are installed
// before the other packages get downloaded
- let mut batches: Vec<IndexMap<i64, std::rc::Rc<dyn OperationInterface>>> = vec![];
- let mut batch: IndexMap<i64, std::rc::Rc<dyn OperationInterface>> = IndexMap::new();
+ let mut batches: Vec<IndexMap<i64, AnyOperation>> = vec![];
+ let mut batch: IndexMap<i64, AnyOperation> = IndexMap::new();
for (index, operation) in operations.into_iter().enumerate() {
let index = index as i64;
- let package: Option<PackageInterfaceHandle> =
- if let Some(update) = operation.as_update_operation() {
- Some(update.get_target_package())
- } else {
- operation
- .as_install_operation()
- .map(|install| install.get_package())
- };
+ let package: Option<PackageInterfaceHandle> = match &operation {
+ AnyOperation::Update(update) => Some(update.get_target_package()),
+ AnyOperation::Install(install) => Some(install.get_package()),
+ _ => None,
+ };
if let Some(package) = package
&& package.get_type() == "composer-plugin"
{
@@ -423,7 +406,7 @@ impl InstallationManager {
async fn download_and_execute_batch(
&self,
repo: &std::cell::RefCell<&mut dyn InstalledRepositoryInterface>,
- operations: IndexMap<i64, std::rc::Rc<dyn OperationInterface>>,
+ operations: IndexMap<i64, AnyOperation>,
cleanup_promises: &mut IndexMap<
i64,
Box<
@@ -435,7 +418,7 @@ impl InstallationManager {
dev_mode: bool,
run_scripts: bool,
download_only: bool,
- all_operations: Vec<std::rc::Rc<dyn OperationInterface>>,
+ all_operations: Vec<AnyOperation>,
) -> anyhow::Result<()> {
let mut promises: Vec<
std::pin::Pin<Box<dyn std::future::Future<Output = anyhow::Result<()>>>>,
@@ -445,24 +428,15 @@ impl InstallationManager {
let op_type = operation.get_operation_type();
// ignoring alias ops as they don't need to execute anything at this stage
- if !["update", "install", "uninstall"].contains(&op_type.as_str()) {
+ if !["update", "install", "uninstall"].contains(&op_type) {
continue;
}
- let package: PackageInterfaceHandle;
- let initial_package: Option<PackageInterfaceHandle>;
- if op_type == "update" {
- // @var UpdateOperation $operation
- let update_op = operation
- .as_update_operation()
- .expect("op_type == \"update\" implies UpdateOperation");
- package = update_op.get_target_package();
- initial_package = Some(update_op.get_initial_package());
- } else {
- // @var InstallOperation|MarkAliasInstalledOperation|MarkAliasUninstalledOperation|UninstallOperation $operation
- package = operation.get_package();
- initial_package = None;
- }
+ let package = operation.get_target_package();
+ let initial_package: Option<PackageInterfaceHandle> = match operation {
+ AnyOperation::Update(update_op) => Some(update_op.get_initial_package()),
+ _ => None,
+ };
let installer = self.get_installer(&package.get_type())?;
// PHP: $cleanupPromises[$index] = static function () use ($opType, $installer, $package, $initialPackage) {
@@ -474,7 +448,6 @@ impl InstallationManager {
>,
> = {
let installer = installer.clone();
- let op_type = op_type.clone();
let package = package.clone();
let initial_package = initial_package.clone();
Box::new(move || {
@@ -488,14 +461,13 @@ impl InstallationManager {
}
let installer = installer.clone();
- let op_type = op_type.clone();
let package = package.clone();
let initial_package = initial_package.clone();
let fut: std::pin::Pin<
Box<dyn std::future::Future<Output = anyhow::Result<()>>>,
> = Box::pin(async move {
installer
- .cleanup(&op_type, package, initial_package)
+ .cleanup(op_type, package, initial_package)
.await
.map(|_| ())
});
@@ -530,17 +502,14 @@ impl InstallationManager {
// execute operations in batches to make sure every plugin is installed in the
// right order and activated before the packages depending on it are installed
- let mut batches: Vec<IndexMap<i64, std::rc::Rc<dyn OperationInterface>>> = vec![];
- let mut batch: IndexMap<i64, std::rc::Rc<dyn OperationInterface>> = IndexMap::new();
+ let mut batches: Vec<IndexMap<i64, AnyOperation>> = vec![];
+ let mut batch: IndexMap<i64, AnyOperation> = IndexMap::new();
for (index, operation) in operations {
- let package: Option<PackageInterfaceHandle> =
- if let Some(update) = operation.as_update_operation() {
- Some(update.get_target_package())
- } else {
- operation
- .as_install_operation()
- .map(|install| install.get_package())
- };
+ let package: Option<PackageInterfaceHandle> = match &operation {
+ AnyOperation::Update(update) => Some(update.get_target_package()),
+ AnyOperation::Install(install) => Some(install.get_package()),
+ _ => None,
+ };
if let Some(package) = package {
let pkg_type = package.get_type();
if pkg_type == "composer-plugin" || pkg_type == "composer-installer" {
@@ -579,7 +548,7 @@ impl InstallationManager {
async fn execute_batch(
&self,
repo: &std::cell::RefCell<&mut dyn InstalledRepositoryInterface>,
- operations: IndexMap<i64, std::rc::Rc<dyn OperationInterface>>,
+ operations: IndexMap<i64, AnyOperation>,
cleanup_promises: &IndexMap<
i64,
Box<
@@ -590,7 +559,7 @@ impl InstallationManager {
>,
dev_mode: bool,
run_scripts: bool,
- all_operations: &[std::rc::Rc<dyn OperationInterface>],
+ all_operations: &[AnyOperation],
) -> anyhow::Result<()> {
let mut promises: Vec<
std::pin::Pin<Box<dyn std::future::Future<Output = anyhow::Result<()>> + '_>>,
@@ -600,7 +569,7 @@ impl InstallationManager {
let op_type = operation.get_operation_type();
// ignoring alias ops as they don't need to execute anything
- if !["update", "install", "uninstall"].contains(&op_type.as_str()) {
+ if !["update", "install", "uninstall"].contains(&op_type) {
// output alias ops in debug verbosity as they have no output otherwise
if self.io.is_debug() {
self.io.write_error3(
@@ -609,23 +578,11 @@ impl InstallationManager {
io_interface::NORMAL,
);
}
- match op_type.as_str() {
- "markAliasInstalled" => {
- let op = operation
- .as_any()
- .downcast_ref::<MarkAliasInstalledOperation>()
- .expect(
- "op_type == \"markAliasInstalled\" implies MarkAliasInstalledOperation",
- );
+ match &operation {
+ AnyOperation::MarkAliasInstalled(op) => {
self.mark_alias_installed(&mut **repo.borrow_mut(), op);
}
- "markAliasUninstalled" => {
- let op = operation
- .as_any()
- .downcast_ref::<MarkAliasUninstalledOperation>()
- .expect(
- "op_type == \"markAliasUninstalled\" implies MarkAliasUninstalledOperation",
- );
+ AnyOperation::MarkAliasUninstalled(op) => {
self.mark_alias_uninstalled(&mut **repo.borrow_mut(), op);
}
_ => {}
@@ -634,20 +591,13 @@ impl InstallationManager {
continue;
}
- let package: PackageInterfaceHandle;
- let initial_package: Option<PackageInterfaceHandle>;
- if op_type == "update" {
- let update_op = operation
- .as_update_operation()
- .expect("op_type == \"update\" implies UpdateOperation");
- package = update_op.get_target_package();
- initial_package = Some(update_op.get_initial_package());
- } else {
- package = operation.get_package();
- initial_package = None;
- }
+ let package = operation.get_target_package();
+ let initial_package: Option<PackageInterfaceHandle> = match &operation {
+ AnyOperation::Update(update_op) => Some(update_op.get_initial_package()),
+ _ => None,
+ };
- let event_name = match op_type.as_str() {
+ let event_name = match op_type {
"install" => PackageEvents::PRE_PACKAGE_INSTALL,
"update" => PackageEvents::PRE_PACKAGE_UPDATE,
"uninstall" => PackageEvents::PRE_PACKAGE_UNINSTALL,
@@ -658,13 +608,7 @@ impl InstallationManager {
// TODO(phase-c): dispatch_package_event takes Box<dyn RepositoryInterface>/Vec<Box<...>>
// but we hold a RefCell'd &mut dyn here. Needs structural rework (likely shared Rc
// on repo and ops).
- let _ = (
- event_name,
- dev_mode,
- &repo,
- &all_operations,
- operation.as_ref(),
- );
+ let _ = (event_name, dev_mode, &repo, &all_operations, &operation);
}
let installer = self.get_installer(&package.get_type())?;
@@ -679,29 +623,23 @@ impl InstallationManager {
promises.push(Box::pin(async move {
let chain_result: anyhow::Result<()> = async {
installer
- .prepare(&op_type, package.clone(), initial_package.clone())
+ .prepare(op_type, package.clone(), initial_package.clone())
.await?;
- match op_type.as_str() {
- "install" => {
- let op = operation
- .as_install_operation()
- .expect("op_type == \"install\" implies InstallOperation");
+ match &operation {
+ AnyOperation::Install(op) => {
self.install(repo, op).await?;
}
- "update" => {
- let op = operation
- .as_update_operation()
- .expect("op_type == \"update\" implies UpdateOperation");
+ AnyOperation::Update(op) => {
self.update(repo, op).await?;
}
- "uninstall" => {
- let op = operation
- .as_uninstall_operation()
- .expect("op_type == \"uninstall\" implies UninstallOperation");
+ AnyOperation::Uninstall(op) => {
self.uninstall(repo, op).await?;
}
- _ => unreachable!("op_type is one of install/update/uninstall"),
+ AnyOperation::MarkAliasInstalled(_)
+ | AnyOperation::MarkAliasUninstalled(_) => {
+ unreachable!("alias operations were skipped above")
+ }
}
if let Some(cleanup) = cleanup_promises.get(&index)
@@ -718,7 +656,7 @@ impl InstallationManager {
if let Err(e) = chain_result {
self.io.write_error(&format!(
" <error>{} of {} failed</error>",
- shirabe_php_shim::ucfirst(&op_type),
+ shirabe_php_shim::ucfirst(op_type),
package.get_pretty_name()
));
return Err(e);
@@ -727,7 +665,7 @@ impl InstallationManager {
// PHP: ->then(fn() => $repo->write($devMode, $this)) persists the repository after each op.
repo.borrow_mut().write(dev_mode, self);
- let event_name_post = match op_type.as_str() {
+ let event_name_post = match op_type {
"install" => PackageEvents::POST_PACKAGE_INSTALL,
"update" => PackageEvents::POST_PACKAGE_UPDATE,
"uninstall" => PackageEvents::POST_PACKAGE_UNINSTALL,
@@ -1087,7 +1025,7 @@ pub trait InstallationManagerInterface: std::fmt::Debug {
fn execute(
&mut self,
repo: &mut dyn InstalledRepositoryInterface,
- operations: Vec<std::rc::Rc<dyn OperationInterface>>,
+ operations: Vec<AnyOperation>,
dev_mode: bool,
run_scripts: bool,
download_only: bool,
@@ -1129,7 +1067,7 @@ impl InstallationManagerInterface for InstallationManager {
fn execute(
&mut self,
repo: &mut dyn InstalledRepositoryInterface,
- operations: Vec<std::rc::Rc<dyn OperationInterface>>,
+ operations: Vec<AnyOperation>,
dev_mode: bool,
run_scripts: bool,
download_only: bool,
diff --git a/crates/shirabe/src/installer/package_event.rs b/crates/shirabe/src/installer/package_event.rs
index 6661e0d1..28a8a2ea 100644
--- a/crates/shirabe/src/installer/package_event.rs
+++ b/crates/shirabe/src/installer/package_event.rs
@@ -1,7 +1,7 @@
//! ref: composer/src/Composer/Installer/PackageEvent.php
use crate::composer::ComposerWeakHandle;
-use crate::dependency_resolver::operation::OperationInterface;
+use crate::dependency_resolver::operation::AnyOperation;
use crate::event_dispatcher::Event;
use crate::event_dispatcher::EventInterface;
use crate::io::IOInterface;
@@ -16,8 +16,8 @@ pub struct PackageEvent {
io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
dev_mode: bool,
local_repo: Box<dyn RepositoryInterface>,
- operations: Vec<std::rc::Rc<dyn OperationInterface>>,
- operation: std::rc::Rc<dyn OperationInterface>,
+ operations: Vec<AnyOperation>,
+ operation: AnyOperation,
}
impl PackageEvent {
@@ -27,8 +27,8 @@ impl PackageEvent {
io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
dev_mode: bool,
local_repo: Box<dyn RepositoryInterface>,
- operations: Vec<std::rc::Rc<dyn OperationInterface>>,
- operation: std::rc::Rc<dyn OperationInterface>,
+ operations: Vec<AnyOperation>,
+ operation: AnyOperation,
) -> Self {
Self {
inner: Event::new(event_name, vec![], IndexMap::new()),
@@ -61,12 +61,12 @@ impl PackageEvent {
self.local_repo.as_ref()
}
- pub fn get_operations(&self) -> &Vec<std::rc::Rc<dyn OperationInterface>> {
+ pub fn get_operations(&self) -> &Vec<AnyOperation> {
&self.operations
}
- pub fn get_operation(&self) -> &dyn OperationInterface {
- self.operation.as_ref()
+ pub fn get_operation(&self) -> &AnyOperation {
+ &self.operation
}
}
diff --git a/crates/shirabe/tests/dependency_resolver/solver_test.rs b/crates/shirabe/tests/dependency_resolver/solver_test.rs
index 7a507da3..be8df4db 100644
--- a/crates/shirabe/tests/dependency_resolver/solver_test.rs
+++ b/crates/shirabe/tests/dependency_resolver/solver_test.rs
@@ -4,6 +4,7 @@ use crate::test_case::{get_alias_package, get_package, get_version_constraint};
use indexmap::IndexMap;
use shirabe::dependency_resolver::PolicyInterface;
use shirabe::dependency_resolver::default_policy::DefaultPolicy;
+use shirabe::dependency_resolver::operation::AnyOperation;
use shirabe::dependency_resolver::pool::Pool;
use shirabe::dependency_resolver::request::Request;
use shirabe::dependency_resolver::solver_problems_exception::SolverProblemsException;
@@ -140,7 +141,7 @@ fn check_solver_result_repo_set(
let mut result_readable: Vec<(String, String)> = Vec::new();
let mut result_ids: Vec<(String, Vec<usize>)> = Vec::new();
for operation in transaction.get_operations() {
- if let Some(update) = operation.as_update_operation() {
+ if let AnyOperation::Update(update) = operation {
let from = update.get_initial_package();
let to = update.get_target_package();
result_readable.push((
@@ -149,15 +150,14 @@ fn check_solver_result_repo_set(
));
result_ids.push(("update".to_string(), vec![from.ptr_id(), to.ptr_id()]));
} else {
- let op_type = operation.get_operation_type();
- let job = match op_type.as_str() {
+ let job = match operation.get_operation_type() {
"markAliasInstalled" => "markAliasInstalled",
"markAliasUninstalled" => "markAliasUninstalled",
"uninstall" => "remove",
"install" => "install",
other => panic!("Unexpected operation: {}", other),
};
- let package = operation.get_package();
+ let package = operation.get_target_package();
result_readable.push((job.to_string(), package.get_unique_name()));
result_ids.push((job.to_string(), vec![package.ptr_id()]));
}
@@ -2521,7 +2521,7 @@ fn test_learn_positive_literal() {
];
let mut result: Vec<(String, String)> = Vec::new();
for operation in transaction.get_operations() {
- if let Some(update) = operation.as_update_operation() {
+ if let AnyOperation::Update(update) = operation {
result.push((
"update".to_string(),
format!(
@@ -2535,9 +2535,9 @@ fn test_learn_positive_literal() {
let job = if op_type == "uninstall" {
"remove".to_string()
} else {
- op_type
+ op_type.to_string()
};
- result.push((job, operation.get_package().get_unique_name()));
+ result.push((job, operation.get_target_package().get_unique_name()));
}
}
assert_eq!(expected, result);
diff --git a/crates/shirabe/tests/dependency_resolver/transaction_test.rs b/crates/shirabe/tests/dependency_resolver/transaction_test.rs
index 99f31c38..3b1006ea 100644
--- a/crates/shirabe/tests/dependency_resolver/transaction_test.rs
+++ b/crates/shirabe/tests/dependency_resolver/transaction_test.rs
@@ -2,6 +2,7 @@
use crate::test_case::{get_alias_package, get_package, get_version_constraint};
use indexmap::IndexMap;
+use shirabe::dependency_resolver::operation::AnyOperation;
use shirabe::dependency_resolver::transaction::Transaction;
use shirabe::package::Link;
use shirabe::package::handle::PackageInterfaceHandle;
@@ -62,15 +63,15 @@ impl PartialEq for OperationEntry {
fn check_transaction_operations(transaction: &Transaction, expected: Vec<OperationEntry>) {
let mut result: Vec<OperationEntry> = vec![];
for operation in transaction.get_operations() {
- if let Some(update) = operation.as_update_operation() {
+ if let AnyOperation::Update(update) = operation {
result.push(OperationEntry::Update {
from: update.get_initial_package(),
to: update.get_target_package(),
});
} else {
result.push(OperationEntry::Job {
- job: operation.get_operation_type(),
- package: operation.get_package(),
+ job: operation.get_operation_type().to_string(),
+ package: operation.get_target_package(),
});
}
}
diff --git a/crates/shirabe/tests/repository/filesystem_repository_test.rs b/crates/shirabe/tests/repository/filesystem_repository_test.rs
index f2cdb670..054a6d7c 100644
--- a/crates/shirabe/tests/repository/filesystem_repository_test.rs
+++ b/crates/shirabe/tests/repository/filesystem_repository_test.rs
@@ -3,7 +3,7 @@
use crate::test_case::{get_alias_package, get_package};
use indexmap::IndexMap;
use serial_test::serial;
-use shirabe::dependency_resolver::operation::OperationInterface;
+use shirabe::dependency_resolver::operation::AnyOperation;
use shirabe::installed_versions::InstalledVersions;
use shirabe::installer::{InstallationManagerInterface, InstallerInterface};
use shirabe::io::IOInterface;
@@ -106,7 +106,7 @@ mockall::mock! {
fn execute(
&mut self,
repo: &mut dyn InstalledRepositoryInterface,
- operations: Vec<std::rc::Rc<dyn OperationInterface>>,
+ operations: Vec<AnyOperation>,
dev_mode: bool,
run_scripts: bool,
download_only: bool,