aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/src/installer
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-05-23 03:07:15 +0900
committernsfisis <nsfisis@gmail.com>2026-05-23 15:48:00 +0900
commite068a9d644fde6659a88accd55b3f1d0d9d7cf46 (patch)
treebb719a70eb8c840957a94a5601df8961055ceb0f /crates/shirabe/src/installer
parent60eb89529c8af2e4477e0bb65ed9e0f2dc7d3dd7 (diff)
downloadphp-shirabe-e068a9d644fde6659a88accd55b3f1d0d9d7cf46.tar.gz
php-shirabe-e068a9d644fde6659a88accd55b3f1d0d9d7cf46.tar.zst
php-shirabe-e068a9d644fde6659a88accd55b3f1d0d9d7cf46.zip
refactor(promise): rewrite promise bodies to async/await
Mechanically convert promise-returning function bodies to async/await: resolve() returns the value directly, forwarding calls get .await, and simple .then chains become await sequences. Also collapse the installer double-Option (Result<Option<Option<PhpMixed>>> -> Result<Option<PhpMixed>>). Hard spots that depend on the Loop::wait / job-machine boundary (accept/reject orchestration, closures capturing &mut self, batch waits) are left intact and marked with TODO(phase-c-promise) for manual porting. The crate does not compile yet; traits still need #[async_trait]. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe/src/installer')
-rw-r--r--crates/shirabe/src/installer/installation_manager.rs32
-rw-r--r--crates/shirabe/src/installer/library_installer.rs75
-rw-r--r--crates/shirabe/src/installer/metapackage_installer.rs24
-rw-r--r--crates/shirabe/src/installer/noop_installer.rs24
-rw-r--r--crates/shirabe/src/installer/plugin_installer.rs48
-rw-r--r--crates/shirabe/src/installer/project_installer.rs15
6 files changed, 82 insertions, 136 deletions
diff --git a/crates/shirabe/src/installer/installation_manager.rs b/crates/shirabe/src/installer/installation_manager.rs
index 114f1fc..ae0470a 100644
--- a/crates/shirabe/src/installer/installation_manager.rs
+++ b/crates/shirabe/src/installer/installation_manager.rs
@@ -285,6 +285,8 @@ impl InstallationManager {
download_only: bool,
all_operations: Vec<Box<dyn OperationInterface>>,
) -> Result<()> {
+ // TODO(phase-c-promise): Loop::wait-driven batch orchestration (download/cleanup promises);
+ // rewrite to await collected futures once the async Loop boundary lands.
let mut promises: Vec<Box<dyn PromiseInterface>> = vec![];
for (index, operation) in &operations {
@@ -401,6 +403,8 @@ impl InstallationManager {
run_scripts: bool,
all_operations: &[Box<dyn OperationInterface>],
) -> Result<()> {
+ // TODO(phase-c-promise): Loop::wait-driven batch orchestration (prepare/install promises);
+ // rewrite to await collected futures once the async Loop boundary lands.
let mut promises: Vec<Box<dyn PromiseInterface>> = vec![];
let mut post_exec_callbacks: Vec<Box<dyn Fn()>> = vec![];
@@ -513,6 +517,7 @@ impl InstallationManager {
/// @param array<PromiseInterface<void|null>> $promises
fn wait_on_promises(&mut self, promises: Vec<Box<dyn PromiseInterface>>) {
+ // TODO(phase-c-promise): thin wrapper over Loop::wait (the async boundary owned separately).
let mut progress: Option<()> = None;
// TODO(phase-b): self.io instanceof ConsoleIO downcast
let io_is_console = false;
@@ -541,7 +546,7 @@ impl InstallationManager {
/// @phpstan-return PromiseInterface<void|null>|null
pub async fn download(&mut self, package: &dyn PackageInterface) -> Option<PhpMixed> {
let installer = self.get_installer(package.get_type()).ok()?;
- let promise = installer.cleanup("install", package, None).ok()?;
+ let promise = installer.cleanup("install", package, None).await.ok()?;
promise
}
@@ -556,7 +561,7 @@ impl InstallationManager {
) -> Option<PhpMixed> {
let package = operation.get_package();
let installer = self.get_installer(package.get_type()).ok()?;
- let promise = installer.install(repo, package).ok()?;
+ let promise = installer.install(repo, package).await.ok()?;
self.mark_for_notification(package);
promise
@@ -578,24 +583,19 @@ impl InstallationManager {
let promise = if initial_type == target_type {
let installer = self.get_installer(initial_type).ok()?;
- let promise = installer.update(repo, initial, target).ok()?;
+ let promise = installer.update(repo, initial, target).await.ok()?;
self.mark_for_notification(target);
promise
} else {
- let promise = self
+ // PHP: uninstall initial, then install target via the target-type installer.
+ let _ = self
.get_installer(initial_type)
.ok()?
.uninstall(repo, initial)
+ .await
.ok()?;
- let promise = match promise {
- Some(p) => p,
- None => promise::resolve(None),
- };
-
- let target_type = target_type.to_string();
- // TODO(phase-b): promise.then(closure capturing self/installer)
- let _ = target_type;
- Some(promise)
+ let installer = self.get_installer(target_type).ok()?;
+ installer.install(repo, target).await.ok()?
};
promise
@@ -612,7 +612,7 @@ impl InstallationManager {
let package = operation.get_package();
let installer = self.get_installer(package.get_type()).ok()?;
- installer.uninstall(repo, package).ok()?
+ installer.uninstall(repo, package).await.ok()?
}
/// Executes markAliasInstalled operation.
@@ -653,6 +653,8 @@ impl InstallationManager {
}
pub fn notify_installs(&mut self, _io: &dyn IOInterface) {
+ // TODO(phase-c-promise): collects http_downloader.add() promises and drives them via Loop::wait;
+ // rewrite to await the collected futures once the async Loop boundary lands.
let mut promises: Vec<Box<dyn PromiseInterface>> = vec![];
let result: Result<()> = (|| -> Result<()> {
@@ -802,6 +804,8 @@ impl InstallationManager {
&mut self,
cleanup_promises: &IndexMap<i64, Box<dyn Fn() -> Option<Box<dyn PromiseInterface>>>>,
) {
+ // TODO(phase-c-promise): runs cleanup closures and drives them via Loop::wait;
+ // rewrite once the async Loop boundary and async cleanup closures land.
let mut promises: Vec<Box<dyn PromiseInterface>> = vec![];
self.loop_.borrow().abort_jobs();
diff --git a/crates/shirabe/src/installer/library_installer.rs b/crates/shirabe/src/installer/library_installer.rs
index a9a77e9..0629de5 100644
--- a/crates/shirabe/src/installer/library_installer.rs
+++ b/crates/shirabe/src/installer/library_installer.rs
@@ -137,11 +137,10 @@ impl LibraryInstaller {
) -> Result<Option<PhpMixed>> {
let download_path = self.get_install_path(package).unwrap();
- Ok(Some(
- self.get_download_manager()
- .borrow()
- .install(package, &download_path)?,
- ))
+ self.get_download_manager()
+ .borrow()
+ .install(package, &download_path)
+ .await
}
/// @return PromiseInterface|null
@@ -159,19 +158,9 @@ impl LibraryInstaller {
if strpos(&initial_download_path, &target_download_path) == Some(0)
|| strpos(&target_download_path, &initial_download_path) == Some(0)
{
- let promise = self.remove_code(initial)?;
- let promise = match promise {
- Some(p) => p,
- None => shirabe_external_packages::react::promise::resolve(None),
- };
-
- // TODO(phase-b): promise.then expects Option<Box<dyn FnOnce(Option<PhpMixed>) -> Option<PhpMixed>>>
- // arguments. Translating the original PHP closure (which captures &self and target)
- // requires restructuring; tracked separately.
- let _ = promise;
- return Ok(Some(todo!(
- "promise.then(...) chain to install_code(target)"
- )));
+ // PHP: return $this->removeCode($initial)->then(fn () => $this->installCode($target));
+ let _ = self.remove_code(initial).await?;
+ return self.install_code(target).await;
}
self.filesystem
@@ -179,11 +168,10 @@ impl LibraryInstaller {
.rename(&initial_download_path, &target_download_path);
}
- Ok(Some(self.get_download_manager().borrow().update(
- initial,
- target,
- &target_download_path,
- )?))
+ self.get_download_manager()
+ .borrow()
+ .update(initial, target, &target_download_path)
+ .await
}
/// @return PromiseInterface|null
@@ -194,11 +182,10 @@ impl LibraryInstaller {
) -> Result<Option<PhpMixed>> {
let download_path = self.get_package_base_path(package);
- Ok(Some(
- self.get_download_manager()
- .borrow()
- .remove(package, &download_path)?,
- ))
+ self.get_download_manager()
+ .borrow()
+ .remove(package, &download_path)
+ .await
}
pub(crate) fn initialize_vendor_dir(&mut self) {
@@ -275,11 +262,10 @@ impl InstallerInterface for LibraryInstaller {
// self.initialize_vendor_dir();
let download_path = self.get_install_path(package).unwrap();
- Ok(Some(self.get_download_manager().borrow().download(
- package,
- &download_path,
- prev_package,
- )?))
+ self.get_download_manager()
+ .borrow()
+ .download(package, &download_path, prev_package)
+ .await
}
async fn prepare(
@@ -292,12 +278,10 @@ impl InstallerInterface for LibraryInstaller {
// self.initialize_vendor_dir();
let download_path = self.get_install_path(package).unwrap();
- Ok(Some(self.get_download_manager().borrow().prepare(
- r#type,
- package,
- &download_path,
- prev_package,
- )?))
+ self.get_download_manager()
+ .borrow()
+ .prepare(r#type, package, &download_path, prev_package)
+ .await
}
async fn cleanup(
@@ -310,12 +294,10 @@ impl InstallerInterface for LibraryInstaller {
// self.initialize_vendor_dir();
let download_path = self.get_install_path(package).unwrap();
- Ok(Some(self.get_download_manager().borrow().cleanup(
- r#type,
- package,
- &download_path,
- prev_package,
- )?))
+ self.get_download_manager()
+ .borrow()
+ .cleanup(r#type, package, &download_path, prev_package)
+ .await
}
async fn install(
@@ -332,6 +314,7 @@ impl InstallerInterface for LibraryInstaller {
self.binary_installer.remove_binaries(package);
}
+ // TODO(phase-c-promise): rewrite install_code().then(installBinaries + repo.addPackage) as an await sequence.
let promise = self.install_code(package)?;
let promise = match promise {
Some(p) => p,
@@ -365,6 +348,7 @@ impl InstallerInterface for LibraryInstaller {
// self.initialize_vendor_dir();
self.binary_installer.remove_binaries(initial);
+ // TODO(phase-c-promise): rewrite update_code().then(installBinaries + repo updates) as an await sequence.
let promise = self.update_code(initial, target)?;
let promise = match promise {
Some(p) => p,
@@ -393,6 +377,7 @@ impl InstallerInterface for LibraryInstaller {
.into());
}
+ // TODO(phase-c-promise): rewrite remove_code().then(remove_binaries/remove_package/rmdir) as an await sequence.
let promise = self.remove_code(package)?;
let promise = match promise {
Some(p) => p,
diff --git a/crates/shirabe/src/installer/metapackage_installer.rs b/crates/shirabe/src/installer/metapackage_installer.rs
index f6d6133..23d92f2 100644
--- a/crates/shirabe/src/installer/metapackage_installer.rs
+++ b/crates/shirabe/src/installer/metapackage_installer.rs
@@ -40,9 +40,7 @@ impl InstallerInterface for MetapackageInstaller {
_package: &dyn PackageInterface,
_prev_package: Option<&dyn PackageInterface>,
) -> Result<Option<PhpMixed>> {
- Ok(Some(shirabe_external_packages::react::promise::resolve(
- None,
- )))
+ Ok(None)
}
async fn prepare(
@@ -51,9 +49,7 @@ impl InstallerInterface for MetapackageInstaller {
_package: &dyn PackageInterface,
_prev_package: Option<&dyn PackageInterface>,
) -> Result<Option<PhpMixed>> {
- Ok(Some(shirabe_external_packages::react::promise::resolve(
- None,
- )))
+ Ok(None)
}
async fn cleanup(
@@ -62,9 +58,7 @@ impl InstallerInterface for MetapackageInstaller {
_package: &dyn PackageInterface,
_prev_package: Option<&dyn PackageInterface>,
) -> Result<Option<PhpMixed>> {
- Ok(Some(shirabe_external_packages::react::promise::resolve(
- None,
- )))
+ Ok(None)
}
async fn install(
@@ -80,9 +74,7 @@ impl InstallerInterface for MetapackageInstaller {
repo.add_package(package.clone_package_box());
- Ok(Some(shirabe_external_packages::react::promise::resolve(
- None,
- )))
+ Ok(None)
}
async fn update(
@@ -108,9 +100,7 @@ impl InstallerInterface for MetapackageInstaller {
repo.remove_package(initial);
repo.add_package(target.clone_package_box());
- Ok(Some(shirabe_external_packages::react::promise::resolve(
- None,
- )))
+ Ok(None)
}
async fn uninstall(
@@ -134,9 +124,7 @@ impl InstallerInterface for MetapackageInstaller {
repo.remove_package(package);
- Ok(Some(shirabe_external_packages::react::promise::resolve(
- None,
- )))
+ Ok(None)
}
fn get_install_path(&self, _package: &dyn PackageInterface) -> Option<String> {
diff --git a/crates/shirabe/src/installer/noop_installer.rs b/crates/shirabe/src/installer/noop_installer.rs
index 263caca..68e4ef8 100644
--- a/crates/shirabe/src/installer/noop_installer.rs
+++ b/crates/shirabe/src/installer/noop_installer.rs
@@ -26,9 +26,7 @@ impl InstallerInterface for NoopInstaller {
_package: &dyn PackageInterface,
_prev_package: Option<&dyn PackageInterface>,
) -> anyhow::Result<Option<PhpMixed>> {
- Ok(Some(shirabe_external_packages::react::promise::resolve(
- None,
- )))
+ Ok(None)
}
async fn prepare(
@@ -37,9 +35,7 @@ impl InstallerInterface for NoopInstaller {
_package: &dyn PackageInterface,
_prev_package: Option<&dyn PackageInterface>,
) -> anyhow::Result<Option<PhpMixed>> {
- Ok(Some(shirabe_external_packages::react::promise::resolve(
- None,
- )))
+ Ok(None)
}
async fn cleanup(
@@ -48,9 +44,7 @@ impl InstallerInterface for NoopInstaller {
_package: &dyn PackageInterface,
_prev_package: Option<&dyn PackageInterface>,
) -> anyhow::Result<Option<PhpMixed>> {
- Ok(Some(shirabe_external_packages::react::promise::resolve(
- None,
- )))
+ Ok(None)
}
async fn install(
@@ -62,9 +56,7 @@ impl InstallerInterface for NoopInstaller {
repo.add_package(package.clone_package_box());
}
- Ok(Some(shirabe_external_packages::react::promise::resolve(
- None,
- )))
+ Ok(None)
}
async fn update(
@@ -86,9 +78,7 @@ impl InstallerInterface for NoopInstaller {
repo.add_package(target.clone_package_box());
}
- Ok(Some(shirabe_external_packages::react::promise::resolve(
- None,
- )))
+ Ok(None)
}
async fn uninstall(
@@ -105,9 +95,7 @@ impl InstallerInterface for NoopInstaller {
}
repo.remove_package(package);
- Ok(Some(shirabe_external_packages::react::promise::resolve(
- None,
- )))
+ Ok(None)
}
fn get_install_path(&self, package: &dyn PackageInterface) -> Option<String> {
diff --git a/crates/shirabe/src/installer/plugin_installer.rs b/crates/shirabe/src/installer/plugin_installer.rs
index fd1fc99..4f9918e 100644
--- a/crates/shirabe/src/installer/plugin_installer.rs
+++ b/crates/shirabe/src/installer/plugin_installer.rs
@@ -96,7 +96,7 @@ impl InstallerInterface for PluginInstaller {
let _ = plugin_optional;
}
- self.inner.prepare(r#type, package, prev_package)
+ self.inner.prepare(r#type, package, prev_package).await
}
async fn download(
@@ -116,7 +116,7 @@ impl InstallerInterface for PluginInstaller {
}.into());
}
- self.inner.download(package, prev_package)
+ self.inner.download(package, prev_package).await
}
async fn install(
@@ -124,22 +124,13 @@ impl InstallerInterface for PluginInstaller {
repo: &mut dyn InstalledRepositoryInterface,
package: &dyn PackageInterface,
) -> Result<Option<PhpMixed>> {
- let promise = self.inner.install(repo, package)?;
- let promise = match promise {
- Some(p) => p,
- None => shirabe_external_packages::react::promise::resolve(None),
- };
+ self.inner.install(repo, package).await?;
// TODO(plugin): register package in plugin manager after install, rollback on failure
- Ok(Some(promise.then(
- Some(Box::new(move |_v| -> Option<PhpMixed> {
- Platform::workaround_filesystem_issues();
- // self.get_plugin_manager().register_package(package, true)?;
- // On error: self.rollback_install(e, repo, package)?;
- None
- })),
- None,
- )))
+ Platform::workaround_filesystem_issues();
+ // self.get_plugin_manager().register_package(package, true)?;
+ // On error: self.rollback_install(e, repo, package)?;
+ Ok(None)
}
async fn update(
@@ -148,23 +139,14 @@ impl InstallerInterface for PluginInstaller {
initial: &dyn PackageInterface,
target: &dyn PackageInterface,
) -> Result<Option<PhpMixed>> {
- let promise = self.inner.update(repo, initial, target)?;
- let promise = match promise {
- Some(p) => p,
- None => shirabe_external_packages::react::promise::resolve(None),
- };
+ self.inner.update(repo, initial, target).await?;
// TODO(plugin): deactivate initial and register target in plugin manager after update, rollback on failure
- Ok(Some(promise.then(
- Some(Box::new(move |_v| -> Option<PhpMixed> {
- Platform::workaround_filesystem_issues();
- // self.get_plugin_manager().deactivate_package(initial);
- // self.get_plugin_manager().register_package(target, true)?;
- // On error: self.rollback_install(e, repo, target)?;
- None
- })),
- None,
- )))
+ Platform::workaround_filesystem_issues();
+ // self.get_plugin_manager().deactivate_package(initial);
+ // self.get_plugin_manager().register_package(target, true)?;
+ // On error: self.rollback_install(e, repo, target)?;
+ Ok(None)
}
async fn uninstall(
@@ -177,7 +159,7 @@ impl InstallerInterface for PluginInstaller {
.borrow_mut()
.uninstall_package(package);
- self.inner.uninstall(repo, package)
+ self.inner.uninstall(repo, package).await
}
async fn cleanup(
@@ -186,7 +168,7 @@ impl InstallerInterface for PluginInstaller {
package: &dyn PackageInterface,
prev_package: Option<&dyn PackageInterface>,
) -> Result<Option<PhpMixed>> {
- self.inner.cleanup(r#type, package, prev_package)
+ self.inner.cleanup(r#type, package, prev_package).await
}
fn get_install_path(&self, package: &dyn PackageInterface) -> Option<String> {
diff --git a/crates/shirabe/src/installer/project_installer.rs b/crates/shirabe/src/installer/project_installer.rs
index 1c50a16..034a07a 100644
--- a/crates/shirabe/src/installer/project_installer.rs
+++ b/crates/shirabe/src/installer/project_installer.rs
@@ -64,7 +64,7 @@ impl InstallerInterface for ProjectInstaller {
self.download_manager
.borrow()
.download(package, install_path, prev_package)
- .map(Some)
+ .await
}
async fn prepare(
@@ -76,7 +76,7 @@ impl InstallerInterface for ProjectInstaller {
self.download_manager
.borrow()
.prepare(r#type, package, &self.install_path, prev_package)
- .map(Some)
+ .await
}
async fn cleanup(
@@ -88,7 +88,7 @@ impl InstallerInterface for ProjectInstaller {
self.download_manager
.borrow()
.cleanup(r#type, package, &self.install_path, prev_package)
- .map(Some)
+ .await
}
async fn install(
@@ -96,11 +96,10 @@ impl InstallerInterface for ProjectInstaller {
_repo: &mut dyn InstalledRepositoryInterface,
package: &dyn PackageInterface,
) -> anyhow::Result<Option<PhpMixed>> {
- Ok(Some(
- self.download_manager
- .borrow()
- .install(package, &self.install_path)?,
- ))
+ self.download_manager
+ .borrow()
+ .install(package, &self.install_path)
+ .await
}
async fn update(