aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/src
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-08-02 08:42:55 +0900
committernsfisis <nsfisis@gmail.com>2026-08-02 08:42:55 +0900
commitb5d6d91054b9ceef95aef0819bb5c4ef7db1abdd (patch)
tree0bd12e599f48fcc63375363363416ca48766c698 /crates/shirabe/src
parent3e367f78eec3521106979461fda717926717515a (diff)
downloadphp-shirabe-b5d6d91054b9ceef95aef0819bb5c4ef7db1abdd.tar.gz
php-shirabe-b5d6d91054b9ceef95aef0819bb5c4ef7db1abdd.tar.zst
php-shirabe-b5d6d91054b9ceef95aef0819bb5c4ef7db1abdd.zip
fix(repository): run lazy initialization in count/has_package
PHP's ArrayRepository::count()/hasPackage() call $this->initialize(), which late-binds to the concrete repository class and lazily loads its packages. The Rust pass-throughs skipped that: they ran ArrayRepository's stub initialize instead, returning 0/false and marking the repository initialized with an empty package list, which made ensure_initialized() skip the real initialization forever after. Take &mut self in RepositoryInterface::count/has_package so the lazy repositories (Filesystem, Platform, Composer) can guard with their real initialize, and return Result from has_package since that initialization can fail (PHP propagates the exception). InstallerInterface::is_installed and InstallationManager::is_package_installed/mark_alias_installed propagate the same way, which also resolves the TODO(phase-d) markers on Package/Path/Artifact/Vcs repositories about initialization errors being swallowed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe/src')
-rw-r--r--crates/shirabe/src/command/show_command.rs10
-rw-r--r--crates/shirabe/src/installer/installation_manager.rs27
-rw-r--r--crates/shirabe/src/installer/installer_interface.rs4
-rw-r--r--crates/shirabe/src/installer/library_installer.rs30
-rw-r--r--crates/shirabe/src/installer/metapackage_installer.rs8
-rw-r--r--crates/shirabe/src/installer/noop_installer.rs12
-rw-r--r--crates/shirabe/src/installer/plugin_installer.rs4
-rw-r--r--crates/shirabe/src/installer/project_installer.rs6
-rw-r--r--crates/shirabe/src/repository/array_repository.rs27
-rw-r--r--crates/shirabe/src/repository/artifact_repository.rs9
-rw-r--r--crates/shirabe/src/repository/composer_repository.rs22
-rw-r--r--crates/shirabe/src/repository/composite_repository.rs10
-rw-r--r--crates/shirabe/src/repository/filesystem_repository.rs8
-rw-r--r--crates/shirabe/src/repository/filter_repository.rs4
-rw-r--r--crates/shirabe/src/repository/handle.rs6
-rw-r--r--crates/shirabe/src/repository/installed_array_repository.rs9
-rw-r--r--crates/shirabe/src/repository/installed_filesystem_repository.rs4
-rw-r--r--crates/shirabe/src/repository/installed_repository.rs4
-rw-r--r--crates/shirabe/src/repository/lock_array_repository.rs4
-rw-r--r--crates/shirabe/src/repository/package_repository.rs9
-rw-r--r--crates/shirabe/src/repository/path_repository.rs11
-rw-r--r--crates/shirabe/src/repository/platform_repository.rs8
-rw-r--r--crates/shirabe/src/repository/repository_interface.rs8
-rw-r--r--crates/shirabe/src/repository/root_package_repository.rs4
-rw-r--r--crates/shirabe/src/repository/vcs_repository.rs9
-rw-r--r--crates/shirabe/src/repository/writable_array_repository.rs9
26 files changed, 139 insertions, 127 deletions
diff --git a/crates/shirabe/src/command/show_command.rs b/crates/shirabe/src/command/show_command.rs
index c4519924..bc36869c 100644
--- a/crates/shirabe/src/command/show_command.rs
+++ b/crates/shirabe/src/command/show_command.rs
@@ -768,7 +768,7 @@ impl Command for ShowCommand {
self.print_package_info_as_json(
package.clone(),
&versions_map,
- &*installed_repo.borrow(),
+ &mut *installed_repo.borrow_mut(),
latest_package,
)?;
} else {
@@ -1696,7 +1696,7 @@ impl ShowCommand {
}
// select an exact match if it is in the installed repo and no specific version was required
- if version.is_null() && installed_repo.has_package(p.clone()) {
+ if version.is_null() && installed_repo.has_package(p.clone())? {
matched_package = Some(p.clone());
}
@@ -1766,7 +1766,7 @@ impl ShowCommand {
latest_package: Option<PackageInterfaceHandle>,
) -> anyhow::Result<()> {
let is_installed_package = !PlatformRepository::is_platform_package(&package.get_name())
- && installed_repo.has_package(package.clone().into());
+ && installed_repo.has_package(package.clone().into())?;
self.get_io().write(&format!(
"<info>name</info> : {}",
@@ -2022,7 +2022,7 @@ impl ShowCommand {
&self,
package: CompletePackageInterfaceHandle,
versions: &IndexMap<String, String>,
- installed_repo: &dyn RepositoryInterface,
+ installed_repo: &mut dyn RepositoryInterface,
latest_package: Option<PackageInterfaceHandle>,
) -> anyhow::Result<()> {
let mut json: IndexMap<String, PhpMixed> = IndexMap::new();
@@ -2113,7 +2113,7 @@ impl ShowCommand {
}
if !PlatformRepository::is_platform_package(&package.get_name())
- && installed_repo.has_package(package.clone().into())
+ && installed_repo.has_package(package.clone().into())?
{
let composer = self.require_composer(None, None)?;
let installation_manager = composer.borrow_partial().get_installation_manager();
diff --git a/crates/shirabe/src/installer/installation_manager.rs b/crates/shirabe/src/installer/installation_manager.rs
index 9517eada..3a04a8e9 100644
--- a/crates/shirabe/src/installer/installation_manager.rs
+++ b/crates/shirabe/src/installer/installation_manager.rs
@@ -198,22 +198,21 @@ impl InstallationManager {
/// Checks whether provided package is installed in one of the registered installers.
pub fn is_package_installed(
&self,
- repo: &dyn InstalledRepositoryInterface,
+ repo: &mut dyn InstalledRepositoryInterface,
package: PackageInterfaceHandle,
) -> anyhow::Result<bool> {
// For testing only (ref InstallationManagerMock::isPackageInstalled).
if self.mock.is_some() {
- return Ok(repo.has_package(package));
+ return repo.has_package(package);
}
if let Some(alias) = package.as_alias() {
let alias_of: PackageInterfaceHandle = alias.get_alias_of().into();
- return Ok(repo.has_package(package) && self.is_package_installed(repo, alias_of)?);
+ return Ok(repo.has_package(package)? && self.is_package_installed(repo, alias_of)?);
}
- Ok(self
- .get_installer(&package.get_type())?
- .is_installed(repo, package))
+ self.get_installer(&package.get_type())?
+ .is_installed(repo, package)
}
/// Install binary for the given package.
@@ -264,7 +263,7 @@ impl InstallationManager {
mock.updated.push((initial.clone(), target.clone()));
mock.trace.push(trace);
repo.remove_package(initial);
- if !repo.has_package(target.clone()) {
+ if !repo.has_package(target.clone())? {
repo.add_package(PackageInterfaceHandle::dup(&target));
}
}
@@ -278,7 +277,7 @@ impl InstallationManager {
let package: PackageInterfaceHandle = op.get_package().into();
mock.installed.push(package.clone());
mock.trace.push(trace);
- if !repo.has_package(package.clone()) {
+ if !repo.has_package(package.clone())? {
repo.add_package(PackageInterfaceHandle::dup(&package));
}
}
@@ -578,7 +577,7 @@ impl InstallationManager {
}
match &operation {
AnyOperation::MarkAliasInstalled(op) => {
- self.mark_alias_installed(&mut **repo.borrow_mut(), op);
+ self.mark_alias_installed(&mut **repo.borrow_mut(), op)?;
}
AnyOperation::MarkAliasUninstalled(op) => {
self.mark_alias_uninstalled(&mut **repo.borrow_mut(), op);
@@ -760,12 +759,14 @@ impl InstallationManager {
&self,
repo: &mut dyn InstalledRepositoryInterface,
operation: &MarkAliasInstalledOperation,
- ) {
+ ) -> anyhow::Result<()> {
let package = operation.get_package();
- if !repo.has_package(package.clone().into()) {
+ if !repo.has_package(package.clone().into())? {
repo.add_package(crate::package::PackageInterfaceHandle::dup(&package.into()));
}
+
+ Ok(())
}
/// Executes markAlias operation.
@@ -1016,7 +1017,7 @@ pub trait InstallationManagerInterface: std::fmt::Debug {
fn disable_plugins(&mut self);
fn is_package_installed(
&mut self,
- repo: &dyn InstalledRepositoryInterface,
+ repo: &mut dyn InstalledRepositoryInterface,
package: PackageInterfaceHandle,
) -> anyhow::Result<bool>;
fn ensure_binaries_presence(&mut self, package: PackageInterfaceHandle);
@@ -1052,7 +1053,7 @@ impl InstallationManagerInterface for InstallationManager {
fn is_package_installed(
&mut self,
- repo: &dyn InstalledRepositoryInterface,
+ repo: &mut dyn InstalledRepositoryInterface,
package: PackageInterfaceHandle,
) -> anyhow::Result<bool> {
InstallationManager::is_package_installed(self, repo, package)
diff --git a/crates/shirabe/src/installer/installer_interface.rs b/crates/shirabe/src/installer/installer_interface.rs
index 6edaddb7..f2c0cd7c 100644
--- a/crates/shirabe/src/installer/installer_interface.rs
+++ b/crates/shirabe/src/installer/installer_interface.rs
@@ -12,9 +12,9 @@ pub trait InstallerInterface: std::fmt::Debug {
fn is_installed(
&self,
- repo: &dyn InstalledRepositoryInterface,
+ repo: &mut dyn InstalledRepositoryInterface,
package: PackageInterfaceHandle,
- ) -> bool;
+ ) -> anyhow::Result<bool>;
async fn download(
&self,
diff --git a/crates/shirabe/src/installer/library_installer.rs b/crates/shirabe/src/installer/library_installer.rs
index 8efd985a..976c5a1f 100644
--- a/crates/shirabe/src/installer/library_installer.rs
+++ b/crates/shirabe/src/installer/library_installer.rs
@@ -241,32 +241,32 @@ impl InstallerInterface for LibraryInstaller {
fn is_installed(
&self,
- repo: &dyn InstalledRepositoryInterface,
+ repo: &mut dyn InstalledRepositoryInterface,
package: PackageInterfaceHandle,
- ) -> bool {
- if !repo.has_package(package.clone()) {
- return false;
+ ) -> anyhow::Result<bool> {
+ if !repo.has_package(package.clone())? {
+ return Ok(false);
}
let install_path = self.get_install_path(package).unwrap();
if Filesystem::is_readable(&install_path) {
- return true;
+ return Ok(true);
}
if Platform::is_windows() && self.filesystem.borrow_mut().is_junction(&install_path) {
- return true;
+ return Ok(true);
}
if is_link(&install_path) {
if realpath(&install_path).is_none() {
- return false;
+ return Ok(false);
}
- return true;
+ return Ok(true);
}
- false
+ Ok(false)
}
async fn download(
@@ -322,7 +322,9 @@ impl InstallerInterface for LibraryInstaller {
let download_path = self.get_install_path(package.clone()).unwrap();
// remove the binaries if it appears the package files are missing
- if !Filesystem::is_readable(&download_path) && repo.borrow().has_package(package.clone()) {
+ if !Filesystem::is_readable(&download_path)
+ && repo.borrow_mut().has_package(package.clone())?
+ {
self.binary_installer
.borrow_mut()
.remove_binaries(package.clone());
@@ -335,7 +337,7 @@ impl InstallerInterface for LibraryInstaller {
.borrow_mut()
.install_binaries(package.clone(), &install_path, true);
let mut repo = repo.borrow_mut();
- if !repo.has_package(package.clone()) {
+ if !repo.has_package(package.clone())? {
repo.add_package(PackageInterfaceHandle::dup(&package));
}
@@ -348,7 +350,7 @@ impl InstallerInterface for LibraryInstaller {
initial: PackageInterfaceHandle,
target: PackageInterfaceHandle,
) -> anyhow::Result<Option<PhpMixed>> {
- if !repo.borrow().has_package(initial.clone()) {
+ if !repo.borrow_mut().has_package(initial.clone())? {
return Err(InvalidArgumentException {
message: format!("Package is not installed: {}", initial),
code: 0,
@@ -369,7 +371,7 @@ impl InstallerInterface for LibraryInstaller {
.install_binaries(target.clone(), &install_path, true);
let mut repo = repo.borrow_mut();
repo.remove_package(initial.clone());
- if !repo.has_package(target.clone()) {
+ if !repo.has_package(target.clone())? {
repo.add_package(PackageInterfaceHandle::dup(&target));
}
@@ -381,7 +383,7 @@ impl InstallerInterface for LibraryInstaller {
repo: &std::cell::RefCell<&mut dyn InstalledRepositoryInterface>,
package: PackageInterfaceHandle,
) -> anyhow::Result<Option<PhpMixed>> {
- if !repo.borrow().has_package(package.clone()) {
+ if !repo.borrow_mut().has_package(package.clone())? {
return Err(InvalidArgumentException {
message: format!("Package is not installed: {}", package),
code: 0,
diff --git a/crates/shirabe/src/installer/metapackage_installer.rs b/crates/shirabe/src/installer/metapackage_installer.rs
index cb6d13c3..26032a6d 100644
--- a/crates/shirabe/src/installer/metapackage_installer.rs
+++ b/crates/shirabe/src/installer/metapackage_installer.rs
@@ -30,9 +30,9 @@ impl InstallerInterface for MetapackageInstaller {
fn is_installed(
&self,
- repo: &dyn InstalledRepositoryInterface,
+ repo: &mut dyn InstalledRepositoryInterface,
package: PackageInterfaceHandle,
- ) -> bool {
+ ) -> anyhow::Result<bool> {
repo.has_package(package)
}
@@ -85,7 +85,7 @@ impl InstallerInterface for MetapackageInstaller {
initial: PackageInterfaceHandle,
target: PackageInterfaceHandle,
) -> anyhow::Result<Option<PhpMixed>> {
- if !repo.borrow().has_package(initial.clone()) {
+ if !repo.borrow_mut().has_package(initial.clone())? {
return Err(InvalidArgumentException {
message: format!("Package is not installed: {}", initial),
code: 0,
@@ -114,7 +114,7 @@ impl InstallerInterface for MetapackageInstaller {
repo: &std::cell::RefCell<&mut dyn InstalledRepositoryInterface>,
package: PackageInterfaceHandle,
) -> anyhow::Result<Option<PhpMixed>> {
- if !repo.borrow().has_package(package.clone()) {
+ if !repo.borrow_mut().has_package(package.clone())? {
return Err(InvalidArgumentException {
message: format!("Package is not installed: {}", package),
code: 0,
diff --git a/crates/shirabe/src/installer/noop_installer.rs b/crates/shirabe/src/installer/noop_installer.rs
index c83bf674..d76ad4ad 100644
--- a/crates/shirabe/src/installer/noop_installer.rs
+++ b/crates/shirabe/src/installer/noop_installer.rs
@@ -16,9 +16,9 @@ impl InstallerInterface for NoopInstaller {
fn is_installed(
&self,
- repo: &dyn InstalledRepositoryInterface,
+ repo: &mut dyn InstalledRepositoryInterface,
package: PackageInterfaceHandle,
- ) -> bool {
+ ) -> anyhow::Result<bool> {
repo.has_package(package)
}
@@ -54,7 +54,7 @@ impl InstallerInterface for NoopInstaller {
package: PackageInterfaceHandle,
) -> anyhow::Result<Option<PhpMixed>> {
let mut repo = repo.borrow_mut();
- if !repo.has_package(package.clone()) {
+ if !repo.has_package(package.clone())? {
repo.add_package(PackageInterfaceHandle::dup(&package));
}
@@ -68,7 +68,7 @@ impl InstallerInterface for NoopInstaller {
target: PackageInterfaceHandle,
) -> anyhow::Result<Option<PhpMixed>> {
let mut repo = repo.borrow_mut();
- if !repo.has_package(initial.clone()) {
+ if !repo.has_package(initial.clone())? {
return Err(InvalidArgumentException {
message: format!("Package is not installed: {}", initial),
code: 0,
@@ -77,7 +77,7 @@ impl InstallerInterface for NoopInstaller {
}
repo.remove_package(initial);
- if !repo.has_package(target.clone()) {
+ if !repo.has_package(target.clone())? {
repo.add_package(PackageInterfaceHandle::dup(&target));
}
@@ -90,7 +90,7 @@ impl InstallerInterface for NoopInstaller {
package: PackageInterfaceHandle,
) -> anyhow::Result<Option<PhpMixed>> {
let mut repo = repo.borrow_mut();
- if !repo.has_package(package.clone()) {
+ if !repo.has_package(package.clone())? {
return Err(InvalidArgumentException {
message: format!("Package is not installed: {}", package),
code: 0,
diff --git a/crates/shirabe/src/installer/plugin_installer.rs b/crates/shirabe/src/installer/plugin_installer.rs
index 86c579b2..c0473fd0 100644
--- a/crates/shirabe/src/installer/plugin_installer.rs
+++ b/crates/shirabe/src/installer/plugin_installer.rs
@@ -79,9 +79,9 @@ impl InstallerInterface for PluginInstaller {
fn is_installed(
&self,
- repo: &dyn InstalledRepositoryInterface,
+ repo: &mut dyn InstalledRepositoryInterface,
package: PackageInterfaceHandle,
- ) -> bool {
+ ) -> anyhow::Result<bool> {
self.inner.is_installed(repo, package)
}
diff --git a/crates/shirabe/src/installer/project_installer.rs b/crates/shirabe/src/installer/project_installer.rs
index 0f2c3ba6..628e4252 100644
--- a/crates/shirabe/src/installer/project_installer.rs
+++ b/crates/shirabe/src/installer/project_installer.rs
@@ -37,10 +37,10 @@ impl InstallerInterface for ProjectInstaller {
fn is_installed(
&self,
- _repo: &dyn InstalledRepositoryInterface,
+ _repo: &mut dyn InstalledRepositoryInterface,
_package: PackageInterfaceHandle,
- ) -> bool {
- false
+ ) -> anyhow::Result<bool> {
+ Ok(false)
}
async fn download(
diff --git a/crates/shirabe/src/repository/array_repository.rs b/crates/shirabe/src/repository/array_repository.rs
index 09c37766..30598b62 100644
--- a/crates/shirabe/src/repository/array_repository.rs
+++ b/crates/shirabe/src/repository/array_repository.rs
@@ -205,6 +205,16 @@ impl ArrayRepository {
*self.packages.borrow_mut() = Some(vec![]);
}
+ /// Shared body of `RepositoryInterface::count`, kept on `&self` for `get_repo_name` (PHP's
+ /// `getRepoName` also triggers lazy initialization through `count()`).
+ pub(crate) fn base_count(&self) -> usize {
+ if self.packages.borrow().is_none() {
+ self.initialize();
+ }
+
+ self.packages.borrow().as_ref().unwrap().len()
+ }
+
/// Resets the packages cache so the next access re-runs `initialize`.
pub(crate) fn reset_packages(&self) {
*self.packages.borrow_mut() = None;
@@ -217,16 +227,12 @@ impl ArrayRepository {
impl RepositoryInterface for ArrayRepository {
/// Returns the number of packages in this repository
- fn count(&self) -> anyhow::Result<usize> {
- if self.packages.borrow().is_none() {
- self.initialize();
- }
-
- Ok(self.packages.borrow().as_ref().unwrap().len())
+ fn count(&mut self) -> anyhow::Result<usize> {
+ Ok(self.base_count())
}
fn get_repo_name(&self) -> String {
- let count = self.count().expect("ArrayRepository::count is infallible");
+ let count = self.base_count();
format!(
"array repo (defining {} package{})",
count,
@@ -409,7 +415,7 @@ impl RepositoryInterface for ArrayRepository {
Ok(matches.into_values().collect())
}
- fn has_package(&self, package: PackageInterfaceHandle) -> bool {
+ fn has_package(&mut self, package: PackageInterfaceHandle) -> anyhow::Result<bool> {
if self.package_map.borrow().is_none() {
let mut map: IndexMap<String, BasePackageHandle> = IndexMap::new();
for repo_package in self.get_packages_internal() {
@@ -418,11 +424,12 @@ impl RepositoryInterface for ArrayRepository {
*self.package_map.borrow_mut() = Some(map);
}
- self.package_map
+ Ok(self
+ .package_map
.borrow()
.as_ref()
.unwrap()
- .contains_key(&package.get_unique_name())
+ .contains_key(&package.get_unique_name()))
}
fn get_providers(
diff --git a/crates/shirabe/src/repository/artifact_repository.rs b/crates/shirabe/src/repository/artifact_repository.rs
index 7d9c02b6..f18f7f04 100644
--- a/crates/shirabe/src/repository/artifact_repository.rs
+++ b/crates/shirabe/src/repository/artifact_repository.rs
@@ -247,16 +247,13 @@ impl RepositoryInterface for ArtifactRepository {
// The structural methods are inherited from ArrayRepository in PHP, where the lazy directory
// scan is driven by the overridden initialize(). Here each one first ensures that scan has
// happened (see ensure_initialized), then delegates to the inner ArrayRepository.
- fn count(&self) -> anyhow::Result<usize> {
+ fn count(&mut self) -> anyhow::Result<usize> {
self.ensure_initialized()?;
self.inner.count()
}
- fn has_package(&self, package: PackageInterfaceHandle) -> bool {
- // TODO(phase-d): hasPackage returns bool and cannot surface an initialization error; a
- // failed scan leaves the inner repository with whatever packages were added before the
- // failure.
- let _ = self.ensure_initialized();
+ fn has_package(&mut self, package: PackageInterfaceHandle) -> anyhow::Result<bool> {
+ self.ensure_initialized()?;
self.inner.has_package(package)
}
diff --git a/crates/shirabe/src/repository/composer_repository.rs b/crates/shirabe/src/repository/composer_repository.rs
index 558d7e00..ba68d22c 100644
--- a/crates/shirabe/src/repository/composer_repository.rs
+++ b/crates/shirabe/src/repository/composer_repository.rs
@@ -79,15 +79,6 @@ pub struct ProviderListingEntry {
#[derive(Debug)]
pub struct ComposerRepository {
- // TODO(phase-c): PHP's ArrayRepository methods that aren't overridden here (findPackage,
- // findPackages, count, hasPackage) call $this->getPackages(), which virtual-dispatches back
- // to ComposerRepository::getPackages() (see its "embedded inheritance does not dispatch back
- // to the wrapper" comment below, and the identical guard in load_packages()). Composition
- // doesn't get that dispatch for free: self.inner.find_package()/find_packages()/count()/
- // has_package() below call ArrayRepository::initialize() (a no-op stub) instead, and will
- // silently see an empty package list if called before get_packages()/load_packages() has
- // run once on this instance. Not yet known to be hit by any test; audit call sites and add
- // the same `if !self.inner.is_initialized() { self.initialize()?; }` guard where needed.
inner: ArrayRepository,
/// Weak reference to the outermost repository handle wrapping this `ComposerRepository`,
/// injected via `set_self_handle`. Used to wire package -> repository back-references.
@@ -3409,11 +3400,20 @@ fn clone_root_data(rd: &RootData) -> RootData {
}
impl RepositoryInterface for ComposerRepository {
- fn count(&self) -> anyhow::Result<usize> {
+ // PHP's ArrayRepository::count()/hasPackage() call $this->initialize(), which
+ // virtual-dispatches to ComposerRepository::initialize(); the guard restores that
+ // (same guard as in get_packages()).
+ fn count(&mut self) -> anyhow::Result<usize> {
+ if !self.inner.is_initialized() {
+ self.initialize()?;
+ }
self.inner.count()
}
- fn has_package(&self, package: PackageInterfaceHandle) -> bool {
+ fn has_package(&mut self, package: PackageInterfaceHandle) -> anyhow::Result<bool> {
+ if !self.inner.is_initialized() {
+ self.initialize()?;
+ }
self.inner.has_package(package)
}
diff --git a/crates/shirabe/src/repository/composite_repository.rs b/crates/shirabe/src/repository/composite_repository.rs
index 9e5c9757..a9c55a0f 100644
--- a/crates/shirabe/src/repository/composite_repository.rs
+++ b/crates/shirabe/src/repository/composite_repository.rs
@@ -60,7 +60,7 @@ impl CompositeRepository {
}
impl RepositoryInterface for CompositeRepository {
- fn count(&self) -> anyhow::Result<usize> {
+ fn count(&mut self) -> anyhow::Result<usize> {
let mut total = 0;
for repository in &self.repositories {
total += repository.count()?;
@@ -78,13 +78,13 @@ impl RepositoryInterface for CompositeRepository {
format!("composite repo ({})", names.join(", "))
}
- fn has_package(&self, package: PackageInterfaceHandle) -> bool {
+ fn has_package(&mut self, package: PackageInterfaceHandle) -> anyhow::Result<bool> {
for repository in &self.repositories {
- if repository.has_package(package.clone()) {
- return true;
+ if repository.has_package(package.clone())? {
+ return Ok(true);
}
}
- false
+ Ok(false)
}
fn find_package(
diff --git a/crates/shirabe/src/repository/filesystem_repository.rs b/crates/shirabe/src/repository/filesystem_repository.rs
index d4b9b72e..9186a836 100644
--- a/crates/shirabe/src/repository/filesystem_repository.rs
+++ b/crates/shirabe/src/repository/filesystem_repository.rs
@@ -716,11 +716,15 @@ impl FilesystemRepository {
}
impl RepositoryInterface for FilesystemRepository {
- fn count(&self) -> anyhow::Result<usize> {
+ // PHP's ArrayRepository::count()/hasPackage() call $this->initialize(), which
+ // virtual-dispatches to FilesystemRepository::initialize(); the guard restores that.
+ fn count(&mut self) -> anyhow::Result<usize> {
+ self.ensure_initialized()?;
self.inner.count()
}
- fn has_package(&self, package: PackageInterfaceHandle) -> bool {
+ fn has_package(&mut self, package: PackageInterfaceHandle) -> anyhow::Result<bool> {
+ self.ensure_initialized()?;
self.inner.has_package(package)
}
diff --git a/crates/shirabe/src/repository/filter_repository.rs b/crates/shirabe/src/repository/filter_repository.rs
index bdf17c54..32a32ba1 100644
--- a/crates/shirabe/src/repository/filter_repository.rs
+++ b/crates/shirabe/src/repository/filter_repository.rs
@@ -148,7 +148,7 @@ impl FilterRepository {
}
impl RepositoryInterface for FilterRepository {
- fn count(&self) -> anyhow::Result<usize> {
+ fn count(&mut self) -> anyhow::Result<usize> {
if self.repo.count()? > 0 {
Ok(self
.repo
@@ -161,7 +161,7 @@ impl RepositoryInterface for FilterRepository {
}
}
- fn has_package(&self, package: PackageInterfaceHandle) -> bool {
+ fn has_package(&mut self, package: PackageInterfaceHandle) -> anyhow::Result<bool> {
self.repo.has_package(package)
}
diff --git a/crates/shirabe/src/repository/handle.rs b/crates/shirabe/src/repository/handle.rs
index f093f66b..497e2b91 100644
--- a/crates/shirabe/src/repository/handle.rs
+++ b/crates/shirabe/src/repository/handle.rs
@@ -84,7 +84,7 @@ impl RepositoryInterfaceHandle {
}
pub fn count(&self) -> anyhow::Result<usize> {
- self.0.borrow().count()
+ self.0.borrow_mut().count()
}
pub fn get_repo_name(&self) -> String {
@@ -95,8 +95,8 @@ impl RepositoryInterfaceHandle {
self.0.borrow_mut().get_packages()
}
- pub fn has_package(&self, package: PackageInterfaceHandle) -> bool {
- self.0.borrow().has_package(package)
+ pub fn has_package(&self, package: PackageInterfaceHandle) -> anyhow::Result<bool> {
+ self.0.borrow_mut().has_package(package)
}
pub fn find_package(
diff --git a/crates/shirabe/src/repository/installed_array_repository.rs b/crates/shirabe/src/repository/installed_array_repository.rs
index dd0f7d38..b458ff61 100644
--- a/crates/shirabe/src/repository/installed_array_repository.rs
+++ b/crates/shirabe/src/repository/installed_array_repository.rs
@@ -39,10 +39,7 @@ impl InstalledRepositoryInterface for InstalledArrayRepository {
}
fn is_fresh(&self) -> bool {
- self.inner
- .count()
- .expect("WritableArrayRepository::count is infallible")
- == 0
+ self.inner.base_count() == 0
}
}
@@ -82,11 +79,11 @@ impl WritableRepositoryInterface for InstalledArrayRepository {
}
impl RepositoryInterface for InstalledArrayRepository {
- fn count(&self) -> anyhow::Result<usize> {
+ fn count(&mut self) -> anyhow::Result<usize> {
self.inner.count()
}
- fn has_package(&self, package: PackageInterfaceHandle) -> bool {
+ fn has_package(&mut self, package: PackageInterfaceHandle) -> anyhow::Result<bool> {
self.inner.has_package(package)
}
fn find_package(
diff --git a/crates/shirabe/src/repository/installed_filesystem_repository.rs b/crates/shirabe/src/repository/installed_filesystem_repository.rs
index 7fab762a..85fb514b 100644
--- a/crates/shirabe/src/repository/installed_filesystem_repository.rs
+++ b/crates/shirabe/src/repository/installed_filesystem_repository.rs
@@ -113,11 +113,11 @@ impl WritableRepositoryInterface for InstalledFilesystemRepository {
}
impl RepositoryInterface for InstalledFilesystemRepository {
- fn count(&self) -> anyhow::Result<usize> {
+ fn count(&mut self) -> anyhow::Result<usize> {
self.inner.count()
}
- fn has_package(&self, package: PackageInterfaceHandle) -> bool {
+ fn has_package(&mut self, package: PackageInterfaceHandle) -> anyhow::Result<bool> {
self.inner.has_package(package)
}
fn find_package(
diff --git a/crates/shirabe/src/repository/installed_repository.rs b/crates/shirabe/src/repository/installed_repository.rs
index 388670d4..08b1f36b 100644
--- a/crates/shirabe/src/repository/installed_repository.rs
+++ b/crates/shirabe/src/repository/installed_repository.rs
@@ -376,7 +376,7 @@ impl InstalledRepository {
}
impl RepositoryInterface for InstalledRepository {
- fn count(&self) -> anyhow::Result<usize> {
+ fn count(&mut self) -> anyhow::Result<usize> {
self.inner.count()
}
@@ -390,7 +390,7 @@ impl RepositoryInterface for InstalledRepository {
format!("installed repo ({})", names.join(", "))
}
- fn has_package(&self, package: PackageInterfaceHandle) -> bool {
+ fn has_package(&mut self, package: PackageInterfaceHandle) -> anyhow::Result<bool> {
self.inner.has_package(package)
}
diff --git a/crates/shirabe/src/repository/lock_array_repository.rs b/crates/shirabe/src/repository/lock_array_repository.rs
index 390fae38..8b909fbc 100644
--- a/crates/shirabe/src/repository/lock_array_repository.rs
+++ b/crates/shirabe/src/repository/lock_array_repository.rs
@@ -31,11 +31,11 @@ impl LockArrayRepository {
}
impl RepositoryInterface for LockArrayRepository {
- fn count(&self) -> anyhow::Result<usize> {
+ fn count(&mut self) -> anyhow::Result<usize> {
self.inner.count()
}
- fn has_package(&self, package: PackageInterfaceHandle) -> bool {
+ fn has_package(&mut self, package: PackageInterfaceHandle) -> anyhow::Result<bool> {
self.inner.has_package(package)
}
diff --git a/crates/shirabe/src/repository/package_repository.rs b/crates/shirabe/src/repository/package_repository.rs
index 3397f071..06b28451 100644
--- a/crates/shirabe/src/repository/package_repository.rs
+++ b/crates/shirabe/src/repository/package_repository.rs
@@ -108,16 +108,13 @@ impl RepositoryInterface for PackageRepository {
// The structural methods are inherited from ArrayRepository in PHP, where the lazy package load
// is driven by the overridden initialize(). Here each one first ensures that load has happened
// (see ensure_initialized), then delegates to the inner ArrayRepository.
- fn count(&self) -> anyhow::Result<usize> {
+ fn count(&mut self) -> anyhow::Result<usize> {
self.ensure_initialized()?;
self.inner.count()
}
- fn has_package(&self, package: PackageInterfaceHandle) -> bool {
- // TODO(phase-d): hasPackage returns bool and cannot surface an initialization error; a
- // failed load leaves the inner repository with whatever packages were added before the
- // failure.
- let _ = self.ensure_initialized();
+ fn has_package(&mut self, package: PackageInterfaceHandle) -> anyhow::Result<bool> {
+ self.ensure_initialized()?;
self.inner.has_package(package)
}
diff --git a/crates/shirabe/src/repository/path_repository.rs b/crates/shirabe/src/repository/path_repository.rs
index d7f24fa7..879b769c 100644
--- a/crates/shirabe/src/repository/path_repository.rs
+++ b/crates/shirabe/src/repository/path_repository.rs
@@ -141,7 +141,7 @@ impl PathRepository {
) -> anyhow::Result<bool> {
self.initialize()?;
use crate::repository::RepositoryInterface;
- Ok(self.inner.has_package(package))
+ self.inner.has_package(package)
}
// In PHP the inherited ArrayRepository methods lazily call the overridden initialize() to glob
@@ -397,16 +397,13 @@ impl RepositoryInterface for PathRepository {
// The structural methods are inherited from ArrayRepository in PHP, where the lazy package load
// is driven by the overridden initialize(). Here each one first ensures that load has happened
// (see ensure_initialized), then delegates to the inner ArrayRepository.
- fn count(&self) -> anyhow::Result<usize> {
+ fn count(&mut self) -> anyhow::Result<usize> {
self.ensure_initialized()?;
self.inner.count()
}
- fn has_package(&self, package: PackageInterfaceHandle) -> bool {
- // TODO(phase-d): hasPackage returns bool and cannot surface an initialization error; a
- // failed load leaves the inner repository with whatever packages were added before the
- // failure.
- let _ = self.ensure_initialized();
+ fn has_package(&mut self, package: PackageInterfaceHandle) -> anyhow::Result<bool> {
+ self.ensure_initialized()?;
self.inner.has_package(package)
}
diff --git a/crates/shirabe/src/repository/platform_repository.rs b/crates/shirabe/src/repository/platform_repository.rs
index e4d93d3b..30164237 100644
--- a/crates/shirabe/src/repository/platform_repository.rs
+++ b/crates/shirabe/src/repository/platform_repository.rs
@@ -1866,11 +1866,15 @@ impl PlatformRepository {
}
impl crate::repository::RepositoryInterface for PlatformRepository {
- fn count(&self) -> anyhow::Result<usize> {
+ // PHP's ArrayRepository::count()/hasPackage() call $this->initialize(), which
+ // virtual-dispatches to PlatformRepository::initialize(); the guard restores that.
+ fn count(&mut self) -> anyhow::Result<usize> {
+ self.ensure_initialized()?;
self.inner.count()
}
- fn has_package(&self, package: PackageInterfaceHandle) -> bool {
+ fn has_package(&mut self, package: PackageInterfaceHandle) -> anyhow::Result<bool> {
+ self.ensure_initialized()?;
self.inner.has_package(package)
}
diff --git a/crates/shirabe/src/repository/repository_interface.rs b/crates/shirabe/src/repository/repository_interface.rs
index 6dbc01da..ab25242c 100644
--- a/crates/shirabe/src/repository/repository_interface.rs
+++ b/crates/shirabe/src/repository/repository_interface.rs
@@ -52,9 +52,13 @@ pub const SEARCH_NAME: i64 = 1;
pub const SEARCH_VENDOR: i64 = 2;
pub trait RepositoryInterface: std::fmt::Debug {
- fn count(&self) -> anyhow::Result<usize>;
+ // count/has_package take &mut self (and has_package returns Result) because PHP's
+ // ArrayRepository::count()/hasPackage() late-bind $this->initialize() to the concrete
+ // repository class, which lazily loads packages and can throw; lazy repositories need the
+ // same guard here (see FilesystemRepository/PlatformRepository/ComposerRepository).
+ fn count(&mut self) -> anyhow::Result<usize>;
- fn has_package(&self, package: PackageInterfaceHandle) -> bool;
+ fn has_package(&mut self, package: PackageInterfaceHandle) -> anyhow::Result<bool>;
fn find_package(
&mut self,
diff --git a/crates/shirabe/src/repository/root_package_repository.rs b/crates/shirabe/src/repository/root_package_repository.rs
index 4357ed69..7630f6c5 100644
--- a/crates/shirabe/src/repository/root_package_repository.rs
+++ b/crates/shirabe/src/repository/root_package_repository.rs
@@ -26,11 +26,11 @@ impl RootPackageRepository {
}
impl RepositoryInterface for RootPackageRepository {
- fn count(&self) -> anyhow::Result<usize> {
+ fn count(&mut self) -> anyhow::Result<usize> {
self.inner.count()
}
- fn has_package(&self, package: PackageInterfaceHandle) -> bool {
+ fn has_package(&mut self, package: PackageInterfaceHandle) -> anyhow::Result<bool> {
self.inner.has_package(package)
}
diff --git a/crates/shirabe/src/repository/vcs_repository.rs b/crates/shirabe/src/repository/vcs_repository.rs
index c04b1b67..b7ce1a6c 100644
--- a/crates/shirabe/src/repository/vcs_repository.rs
+++ b/crates/shirabe/src/repository/vcs_repository.rs
@@ -1053,16 +1053,13 @@ impl RepositoryInterface for VcsRepository {
// The structural methods are inherited from ArrayRepository in PHP, where the lazy package load
// is driven by the overridden initialize(). Here each one first ensures that load has happened
// (see ensure_initialized), then delegates to the inner ArrayRepository.
- fn count(&self) -> anyhow::Result<usize> {
+ fn count(&mut self) -> anyhow::Result<usize> {
self.ensure_initialized()?;
self.inner.count()
}
- fn has_package(&self, package: PackageInterfaceHandle) -> bool {
- // TODO(phase-d): hasPackage returns bool and cannot surface an initialization error; a
- // failed load leaves the inner repository with whatever packages were added before the
- // failure.
- let _ = self.ensure_initialized();
+ fn has_package(&mut self, package: PackageInterfaceHandle) -> anyhow::Result<bool> {
+ self.ensure_initialized()?;
self.inner.has_package(package)
}
diff --git a/crates/shirabe/src/repository/writable_array_repository.rs b/crates/shirabe/src/repository/writable_array_repository.rs
index e415a1e1..f5db2bd9 100644
--- a/crates/shirabe/src/repository/writable_array_repository.rs
+++ b/crates/shirabe/src/repository/writable_array_repository.rs
@@ -31,6 +31,11 @@ impl WritableArrayRepository {
self.dev_mode
}
+ /// See `ArrayRepository::base_count`; kept on `&self` for `is_fresh` callers.
+ pub(crate) fn base_count(&self) -> usize {
+ self.inner.base_count()
+ }
+
pub fn set_dev_package_names(&mut self, dev_package_names: Vec<String>) {
self.dev_package_names = dev_package_names;
}
@@ -124,11 +129,11 @@ impl WritableArrayRepository {
}
impl RepositoryInterface for WritableArrayRepository {
- fn count(&self) -> anyhow::Result<usize> {
+ fn count(&mut self) -> anyhow::Result<usize> {
self.inner.count()
}
- fn has_package(&self, package: PackageInterfaceHandle) -> bool {
+ fn has_package(&mut self, package: PackageInterfaceHandle) -> anyhow::Result<bool> {
self.inner.has_package(package)
}