diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-05-26 20:04:02 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-05-26 20:04:02 +0900 |
| commit | f411daceacad66e0bd774fda7d3c5ef8533cc55c (patch) | |
| tree | eefb065e4d676a3f7031ca49bab21c773b00b134 /crates/shirabe/src/command | |
| parent | 1921f173ea219cb4b25847294d2d3fa465550fbb (diff) | |
| download | php-shirabe-f411daceacad66e0bd774fda7d3c5ef8533cc55c.tar.gz php-shirabe-f411daceacad66e0bd774fda7d3c5ef8533cc55c.tar.zst php-shirabe-f411daceacad66e0bd774fda7d3c5ef8533cc55c.zip | |
refactor(io): share IOInterface via Rc<RefCell<dyn _>> handle
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe/src/command')
31 files changed, 171 insertions, 111 deletions
diff --git a/crates/shirabe/src/command/about_command.rs b/crates/shirabe/src/command/about_command.rs index ddb9f12..3e74d6e 100644 --- a/crates/shirabe/src/command/about_command.rs +++ b/crates/shirabe/src/command/about_command.rs @@ -6,6 +6,7 @@ use crate::command::HasBaseCommandData; use crate::composer; use crate::composer::ComposerHandle; use crate::io::IOInterface; +use crate::io::IOInterfaceImmutable; use shirabe_external_packages::symfony::component::console::input::InputInterface; use shirabe_external_packages::symfony::component::console::output::OutputInterface; diff --git a/crates/shirabe/src/command/archive_command.rs b/crates/shirabe/src/command/archive_command.rs index 1b21242..225b092 100644 --- a/crates/shirabe/src/command/archive_command.rs +++ b/crates/shirabe/src/command/archive_command.rs @@ -14,6 +14,7 @@ use crate::console::input::InputArgument; use crate::console::input::InputOption; use crate::factory::Factory; use crate::io::IOInterface; +use crate::io::IOInterfaceImmutable; use crate::package::archiver::ArchiveManager; use crate::package::version::VersionParser; use crate::package::version::VersionSelector; @@ -111,9 +112,9 @@ impl ArchiveCommand { }); // TODO(phase-b): clone_box to release self borrow held by get_io. - let mut io_box = self.get_io().clone_box(); + let io_box = self.get_io().clone(); let return_code = self.archive( - io_box.as_mut(), + io_box.clone(), &config, input .get_argument("package") @@ -153,7 +154,7 @@ impl ArchiveCommand { pub fn archive( &mut self, - io: &mut dyn IOInterface, + io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>, config: &std::rc::Rc<std::cell::RefCell<Config>>, package_name: Option<String>, version: Option<String>, @@ -173,12 +174,17 @@ impl ArchiveCommand { &composer_archive_manager_ref } else { let factory = Factory; - let process = std::rc::Rc::new(std::cell::RefCell::new(ProcessExecutor::new(()))); + let process = std::rc::Rc::new(std::cell::RefCell::new(ProcessExecutor::new(None))); let http_downloader = std::rc::Rc::new(std::cell::RefCell::new( - Factory::create_http_downloader(io, config, indexmap::IndexMap::new())?, + Factory::create_http_downloader(io.clone(), config, indexmap::IndexMap::new())?, )); - let download_manager = - factory.create_download_manager(io, config, &http_downloader, &process, None)?; + let download_manager = factory.create_download_manager( + io.clone(), + config, + &http_downloader, + &process, + None, + )?; let loop_ = std::rc::Rc::new(std::cell::RefCell::new(Loop::new( http_downloader.clone(), Some(process), @@ -190,7 +196,7 @@ impl ArchiveCommand { let package: crate::package::CompletePackageInterfaceHandle = if let Some(name) = package_name { - match self.select_package(io, &name, version.as_deref())? { + match self.select_package(io.clone(), &name, version.as_deref())? { Some(p) => p, None => return Ok(1), } @@ -227,7 +233,7 @@ impl ArchiveCommand { pub fn select_package( &mut self, - io: &mut dyn IOInterface, + io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>, package_name: &str, version: Option<&str>, ) -> Result<Option<crate::package::CompletePackageInterfaceHandle>> { @@ -253,7 +259,7 @@ impl ArchiveCommand { repo = CompositeRepository::new(repos); min_stability = composer.get_package().get_minimum_stability().to_string(); } else { - let default_repos = RepositoryFactory::default_repos_with_default_manager(io)?; + let default_repos = RepositoryFactory::default_repos_with_default_manager(io.clone())?; let repo_names: Vec<String> = default_repos.keys().cloned().collect(); io.write_error(&format!( "No composer.json found in the current directory, searching packages from {}", diff --git a/crates/shirabe/src/command/audit_command.rs b/crates/shirabe/src/command/audit_command.rs index d3dadbd..ec8b495 100644 --- a/crates/shirabe/src/command/audit_command.rs +++ b/crates/shirabe/src/command/audit_command.rs @@ -6,6 +6,7 @@ use crate::command::{BaseCommand, BaseCommandData, HasBaseCommandData}; use crate::composer::PartialComposerHandle; use crate::console::input::InputOption; use crate::io::IOInterface; +use crate::io::IOInterfaceImmutable; use crate::repository::CanonicalPackagesTrait; use crate::repository::InstalledRepository; use crate::repository::RepositoryInterface; @@ -127,7 +128,7 @@ impl AuditCommand { let _ = ignore_severities; Ok(auditor .audit( - self.get_io(), + &mut *self.get_io().borrow_mut(), &repo_set, packages, &audit_format, diff --git a/crates/shirabe/src/command/base_command.rs b/crates/shirabe/src/command/base_command.rs index 9511c4d..6b673ed 100644 --- a/crates/shirabe/src/command/base_command.rs +++ b/crates/shirabe/src/command/base_command.rs @@ -13,6 +13,8 @@ use shirabe_php_shim::{ InvalidArgumentException, LogicException, PhpMixed, RuntimeException, UnexpectedValueException, count, explode, in_array, is_string, max, }; +use std::cell::RefCell; +use std::rc::Rc; use crate::advisory::AuditConfig; use crate::advisory::Auditor; @@ -27,6 +29,7 @@ use crate::factory::Factory; use crate::filter::platform_requirement_filter::PlatformRequirementFilterFactory; use crate::filter::platform_requirement_filter::PlatformRequirementFilterInterface; use crate::io::IOInterface; +use crate::io::IOInterfaceImmutable; use crate::io::NullIO; use crate::package::version::VersionParser; use crate::plugin::PluginEvents; @@ -184,9 +187,9 @@ pub trait BaseCommand { /// Whether or not this command is meant to call another command. fn is_proxy_command(&self) -> bool; - fn get_io(&mut self) -> &mut dyn IOInterface; + fn get_io(&mut self) -> Rc<RefCell<dyn IOInterface>>; - fn set_io(&mut self, io: Box<dyn IOInterface>); + fn set_io(&mut self, io: Rc<RefCell<dyn IOInterface>>); // TODO(cli-completion): fn complete(&self, input: &CompletionInput, suggestions: &mut CompletionSuggestions); @@ -201,7 +204,7 @@ pub trait BaseCommand { fn create_composer_instance( &self, input: &dyn InputInterface, - io: &dyn IOInterface, + io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>, config: Option<IndexMap<String, PhpMixed>>, disable_plugins: bool, disable_scripts: Option<bool>, @@ -254,7 +257,7 @@ pub trait BaseCommand { #[derive(Debug)] pub struct BaseCommandData { pub(crate) composer: Option<PartialComposerHandle>, - pub(crate) io: Option<Box<dyn IOInterface>>, + pub(crate) io: Option<Rc<RefCell<dyn IOInterface>>>, } pub trait HasBaseCommandData { @@ -269,11 +272,11 @@ pub trait HasBaseCommandData { &mut self.base_command_data_mut().composer } - fn io(&self) -> Option<&dyn IOInterface> { - self.base_command_data().io.as_deref() + fn io(&self) -> Option<Rc<RefCell<dyn IOInterface>>> { + self.base_command_data().io.clone() } - fn io_mut(&mut self) -> &mut Option<Box<dyn IOInterface>> { + fn io_mut(&mut self) -> &mut Option<Rc<RefCell<dyn IOInterface>>> { &mut self.base_command_data_mut().io } } @@ -335,16 +338,16 @@ impl<C: HasBaseCommandData> BaseCommand for C { false } - fn get_io(&mut self) -> &mut dyn IOInterface { + fn get_io(&mut self) -> Rc<RefCell<dyn IOInterface>> { if self.io().is_none() { // TODO(phase-b): requires inner Symfony Application access - *self.io_mut() = Some(Box::new(NullIO::new())); + *self.io_mut() = Some(Rc::new(RefCell::new(NullIO::new()))); } - &mut **self.io_mut().as_mut().unwrap() + self.io().unwrap() } - fn set_io(&mut self, io: Box<dyn IOInterface>) { + fn set_io(&mut self, io: Rc<RefCell<dyn IOInterface>>) { *self.io_mut() = Some(io); } @@ -363,9 +366,7 @@ impl<C: HasBaseCommandData> BaseCommand for C { // TODO(phase-b): `$this instanceof SelfUpdateCommand` not representable let composer = self.try_composer(Some(disable_plugins), Some(disable_scripts)); - // TODO(phase-b): re-borrow self for get_io after try_composer move - let io_ptr: *const dyn IOInterface = self.get_io(); - let io = unsafe { &*io_ptr }; + let io = self.get_io(); let disable_plugins_kind = if disable_plugins { crate::factory::DisablePlugins::All @@ -373,7 +374,7 @@ impl<C: HasBaseCommandData> BaseCommand for C { crate::factory::DisablePlugins::None }; let composer = if composer.is_none() { - Factory::create_global(io, disable_plugins_kind, disable_scripts) + Factory::create_global(io.clone(), disable_plugins_kind, disable_scripts) } else { composer }; @@ -476,7 +477,7 @@ impl<C: HasBaseCommandData> BaseCommand for C { fn create_composer_instance( &self, input: &dyn InputInterface, - io: &dyn IOInterface, + io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>, config: Option<IndexMap<String, PhpMixed>>, disable_plugins: bool, disable_scripts: Option<bool>, diff --git a/crates/shirabe/src/command/base_config_command.rs b/crates/shirabe/src/command/base_config_command.rs index 85e68b3..1b7294e 100644 --- a/crates/shirabe/src/command/base_config_command.rs +++ b/crates/shirabe/src/command/base_config_command.rs @@ -37,9 +37,9 @@ pub trait BaseConfigCommand: BaseCommand { } // TODO(phase-b): clone_box to release the &mut self borrow held by get_io. - let io = self.get_io().clone_box(); + let io = self.get_io().clone(); *self.config_mut() = Some(std::rc::Rc::new(std::cell::RefCell::new( - Factory::create_config(Some(io.as_ref()), None)?, + Factory::create_config(Some(io.clone()), None)?, ))); let config_rc = self.config().unwrap().clone(); @@ -62,7 +62,7 @@ pub trait BaseConfigCommand: BaseCommand { self.set_config_file(Some(JsonFile::new( config_file.clone(), None, - Some(io.clone_box()), + Some(io.clone()), )?)); // TODO(phase-b): JsonConfigSource::new takes owned JsonFile, but PHP shares the same // instance with $this->configFile. Needs Rc<RefCell<JsonFile>> refactor on both sides. diff --git a/crates/shirabe/src/command/base_dependency_command.rs b/crates/shirabe/src/command/base_dependency_command.rs index 8ea10b5..f449629 100644 --- a/crates/shirabe/src/command/base_dependency_command.rs +++ b/crates/shirabe/src/command/base_dependency_command.rs @@ -10,6 +10,8 @@ use shirabe_semver::constraint::AnyConstraint; use shirabe_semver::constraint::Bound; use crate::command::{BaseCommand, BaseCommandData, HasBaseCommandData}; +use crate::io::IOInterface; +use crate::io::IOInterfaceImmutable; use crate::package::CompletePackageInterface; use crate::package::Link; use crate::package::Package; diff --git a/crates/shirabe/src/command/check_platform_reqs_command.rs b/crates/shirabe/src/command/check_platform_reqs_command.rs index 5d886e7..fd5edd9 100644 --- a/crates/shirabe/src/command/check_platform_reqs_command.rs +++ b/crates/shirabe/src/command/check_platform_reqs_command.rs @@ -11,6 +11,7 @@ use shirabe_semver::constraint::SimpleConstraint; use crate::command::{BaseCommand, BaseCommandData, HasBaseCommandData}; use crate::console::input::InputOption; use crate::io::IOInterface; +use crate::io::IOInterfaceImmutable; use crate::json::JsonFile; use crate::package::Link; use crate::repository::InstalledRepository; diff --git a/crates/shirabe/src/command/config_command.rs b/crates/shirabe/src/command/config_command.rs index 6412160..476be75 100644 --- a/crates/shirabe/src/command/config_command.rs +++ b/crates/shirabe/src/command/config_command.rs @@ -25,6 +25,7 @@ use crate::config::JsonConfigSource; use crate::console::input::InputArgument; use crate::factory::Factory; use crate::io::IOInterface; +use crate::io::IOInterfaceImmutable; use crate::json::JsonFile; use crate::package::base_package::{self, BasePackage}; use crate::util::Filesystem; @@ -130,7 +131,7 @@ impl ConfigCommand { self.auth_config_file = Some(JsonFile::new( auth_config_file, None, - Some(self.get_io().clone_box()), + Some(self.get_io().clone()), )?); // TODO(phase-b): JsonConfigSource::new takes owned JsonFile (PHP sharing semantics). // Skipping auth_config_source assignment until Rc<RefCell<JsonFile>> refactor lands. @@ -257,6 +258,7 @@ impl ConfigCommand { { let config_rc = self.config.as_ref().unwrap().clone(); self.get_io() + .borrow_mut() .load_configuration(&mut *config_rc.borrow_mut())?; } diff --git a/crates/shirabe/src/command/create_project_command.rs b/crates/shirabe/src/command/create_project_command.rs index e0cb3d4..d5a8a0c 100644 --- a/crates/shirabe/src/command/create_project_command.rs +++ b/crates/shirabe/src/command/create_project_command.rs @@ -30,6 +30,7 @@ use crate::installer::Installer; use crate::installer::ProjectInstaller; use crate::installer::SuggestedPackagesReporter; use crate::io::IOInterface; +use crate::io::IOInterfaceImmutable; use crate::json::JsonFile; use crate::package::version::VersionParser; use crate::package::version::VersionSelector; @@ -113,7 +114,7 @@ impl CreateProjectCommand { ) -> Result<i64> { let config = std::rc::Rc::new(std::cell::RefCell::new(Factory::create_config(None, None)?)); // TODO(phase-b): get_io returns &mut Self-borrow; clone_box for an owned Box to dodge. - let io: Box<dyn IOInterface> = self.get_io().clone_box(); + let io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>> = self.get_io().clone(); let (prefer_source, prefer_dist) = self.get_preferred_install_options(&config.borrow(), input, true)?; @@ -160,9 +161,8 @@ impl CreateProjectCommand { Some(repository_url_opt) }; - let mut io = io; self.install_project( - &mut *io, + io, config, input, input @@ -207,7 +207,7 @@ impl CreateProjectCommand { #[allow(clippy::too_many_arguments)] pub fn install_project( &mut self, - io: &mut dyn IOInterface, + io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>, config: std::rc::Rc<std::cell::RefCell<Config>>, input: &dyn InputInterface, package_name: Option<String>, @@ -247,14 +247,15 @@ impl CreateProjectCommand { .unwrap_or_else(PlatformRequirementFilterFactory::ignore_nothing); // we need to manually load the configuration to pass the auth credentials to the io interface! - io.load_configuration(&mut *config.borrow_mut())?; + io.borrow_mut() + .load_configuration(&mut *config.borrow_mut())?; - self.suggested_packages_reporter = Some(SuggestedPackagesReporter::new(io.clone_box())); + self.suggested_packages_reporter = Some(SuggestedPackagesReporter::new(io.clone())); let installed_from_vcs = if let Some(package_name) = package_name.as_ref() { self.install_root_package( input, - io, + io.clone(), &config, package_name, &*platform_requirement_filter, @@ -278,8 +279,13 @@ impl CreateProjectCommand { unlink("composer.lock"); } - let mut composer_handle = - self.create_composer_instance(input, io, None, disable_plugins, Some(disable_scripts))?; + let mut composer_handle = self.create_composer_instance( + input, + io.clone(), + None, + disable_plugins, + Some(disable_scripts), + )?; // add the repository to the composer.json and use it for the install run later if let Some(repos) = repositories.as_ref() { @@ -287,7 +293,7 @@ impl CreateProjectCommand { for (index, repo) in repos.iter().enumerate() { let config = crate::command::composer_full(&composer_handle).get_config(); let repo_config = - RepositoryFactory::config_from_string(io, &config, repo, true)?; + RepositoryFactory::config_from_string(io.clone(), &config, repo, true)?; let composer_json_repositories_config = crate::command::composer_full(&composer_handle) .get_config() @@ -332,8 +338,13 @@ impl CreateProjectCommand { ); } - composer_handle = - self.create_composer_instance(input, io, None, disable_plugins, None)?; + composer_handle = self.create_composer_instance( + input, + io.clone(), + None, + disable_plugins, + None, + )?; } } } @@ -371,7 +382,7 @@ impl CreateProjectCommand { .borrow_mut() .set_output_progress(!no_progress); - let mut installer = Installer::create(io.clone_box(), &composer_handle); + let mut installer = Installer::create(io.clone(), &composer_handle); // TODO(phase-b): set_suggested_packages_reporter takes by value but PHP class // means shared ownership; needs Rc<SuggestedPackagesReporter> for proper sharing. installer @@ -379,7 +390,7 @@ impl CreateProjectCommand { .set_prefer_dist(prefer_dist) .set_dev_mode(install_dev_packages) .set_platform_requirement_filter(platform_requirement_filter.clone_box()) - .set_suggested_packages_reporter(SuggestedPackagesReporter::new(io.clone_box())) + .set_suggested_packages_reporter(SuggestedPackagesReporter::new(io.clone())) .set_optimize_autoloader( config .borrow_mut() @@ -540,7 +551,7 @@ impl CreateProjectCommand { fn install_root_package( &self, input: &dyn InputInterface, - io: &dyn IOInterface, + io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>, config: &std::rc::Rc<std::cell::RefCell<Config>>, package_name: &str, platform_requirement_filter: &dyn PlatformRequirementFilterInterface, @@ -584,7 +595,7 @@ impl CreateProjectCommand { directory = rtrim(&directory, Some("/\\")); let process = std::rc::Rc::new(std::cell::RefCell::new(ProcessExecutor::new(Some( - io.clone_box(), + io.clone(), )))); let fs = std::rc::Rc::new(std::cell::RefCell::new(Filesystem::new(Some(process)))); if !fs.borrow().is_absolute_path(&directory) { @@ -704,7 +715,7 @@ impl CreateProjectCommand { let composer_handle = self.create_composer_instance( input, - io, + io.clone(), Some(config.borrow_mut().all(0)?), disable_plugins, Some(disable_scripts), @@ -727,7 +738,7 @@ impl CreateProjectCommand { // TODO(phase-b): default_repos needs &mut RepositoryManager but we hold &RepositoryManager. let _ = rm; repository_set.add_repository(Box::new(CompositeRepository::new( - RepositoryFactory::default_repos(Some(io), Some(config.clone()), None)? + RepositoryFactory::default_repos(Some(io.clone()), Some(config.clone()), None)? .into_iter() .map(|(_, v)| v) .collect(), @@ -735,7 +746,7 @@ impl CreateProjectCommand { } else { for repo in repositories.unwrap() { let mut repo_config = - RepositoryFactory::config_from_string(io, &config, repo, true)?; + RepositoryFactory::config_from_string(io.clone(), &config, repo, true)?; let is_packagist_disabled = (repo_config.contains_key("packagist") && repo_config.len() == 1 && repo_config.get("packagist").and_then(|v| v.as_bool()) == Some(false)) @@ -767,7 +778,7 @@ impl CreateProjectCommand { } repository_set.add_repository(RepositoryFactory::create_repo( - io, + io.clone(), &config, repo_config.clone(), None, @@ -803,7 +814,7 @@ impl CreateProjectCommand { &stability, None, 0, - Some(io), + Some(&*io.borrow()), PhpMixed::Bool(true), )?; @@ -913,7 +924,7 @@ impl CreateProjectCommand { true, false, )?; - im.notify_installs(io); + im.notify_installs(&*io.borrow()); // collect suggestions // TODO(phase-b): self.suggested_packages_reporter is on the outer scope via &self @@ -947,7 +958,7 @@ impl CreateProjectCommand { fn create_composer_instance( &self, input: &dyn InputInterface, - io: &dyn IOInterface, + io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>, config: Option<indexmap::IndexMap<String, PhpMixed>>, disable_plugins: bool, disable_scripts: Option<bool>, diff --git a/crates/shirabe/src/command/diagnose_command.rs b/crates/shirabe/src/command/diagnose_command.rs index fe57e5c..c64fc39 100644 --- a/crates/shirabe/src/command/diagnose_command.rs +++ b/crates/shirabe/src/command/diagnose_command.rs @@ -27,6 +27,7 @@ use crate::downloader::TransportException; use crate::factory::Factory; use crate::io::BufferIO; use crate::io::IOInterface; +use crate::io::IOInterfaceImmutable; use crate::io::NullIO; use crate::json::JsonFile; use crate::json::JsonValidationException; @@ -78,7 +79,7 @@ impl DiagnoseCommand { output: &dyn OutputInterface, ) -> anyhow::Result<i64> { let mut composer = self.try_composer(None, None); - let io_boxed: Box<dyn IOInterface> = self.get_io().clone_box(); + let io_boxed: std::rc::Rc<std::cell::RefCell<dyn IOInterface>> = self.get_io().clone(); let config: std::rc::Rc<std::cell::RefCell<Config>>; if let Some(ref mut c) = composer { @@ -103,7 +104,7 @@ impl DiagnoseCommand { .map(std::rc::Rc::clone) .unwrap_or_else(|| { std::rc::Rc::new(std::cell::RefCell::new(ProcessExecutor::new(Some( - io_boxed.clone_box(), + io_boxed.clone(), )))) }), ); @@ -111,12 +112,13 @@ impl DiagnoseCommand { config = std::rc::Rc::new(std::cell::RefCell::new(Factory::create_config(None, None)?)); self.process = Some(std::rc::Rc::new(std::cell::RefCell::new( - ProcessExecutor::new(Some(io_boxed.clone_box())), + ProcessExecutor::new(Some(io_boxed.clone())), ))); } // TODO(phase-b): clone_box to release self borrow held by get_io. - let io_box = self.get_io().clone_box(); - let io: &dyn IOInterface = io_box.as_ref(); + let io_box = self.get_io().clone(); + let io_ref = io_box.borrow(); + let io: &dyn IOInterface = &*io_ref; let mut config_inner: IndexMap<String, Box<PhpMixed>> = IndexMap::new(); config_inner.insert("secure-http".to_string(), Box::new(PhpMixed::Bool(false))); @@ -133,7 +135,7 @@ impl DiagnoseCommand { ); self.http_downloader = Some(std::rc::Rc::new(std::cell::RefCell::new( - Factory::create_http_downloader(io, &config, indexmap::IndexMap::new())?, + Factory::create_http_downloader(io_box.clone(), &config, indexmap::IndexMap::new())?, ))); if strpos(file!(), "phar:") == Some(0) { @@ -295,7 +297,7 @@ impl DiagnoseCommand { .collect(); let composer_repo = ComposerRepository::new( repo_arr_unboxed, - self.get_io().clone_box(), + self.get_io().clone(), &*config.borrow(), self.http_downloader.clone().unwrap(), None, @@ -427,7 +429,7 @@ impl DiagnoseCommand { } fn check_composer_schema(&mut self) -> anyhow::Result<PhpMixed> { - let validator = ConfigValidator::new(self.get_io().clone_box()); + let validator = ConfigValidator::new(self.get_io().clone()); let (errors, _, warnings) = validator.validate(&Factory::get_composer_file()?, 0, 0); if !errors.is_empty() || !warnings.is_empty() { @@ -680,7 +682,7 @@ impl DiagnoseCommand { return Ok(result); } - self.get_io().set_authentication( + self.get_io().borrow_mut().set_authentication( domain.to_string(), token.to_string(), Some("x-oauth-basic".to_string()), @@ -744,7 +746,7 @@ impl DiagnoseCommand { } if let Some(t) = token { - self.get_io().set_authentication( + self.get_io().borrow_mut().set_authentication( domain.to_string(), t.to_string(), Some("x-oauth-basic".to_string()), @@ -939,7 +941,7 @@ impl DiagnoseCommand { // TODO(phase-b): ComposerRepository does not implement RepositoryInterface yet let _composer_repo = ComposerRepository::new( repo_config, - Box::new(NullIO::new()), + std::rc::Rc::new(std::cell::RefCell::new(NullIO::new())), config, self.http_downloader.clone().unwrap(), None, diff --git a/crates/shirabe/src/command/dump_autoload_command.rs b/crates/shirabe/src/command/dump_autoload_command.rs index 275e635..6f361da 100644 --- a/crates/shirabe/src/command/dump_autoload_command.rs +++ b/crates/shirabe/src/command/dump_autoload_command.rs @@ -8,6 +8,7 @@ use shirabe_php_shim::{InvalidArgumentException, PhpMixed, file_exists}; use crate::command::{BaseCommand, BaseCommandData, HasBaseCommandData}; use crate::console::input::InputOption; use crate::io::IOInterface; +use crate::io::IOInterfaceImmutable; use crate::plugin::CommandEvent; use crate::plugin::PluginEvents; diff --git a/crates/shirabe/src/command/exec_command.rs b/crates/shirabe/src/command/exec_command.rs index 23aa103..3f70cf8 100644 --- a/crates/shirabe/src/command/exec_command.rs +++ b/crates/shirabe/src/command/exec_command.rs @@ -9,6 +9,7 @@ use crate::command::{BaseCommand, BaseCommandData, HasBaseCommandData}; use crate::console::input::InputArgument; use crate::console::input::InputOption; use crate::io::IOInterface; +use crate::io::IOInterfaceImmutable; #[derive(Debug)] pub struct ExecCommand { diff --git a/crates/shirabe/src/command/fund_command.rs b/crates/shirabe/src/command/fund_command.rs index f829342..340424f 100644 --- a/crates/shirabe/src/command/fund_command.rs +++ b/crates/shirabe/src/command/fund_command.rs @@ -15,6 +15,7 @@ use shirabe_semver::constraint::MatchAllConstraint; use crate::command::{BaseCommand, BaseCommandData, HasBaseCommandData}; use crate::console::input::InputOption; use crate::io::IOInterface; +use crate::io::IOInterfaceImmutable; use crate::json::JsonFile; use crate::package::AliasPackage; use crate::package::CompletePackage; diff --git a/crates/shirabe/src/command/global_command.rs b/crates/shirabe/src/command/global_command.rs index a8cf1d4..a3d5a78 100644 --- a/crates/shirabe/src/command/global_command.rs +++ b/crates/shirabe/src/command/global_command.rs @@ -13,6 +13,7 @@ use crate::command::{BaseCommand, BaseCommandData, HasBaseCommandData}; use crate::console::input::InputArgument; use crate::factory::Factory; use crate::io::IOInterface; +use crate::io::IOInterfaceImmutable; use crate::util::Filesystem; use crate::util::Platform; diff --git a/crates/shirabe/src/command/home_command.rs b/crates/shirabe/src/command/home_command.rs index 673039a..c048bfd 100644 --- a/crates/shirabe/src/command/home_command.rs +++ b/crates/shirabe/src/command/home_command.rs @@ -9,6 +9,7 @@ use crate::command::{BaseCommand, BaseCommandData, HasBaseCommandData}; use crate::console::input::InputArgument; use crate::console::input::InputOption; use crate::io::IOInterface; +use crate::io::IOInterfaceImmutable; use crate::package::CompletePackageInterfaceHandle; use crate::package::PackageInterface; use crate::package::RootPackageInterface; @@ -73,8 +74,9 @@ impl HomeCommand { ) -> Result<i64> { let repos = self.initialize_repos()?; // TODO(phase-b): clone_box to release self borrow held by get_io. - let io_box = self.get_io().clone_box(); - let io: &dyn IOInterface = io_box.as_ref(); + let io_box = self.get_io().clone(); + let io_ref = io_box.borrow(); + let io: &dyn IOInterface = &*io_ref; let mut return_code: i64 = 0; let packages: Vec<String> = input @@ -172,7 +174,7 @@ impl HomeCommand { } fn open_browser(&mut self, url: &str) { - let mut process = ProcessExecutor::new(Some(self.get_io().clone_box())); + let mut process = ProcessExecutor::new(Some(self.get_io().clone())); if Platform::is_windows() { let _ = process.execute( PhpMixed::from(vec!["start", "\"web\"", "explorer", url]), diff --git a/crates/shirabe/src/command/init_command.rs b/crates/shirabe/src/command/init_command.rs index 122642d..730658c 100644 --- a/crates/shirabe/src/command/init_command.rs +++ b/crates/shirabe/src/command/init_command.rs @@ -23,6 +23,7 @@ use crate::composer::PartialComposerHandle; use crate::console::input::InputOption; use crate::factory::Factory; use crate::io::IOInterface; +use crate::io::IOInterfaceImmutable; use crate::json::JsonFile; use crate::json::JsonValidationException; use crate::package::base_package::{self, BasePackage}; @@ -52,7 +53,7 @@ impl PackageDiscoveryTrait for InitCommand { todo!() } - fn get_io(&self) -> &dyn IOInterface { + fn get_io(&self) -> std::rc::Rc<std::cell::RefCell<dyn IOInterface>> { todo!() } @@ -193,11 +194,12 @@ impl InitCommand { .unwrap_or_default(); if (repositories.len() as i64) > 0 { let config = std::rc::Rc::new(std::cell::RefCell::new(Factory::create_config( - Some(io), + Some(io.clone()), None, )?)); for repo in &repositories { - let repo_config = RepositoryFactory::config_from_string(io, &config, repo, true)?; + let repo_config = + RepositoryFactory::config_from_string(io.clone(), &config, repo, true)?; let entry = options .entry("repositories".to_string()) .or_insert_with(|| PhpMixed::List(vec![])); @@ -445,17 +447,20 @@ impl InitCommand { .unwrap_or_default(); if (repositories.len() as i64) > 0 { let config = std::rc::Rc::new(std::cell::RefCell::new(Factory::create_config( - Some(io), + Some(io.clone()), None, )?)); - io.load_configuration(&mut *config.borrow_mut())?; - let mut repo_manager = RepositoryFactory::manager(io, &config, None, None, None)?; + io.borrow_mut() + .load_configuration(&mut *config.borrow_mut())?; + let mut repo_manager = + RepositoryFactory::manager(io.clone(), &config, None, None, None)?; let mut repos: Vec<Box<dyn crate::repository::RepositoryInterface>> = vec![Box::new(PlatformRepository::new(vec![], IndexMap::new())?)]; let mut create_default_packagist_repo = true; for repo in &repositories { - let repo_config = RepositoryFactory::config_from_string(io, &config, repo, true)?; + let repo_config = + RepositoryFactory::config_from_string(io.clone(), &config, repo, true)?; let is_packagist_false = repo_config .get("packagist") .map(|v| v.as_bool() == Some(false)) @@ -471,7 +476,7 @@ impl InitCommand { continue; } repos.push(RepositoryFactory::create_repo( - io, + io.clone(), &config, repo_config, Some(&mut repo_manager), @@ -486,7 +491,7 @@ impl InitCommand { PhpMixed::String("https://repo.packagist.org".to_string()), ); repos.push(RepositoryFactory::create_repo( - io, + io.clone(), &config, default_config, Some(&mut repo_manager), @@ -943,7 +948,7 @@ impl InitCommand { return self.git_config.clone().unwrap_or_default(); } - let mut process = ProcessExecutor::new(Some(self.get_io().clone_box())); + let mut process = ProcessExecutor::new(Some(self.get_io().clone())); let mut output = String::new(); if process.execute_args( diff --git a/crates/shirabe/src/command/install_command.rs b/crates/shirabe/src/command/install_command.rs index a0710dc..4c869f4 100644 --- a/crates/shirabe/src/command/install_command.rs +++ b/crates/shirabe/src/command/install_command.rs @@ -67,8 +67,9 @@ impl InstallCommand { output: &dyn OutputInterface, ) -> Result<i64> { // TODO(phase-b): clone_box to release self borrow held by get_io. - let io_box = self.get_io().clone_box(); - let io: &dyn IOInterface = io_box.as_ref(); + let io_box = self.get_io().clone(); + let io_ref = io_box.borrow(); + let io: &dyn IOInterface = &*io_ref; if input.get_option("dev").as_bool().unwrap_or(false) { io.write_error("<warning>You are using the deprecated option \"--dev\". It has no effect and will break in Composer 3.</warning>"); @@ -114,7 +115,7 @@ impl InstallCommand { .borrow_mut() .dispatch(Some(command_event.get_name()), None); - let mut install = Installer::create(io.clone_box(), &composer_handle); + let mut install = Installer::create(io_box.clone(), &composer_handle); let config = composer.get_config(); let (prefer_source, prefer_dist) = diff --git a/crates/shirabe/src/command/licenses_command.rs b/crates/shirabe/src/command/licenses_command.rs index 2bcecd5..6c7ea73 100644 --- a/crates/shirabe/src/command/licenses_command.rs +++ b/crates/shirabe/src/command/licenses_command.rs @@ -14,6 +14,7 @@ use shirabe_php_shim::{PhpMixed, RuntimeException, UnexpectedValueException}; use crate::command::{BaseCommand, BaseCommandData, HasBaseCommandData}; use crate::console::input::InputOption; use crate::io::IOInterface; +use crate::io::IOInterfaceImmutable; use crate::json::JsonFile; use crate::package::BasePackage; use crate::package::CompletePackage; diff --git a/crates/shirabe/src/command/package_discovery_trait.rs b/crates/shirabe/src/command/package_discovery_trait.rs index a268469..e8a56a9 100644 --- a/crates/shirabe/src/command/package_discovery_trait.rs +++ b/crates/shirabe/src/command/package_discovery_trait.rs @@ -20,6 +20,7 @@ use crate::factory::Factory; use crate::filter::platform_requirement_filter::IgnoreAllPlatformRequirementFilter; use crate::filter::platform_requirement_filter::PlatformRequirementFilterFactory; use crate::io::IOInterface; +use crate::io::IOInterfaceImmutable; use crate::package::BasePackage; use crate::package::CompletePackageInterface; use crate::package::PackageInterface; @@ -40,7 +41,7 @@ pub trait PackageDiscoveryTrait { fn get_repository_sets_mut(&mut self) -> &mut IndexMap<String, RepositorySet>; // PHP: trait dependencies (provided by BaseCommand) - fn get_io(&self) -> &dyn IOInterface; + fn get_io(&self) -> std::rc::Rc<std::cell::RefCell<dyn IOInterface>>; fn try_composer(&self) -> Option<PartialComposerHandle>; fn require_composer( &self, @@ -61,8 +62,8 @@ pub trait PackageDiscoveryTrait { // TODO(phase-b): PlatformRepository::new() signature Box::new(todo!("PlatformRepository::new()") as PlatformRepository), ]; - let mut io_owned: Box<dyn IOInterface> = todo!("clone self.get_io() into a Box"); - for (_, repo) in RepositoryFactory::default_repos_with_default_manager(&mut *io_owned) + let io_owned: std::rc::Rc<std::cell::RefCell<dyn IOInterface>> = self.get_io(); + for (_, repo) in RepositoryFactory::default_repos_with_default_manager(io_owned) .unwrap() .into_iter() { diff --git a/crates/shirabe/src/command/reinstall_command.rs b/crates/shirabe/src/command/reinstall_command.rs index 1e3114b..ad4739b 100644 --- a/crates/shirabe/src/command/reinstall_command.rs +++ b/crates/shirabe/src/command/reinstall_command.rs @@ -16,6 +16,7 @@ use crate::dependency_resolver::Transaction; use crate::dependency_resolver::operation::InstallOperation; use crate::dependency_resolver::operation::UninstallOperation; use crate::io::IOInterface; +use crate::io::IOInterfaceImmutable; use crate::package::base_package; use crate::plugin::CommandEvent; use crate::plugin::PluginEvents; diff --git a/crates/shirabe/src/command/remove_command.rs b/crates/shirabe/src/command/remove_command.rs index 49b21dc..9ea7329 100644 --- a/crates/shirabe/src/command/remove_command.rs +++ b/crates/shirabe/src/command/remove_command.rs @@ -17,6 +17,7 @@ use crate::dependency_resolver::Request; use crate::factory::Factory; use crate::installer::Installer; use crate::io::IOInterface; +use crate::io::IOInterfaceImmutable; use crate::json::JsonFile; use crate::package::BasePackage; use crate::package::base_package; @@ -510,8 +511,9 @@ impl RemoveCommand { .borrow_mut() .set_output_progress(!input.get_option("no-progress").as_bool().unwrap_or(false)); - // TODO(phase-b): Installer::create expects Box<dyn IOInterface>; io here is &mut dyn IOInterface - let io_box: Box<dyn IOInterface> = todo!("share IOInterface as Box<dyn IOInterface>"); + // TODO(phase-b): Installer::create expects std::rc::Rc<std::cell::RefCell<dyn IOInterface>>; io here is &mut dyn IOInterface + let io_box: std::rc::Rc<std::cell::RefCell<dyn IOInterface>> = + todo!("share IOInterface as Box<dyn IOInterface>"); let mut install = Installer::create(io_box, &composer_handle); let update_dev_mode = !input.get_option("update-no-dev").as_bool().unwrap_or(false); diff --git a/crates/shirabe/src/command/repository_command.rs b/crates/shirabe/src/command/repository_command.rs index 1f6599b..bf000e4 100644 --- a/crates/shirabe/src/command/repository_command.rs +++ b/crates/shirabe/src/command/repository_command.rs @@ -17,6 +17,7 @@ use crate::console::input::InputArgument; use crate::console::input::InputOption; use crate::factory::Factory; use crate::io::IOInterface; +use crate::io::IOInterfaceImmutable; use crate::json::JsonFile; #[derive(Debug)] diff --git a/crates/shirabe/src/command/require_command.rs b/crates/shirabe/src/command/require_command.rs index f0dce6b..66e1134 100644 --- a/crates/shirabe/src/command/require_command.rs +++ b/crates/shirabe/src/command/require_command.rs @@ -25,6 +25,7 @@ use crate::factory::Factory; use crate::installer::Installer; use crate::installer::InstallerEvents; use crate::io::IOInterface; +use crate::io::IOInterfaceImmutable; use crate::json::JsonFile; use crate::json::JsonManipulator; use crate::package::base_package; @@ -67,7 +68,7 @@ impl PackageDiscoveryTrait for RequireCommand { todo!() } - fn get_io(&self) -> &dyn IOInterface { + fn get_io(&self) -> std::rc::Rc<std::cell::RefCell<dyn IOInterface>> { todo!() } @@ -845,10 +846,12 @@ impl RequireCommand { .borrow_mut() .set_output_progress(!input.get_option("no-progress").as_bool().unwrap_or(false)); - // TODO(phase-b): Installer::create takes Box<dyn IOInterface> for ownership but io is a + // TODO(phase-b): Installer::create takes std::rc::Rc<std::cell::RefCell<dyn IOInterface>> for ownership but io is a // borrowed &dyn here; needs Rc<dyn IOInterface> for proper sharing. - let mut install = - Installer::create(todo!("share io as Box<dyn IOInterface>"), &composer_handle); + let mut install = Installer::create( + todo!("share io as std::rc::Rc<std::cell::RefCell<dyn IOInterface>>"), + &composer_handle, + ); let (prefer_source, prefer_dist) = self.get_preferred_install_options(&*composer.get_config().borrow(), input, false)?; diff --git a/crates/shirabe/src/command/run_script_command.rs b/crates/shirabe/src/command/run_script_command.rs index e58ad24..9118463 100644 --- a/crates/shirabe/src/command/run_script_command.rs +++ b/crates/shirabe/src/command/run_script_command.rs @@ -10,6 +10,7 @@ use crate::command::{BaseCommand, BaseCommandData, HasBaseCommandData}; use crate::console::input::InputArgument; use crate::console::input::InputOption; use crate::io::IOInterface; +use crate::io::IOInterfaceImmutable; use crate::script::Event as ScriptEvent; use crate::script::ScriptEvents; use crate::util::Platform; diff --git a/crates/shirabe/src/command/search_command.rs b/crates/shirabe/src/command/search_command.rs index 9375ec7..2033cfc 100644 --- a/crates/shirabe/src/command/search_command.rs +++ b/crates/shirabe/src/command/search_command.rs @@ -4,6 +4,7 @@ use crate::command::{BaseCommand, BaseCommandData, HasBaseCommandData}; use crate::console::input::InputArgument; use crate::console::input::InputOption; use crate::io::IOInterface; +use crate::io::IOInterfaceImmutable; use crate::json::JsonFile; use crate::plugin::CommandEvent; use crate::plugin::PluginEvents; @@ -73,8 +74,8 @@ impl SearchCommand { c } else { // TODO(phase-b): clone_box to release self borrow held by get_io. - let io_box = self.get_io().clone_box(); - self.create_composer_instance(input, io_box.as_ref(), None, false, None)? + let io_box = self.get_io().clone(); + self.create_composer_instance(input, io_box, None, false, None)? }; let composer_ref = crate::command::composer_full(&composer); // TODO(phase-b): get_local_repository returns &dyn InstalledRepositoryInterface but we need Box<dyn RepositoryInterface> diff --git a/crates/shirabe/src/command/self_update_command.rs b/crates/shirabe/src/command/self_update_command.rs index 80d8b01..fc22ab7 100644 --- a/crates/shirabe/src/command/self_update_command.rs +++ b/crates/shirabe/src/command/self_update_command.rs @@ -28,6 +28,7 @@ use crate::console::input::InputOption; use crate::downloader::FilesystemException; use crate::factory::Factory; use crate::io::IOInterface; +use crate::io::IOInterfaceImmutable; use crate::self_update::Keys; use crate::self_update::Versions; use crate::util::Filesystem; @@ -132,7 +133,7 @@ impl SelfUpdateCommand { let io = self.get_io(); let http_downloader = std::rc::Rc::new(std::cell::RefCell::new( - Factory::create_http_downloader(io, &config, indexmap::IndexMap::new())?, + Factory::create_http_downloader(io.clone(), &config, indexmap::IndexMap::new())?, )); let mut versions_util = Versions::new(config.clone(), http_downloader.clone()); @@ -142,7 +143,7 @@ impl SelfUpdateCommand { for channel in Versions::CHANNELS { if input.get_option(channel).as_bool().unwrap_or(false) { requested_channel = Some(channel.to_string()); - versions_util.set_channel(channel.to_string(), Some(io))??; + versions_util.set_channel(channel.to_string(), Some(&*io.borrow()))??; break; } } diff --git a/crates/shirabe/src/command/show_command.rs b/crates/shirabe/src/command/show_command.rs index c7c2f9d..f3c1b3d 100644 --- a/crates/shirabe/src/command/show_command.rs +++ b/crates/shirabe/src/command/show_command.rs @@ -22,6 +22,7 @@ use crate::dependency_resolver::DefaultPolicy; use crate::dependency_resolver::PolicyInterface; use crate::filter::platform_requirement_filter::PlatformRequirementFilterInterface; use crate::io::IOInterface; +use crate::io::IOInterfaceImmutable; use crate::json::JsonFile; use crate::package::CompletePackageInterface; use crate::package::Link; @@ -1144,7 +1145,7 @@ impl ShowCommand { ), ); } - let io: &mut dyn IOInterface = self.get_io(); + let io = self.get_io(); io.write(&JsonFile::encode( &PhpMixed::Array( json_map @@ -1158,7 +1159,7 @@ impl ShowCommand { if input.get_option("latest").as_bool() == Some(true) && view_data.values().any(|v| !v.is_empty()) { - let io: &mut dyn IOInterface = self.get_io(); + let io = self.get_io(); if !io.is_decorated() { io.write_error("Legend:"); io.write_error("! patch or minor release available - update recommended"); @@ -1315,7 +1316,7 @@ impl ShowCommand { write_release_date: bool, release_date_length: usize, ) { - let io: &mut dyn IOInterface = self.get_io(); + let io = self.get_io(); let pad_name = write_version || write_latest || write_release_date || write_description; let pad_version = write_latest || write_release_date || write_description; let pad_latest = write_description || write_release_date; @@ -2681,7 +2682,7 @@ impl ShowCommand { &best_stability, None, 0, - Some(self.get_io()), + Some(&*self.get_io().borrow()), PhpMixed::Bool(true), )?; while let Some(ref c) = candidate { diff --git a/crates/shirabe/src/command/status_command.rs b/crates/shirabe/src/command/status_command.rs index 69c36a1..182dec8 100644 --- a/crates/shirabe/src/command/status_command.rs +++ b/crates/shirabe/src/command/status_command.rs @@ -87,8 +87,9 @@ impl StatusCommand { let composer = self.require_composer(None, None)?; let mut composer = crate::command::composer_full_mut(&composer); // TODO(phase-b): release the &mut self borrow held by get_io via clone_box. - let io_box = self.get_io().clone_box(); - let io: &dyn IOInterface = io_box.as_ref(); + let io_box = self.get_io().clone(); + let io_ref = io_box.borrow(); + let io: &dyn IOInterface = &*io_ref; let mut errors: IndexMap<String, String> = IndexMap::new(); let mut unpushed_changes: IndexMap<String, String> = IndexMap::new(); @@ -101,12 +102,16 @@ impl StatusCommand { .borrow() .get_process_executor() .map(std::rc::Rc::clone) - .unwrap_or_else(|| std::rc::Rc::new(std::cell::RefCell::new(ProcessExecutor::new(io)))); + .unwrap_or_else(|| { + std::rc::Rc::new(std::cell::RefCell::new(ProcessExecutor::new(Some( + io_box.clone(), + )))) + }); let mut guesser = VersionGuesser::new( composer.get_config(), process_executor.clone(), parser.clone(), - Some(io_box.clone_box()), + Some(io_box.clone()), ); let dumper = ArrayDumper::new(); diff --git a/crates/shirabe/src/command/suggests_command.rs b/crates/shirabe/src/command/suggests_command.rs index 8166c1e..b4693a2 100644 --- a/crates/shirabe/src/command/suggests_command.rs +++ b/crates/shirabe/src/command/suggests_command.rs @@ -90,8 +90,9 @@ impl SuggestsCommand { } let installed_repo = InstalledRepository::new(installed_repos); - // TODO(phase-b): SuggestedPackagesReporter::new expects Box<dyn IOInterface>; self.get_io() returns &mut dyn IOInterface - let io_box: Box<dyn IOInterface> = todo!("share IOInterface as Box<dyn IOInterface>"); + // TODO(phase-b): SuggestedPackagesReporter::new expects std::rc::Rc<std::cell::RefCell<dyn IOInterface>>; self.get_io() returns &mut dyn IOInterface + let io_box: std::rc::Rc<std::cell::RefCell<dyn IOInterface>> = + todo!("share IOInterface as Box<dyn IOInterface>"); let mut reporter = SuggestedPackagesReporter::new(io_box); let filter = input.get_argument("packages"); diff --git a/crates/shirabe/src/command/update_command.rs b/crates/shirabe/src/command/update_command.rs index 06984e2..f879283 100644 --- a/crates/shirabe/src/command/update_command.rs +++ b/crates/shirabe/src/command/update_command.rs @@ -77,8 +77,9 @@ impl UpdateCommand { ) -> Result<i64> { // TODO(phase-b): clone_box avoids the &mut self conflict with require_composer // below; revisit when get_io can return an Rc/Arc owned handle. - let io_box = self.get_io().clone_box(); - let io: &dyn IOInterface = &*io_box; + let io_box = self.get_io().clone(); + let io_ref = io_box.borrow(); + let io: &dyn IOInterface = &*io_ref; if input.get_option("dev").as_bool().unwrap_or(false) { io.write_error3( "<warning>You are using the deprecated option \"--dev\". It has no effect and will break in Composer 3.</warning>", @@ -311,7 +312,7 @@ impl UpdateCommand { .borrow_mut() .set_output_progress(!input.get_option("no-progress").as_bool().unwrap_or(false)); - let mut install = Installer::create(io.clone_box(), &composer_handle); + let mut install = Installer::create(io_box.clone(), &composer_handle); let config = composer.get_config(); let (prefer_source, prefer_dist) = diff --git a/crates/shirabe/src/command/validate_command.rs b/crates/shirabe/src/command/validate_command.rs index 814f09f..cb8fa89 100644 --- a/crates/shirabe/src/command/validate_command.rs +++ b/crates/shirabe/src/command/validate_command.rs @@ -119,8 +119,9 @@ impl ValidateCommand { .map(Ok) .unwrap_or_else(Factory::get_composer_file)?; // TODO(phase-b): get_io() takes &mut self via BaseCommand; clone_box to release the borrow. - let io_box = self.get_io().clone_box(); - let io: &dyn IOInterface = io_box.as_ref(); + let io_box = self.get_io().clone(); + let io_ref = io_box.borrow(); + let io: &dyn IOInterface = &*io_ref; if !std::path::Path::new(&file).exists() { io.write_error(&format!("<error>{} not found.</error>", file)); @@ -131,7 +132,7 @@ impl ValidateCommand { return Ok(3); } - let validator = ConfigValidator::new(io.clone_box()); + let validator = ConfigValidator::new(io_box.clone()); let check_all = if input.get_option("no-check-all").as_bool().unwrap_or(false) { 0 } else { @@ -156,7 +157,7 @@ impl ValidateCommand { validator.validate(&file, check_all, check_version); let mut lock_errors: Vec<String> = vec![]; - let composer = self.create_composer_instance(input, io, None, false, None)?; + let composer = self.create_composer_instance(input, io_box.clone(), None, false, None)?; let mut composer = crate::command::composer_full_mut(&composer); let check_lock = (check_lock && composer |
