aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/src/command
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-06-08 01:54:56 +0900
committernsfisis <nsfisis@gmail.com>2026-06-08 01:54:56 +0900
commit318ea948f5932dfa7942081a269d62fd7161a9bf (patch)
tree0fff2fe818f87a20dea89a51901f9e16071f2f53 /crates/shirabe/src/command
parentf232d7f9d2936ef84bd904cacd21c12cb7012b34 (diff)
downloadphp-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.rs12
-rw-r--r--crates/shirabe/src/command/init_command.rs24
-rw-r--r--crates/shirabe/src/command/self_update_command.rs44
-rw-r--r--crates/shirabe/src/command/show_command.rs37
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