aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/src/command/require_command.rs
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-07-24 20:23:42 +0900
committernsfisis <nsfisis@gmail.com>2026-07-24 20:23:42 +0900
commit90d9b1dc0035a70dab76d520b9dcd14ec57273ad (patch)
tree30f6576fddcd4b6fb6fc883c28610b324a15b3cc /crates/shirabe/src/command/require_command.rs
parent4a8f5a83b933a06974916b102da673f2a88aebe8 (diff)
downloadphp-shirabe-90d9b1dc0035a70dab76d520b9dcd14ec57273ad.tar.gz
php-shirabe-90d9b1dc0035a70dab76d520b9dcd14ec57273ad.tar.zst
php-shirabe-90d9b1dc0035a70dab76d520b9dcd14ec57273ad.zip
fix(event-dispatcher): invoke Closure listeners instead of always failing is_callable
RequireCommand registers an inline listener on InstallerEvents::PRE_OPERATIONS_EXEC to track dependency_resolution_completed, mirroring PHP's `function () use (&$dependencyResolutionCompleted) { ... }`. This is Composer's own code, not a Plugin subscriber, but it went through the shared non-string-callable path, which checked is_callable() against a hardcoded PhpMixed::Null and always failed, breaking every `require` that reaches the install step. Callable::Closure now carries the actual Rc<dyn Fn> instead of being a data-less placeholder, and is invoked directly (Closures are always callable in PHP). The ArrayCallable path used by future Plugin subscribers is untouched. Un-ignoring the two require_command_test cases that cited this bug reveals two separate, pre-existing issues (a missing ext-requirement warning message, and a RefCell re-entrancy panic in ConsoleIO::ask_question); their #[ignore] reasons are updated to describe the real current blocker instead of the now-fixed one.
Diffstat (limited to 'crates/shirabe/src/command/require_command.rs')
-rw-r--r--crates/shirabe/src/command/require_command.rs15
1 files changed, 7 insertions, 8 deletions
diff --git a/crates/shirabe/src/command/require_command.rs b/crates/shirabe/src/command/require_command.rs
index 05f86480..c1730942 100644
--- a/crates/shirabe/src/command/require_command.rs
+++ b/crates/shirabe/src/command/require_command.rs
@@ -53,7 +53,7 @@ pub struct RequireCommand {
lock: std::cell::RefCell<String>,
/// contents before modification if the lock file exists
lock_backup: std::cell::RefCell<Option<String>>,
- dependency_resolution_completed: std::cell::Cell<bool>,
+ dependency_resolution_completed: std::rc::Rc<std::cell::Cell<bool>>,
repos: std::cell::RefCell<Option<crate::repository::RepositoryInterfaceHandle>>,
repository_sets:
std::cell::RefCell<IndexMap<String, std::rc::Rc<std::cell::RefCell<RepositorySet>>>>,
@@ -76,7 +76,7 @@ impl RequireCommand {
composer_backup: std::cell::RefCell::new(String::new()),
lock: std::cell::RefCell::new(String::new()),
lock_backup: std::cell::RefCell::new(None),
- dependency_resolution_completed: std::cell::Cell::new(false),
+ dependency_resolution_completed: std::rc::Rc::new(std::cell::Cell::new(false)),
repos: std::cell::RefCell::new(None),
repository_sets: std::cell::RefCell::new(IndexMap::new()),
};
@@ -759,14 +759,13 @@ impl RequireCommand {
self.dependency_resolution_completed.set(false);
// PHP: $composer->getEventDispatcher()->addListener(InstallerEvents::PRE_OPERATIONS_EXEC,
// function () use (&$dependencyResolutionCompleted) { $dependencyResolutionCompleted = true; }, 10000);
- // TODO(phase-c): the event dispatcher's Callable::Closure is a placeholder variant that
- // stores no actual closure, so the listener that flips dependency_resolution_completed
- // cannot be registered. Resolving needs the closure model (Callable holding an Rc<dyn Fn>)
- // plus dependency_resolution_completed shared (Rc<RefCell<bool>>) into both the listener
- // and this command.
+ let dependency_resolution_completed = self.dependency_resolution_completed.clone();
composer.get_event_dispatcher().borrow_mut().add_listener(
InstallerEvents::PRE_OPERATIONS_EXEC,
- crate::event_dispatcher::Callable::Closure,
+ crate::event_dispatcher::Callable::Closure(std::rc::Rc::new(move |_event| {
+ dependency_resolution_completed.set(true);
+ PhpMixed::Null
+ })),
10000,
);