diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-06-08 01:54:56 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-06-08 01:54:56 +0900 |
| commit | 318ea948f5932dfa7942081a269d62fd7161a9bf (patch) | |
| tree | 0fff2fe818f87a20dea89a51901f9e16071f2f53 /crates/shirabe/src/command | |
| parent | f232d7f9d2936ef84bd904cacd21c12cb7012b34 (diff) | |
| download | php-shirabe-318ea948f5932dfa7942081a269d62fd7161a9bf.tar.gz php-shirabe-318ea948f5932dfa7942081a269d62fd7161a9bf.tar.zst php-shirabe-318ea948f5932dfa7942081a269d62fd7161a9bf.zip | |
feat(phase-c): resolve reflection/downcast phase-b TODOs
Resolve category F phase-b TODOs (class-string, instanceof, get_class,
method_exists, __FILE__, Reflection API, downcast).
- VcsRepository: dispatch drivers through a VcsDriverKind enum
(instantiate/supports/php_class_name) and add constructors to the
concrete VCS drivers
- repository downcasts via RepositoryInterfaceHandle::downcast_rc and
as_any (init/show commands, vcs ValidatingArrayLoader)
- BaseCommand::is_self_update_command override replaces an instanceof
- Factory::create narrows PartialComposer to ComposerHandle via as_full
- InstalledVersions gains set_self_dir/set_installed_is_local_dir,
replacing Reflection-based static property mutation
- ClassLoader::as_array_iter ports the PHP (array) cast
- drop the unnecessary __FILE__ phar branch in self-update
application get_class(command) reclassified TODO(plugin); buffer_io
StreamableInputInterface downcast and the ValidatingArrayLoader trait
redesign left as tracked TODOs.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe/src/command')
| -rw-r--r-- | crates/shirabe/src/command/base_command.rs | 12 | ||||
| -rw-r--r-- | crates/shirabe/src/command/init_command.rs | 24 | ||||
| -rw-r--r-- | crates/shirabe/src/command/self_update_command.rs | 44 | ||||
| -rw-r--r-- | crates/shirabe/src/command/show_command.rs | 37 |
4 files changed, 59 insertions, 58 deletions
diff --git a/crates/shirabe/src/command/base_command.rs b/crates/shirabe/src/command/base_command.rs index 24b5a2b..d0818bf 100644 --- a/crates/shirabe/src/command/base_command.rs +++ b/crates/shirabe/src/command/base_command.rs @@ -279,6 +279,10 @@ pub trait HasBaseCommandData { fn io_mut(&mut self) -> &mut Option<Rc<RefCell<dyn IOInterface>>> { &mut self.base_command_data_mut().io } + + fn is_self_update_command(&self) -> bool { + false + } } impl<C: HasBaseCommandData> BaseCommand for C { @@ -352,7 +356,11 @@ impl<C: HasBaseCommandData> BaseCommand for C { .has_parameter_option(&["--no-scripts"], false); // TODO(phase-b): requires inner Symfony Application access for disable_plugins_by_default / disable_scripts_by_default - // TODO(phase-b): `$this instanceof SelfUpdateCommand` not representable + + if self.is_self_update_command() { + disable_plugins = true; + disable_scripts = true; + } let composer = self.try_composer(Some(disable_plugins), Some(disable_scripts)); let io = self.get_io(); @@ -503,7 +511,7 @@ impl<C: HasBaseCommandData> BaseCommand for C { }; // TODO(phase-b): Option<IndexMap<String, PhpMixed>> -> Option<LocalConfigInput> conversion let _ = config; - Factory::create(io, None, disable_plugins_kind, disable_scripts) + Factory::create(io, None, disable_plugins_kind, disable_scripts).map(|c| c.upcast()) } fn get_preferred_install_options( diff --git a/crates/shirabe/src/command/init_command.rs b/crates/shirabe/src/command/init_command.rs index f8bdad9..2a67532 100644 --- a/crates/shirabe/src/command/init_command.rs +++ b/crates/shirabe/src/command/init_command.rs @@ -757,17 +757,27 @@ impl InitCommand { io.write_error3("\nDefine your dependencies.\n", true, io_interface::NORMAL); // prepare to resolve dependencies - let _repos = self.get_repos(); + let repos = self.get_repos(); let preferred_stability = if let Some(s) = minimum_stability_default.clone().filter(|s| !s.is_empty()) { s } else { "stable".to_string() }; - // TODO(phase-b): repos instanceof CompositeRepository downcast - let _platform_repo: Option<&PlatformRepositoryHandle> = None; - - // (omitted: iterate repos to find PlatformRepository instance) + let platform_repo: Option<PlatformRepositoryHandle> = if repos.is::<CompositeRepository>() { + let borrowed = repos.borrow(); + let composite = borrowed + .as_any() + .downcast_ref::<CompositeRepository>() + .expect("is::<CompositeRepository>() checked above"); + composite + .get_repositories() + .iter() + .find(|candidate| candidate.is::<PlatformRepository>()) + .and_then(|candidate| candidate.as_platform_repository()) + } else { + None + }; let question = "Would you like to define your dependencies (require) interactively [<comment>yes</comment>]? ".to_string(); let require: Vec<String> = input @@ -785,7 +795,7 @@ impl InitCommand { input, _output, require, - _platform_repo, + platform_repo.as_ref(), &preferred_stability, false, false, @@ -820,7 +830,7 @@ impl InitCommand { input, _output, require_dev, - _platform_repo, + platform_repo.as_ref(), &preferred_stability, false, false, diff --git a/crates/shirabe/src/command/self_update_command.rs b/crates/shirabe/src/command/self_update_command.rs index 127661a..d0ffcde 100644 --- a/crates/shirabe/src/command/self_update_command.rs +++ b/crates/shirabe/src/command/self_update_command.rs @@ -15,8 +15,8 @@ use shirabe_php_shim::{ function_exists, hash_file, in_array, ini_get, is_array, is_file, is_numeric, is_writable, iterator_to_array, json_decode, openssl_free_key, openssl_get_md_methods, openssl_pkey_get_public, openssl_verify, posix_geteuid, posix_getpwuid, random_int, rename, - server_argv, sprintf, str_contains, str_replace, strpos, strtolower, strtr, tempnam, unlink, - usleep, version_compare, + server_argv, sprintf, str_replace, strpos, strtolower, strtr, tempnam, unlink, usleep, + version_compare, }; use crate::command::{BaseCommand, BaseCommandData, HasBaseCommandData}; @@ -78,42 +78,6 @@ impl SelfUpdateCommand { input: std::rc::Rc<std::cell::RefCell<dyn InputInterface>>, output: std::rc::Rc<std::cell::RefCell<dyn OutputInterface>>, ) -> Result<i64> { - // TODO(phase-b): __FILE__ / __DIR__ have no direct Rust equivalent - let file_path: &str = ""; - let dir_path: &str = ""; - - if strpos(file_path, "phar:") != Some(0) { - if str_contains(&strtr(dir_path, "\\", "/"), "vendor/composer/composer") { - let proj_dir = shirabe_php_shim::dirname_levels(dir_path, 6); - output.borrow().writeln( - "<error>This instance of Composer does not have the self-update command.</error>", - io_interface::NORMAL, - ); - output.borrow().writeln( - &format!( - "<comment>You are running Composer installed as a package in your current project (\"{}\").</comment>", - proj_dir - ), - io_interface::NORMAL, - ); - output.borrow().writeln( - "<comment>To update Composer, download a composer.phar from https://getcomposer.org and then run `composer.phar update composer/composer` in your project.</comment>", - io_interface::NORMAL, - ); - } else { - output.borrow().writeln( - "<error>This instance of Composer does not have the self-update command.</error>", - io_interface::NORMAL, - ); - output.borrow().writeln( - "<comment>This could be due to a number of reasons, such as Composer being installed as a system package on your OS, or Composer being installed as a package in the current project.</comment>", - io_interface::NORMAL, - ); - } - - return Ok(1); - } - if server_argv().get(0).map(|s| s.as_str()) == Some("Standard input code") { return Ok(1); } @@ -1207,4 +1171,8 @@ impl HasBaseCommandData for SelfUpdateCommand { fn base_command_data_mut(&mut self) -> &mut BaseCommandData { &mut self.base_command_data } + + fn is_self_update_command(&self) -> bool { + true + } } diff --git a/crates/shirabe/src/command/show_command.rs b/crates/shirabe/src/command/show_command.rs index f324a5c..a316c19 100644 --- a/crates/shirabe/src/command/show_command.rs +++ b/crates/shirabe/src/command/show_command.rs @@ -33,6 +33,7 @@ use crate::package::version::VersionParser; use crate::package::version::VersionSelector; use crate::plugin::CommandEvent; use crate::plugin::PluginEvents; +use crate::repository::ComposerRepository; use crate::repository::CompositeRepository; use crate::repository::FilterRepository; use crate::repository::InstalledArrayRepository; @@ -745,23 +746,37 @@ impl ShowCommand { } for repo in RepositoryUtils::flatten_repositories(repos.clone(), false) { - // TODO(phase-b): InstalledRepository needs as_repository_interface / get_repositories - // wired through; placeholder classification until then. let r#type = if Self::same_repository(&repo, &platform_repo) { "platform" - } else if let Some(ref lr) = locked_repo { - if Self::same_repository(&repo, lr) { - "locked" - } else { - "available" - } + } else if locked_repo + .as_ref() + .map_or(false, |lr| Self::same_repository(&repo, lr)) + { + "locked" + } else if Self::same_repository(&repo, &installed_repo) + || installed_repo + .borrow() + .as_any() + .downcast_ref::<InstalledRepository>() + .map_or(false, |ir| { + ir.get_repositories().iter().any(|r| r.ptr_eq(&repo)) + }) + { + "installed" } else { "available" }; let type_owned = r#type.to_string(); - // TODO(phase-b): RepositoryInterface needs as_composer_repository_mut downcast helper - if false { - let _ = package_filter.as_deref(); + if let Some(cr_rc) = repo.downcast_rc::<ComposerRepository>() { + let names = cr_rc + .borrow_mut() + .get_package_names(package_filter.as_deref())?; + for name in names { + packages + .entry(type_owned.clone()) + .or_insert_with(IndexMap::new) + .insert(name.clone(), PackageOrName::Name(name)); + } } else { for package in repo.get_packages()? { let existing = packages |
