aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/src
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-05-26 20:04:02 +0900
committernsfisis <nsfisis@gmail.com>2026-05-26 20:04:02 +0900
commitf411daceacad66e0bd774fda7d3c5ef8533cc55c (patch)
treeeefb065e4d676a3f7031ca49bab21c773b00b134 /crates/shirabe/src
parent1921f173ea219cb4b25847294d2d3fa465550fbb (diff)
downloadphp-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')
-rw-r--r--crates/shirabe/src/autoload/autoload_generator.rs8
-rw-r--r--crates/shirabe/src/autoload/class_map_generator.rs3
-rw-r--r--crates/shirabe/src/cache.rs5
-rw-r--r--crates/shirabe/src/command/about_command.rs1
-rw-r--r--crates/shirabe/src/command/archive_command.rs26
-rw-r--r--crates/shirabe/src/command/audit_command.rs3
-rw-r--r--crates/shirabe/src/command/base_command.rs33
-rw-r--r--crates/shirabe/src/command/base_config_command.rs6
-rw-r--r--crates/shirabe/src/command/base_dependency_command.rs2
-rw-r--r--crates/shirabe/src/command/check_platform_reqs_command.rs1
-rw-r--r--crates/shirabe/src/command/config_command.rs4
-rw-r--r--crates/shirabe/src/command/create_project_command.rs57
-rw-r--r--crates/shirabe/src/command/diagnose_command.rs24
-rw-r--r--crates/shirabe/src/command/dump_autoload_command.rs1
-rw-r--r--crates/shirabe/src/command/exec_command.rs1
-rw-r--r--crates/shirabe/src/command/fund_command.rs1
-rw-r--r--crates/shirabe/src/command/global_command.rs1
-rw-r--r--crates/shirabe/src/command/home_command.rs8
-rw-r--r--crates/shirabe/src/command/init_command.rs25
-rw-r--r--crates/shirabe/src/command/install_command.rs7
-rw-r--r--crates/shirabe/src/command/licenses_command.rs1
-rw-r--r--crates/shirabe/src/command/package_discovery_trait.rs7
-rw-r--r--crates/shirabe/src/command/reinstall_command.rs1
-rw-r--r--crates/shirabe/src/command/remove_command.rs6
-rw-r--r--crates/shirabe/src/command/repository_command.rs1
-rw-r--r--crates/shirabe/src/command/require_command.rs11
-rw-r--r--crates/shirabe/src/command/run_script_command.rs1
-rw-r--r--crates/shirabe/src/command/search_command.rs5
-rw-r--r--crates/shirabe/src/command/self_update_command.rs5
-rw-r--r--crates/shirabe/src/command/show_command.rs9
-rw-r--r--crates/shirabe/src/command/status_command.rs13
-rw-r--r--crates/shirabe/src/command/suggests_command.rs5
-rw-r--r--crates/shirabe/src/command/update_command.rs7
-rw-r--r--crates/shirabe/src/command/validate_command.rs9
-rw-r--r--crates/shirabe/src/compiler.rs2
-rw-r--r--crates/shirabe/src/console/application.rs36
-rw-r--r--crates/shirabe/src/console/github_action_error.rs5
-rw-r--r--crates/shirabe/src/dependency_resolver/pool_builder.rs5
-rw-r--r--crates/shirabe/src/dependency_resolver/solver.rs5
-rw-r--r--crates/shirabe/src/downloader/archive_downloader.rs2
-rw-r--r--crates/shirabe/src/downloader/download_manager.rs5
-rw-r--r--crates/shirabe/src/downloader/file_downloader.rs8
-rw-r--r--crates/shirabe/src/downloader/fossil_downloader.rs7
-rw-r--r--crates/shirabe/src/downloader/git_downloader.rs5
-rw-r--r--crates/shirabe/src/downloader/gzip_downloader.rs2
-rw-r--r--crates/shirabe/src/downloader/hg_downloader.rs7
-rw-r--r--crates/shirabe/src/downloader/path_downloader.rs5
-rw-r--r--crates/shirabe/src/downloader/perforce_downloader.rs5
-rw-r--r--crates/shirabe/src/downloader/phar_downloader.rs2
-rw-r--r--crates/shirabe/src/downloader/rar_downloader.rs2
-rw-r--r--crates/shirabe/src/downloader/svn_downloader.rs11
-rw-r--r--crates/shirabe/src/downloader/tar_downloader.rs2
-rw-r--r--crates/shirabe/src/downloader/vcs_downloader.rs14
-rw-r--r--crates/shirabe/src/downloader/xz_downloader.rs2
-rw-r--r--crates/shirabe/src/downloader/zip_downloader.rs4
-rw-r--r--crates/shirabe/src/event_dispatcher/event_dispatcher.rs16
-rw-r--r--crates/shirabe/src/factory.rs137
-rw-r--r--crates/shirabe/src/installer.rs20
-rw-r--r--crates/shirabe/src/installer/binary_installer.rs5
-rw-r--r--crates/shirabe/src/installer/installation_manager.rs5
-rw-r--r--crates/shirabe/src/installer/installer_event.rs8
-rw-r--r--crates/shirabe/src/installer/library_installer.rs4
-rw-r--r--crates/shirabe/src/installer/metapackage_installer.rs5
-rw-r--r--crates/shirabe/src/installer/package_event.rs8
-rw-r--r--crates/shirabe/src/installer/plugin_installer.rs3
-rw-r--r--crates/shirabe/src/installer/suggested_packages_reporter.rs5
-rw-r--r--crates/shirabe/src/io/buffer_io.rs52
-rw-r--r--crates/shirabe/src/io/console_io.rs63
-rw-r--r--crates/shirabe/src/io/io_interface.rs215
-rw-r--r--crates/shirabe/src/io/null_io.rs59
-rw-r--r--crates/shirabe/src/json/json_file.rs5
-rw-r--r--crates/shirabe/src/package/loader/root_package_loader.rs9
-rw-r--r--crates/shirabe/src/package/locker.rs2
-rw-r--r--crates/shirabe/src/package/version/version_guesser.rs6
-rw-r--r--crates/shirabe/src/platform/hhvm_detector.rs2
-rw-r--r--crates/shirabe/src/plugin/plugin_manager.rs11
-rw-r--r--crates/shirabe/src/repository/artifact_repository.rs5
-rw-r--r--crates/shirabe/src/repository/composer_repository.rs18
-rw-r--r--crates/shirabe/src/repository/path_repository.rs6
-rw-r--r--crates/shirabe/src/repository/repository_factory.rs34
-rw-r--r--crates/shirabe/src/repository/repository_manager.rs14
-rw-r--r--crates/shirabe/src/repository/repository_set.rs4
-rw-r--r--crates/shirabe/src/repository/vcs/forgejo_driver.rs3
-rw-r--r--crates/shirabe/src/repository/vcs/fossil_driver.rs12
-rw-r--r--crates/shirabe/src/repository/vcs/git_bitbucket_driver.rs5
-rw-r--r--crates/shirabe/src/repository/vcs/git_driver.rs23
-rw-r--r--crates/shirabe/src/repository/vcs/github_driver.rs7
-rw-r--r--crates/shirabe/src/repository/vcs/gitlab_driver.rs7
-rw-r--r--crates/shirabe/src/repository/vcs/hg_driver.rs16
-rw-r--r--crates/shirabe/src/repository/vcs/perforce_driver.rs11
-rw-r--r--crates/shirabe/src/repository/vcs/svn_driver.rs9
-rw-r--r--crates/shirabe/src/repository/vcs/vcs_driver.rs4
-rw-r--r--crates/shirabe/src/repository/vcs_repository.rs7
-rw-r--r--crates/shirabe/src/script/event.rs8
-rw-r--r--crates/shirabe/src/util/auth_helper.rs12
-rw-r--r--crates/shirabe/src/util/bitbucket.rs15
-rw-r--r--crates/shirabe/src/util/config_validator.rs6
-rw-r--r--crates/shirabe/src/util/filesystem.rs2
-rw-r--r--crates/shirabe/src/util/forgejo.rs7
-rw-r--r--crates/shirabe/src/util/git.rs37
-rw-r--r--crates/shirabe/src/util/github.rs15
-rw-r--r--crates/shirabe/src/util/gitlab.rs33
-rw-r--r--crates/shirabe/src/util/hg.rs7
-rw-r--r--crates/shirabe/src/util/http/curl_downloader.rs9
-rw-r--r--crates/shirabe/src/util/http_downloader.rs13
-rw-r--r--crates/shirabe/src/util/perforce.rs7
-rw-r--r--crates/shirabe/src/util/process_executor.rs51
-rw-r--r--crates/shirabe/src/util/remote_filesystem.rs14
-rw-r--r--crates/shirabe/src/util/stream_context_factory.rs5
-rw-r--r--crates/shirabe/src/util/svn.rs11
110 files changed, 887 insertions, 624 deletions
diff --git a/crates/shirabe/src/autoload/autoload_generator.rs b/crates/shirabe/src/autoload/autoload_generator.rs
index 3786011..59cf6ae 100644
--- a/crates/shirabe/src/autoload/autoload_generator.rs
+++ b/crates/shirabe/src/autoload/autoload_generator.rs
@@ -25,6 +25,7 @@ use crate::filter::platform_requirement_filter::PlatformRequirementFilterFactory
use crate::filter::platform_requirement_filter::PlatformRequirementFilterInterface;
use crate::installer::InstallationManager;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::io::NullIO;
use crate::json::JsonFile;
use crate::package::Locker;
@@ -40,7 +41,7 @@ use crate::util::Platform;
#[derive(Debug)]
pub struct AutoloadGenerator {
event_dispatcher: std::rc::Rc<std::cell::RefCell<EventDispatcher>>,
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
dev_mode: Option<bool>,
class_map_authoritative: bool,
apcu: bool,
@@ -53,9 +54,10 @@ pub struct AutoloadGenerator {
impl AutoloadGenerator {
pub fn new(
event_dispatcher: std::rc::Rc<std::cell::RefCell<EventDispatcher>>,
- io: Option<Box<dyn IOInterface>>,
+ io: Option<std::rc::Rc<std::cell::RefCell<dyn IOInterface>>>,
) -> Self {
- let io: Box<dyn IOInterface> = io.unwrap_or_else(|| Box::new(NullIO::new()));
+ let io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>> =
+ io.unwrap_or_else(|| std::rc::Rc::new(std::cell::RefCell::new(NullIO::new())));
Self {
event_dispatcher,
diff --git a/crates/shirabe/src/autoload/class_map_generator.rs b/crates/shirabe/src/autoload/class_map_generator.rs
index da086ad..6aa6492 100644
--- a/crates/shirabe/src/autoload/class_map_generator.rs
+++ b/crates/shirabe/src/autoload/class_map_generator.rs
@@ -6,6 +6,7 @@ use shirabe_class_map_generator::class_map_generator::ClassMapGenerator as Exter
use shirabe_php_shim::PhpMixed;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
#[derive(Debug)]
pub struct ClassMapGenerator;
@@ -41,7 +42,7 @@ impl ClassMapGenerator {
pub fn create_map(
path: PhpMixed,
excluded: Option<String>,
- mut io: Option<Box<dyn IOInterface>>,
+ mut io: Option<std::rc::Rc<std::cell::RefCell<dyn IOInterface>>>,
namespace: Option<String>,
autoload_type: Option<String>,
scanned_files: &mut IndexMap<String, bool>,
diff --git a/crates/shirabe/src/cache.rs b/crates/shirabe/src/cache.rs
index c4fd181..c6566f2 100644
--- a/crates/shirabe/src/cache.rs
+++ b/crates/shirabe/src/cache.rs
@@ -12,6 +12,7 @@ use shirabe_php_shim::{
};
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::util::Filesystem;
use crate::util::Platform;
use crate::util::Silencer;
@@ -19,7 +20,7 @@ use crate::util::Silencer;
/// Reads/writes to a filesystem cache
#[derive(Debug)]
pub struct Cache {
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
root: String,
enabled: Option<bool>,
allowlist: String,
@@ -36,7 +37,7 @@ impl Cache {
/// @param Filesystem $filesystem optional filesystem instance
/// @param bool $readOnly whether the cache is in readOnly mode
pub fn new(
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
cache_dir: &str,
allowlist: Option<&str>,
filesystem: Option<std::rc::Rc<std::cell::RefCell<Filesystem>>>,
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
diff --git a/crates/shirabe/src/compiler.rs b/crates/shirabe/src/compiler.rs
index bad682b..e9a0ca4 100644
--- a/crates/shirabe/src/compiler.rs
+++ b/crates/shirabe/src/compiler.rs
@@ -45,7 +45,7 @@ impl Compiler {
shirabe_php_shim::unlink(phar_file);
}
- 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 command = Git::build_rev_list_command(
&process,
diff --git a/crates/shirabe/src/console/application.rs b/crates/shirabe/src/console/application.rs
index 0b04e26..3a6b847 100644
--- a/crates/shirabe/src/console/application.rs
+++ b/crates/shirabe/src/console/application.rs
@@ -77,6 +77,7 @@ use crate::factory::Factory;
use crate::installer::Installer;
use crate::io::ConsoleIO;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::io::NullIO;
use crate::json::JsonValidationException;
use crate::util::ErrorHandler;
@@ -89,7 +90,7 @@ use crate::util::Silencer;
pub struct Application {
inner: BaseApplication,
pub(crate) composer: Option<PartialComposerHandle>,
- pub(crate) io: Box<dyn IOInterface>,
+ pub(crate) io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
has_plugin_commands: bool,
disable_plugins_by_default: bool,
disable_scripts_by_default: bool,
@@ -124,7 +125,8 @@ impl Application {
date_default_timezone_set(&tz);
}
- let io: Box<dyn IOInterface> = Box::new(NullIO::new());
+ let io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>> =
+ std::rc::Rc::new(std::cell::RefCell::new(NullIO::new()));
SHUTDOWN_REGISTERED.get_or_init(|| {
register_shutdown_function(Box::new(|| {
@@ -207,7 +209,7 @@ impl Application {
let _ = ConsoleIO::new;
let _ = HelperSet::new(helpers);
// self.io stays as the NullIO that was set during construction.
- let io_owned = self.io.clone_box();
+ let io_owned = self.io.clone();
let _ = io_owned;
// Register error handler again to pass it the IO instance
@@ -458,7 +460,7 @@ impl Application {
}
}
- let mut ghe = GithubActionError::new(self.io.clone_box());
+ let mut ghe = GithubActionError::new(self.io.clone());
ghe.emit(&pe.message, file.as_deref(), line);
return Err(e);
@@ -783,7 +785,7 @@ impl Application {
Ok(see.get_code())
} else {
- let mut ghe = GithubActionError::new(self.io.clone_box());
+ let mut ghe = GithubActionError::new(self.io.clone());
ghe.emit(&e.to_string(), None, None);
self.hint_common_errors(&e, output);
@@ -993,22 +995,18 @@ impl Application {
let disable_scripts = disable_scripts.unwrap_or(self.disable_scripts_by_default);
if self.composer.is_none() {
- let io_for_factory: Box<dyn IOInterface> = if Platform::is_input_completion_process() {
- Box::new(NullIO::new())
- } else {
- self.io.clone_box()
- };
+ let io_for_factory: std::rc::Rc<std::cell::RefCell<dyn IOInterface>> =
+ if Platform::is_input_completion_process() {
+ std::rc::Rc::new(std::cell::RefCell::new(NullIO::new()))
+ } else {
+ self.io.clone()
+ };
let disable_plugins_enum = if disable_plugins {
crate::factory::DisablePlugins::All
} else {
crate::factory::DisablePlugins::None
};
- match Factory::create(
- &*io_for_factory,
- None,
- disable_plugins_enum,
- disable_scripts,
- ) {
+ match Factory::create(io_for_factory, None, disable_plugins_enum, disable_scripts) {
Ok(c) => self.composer = Some(c),
Err(e) => {
if e.downcast_ref::<JsonValidationException>().is_some()
@@ -1044,8 +1042,8 @@ impl Application {
todo!()
}
- pub fn get_io(&self) -> &dyn IOInterface {
- &*self.io
+ pub fn get_io(&self) -> std::rc::Rc<std::cell::RefCell<dyn IOInterface>> {
+ self.io.clone()
}
pub fn get_help(&self) -> String {
@@ -1175,7 +1173,7 @@ impl Application {
}
fn get_use_parent_dir_config_value(&self) -> PhpMixed {
- let config = match Factory::create_config(Some(&*self.io), None) {
+ let config = match Factory::create_config(Some(self.io.clone()), None) {
Ok(c) => c,
Err(_) => return PhpMixed::Bool(false),
};
diff --git a/crates/shirabe/src/console/github_action_error.rs b/crates/shirabe/src/console/github_action_error.rs
index 933ba0a..963f5c1 100644
--- a/crates/shirabe/src/console/github_action_error.rs
+++ b/crates/shirabe/src/console/github_action_error.rs
@@ -1,15 +1,16 @@
//! ref: composer/src/Composer/Console/GithubActionError.php
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::util::Platform;
#[derive(Debug)]
pub struct GithubActionError {
- pub(crate) io: Box<dyn IOInterface>,
+ pub(crate) io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
}
impl GithubActionError {
- pub fn new(io: Box<dyn IOInterface>) -> Self {
+ pub fn new(io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>) -> Self {
Self { io }
}
diff --git a/crates/shirabe/src/dependency_resolver/pool_builder.rs b/crates/shirabe/src/dependency_resolver/pool_builder.rs
index 38a083e..0efaac5 100644
--- a/crates/shirabe/src/dependency_resolver/pool_builder.rs
+++ b/crates/shirabe/src/dependency_resolver/pool_builder.rs
@@ -22,6 +22,7 @@ use crate::dependency_resolver::Request;
use crate::dependency_resolver::SecurityAdvisoryPoolFilter;
use crate::event_dispatcher::EventDispatcher;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::package::AliasPackage;
use crate::package::BasePackageHandle;
use crate::package::CompleteAliasPackage;
@@ -46,7 +47,7 @@ pub struct PoolBuilder {
temporary_constraints: IndexMap<String, AnyConstraint>,
event_dispatcher: Option<std::rc::Rc<std::cell::RefCell<EventDispatcher>>>,
pool_optimizer: Option<PoolOptimizer>,
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
alias_map: IndexMap<String, IndexMap<i64, AliasPackage>>,
packages_to_load: IndexMap<String, AnyConstraint>,
loaded_packages: IndexMap<String, AnyConstraint>,
@@ -87,7 +88,7 @@ impl PoolBuilder {
stability_flags: IndexMap<String, i64>,
root_aliases: IndexMap<String, IndexMap<String, IndexMap<String, String>>>,
root_references: IndexMap<String, String>,
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
event_dispatcher: Option<std::rc::Rc<std::cell::RefCell<EventDispatcher>>>,
pool_optimizer: Option<PoolOptimizer>,
temporary_constraints: IndexMap<String, AnyConstraint>,
diff --git a/crates/shirabe/src/dependency_resolver/solver.rs b/crates/shirabe/src/dependency_resolver/solver.rs
index 2610f07..4f8d91d 100644
--- a/crates/shirabe/src/dependency_resolver/solver.rs
+++ b/crates/shirabe/src/dependency_resolver/solver.rs
@@ -29,6 +29,7 @@ use crate::filter::platform_requirement_filter::IgnoreListPlatformRequirementFil
use crate::filter::platform_requirement_filter::PlatformRequirementFilterFactory;
use crate::filter::platform_requirement_filter::PlatformRequirementFilterInterface;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::package::BasePackageHandle;
#[derive(Debug)]
@@ -51,7 +52,7 @@ pub struct Solver {
pub test_flag_learned_positive_literal: bool,
- pub(crate) io: Box<dyn IOInterface>,
+ pub(crate) io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
}
impl Solver {
@@ -61,7 +62,7 @@ impl Solver {
pub fn new(
policy: Box<dyn PolicyInterface>,
pool: std::rc::Rc<std::cell::RefCell<Pool>>,
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
) -> Self {
let decisions = Decisions::new(pool.clone());
Self {
diff --git a/crates/shirabe/src/downloader/archive_downloader.rs b/crates/shirabe/src/downloader/archive_downloader.rs
index 6c8a8f9..ffa2ef4 100644
--- a/crates/shirabe/src/downloader/archive_downloader.rs
+++ b/crates/shirabe/src/downloader/archive_downloader.rs
@@ -11,6 +11,8 @@ use shirabe_php_shim::{
use crate::dependency_resolver::operation::InstallOperation;
use crate::downloader::DownloaderInterface;
use crate::downloader::FileDownloader;
+use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::package::PackageInterface;
use crate::util::Filesystem;
use crate::util::Platform;
diff --git a/crates/shirabe/src/downloader/download_manager.rs b/crates/shirabe/src/downloader/download_manager.rs
index f5201cc..83a03c4 100644
--- a/crates/shirabe/src/downloader/download_manager.rs
+++ b/crates/shirabe/src/downloader/download_manager.rs
@@ -13,6 +13,7 @@ use shirabe_php_shim::{
use crate::downloader::DownloaderInterface;
use crate::exception::IrrecoverableDownloadException;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::package::PackageInterface;
use crate::util::Filesystem;
@@ -20,7 +21,7 @@ use crate::util::Filesystem;
#[derive(Debug)]
pub struct DownloadManager {
/// @var IOInterface
- pub(crate) io: Box<dyn IOInterface>,
+ pub(crate) io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
/// @var bool
prefer_dist: bool,
/// @var bool
@@ -40,7 +41,7 @@ impl DownloadManager {
/// @param bool $preferSource prefer downloading from source
/// @param Filesystem|null $filesystem custom Filesystem object
pub fn new(
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
prefer_source: bool,
filesystem: Option<std::rc::Rc<std::cell::RefCell<Filesystem>>>,
) -> Self {
diff --git a/crates/shirabe/src/downloader/file_downloader.rs b/crates/shirabe/src/downloader/file_downloader.rs
index dc8c5a5..4f2ee63 100644
--- a/crates/shirabe/src/downloader/file_downloader.rs
+++ b/crates/shirabe/src/downloader/file_downloader.rs
@@ -25,6 +25,8 @@ use crate::downloader::TransportException;
use crate::event_dispatcher::EventDispatcher;
use crate::exception::IrrecoverableDownloadException;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
+use crate::io::IOInterfaceMutable;
use crate::io::NullIO;
use crate::package::PackageInterface;
use crate::package::comparer::Comparer;
@@ -55,7 +57,7 @@ pub static RESPONSE_HEADERS: LazyLock<Mutex<IndexMap<String, Vec<String>>>> =
#[derive(Debug)]
pub struct FileDownloader {
/// @var IOInterface
- pub(crate) io: Box<dyn IOInterface>,
+ pub(crate) io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
/// @var Config
pub(crate) config: std::rc::Rc<std::cell::RefCell<Config>>,
/// @var HttpDownloader
@@ -92,7 +94,7 @@ impl FileDownloader {
/// Constructor.
pub fn new(
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: std::rc::Rc<std::cell::RefCell<Config>>,
http_downloader: std::rc::Rc<std::cell::RefCell<HttpDownloader>>,
event_dispatcher: Option<std::rc::Rc<std::cell::RefCell<EventDispatcher>>>,
@@ -102,7 +104,7 @@ impl FileDownloader {
) -> Self {
let process = process.unwrap_or_else(|| {
std::rc::Rc::new(std::cell::RefCell::new(ProcessExecutor::new(Some(
- io.clone_box(),
+ io.clone(),
))))
});
let filesystem = filesystem.unwrap_or_else(|| {
diff --git a/crates/shirabe/src/downloader/fossil_downloader.rs b/crates/shirabe/src/downloader/fossil_downloader.rs
index 1e164b8..9f0277e 100644
--- a/crates/shirabe/src/downloader/fossil_downloader.rs
+++ b/crates/shirabe/src/downloader/fossil_downloader.rs
@@ -4,6 +4,7 @@ use crate::config::Config;
use crate::downloader::DownloaderInterface;
use crate::downloader::VcsDownloaderBase;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::package::PackageInterface;
use crate::util::Filesystem;
use crate::util::ProcessExecutor;
@@ -18,7 +19,7 @@ pub struct FossilDownloader {
impl FossilDownloader {
pub fn new(
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: std::rc::Rc<std::cell::RefCell<Config>>,
process: std::rc::Rc<std::cell::RefCell<ProcessExecutor>>,
fs: std::rc::Rc<std::cell::RefCell<Filesystem>>,
@@ -46,7 +47,7 @@ impl FossilDownloader {
) -> Result<Option<PhpMixed>> {
self.inner.config.borrow_mut().prohibit_url_by_config(
&url,
- Some(self.inner.io.as_ref()),
+ Some(&*self.inner.io.borrow()),
&indexmap::IndexMap::new(),
)?;
@@ -107,7 +108,7 @@ impl FossilDownloader {
) -> Result<Option<PhpMixed>> {
self.inner.config.borrow_mut().prohibit_url_by_config(
&url,
- Some(self.inner.io.as_ref()),
+ Some(&*self.inner.io.borrow()),
&indexmap::IndexMap::new(),
)?;
diff --git a/crates/shirabe/src/downloader/git_downloader.rs b/crates/shirabe/src/downloader/git_downloader.rs
index a5e3638..b3e00a2 100644
--- a/crates/shirabe/src/downloader/git_downloader.rs
+++ b/crates/shirabe/src/downloader/git_downloader.rs
@@ -14,6 +14,7 @@ use crate::config::Config;
use crate::downloader::DvcsDownloaderInterface;
use crate::downloader::VcsDownloaderBase;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::package::PackageInterface;
use crate::util::Filesystem;
use crate::util::Git as GitUtil;
@@ -35,14 +36,14 @@ pub struct GitDownloader {
impl GitDownloader {
pub fn new(
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: std::rc::Rc<std::cell::RefCell<Config>>,
process: Option<std::rc::Rc<std::cell::RefCell<ProcessExecutor>>>,
fs: Option<std::rc::Rc<std::cell::RefCell<Filesystem>>>,
) -> Self {
let inner = VcsDownloaderBase::new(io, config, process, fs);
let git_util = GitUtil::new(
- inner.io.clone_box(),
+ inner.io.clone(),
inner.config.clone(),
inner.process.clone(),
inner.filesystem.clone(),
diff --git a/crates/shirabe/src/downloader/gzip_downloader.rs b/crates/shirabe/src/downloader/gzip_downloader.rs
index fe44fed..55dff10 100644
--- a/crates/shirabe/src/downloader/gzip_downloader.rs
+++ b/crates/shirabe/src/downloader/gzip_downloader.rs
@@ -27,7 +27,7 @@ pub struct GzipDownloader {
impl GzipDownloader {
pub fn new(
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: std::rc::Rc<std::cell::RefCell<Config>>,
http_downloader: std::rc::Rc<std::cell::RefCell<HttpDownloader>>,
event_dispatcher: Option<std::rc::Rc<std::cell::RefCell<EventDispatcher>>>,
diff --git a/crates/shirabe/src/downloader/hg_downloader.rs b/crates/shirabe/src/downloader/hg_downloader.rs
index b12e348..d4c53f3 100644
--- a/crates/shirabe/src/downloader/hg_downloader.rs
+++ b/crates/shirabe/src/downloader/hg_downloader.rs
@@ -4,6 +4,7 @@ use crate::config::Config;
use crate::downloader::DownloaderInterface;
use crate::downloader::VcsDownloaderBase;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::package::PackageInterface;
use crate::util::Filesystem;
use crate::util::Hg as HgUtils;
@@ -18,7 +19,7 @@ pub struct HgDownloader {
impl HgDownloader {
pub fn new(
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: std::rc::Rc<std::cell::RefCell<Config>>,
process: std::rc::Rc<std::cell::RefCell<ProcessExecutor>>,
fs: std::rc::Rc<std::cell::RefCell<Filesystem>>,
@@ -53,7 +54,7 @@ impl HgDownloader {
url: String,
) -> Result<Option<PhpMixed>> {
let hg_utils = HgUtils::new(
- &*self.inner.io,
+ self.inner.io.clone(),
&*self.inner.config.borrow(),
&self.inner.process,
);
@@ -108,7 +109,7 @@ impl HgDownloader {
url: String,
) -> Result<Option<PhpMixed>> {
let hg_utils = HgUtils::new(
- &*self.inner.io,
+ self.inner.io.clone(),
&*self.inner.config.borrow(),
&self.inner.process,
);
diff --git a/crates/shirabe/src/downloader/path_downloader.rs b/crates/shirabe/src/downloader/path_downloader.rs
index 46090ac..44541d4 100644
--- a/crates/shirabe/src/downloader/path_downloader.rs
+++ b/crates/shirabe/src/downloader/path_downloader.rs
@@ -19,6 +19,7 @@ use crate::downloader::FileDownloader;
use crate::downloader::VcsCapableDownloaderInterface;
use crate::event_dispatcher::EventDispatcher;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::package::PackageInterface;
use crate::package::archiver::ArchivableFilesFinder;
use crate::package::dumper::ArrayDumper;
@@ -39,7 +40,7 @@ impl PathDownloader {
const STRATEGY_MIRROR: i64 = 20;
pub fn new(
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: std::rc::Rc<std::cell::RefCell<Config>>,
http_downloader: std::rc::Rc<std::cell::RefCell<HttpDownloader>>,
event_dispatcher: Option<std::rc::Rc<std::cell::RefCell<EventDispatcher>>>,
@@ -391,7 +392,7 @@ impl PathDownloader {
self.inner.config.clone(),
self.inner.process.clone(),
parser.clone(),
- Some(self.inner.io.clone_box()),
+ Some(self.inner.io.clone()),
);
let dumper = ArrayDumper::new();
diff --git a/crates/shirabe/src/downloader/perforce_downloader.rs b/crates/shirabe/src/downloader/perforce_downloader.rs
index b3f7bc9..f967111 100644
--- a/crates/shirabe/src/downloader/perforce_downloader.rs
+++ b/crates/shirabe/src/downloader/perforce_downloader.rs
@@ -4,6 +4,7 @@ use crate::config::Config;
use crate::downloader::DownloaderInterface;
use crate::downloader::VcsDownloaderBase;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::package::PackageInterface;
use crate::repository::VcsRepository;
use crate::util::Filesystem;
@@ -22,7 +23,7 @@ pub struct PerforceDownloader {
impl PerforceDownloader {
pub fn new(
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: std::rc::Rc<std::cell::RefCell<Config>>,
process: std::rc::Rc<std::cell::RefCell<ProcessExecutor>>,
fs: std::rc::Rc<std::cell::RefCell<Filesystem>>,
@@ -103,7 +104,7 @@ impl PerforceDownloader {
url,
path,
self.inner.process.clone(),
- self.inner.io.clone_box(),
+ self.inner.io.clone(),
));
}
diff --git a/crates/shirabe/src/downloader/phar_downloader.rs b/crates/shirabe/src/downloader/phar_downloader.rs
index a598437..235e0bb 100644
--- a/crates/shirabe/src/downloader/phar_downloader.rs
+++ b/crates/shirabe/src/downloader/phar_downloader.rs
@@ -23,7 +23,7 @@ pub struct PharDownloader {
impl PharDownloader {
pub fn new(
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: std::rc::Rc<std::cell::RefCell<Config>>,
http_downloader: std::rc::Rc<std::cell::RefCell<HttpDownloader>>,
event_dispatcher: Option<std::rc::Rc<std::cell::RefCell<EventDispatcher>>>,
diff --git a/crates/shirabe/src/downloader/rar_downloader.rs b/crates/shirabe/src/downloader/rar_downloader.rs
index f482582..bb0c2f8 100644
--- a/crates/shirabe/src/downloader/rar_downloader.rs
+++ b/crates/shirabe/src/downloader/rar_downloader.rs
@@ -26,7 +26,7 @@ pub struct RarDownloader {
impl RarDownloader {
pub fn new(
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: std::rc::Rc<std::cell::RefCell<Config>>,
http_downloader: std::rc::Rc<std::cell::RefCell<HttpDownloader>>,
event_dispatcher: Option<std::rc::Rc<std::cell::RefCell<EventDispatcher>>>,
diff --git a/crates/shirabe/src/downloader/svn_downloader.rs b/crates/shirabe/src/downloader/svn_downloader.rs
index 162e91c..f3683dd 100644
--- a/crates/shirabe/src/downloader/svn_downloader.rs
+++ b/crates/shirabe/src/downloader/svn_downloader.rs
@@ -9,6 +9,7 @@ use crate::config::Config;
use crate::downloader::DownloaderInterface;
use crate::downloader::VcsDownloaderBase;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::package::PackageInterface;
use crate::repository::VcsRepository;
use crate::util::Filesystem;
@@ -23,7 +24,7 @@ pub struct SvnDownloader {
impl SvnDownloader {
pub fn new(
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: std::rc::Rc<std::cell::RefCell<Config>>,
process: std::rc::Rc<std::cell::RefCell<ProcessExecutor>>,
fs: std::rc::Rc<std::cell::RefCell<Filesystem>>,
@@ -44,7 +45,7 @@ impl SvnDownloader {
SvnUtil::clean_env();
let mut util = SvnUtil::new(
url.to_string(),
- self.inner.io.clone_box(),
+ self.inner.io.clone(),
self.inner.config.clone(),
Some(self.inner.process.clone()),
);
@@ -126,7 +127,7 @@ impl SvnDownloader {
let mut util = SvnUtil::new(
url.to_string(),
- self.inner.io.clone_box(),
+ self.inner.io.clone(),
self.inner.config.clone(),
Some(self.inner.process.clone()),
);
@@ -186,7 +187,7 @@ impl SvnDownloader {
) -> anyhow::Result<String> {
let mut util = SvnUtil::new(
base_url.to_string(),
- self.inner.io.clone_box(),
+ self.inner.io.clone(),
self.inner.config.clone(),
Some(self.inner.process.clone()),
);
@@ -381,7 +382,7 @@ impl SvnDownloader {
let mut util = SvnUtil::new(
base_url,
- self.inner.io.clone_box(),
+ self.inner.io.clone(),
self.inner.config.clone(),
Some(self.inner.process.clone()),
);
diff --git a/crates/shirabe/src/downloader/tar_downloader.rs b/crates/shirabe/src/downloader/tar_downloader.rs
index 09b6f5a..7314ecd 100644
--- a/crates/shirabe/src/downloader/tar_downloader.rs
+++ b/crates/shirabe/src/downloader/tar_downloader.rs
@@ -23,7 +23,7 @@ pub struct TarDownloader {
impl TarDownloader {
pub fn new(
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: std::rc::Rc<std::cell::RefCell<Config>>,
http_downloader: std::rc::Rc<std::cell::RefCell<HttpDownloader>>,
event_dispatcher: Option<std::rc::Rc<std::cell::RefCell<EventDispatcher>>>,
diff --git a/crates/shirabe/src/downloader/vcs_downloader.rs b/crates/shirabe/src/downloader/vcs_downloader.rs
index 096e93d..736d433 100644
--- a/crates/shirabe/src/downloader/vcs_downloader.rs
+++ b/crates/shirabe/src/downloader/vcs_downloader.rs
@@ -17,6 +17,7 @@ use crate::downloader::ChangeReportInterface;
use crate::downloader::DownloaderInterface;
use crate::downloader::VcsCapableDownloaderInterface;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::package::PackageInterface;
use crate::package::dumper::ArrayDumper;
use crate::package::version::VersionGuesser;
@@ -26,7 +27,7 @@ use crate::util::ProcessExecutor;
#[derive(Debug)]
pub struct VcsDownloaderBase {
- pub io: Box<dyn IOInterface>,
+ pub io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
pub config: std::rc::Rc<std::cell::RefCell<Config>>,
pub process: std::rc::Rc<std::cell::RefCell<ProcessExecutor>>,
pub filesystem: std::rc::Rc<std::cell::RefCell<Filesystem>>,
@@ -35,13 +36,14 @@ pub struct VcsDownloaderBase {
impl VcsDownloaderBase {
pub fn new(
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: std::rc::Rc<std::cell::RefCell<Config>>,
process: Option<std::rc::Rc<std::cell::RefCell<ProcessExecutor>>>,
fs: Option<std::rc::Rc<std::cell::RefCell<Filesystem>>>,
) -> Self {
- let process = process
- .unwrap_or_else(|| std::rc::Rc::new(std::cell::RefCell::new(ProcessExecutor::new(()))));
+ let process = process.unwrap_or_else(|| {
+ std::rc::Rc::new(std::cell::RefCell::new(ProcessExecutor::new(None)))
+ });
let filesystem =
fs.unwrap_or_else(|| std::rc::Rc::new(std::cell::RefCell::new(Filesystem::new(None))));
Self {
@@ -72,7 +74,7 @@ impl VcsDownloaderBase {
pub trait VcsDownloader:
DownloaderInterface + ChangeReportInterface + VcsCapableDownloaderInterface
{
- fn io(&self) -> &dyn IOInterface;
+ fn io(&self) -> std::rc::Rc<std::cell::RefCell<dyn IOInterface>>;
fn io_mut(&mut self) -> &mut dyn IOInterface;
fn config(&self) -> &std::rc::Rc<std::cell::RefCell<Config>>;
fn config_mut(&mut self) -> &mut std::rc::Rc<std::cell::RefCell<Config>>;
@@ -442,7 +444,7 @@ pub trait VcsDownloader:
self.config().clone(),
self.process().clone(),
parser.clone(),
- Some(self.io().clone_box()),
+ Some(self.io().clone()),
);
let dumper = ArrayDumper::new();
diff --git a/crates/shirabe/src/downloader/xz_downloader.rs b/crates/shirabe/src/downloader/xz_downloader.rs
index ca867df..fd83b28 100644
--- a/crates/shirabe/src/downloader/xz_downloader.rs
+++ b/crates/shirabe/src/downloader/xz_downloader.rs
@@ -22,7 +22,7 @@ pub struct XzDownloader {
impl XzDownloader {
pub fn new(
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: std::rc::Rc<std::cell::RefCell<Config>>,
http_downloader: std::rc::Rc<std::cell::RefCell<HttpDownloader>>,
event_dispatcher: Option<std::rc::Rc<std::cell::RefCell<EventDispatcher>>>,
diff --git a/crates/shirabe/src/downloader/zip_downloader.rs b/crates/shirabe/src/downloader/zip_downloader.rs
index eb057e0..4c72b91 100644
--- a/crates/shirabe/src/downloader/zip_downloader.rs
+++ b/crates/shirabe/src/downloader/zip_downloader.rs
@@ -3,6 +3,8 @@
use crate::downloader::ArchiveDownloader;
use crate::downloader::DownloaderInterface;
use crate::downloader::FileDownloader;
+use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::package::PackageInterface;
use crate::util::IniHelper;
use crate::util::Platform;
@@ -33,7 +35,7 @@ pub struct ZipDownloader {
impl ZipDownloader {
pub fn new(
- io: Box<dyn crate::io::IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn crate::io::IOInterface>>,
config: std::rc::Rc<std::cell::RefCell<crate::config::Config>>,
http_downloader: std::rc::Rc<std::cell::RefCell<crate::util::HttpDownloader>>,
event_dispatcher: Option<
diff --git a/crates/shirabe/src/event_dispatcher/event_dispatcher.rs b/crates/shirabe/src/event_dispatcher/event_dispatcher.rs
index ae86fcf..3a037c9 100644
--- a/crates/shirabe/src/event_dispatcher/event_dispatcher.rs
+++ b/crates/shirabe/src/event_dispatcher/event_dispatcher.rs
@@ -31,6 +31,7 @@ use crate::installer::InstallerEvent;
use crate::installer::PackageEvent;
use crate::io::ConsoleIO;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::plugin::CommandEvent;
use crate::plugin::PreCommandRunEvent;
use crate::repository::RepositoryInterface;
@@ -62,7 +63,7 @@ pub enum Callable {
#[derive(Debug)]
pub struct EventDispatcher {
pub(crate) composer: PartialComposerWeakHandle,
- pub(crate) io: Box<dyn IOInterface>,
+ pub(crate) io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
pub(crate) loader: Option<ClassLoader>,
pub(crate) process: std::rc::Rc<std::cell::RefCell<ProcessExecutor>>,
pub(crate) listeners: IndexMap<String, IndexMap<i64, Vec<Callable>>>,
@@ -76,11 +77,13 @@ pub struct EventDispatcher {
impl EventDispatcher {
pub fn new(
composer: PartialComposerWeakHandle,
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
process: Option<std::rc::Rc<std::cell::RefCell<ProcessExecutor>>>,
) -> Self {
let process = process.unwrap_or_else(|| {
- std::rc::Rc::new(std::cell::RefCell::new(ProcessExecutor::new(&*io)))
+ std::rc::Rc::new(std::cell::RefCell::new(ProcessExecutor::new(Some(
+ io.clone(),
+ ))))
});
let event_stack: Vec<String> = Vec::new();
let skip_scripts_env =
@@ -609,7 +612,8 @@ impl EventDispatcher {
// TODO(phase-b): IOInterface needs an `as_any` shim before
// `instanceof ConsoleIO` can be expressed; treat io as a
// generic IOInterface for now.
- let _io_ref: &dyn IOInterface = &*self.io;
+ let _io_ref_guard = self.io.borrow();
+ let _io_ref: &dyn IOInterface = &*_io_ref_guard;
let downcast: Option<&ConsoleIO> = None;
let output: ConsoleOutput = if let Some(_console_io) = downcast {
// TODO(plugin): \ReflectionProperty to read private `output` from ConsoleIO
@@ -1311,9 +1315,9 @@ impl EventDispatcher {
// ---- helpers ----
- fn io_clone(&self) -> Box<dyn IOInterface> {
+ fn io_clone(&self) -> std::rc::Rc<std::cell::RefCell<dyn IOInterface>> {
// TODO(phase-b): IOInterface is not Clone — placeholder until io ownership is resolved.
- todo!("clone Box<dyn IOInterface>")
+ todo!("clone std::rc::Rc<std::cell::RefCell<dyn IOInterface>>")
}
fn composer(&self) -> PartialComposerHandle {
diff --git a/crates/shirabe/src/factory.rs b/crates/shirabe/src/factory.rs
index 1370080..0084c73 100644
--- a/crates/shirabe/src/factory.rs
+++ b/crates/shirabe/src/factory.rs
@@ -43,6 +43,7 @@ use crate::installer::LibraryInstaller;
use crate::installer::MetapackageInstaller;
use crate::installer::PluginInstaller;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::json::JsonFile;
use crate::json::JsonValidationException;
use crate::package::Locker;
@@ -231,7 +232,7 @@ impl Factory {
}
pub fn create_config(
- io: Option<&dyn IOInterface>,
+ io: Option<std::rc::Rc<std::cell::RefCell<dyn IOInterface>>>,
cwd: Option<&str>,
) -> anyhow::Result<Config> {
let cwd = match cwd {
@@ -262,9 +263,9 @@ impl Factory {
// load global config
let global_config_path = format!("{}/config.json", config.get_str("home")?);
- let mut file = JsonFile::new(global_config_path.clone(), None, io.map(|i| i.clone_box()))?;
+ let mut file = JsonFile::new(global_config_path.clone(), None, io.clone())?;
if file.exists() {
- if let Some(io_ref) = io {
+ if let Some(io_ref) = &io {
io_ref.write_error3(
&format!("Loading config file {}", file.get_path()),
true,
@@ -273,11 +274,11 @@ impl Factory {
}
// TODO(phase-b): validate_json_schema takes ownership of JsonFile; recreate it
Self::validate_json_schema(
- io,
+ io.clone(),
ValidateJsonInput::File(JsonFile::new(
global_config_path.clone(),
None,
- io.map(|i| i.clone_box()),
+ io.clone(),
)?),
JsonFile::LAX_SCHEMA,
None,
@@ -323,9 +324,9 @@ impl Factory {
// load global auth file
let auth_file_path = format!("{}/auth.json", config.get_str("home")?);
- let mut auth_file = JsonFile::new(auth_file_path.clone(), None, io.map(|i| i.clone_box()))?;
+ let mut auth_file = JsonFile::new(auth_file_path.clone(), None, io.clone())?;
if auth_file.exists() {
- if let Some(io_ref) = io {
+ if let Some(io_ref) = &io {
io_ref.write_error3(
&format!("Loading config file {}", auth_file.get_path()),
true,
@@ -334,12 +335,8 @@ impl Factory {
}
// TODO(phase-b): validate_json_schema takes ownership; recreate JsonFile
Self::validate_json_schema(
- io,
- ValidateJsonInput::File(JsonFile::new(
- auth_file_path.clone(),
- None,
- io.map(|i| i.clone_box()),
- )?),
+ io.clone(),
+ ValidateJsonInput::File(JsonFile::new(auth_file_path.clone(), None, io.clone())?),
JsonFile::AUTH_SCHEMA,
None,
)?;
@@ -433,7 +430,7 @@ impl Factory {
/// Creates a Composer instance
pub fn create_composer(
&self,
- io: &dyn IOInterface,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
local_config: Option<LocalConfigInput>,
disable_plugins: DisablePlugins,
cwd: Option<&str>,
@@ -465,7 +462,7 @@ impl Factory {
if let Some(LocalConfigInput::Path(path)) = &local_config {
composer_file = Some(path.clone());
- let mut file = JsonFile::new(path.clone(), None, Some(io.clone_box()))?;
+ let mut file = JsonFile::new(path.clone(), None, Some(io.clone()))?;
if !file.exists() {
let message = if path == "./composer.json" || path == "composer.json" {
@@ -512,7 +509,7 @@ impl Factory {
}
// Load config and override with local config/auth config
- let mut config = Self::create_config(Some(io), Some(&cwd))?;
+ let mut config = Self::create_config(Some(io.clone()), Some(&cwd))?;
let is_global = local_config_source != Config::SOURCE_UNKNOWN
&& realpath(&config.get_str("home")?) == realpath(&dirname(&local_config_source));
config.merge(&local_config_data, &local_config_source);
@@ -531,7 +528,7 @@ impl Factory {
JsonFile::new(
realpath(composer_file_path).unwrap_or_default(),
None,
- Some(io.clone_box()),
+ Some(io.clone()),
)?,
false,
)));
@@ -542,7 +539,7 @@ impl Factory {
dirname(&realpath(composer_file_path).unwrap_or_default())
),
None,
- Some(io.clone_box()),
+ Some(io.clone()),
)?;
if local_auth_file.exists() {
io.write_error3(
@@ -566,7 +563,7 @@ impl Factory {
}
// make sure we load the auth env again over the local auth.json + composer.json config
- Self::load_composer_auth_env(&mut config, Some(io))?;
+ Self::load_composer_auth_env(&mut config, Some(io.clone()))?;
let vendor_dir = config.get_str("vendor-dir")?;
@@ -620,10 +617,10 @@ impl Factory {
}
let http_downloader = std::rc::Rc::new(std::cell::RefCell::new(
- Self::create_http_downloader(io, &config, IndexMap::new())?,
+ Self::create_http_downloader(io.clone(), &config, IndexMap::new())?,
));
let process = std::rc::Rc::new(std::cell::RefCell::new(ProcessExecutor::new(
- Some(io.clone_box()),
+ Some(io.clone()),
)));
let r#loop = std::rc::Rc::new(std::cell::RefCell::new(Loop::new(
http_downloader.clone(),
@@ -635,7 +632,7 @@ impl Factory {
let dispatcher = {
let mut d = EventDispatcher::new(
PartialComposerWeakHandle::from_weak(composer_weak.clone()),
- io.clone_box(),
+ io.clone(),
Some(process.clone()),
);
d.set_run_scripts(!disable_scripts);
@@ -645,7 +642,7 @@ impl Factory {
// initialize repository manager
let rm = std::rc::Rc::new(std::cell::RefCell::new(RepositoryFactory::manager(
- io,
+ io.clone(),
&config,
Some(http_downloader.clone()),
Some(dispatcher.clone()),
@@ -665,14 +662,14 @@ impl Factory {
config.clone(),
process.clone(),
parser.clone(),
- Some(io.clone_box()),
+ Some(io.clone()),
);
let mut loader = self.load_root_package(
rm.clone(),
config.clone(),
parser,
guesser,
- io.clone_box(),
+ io.clone(),
);
let package = loader.load(
local_config_data
@@ -688,7 +685,7 @@ impl Factory {
// load local repository
self.add_local_repository(
- io,
+ io.clone(),
&mut rm.borrow_mut(),
&vendor_dir,
composer.get_package().clone(),
@@ -700,7 +697,7 @@ impl Factory {
let im = std::rc::Rc::new(std::cell::RefCell::new(
self.create_installation_manager(
r#loop.clone(),
- io.clone_box(),
+ io.clone(),
Some(dispatcher.clone()),
),
));
@@ -709,7 +706,7 @@ impl Factory {
if let PartialOrFullComposer::Full(ref mut composer_full) = composer {
// initialize download manager
let dm = self.create_download_manager(
- io,
+ io.clone(),
&config,
&http_downloader,
&process,
@@ -719,7 +716,7 @@ impl Factory {
// initialize autoload generator
let generator =
- AutoloadGenerator::new(dispatcher.clone(), Some(io.clone_box()));
+ AutoloadGenerator::new(dispatcher.clone(), Some(io.clone()));
composer_full.set_autoload_generator(std::rc::Rc::new(
std::cell::RefCell::new(generator),
));
@@ -731,7 +728,7 @@ impl Factory {
}
// add installers to the manager (must happen after download manager is created since they read it out of $composer)
- self.create_default_installers(&im, &composer, io, Some(&process));
+ self.create_default_installers(&im, &composer, io.clone(), Some(&process));
// init locker if possible
if let PartialOrFullComposer::Full(ref mut composer_full) = composer {
@@ -754,7 +751,7 @@ impl Factory {
}
let locker = Locker::new(
- io.clone_box(),
+ io.clone(),
JsonFile::new(
if lock_enabled {
lock_file
@@ -762,7 +759,7 @@ impl Factory {
Platform::get_dev_null()
},
None,
- Some(io.clone_box()),
+ Some(io.clone()),
)?,
im.clone(),
&file_get_contents(composer_file_path).unwrap_or_default(),
@@ -781,12 +778,8 @@ impl Factory {
448,
);
let locker = Locker::new(
- io.clone_box(),
- JsonFile::new(
- Platform::get_dev_null(),
- None,
- Some(io.clone_box()),
- )?,
+ io.clone(),
+ JsonFile::new(Platform::get_dev_null(), None, Some(io.clone()))?,
im.clone(),
&lock_contents,
process.clone(),
@@ -799,7 +792,7 @@ impl Factory {
if let Some(full_composer) = composer.as_full_mut() {
let global_composer = if !full_composer.is_global() {
self.create_global_composer(
- io,
+ io.clone(),
&*config.borrow(),
disable_plugins,
disable_scripts,
@@ -809,7 +802,7 @@ impl Factory {
None
};
let mut pm = self.create_plugin_manager(
- io,
+ &*io.borrow(),
ComposerWeakHandle::from_weak(composer_weak.clone()),
global_composer,
disable_plugins,
@@ -857,19 +850,19 @@ impl Factory {
}
pub fn create_global(
- io: &dyn IOInterface,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
disable_plugins: DisablePlugins,
disable_scripts: bool,
) -> Option<PartialComposerHandle> {
let factory = Self;
- let config = Self::create_config(Some(io), None).ok()?;
+ let config = Self::create_config(Some(io.clone()), None).ok()?;
factory.create_global_composer(io, &config, disable_plugins, disable_scripts, true)
}
fn add_local_repository(
&self,
- io: &dyn IOInterface,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
rm: &mut RepositoryManager,
vendor_dir: &str,
root_package: RootPackageInterfaceHandle,
@@ -883,7 +876,7 @@ impl Factory {
JsonFile::new(
format!("{}/composer/installed.json", vendor_dir),
None,
- Some(io.clone_box()),
+ Some(io.clone()),
)
.expect("installed.json path is always valid"),
true,
@@ -896,7 +889,7 @@ impl Factory {
fn create_global_composer(
&self,
- io: &dyn IOInterface,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: &Config,
disable_plugins: DisablePlugins,
disable_scripts: bool,
@@ -913,7 +906,7 @@ impl Factory {
};
match self.create_composer(
- io,
+ io.clone(),
Some(LocalConfigInput::Path(format!(
"{}/composer.json",
config.get_str("home").ok()?
@@ -937,7 +930,7 @@ impl Factory {
pub fn create_download_manager(
&self,
- io: &dyn IOInterface,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: &std::rc::Rc<std::cell::RefCell<Config>>,
http_downloader: &std::rc::Rc<std::cell::RefCell<HttpDownloader>>,
process: &std::rc::Rc<std::cell::RefCell<ProcessExecutor>>,
@@ -950,7 +943,7 @@ impl Factory {
.unwrap_or(0);
let cache = if cache_files_ttl > 0 {
let mut cache = Cache::new(
- io.clone_box(),
+ io.clone(),
&config.borrow_mut().get_str("cache-files-dir")?,
Some("a-z0-9_./"),
None,
@@ -972,7 +965,7 @@ impl Factory {
process.clone(),
))));
- let mut dm = DownloadManager::new(io.clone_box(), false, Some(fs.clone()));
+ let mut dm = DownloadManager::new(io.clone(), false, Some(fs.clone()));
let preferred = config.borrow_mut().get("preferred-install");
match preferred.as_string() {
Some("dist") => {
@@ -1006,7 +999,7 @@ impl Factory {
dm.set_downloader(
"git",
Box::new(GitDownloader::new(
- io.clone_box(),
+ io.clone(),
config.clone(),
Some(process.clone()),
Some(fs.clone()),
@@ -1015,7 +1008,7 @@ impl Factory {
dm.set_downloader(
"svn",
Box::new(SvnDownloader::new(
- io.clone_box(),
+ io.clone(),
config.clone(),
process.clone(),
fs.clone(),
@@ -1024,7 +1017,7 @@ impl Factory {
dm.set_downloader(
"fossil",
Box::new(FossilDownloader::new(
- io.clone_box(),
+ io.clone(),
config.clone(),
process.clone(),
fs.clone(),
@@ -1033,7 +1026,7 @@ impl Factory {
dm.set_downloader(
"hg",
Box::new(HgDownloader::new(
- io.clone_box(),
+ io.clone(),
config.clone(),
process.clone(),
fs.clone(),
@@ -1042,7 +1035,7 @@ impl Factory {
dm.set_downloader(
"perforce",
Box::new(PerforceDownloader::new(
- io.clone_box(),
+ io.clone(),
config.clone(),
process.clone(),
fs.clone(),
@@ -1051,7 +1044,7 @@ impl Factory {
dm.set_downloader(
"zip",
Box::new(ZipDownloader::new(
- io.clone_box(),
+ io.clone(),
config.clone(),
http_downloader.clone(),
event_dispatcher.cloned(),
@@ -1063,7 +1056,7 @@ impl Factory {
dm.set_downloader(
"rar",
Box::new(RarDownloader::new(
- io.clone_box(),
+ io.clone(),
config.clone(),
http_downloader.clone(),
event_dispatcher.cloned(),
@@ -1075,7 +1068,7 @@ impl Factory {
dm.set_downloader(
"tar",
Box::new(TarDownloader::new(
- io.clone_box(),
+ io.clone(),
config.clone(),
http_downloader.clone(),
event_dispatcher.cloned(),
@@ -1087,7 +1080,7 @@ impl Factory {
dm.set_downloader(
"gzip",
Box::new(GzipDownloader::new(
- io.clone_box(),
+ io.clone(),
config.clone(),
http_downloader.clone(),
event_dispatcher.cloned(),
@@ -1099,7 +1092,7 @@ impl Factory {
dm.set_downloader(
"xz",
Box::new(XzDownloader::new(
- io.clone_box(),
+ io.clone(),
config.clone(),
http_downloader.clone(),
event_dispatcher.cloned(),
@@ -1111,7 +1104,7 @@ impl Factory {
dm.set_downloader(
"phar",
Box::new(PharDownloader::new(
- io.clone_box(),
+ io.clone(),
config.clone(),
http_downloader.clone(),
event_dispatcher.cloned(),
@@ -1123,7 +1116,7 @@ impl Factory {
dm.set_downloader(
"file",
Box::new(FileDownloader::new(
- io.clone_box(),
+ io.clone(),
config.clone(),
http_downloader.clone(),
event_dispatcher.cloned(),
@@ -1135,7 +1128,7 @@ impl Factory {
dm.set_downloader(
"path",
Box::new(PathDownloader::new(
- io.clone_box(),
+ io.clone(),
config.clone(),
http_downloader.clone(),
event_dispatcher.cloned(),
@@ -1181,7 +1174,7 @@ impl Factory {
pub fn create_installation_manager(
&self,
r#loop: std::rc::Rc<std::cell::RefCell<Loop>>,
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
event_dispatcher: Option<std::rc::Rc<std::cell::RefCell<EventDispatcher>>>,
) -> InstallationManager {
InstallationManager::new(r#loop, io, event_dispatcher)
@@ -1191,7 +1184,7 @@ impl Factory {
&self,
im: &std::rc::Rc<std::cell::RefCell<InstallationManager>>,
composer: &PartialOrFullComposer,
- io: &dyn IOInterface,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
process: Option<&std::rc::Rc<std::cell::RefCell<ProcessExecutor>>>,
) {
let fs = std::rc::Rc::new(std::cell::RefCell::new(Filesystem::new(
@@ -1221,7 +1214,7 @@ impl Factory {
// TODO(phase-b): BinaryInstaller is a PHP class so it can't be cloned. Sharing requires
// Rc<RefCell<BinaryInstaller>>; for now construct one per installer.
let _binary_installer = BinaryInstaller::new(
- io.clone_box(),
+ io.clone(),
bin_dir.clone(),
bin_compat.clone(),
Some(fs.clone()),
@@ -1251,13 +1244,13 @@ impl Factory {
config: std::rc::Rc<std::cell::RefCell<Config>>,
parser: VersionParser,
guesser: VersionGuesser,
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
) -> RootPackageLoader {
RootPackageLoader::new(rm, config, Some(parser), Some(guesser), Some(io))
}
pub fn create(
- io: &dyn IOInterface,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: Option<LocalConfigInput>,
disable_plugins: DisablePlugins,
disable_scripts: bool,
@@ -1296,7 +1289,7 @@ impl Factory {
/// If you are calling this in a plugin, you probably should instead use `$composer->getLoop()->getHttpDownloader()`
pub fn create_http_downloader(
- io: &dyn IOInterface,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: &std::rc::Rc<std::cell::RefCell<Config>>,
options: IndexMap<String, PhpMixed>,
) -> anyhow::Result<HttpDownloader> {
@@ -1366,7 +1359,7 @@ impl Factory {
array_replace_recursive(http_downloader_options, options.clone());
}
let http_downloader_result: anyhow::Result<HttpDownloader> = Ok(HttpDownloader::new(
- io.clone_box(),
+ io.clone(),
config.clone(),
http_downloader_options,
disable_tls,
@@ -1402,7 +1395,7 @@ impl Factory {
fn load_composer_auth_env(
config: &mut Config,
- io: Option<&dyn IOInterface>,
+ io: Option<std::rc::Rc<std::cell::RefCell<dyn IOInterface>>>,
) -> anyhow::Result<()> {
let composer_auth_env = Platform::get_env("COMPOSER_AUTH");
let composer_auth_env_str = match composer_auth_env {
@@ -1420,7 +1413,7 @@ impl Factory {
}));
}
- if let Some(io_ref) = io {
+ if let Some(io_ref) = &io {
io_ref.write_error3(
"Loading auth config from COMPOSER_AUTH",
true,
@@ -1468,7 +1461,7 @@ impl Factory {
}
fn validate_json_schema(
- io: Option<&dyn IOInterface>,
+ io: Option<std::rc::Rc<std::cell::RefCell<dyn IOInterface>>>,
file_or_data: ValidateJsonInput,
schema: i64,
source: Option<&str>,
diff --git a/crates/shirabe/src/installer.rs b/crates/shirabe/src/installer.rs
index c3ef76f..70062aa 100644
--- a/crates/shirabe/src/installer.rs
+++ b/crates/shirabe/src/installer.rs
@@ -69,6 +69,7 @@ use crate::filter::platform_requirement_filter::IgnoreListPlatformRequirementFil
use crate::filter::platform_requirement_filter::PlatformRequirementFilterFactory;
use crate::filter::platform_requirement_filter::PlatformRequirementFilterInterface;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::package::AliasPackage;
use crate::package::CompletePackage;
use crate::package::CompletePackageInterface;
@@ -104,7 +105,7 @@ use shirabe_semver::constraint::SimpleConstraint;
#[derive(Debug)]
pub struct Installer {
- pub(crate) io: Box<dyn IOInterface>,
+ pub(crate) io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
pub(crate) config: std::rc::Rc<std::cell::RefCell<Config>>,
pub(crate) package: RootPackageInterfaceHandle,
// TODO can we get rid of the below and just use the package itself?
@@ -161,7 +162,7 @@ impl Installer {
pub const ERROR_TRANSPORT_EXCEPTION: i64 = 100;
pub fn new(
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: std::rc::Rc<std::cell::RefCell<Config>>,
package: RootPackageInterfaceHandle,
download_manager: std::rc::Rc<std::cell::RefCell<DownloadManager>>,
@@ -171,7 +172,7 @@ impl Installer {
event_dispatcher: std::rc::Rc<std::cell::RefCell<EventDispatcher>>,
autoload_generator: std::rc::Rc<std::cell::RefCell<AutoloadGenerator>>,
) -> Self {
- let suggested_packages_reporter = SuggestedPackagesReporter::new(io.clone_box());
+ let suggested_packages_reporter = SuggestedPackagesReporter::new(io.clone());
let platform_requirement_filter = PlatformRequirementFilterFactory::ignore_nothing();
let write_lock = config.borrow_mut().get("lock").as_bool().unwrap_or(false);
@@ -325,7 +326,7 @@ impl Installer {
{
self.installation_manager
.borrow_mut()
- .notify_installs(&*self.io);
+ .notify_installs(&*self.io.borrow());
}
return Err(e);
}
@@ -343,7 +344,7 @@ impl Installer {
{
self.installation_manager
.borrow_mut()
- .notify_installs(&*self.io);
+ .notify_installs(&*self.io.borrow());
}
if self.update {
@@ -650,7 +651,7 @@ impl Installer {
let _ = allow_list;
}
- // TODO(phase-b): create_pool takes owned Request, Box<dyn IOInterface>, Option<Rc<...>>
+ // TODO(phase-b): create_pool takes owned Request, std::rc::Rc<std::cell::RefCell<dyn IOInterface>>, Option<Rc<...>>
// but locally we only have refs. PHP classes (IO, dispatcher) shouldn't Clone.
let mut pool: Option<Pool> = {
let _ = (&request, &self.event_dispatcher, &policy, &repository_set);
@@ -1095,7 +1096,7 @@ impl Installer {
}
drop(root_requires);
- // TODO(phase-b): create_pool takes owned Request, Box<dyn IOInterface>, Option<Rc<...>>
+ // TODO(phase-b): create_pool takes owned Request, std::rc::Rc<std::cell::RefCell<dyn IOInterface>>, Option<Rc<...>>
let pool: Pool = {
let _ = (&request, &self.io, &self.event_dispatcher, &repository_set);
todo!()
@@ -1677,7 +1678,10 @@ impl Installer {
}
/// Create Installer
- pub fn create(io: Box<dyn IOInterface>, composer: &PartialComposerHandle) -> Self {
+ pub fn create(
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
+ composer: &PartialComposerHandle,
+ ) -> Self {
let composer = crate::composer::composer_full(composer);
Self::new(
io,
diff --git a/crates/shirabe/src/installer/binary_installer.rs b/crates/shirabe/src/installer/binary_installer.rs
index 54e1143..a555d83 100644
--- a/crates/shirabe/src/installer/binary_installer.rs
+++ b/crates/shirabe/src/installer/binary_installer.rs
@@ -10,6 +10,7 @@ use shirabe_php_shim::{
};
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::package::PackageInterface;
use crate::util::Filesystem;
use crate::util::Platform;
@@ -21,14 +22,14 @@ use crate::util::Silencer;
pub struct BinaryInstaller {
pub(crate) bin_dir: String,
pub(crate) bin_compat: String,
- pub(crate) io: Box<dyn IOInterface>,
+ pub(crate) io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
pub(crate) filesystem: std::rc::Rc<std::cell::RefCell<Filesystem>>,
vendor_dir: Option<String>,
}
impl BinaryInstaller {
pub fn new(
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
bin_dir: String,
bin_compat: String,
filesystem: Option<std::rc::Rc<std::cell::RefCell<Filesystem>>>,
diff --git a/crates/shirabe/src/installer/installation_manager.rs b/crates/shirabe/src/installer/installation_manager.rs
index 3e455b4..5f312b6 100644
--- a/crates/shirabe/src/installer/installation_manager.rs
+++ b/crates/shirabe/src/installer/installation_manager.rs
@@ -23,6 +23,7 @@ use crate::installer::PackageEvents;
use crate::installer::PluginInstaller;
use crate::io::ConsoleIO;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::package::PackageInterface;
use crate::package::PackageInterfaceHandle;
use crate::repository::InstalledRepositoryInterface;
@@ -39,7 +40,7 @@ pub struct InstallationManager {
/// @var array<string, array<PackageInterface>>
notifiable_packages: IndexMap<String, Vec<PackageInterfaceHandle>>,
loop_: std::rc::Rc<std::cell::RefCell<Loop>>,
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
event_dispatcher: Option<std::rc::Rc<std::cell::RefCell<EventDispatcher>>>,
output_progress: bool,
}
@@ -47,7 +48,7 @@ pub struct InstallationManager {
impl InstallationManager {
pub fn new(
loop_: std::rc::Rc<std::cell::RefCell<Loop>>,
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
event_dispatcher: Option<std::rc::Rc<std::cell::RefCell<EventDispatcher>>>,
) -> Self {
Self {
diff --git a/crates/shirabe/src/installer/installer_event.rs b/crates/shirabe/src/installer/installer_event.rs
index 3c02b7f..5adde1c 100644
--- a/crates/shirabe/src/installer/installer_event.rs
+++ b/crates/shirabe/src/installer/installer_event.rs
@@ -9,7 +9,7 @@ use crate::io::IOInterface;
pub struct InstallerEvent {
inner: Event,
composer: ComposerWeakHandle,
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
dev_mode: bool,
execute_operations: bool,
transaction: Transaction,
@@ -19,7 +19,7 @@ impl InstallerEvent {
pub fn new(
event_name: String,
composer: ComposerWeakHandle,
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
dev_mode: bool,
execute_operations: bool,
transaction: Transaction,
@@ -39,8 +39,8 @@ impl InstallerEvent {
&self.composer
}
- pub fn get_io(&self) -> &dyn IOInterface {
- self.io.as_ref()
+ pub fn get_io(&self) -> std::rc::Rc<std::cell::RefCell<dyn IOInterface>> {
+ self.io.clone()
}
pub fn is_dev_mode(&self) -> bool {
diff --git a/crates/shirabe/src/installer/library_installer.rs b/crates/shirabe/src/installer/library_installer.rs
index 332bdea..17ec8d4 100644
--- a/crates/shirabe/src/installer/library_installer.rs
+++ b/crates/shirabe/src/installer/library_installer.rs
@@ -28,7 +28,7 @@ pub struct LibraryInstaller {
pub(crate) composer: PartialComposerWeakHandle,
pub(crate) vendor_dir: String,
pub(crate) download_manager: Option<std::rc::Rc<std::cell::RefCell<DownloadManager>>>,
- pub(crate) io: Box<dyn IOInterface>,
+ pub(crate) io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
pub(crate) r#type: Option<String>,
pub(crate) filesystem: std::rc::Rc<std::cell::RefCell<Filesystem>>,
pub(crate) binary_installer: BinaryInstaller,
@@ -37,7 +37,7 @@ pub struct LibraryInstaller {
impl LibraryInstaller {
/// Initializes library installer.
pub fn new(
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
composer: PartialComposerWeakHandle,
r#type: Option<String>,
filesystem: Option<std::rc::Rc<std::cell::RefCell<Filesystem>>>,
diff --git a/crates/shirabe/src/installer/metapackage_installer.rs b/crates/shirabe/src/installer/metapackage_installer.rs
index cda7bf0..fe41dd3 100644
--- a/crates/shirabe/src/installer/metapackage_installer.rs
+++ b/crates/shirabe/src/installer/metapackage_installer.rs
@@ -5,6 +5,7 @@ use crate::dependency_resolver::operation::UninstallOperation;
use crate::dependency_resolver::operation::UpdateOperation;
use crate::installer::InstallerInterface;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::io::io_interface;
use crate::package::PackageInterface;
use crate::package::PackageInterfaceHandle;
@@ -14,11 +15,11 @@ use shirabe_php_shim::{InvalidArgumentException, PhpMixed};
#[derive(Debug)]
pub struct MetapackageInstaller {
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
}
impl MetapackageInstaller {
- pub fn new(io: Box<dyn IOInterface>) -> Self {
+ pub fn new(io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>) -> Self {
Self { io }
}
}
diff --git a/crates/shirabe/src/installer/package_event.rs b/crates/shirabe/src/installer/package_event.rs
index d0aecc8..342732d 100644
--- a/crates/shirabe/src/installer/package_event.rs
+++ b/crates/shirabe/src/installer/package_event.rs
@@ -11,7 +11,7 @@ use indexmap::IndexMap;
pub struct PackageEvent {
inner: Event,
composer: ComposerWeakHandle,
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
dev_mode: bool,
local_repo: Box<dyn RepositoryInterface>,
operations: Vec<Box<dyn OperationInterface>>,
@@ -22,7 +22,7 @@ impl PackageEvent {
pub fn new(
event_name: String,
composer: ComposerWeakHandle,
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
dev_mode: bool,
local_repo: Box<dyn RepositoryInterface>,
operations: Vec<Box<dyn OperationInterface>>,
@@ -47,8 +47,8 @@ impl PackageEvent {
&self.composer
}
- pub fn get_io(&self) -> &dyn IOInterface {
- self.io.as_ref()
+ pub fn get_io(&self) -> std::rc::Rc<std::cell::RefCell<dyn IOInterface>> {
+ self.io.clone()
}
pub fn is_dev_mode(&self) -> bool {
diff --git a/crates/shirabe/src/installer/plugin_installer.rs b/crates/shirabe/src/installer/plugin_installer.rs
index 2135bb3..deadcb7 100644
--- a/crates/shirabe/src/installer/plugin_installer.rs
+++ b/crates/shirabe/src/installer/plugin_installer.rs
@@ -5,6 +5,7 @@ use crate::installer::BinaryInstaller;
use crate::installer::InstallerInterface;
use crate::installer::LibraryInstaller;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::package::PackageInterface;
use crate::package::PackageInterfaceHandle;
use crate::plugin::PluginManager;
@@ -21,7 +22,7 @@ pub struct PluginInstaller {
impl PluginInstaller {
pub fn new(
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
composer: PartialComposerWeakHandle,
fs: Option<std::rc::Rc<std::cell::RefCell<Filesystem>>>,
binary_installer: Option<BinaryInstaller>,
diff --git a/crates/shirabe/src/installer/suggested_packages_reporter.rs b/crates/shirabe/src/installer/suggested_packages_reporter.rs
index fc4165a..8faae9c 100644
--- a/crates/shirabe/src/installer/suggested_packages_reporter.rs
+++ b/crates/shirabe/src/installer/suggested_packages_reporter.rs
@@ -1,6 +1,7 @@
//! ref: composer/src/Composer/Installer/SuggestedPackagesReporter.php
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::package::PackageInterface;
use crate::repository::InstalledRepository;
use crate::repository::RepositoryInterface;
@@ -11,7 +12,7 @@ use shirabe_external_packages::symfony::component::console::formatter::OutputFor
#[derive(Debug)]
pub struct SuggestedPackagesReporter {
suggested_packages: Vec<IndexMap<String, String>>,
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
}
impl SuggestedPackagesReporter {
@@ -19,7 +20,7 @@ impl SuggestedPackagesReporter {
pub const MODE_BY_PACKAGE: i64 = 2;
pub const MODE_BY_SUGGESTION: i64 = 4;
- pub fn new(io: Box<dyn IOInterface>) -> Self {
+ pub fn new(io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>) -> Self {
Self {
suggested_packages: Vec::new(),
io,
diff --git a/crates/shirabe/src/io/buffer_io.rs b/crates/shirabe/src/io/buffer_io.rs
index 867eb0e..ed87b71 100644
--- a/crates/shirabe/src/io/buffer_io.rs
+++ b/crates/shirabe/src/io/buffer_io.rs
@@ -129,39 +129,9 @@ impl BufferIO {
}
}
-// TODO(phase-b): PHP `class BufferIO extends ConsoleIO` — delegate all IOInterface,
-// LoggerInterface, and BaseIO methods to `self.inner` (ConsoleIO).
-impl shirabe_external_packages::psr::log::LoggerInterface for BufferIO {
- fn emergency(&self, message: &str, context: &[(&str, &str)]) {
- self.inner.emergency(message, context)
- }
- fn alert(&self, message: &str, context: &[(&str, &str)]) {
- self.inner.alert(message, context)
- }
- fn critical(&self, message: &str, context: &[(&str, &str)]) {
- self.inner.critical(message, context)
- }
- fn error(&self, message: &str, context: &[(&str, &str)]) {
- self.inner.error(message, context)
- }
- fn warning(&self, message: &str, context: &[(&str, &str)]) {
- self.inner.warning(message, context)
- }
- fn notice(&self, message: &str, context: &[(&str, &str)]) {
- self.inner.notice(message, context)
- }
- fn info(&self, message: &str, context: &[(&str, &str)]) {
- self.inner.info(message, context)
- }
- fn debug(&self, message: &str, context: &[(&str, &str)]) {
- self.inner.debug(message, context)
- }
- fn log(&self, level: &str, message: &str, context: &[(&str, &str)]) {
- self.inner.log(level, message, context)
- }
-}
-
-impl crate::io::IOInterface for BufferIO {
+// TODO(phase-b): PHP `class BufferIO extends ConsoleIO` — delegate all
+// IOInterface and BaseIO methods to `self.inner` (ConsoleIO).
+impl crate::io::IOInterfaceImmutable for BufferIO {
fn is_interactive(&self) -> bool {
self.inner.is_interactive()
}
@@ -247,6 +217,20 @@ impl crate::io::IOInterface for BufferIO {
) -> indexmap::IndexMap<String, Option<String>> {
self.inner.get_authentication(repository_name)
}
+ fn error(&self, message: &str, context: &[(&str, &str)]) {
+ self.inner.error(message, context)
+ }
+
+ fn warning(&self, message: &str, context: &[(&str, &str)]) {
+ self.inner.warning(message, context)
+ }
+
+ fn debug(&self, message: &str, context: &[(&str, &str)]) {
+ self.inner.debug(message, context)
+ }
+}
+
+impl crate::io::IOInterfaceMutable for BufferIO {
fn set_authentication(
&mut self,
repository_name: String,
@@ -261,6 +245,8 @@ impl crate::io::IOInterface for BufferIO {
}
}
+impl crate::io::IOInterface for BufferIO {}
+
impl crate::io::BaseIO for BufferIO {
fn authentications(
&self,
diff --git a/crates/shirabe/src/io/console_io.rs b/crates/shirabe/src/io/console_io.rs
index b4bae47..2b1c334 100644
--- a/crates/shirabe/src/io/console_io.rs
+++ b/crates/shirabe/src/io/console_io.rs
@@ -5,7 +5,6 @@ use crate::io::io_interface;
use indexmap::IndexMap;
use indexmap::indexmap;
use shirabe_external_packages::composer::pcre::Preg;
-use shirabe_external_packages::psr::log::LoggerInterface;
use shirabe_external_packages::symfony::component::console::helper::HelperSet;
use shirabe_external_packages::symfony::component::console::helper::ProgressBar;
use shirabe_external_packages::symfony::component::console::helper::Table;
@@ -25,6 +24,8 @@ use std::cell::RefCell;
use crate::io::BaseIO;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
+use crate::io::IOInterfaceMutable;
use crate::question::StrictConfirmationQuestion;
use crate::util::Silencer;
@@ -378,49 +379,7 @@ impl ConsoleIO {
}
}
-impl LoggerInterface for ConsoleIO {
- // TODO(phase-b): BaseIO's emergency/alert/.../log take PhpMixed and
- // IndexMap<String, Box<PhpMixed>> while LoggerInterface takes &str and
- // &[(&str, &str)]. Delegation requires reconciling signatures; for now,
- // mirror NullIO and panic via todo!().
- fn emergency(&self, _message: &str, _context: &[(&str, &str)]) {
- todo!()
- }
-
- fn alert(&self, _message: &str, _context: &[(&str, &str)]) {
- todo!()
- }
-
- fn critical(&self, _message: &str, _context: &[(&str, &str)]) {
- todo!()
- }
-
- fn error(&self, _message: &str, _context: &[(&str, &str)]) {
- todo!()
- }
-
- fn warning(&self, _message: &str, _context: &[(&str, &str)]) {
- todo!()
- }
-
- fn notice(&self, _message: &str, _context: &[(&str, &str)]) {
- todo!()
- }
-
- fn info(&self, _message: &str, _context: &[(&str, &str)]) {
- todo!()
- }
-
- fn debug(&self, _message: &str, _context: &[(&str, &str)]) {
- todo!()
- }
-
- fn log(&self, _level: &str, _message: &str, _context: &[(&str, &str)]) {
- todo!()
- }
-}
-
-impl IOInterface for ConsoleIO {
+impl IOInterfaceImmutable for ConsoleIO {
fn is_interactive(&self) -> bool {
self.input.is_interactive()
}
@@ -690,6 +649,20 @@ impl IOInterface for ConsoleIO {
<Self as BaseIO>::get_authentication(self, repository_name)
}
+ fn error(&self, _message: &str, _context: &[(&str, &str)]) {
+ todo!()
+ }
+
+ fn warning(&self, _message: &str, _context: &[(&str, &str)]) {
+ todo!()
+ }
+
+ fn debug(&self, _message: &str, _context: &[(&str, &str)]) {
+ todo!()
+ }
+}
+
+impl IOInterfaceMutable for ConsoleIO {
fn set_authentication(
&mut self,
repository_name: String,
@@ -704,6 +677,8 @@ impl IOInterface for ConsoleIO {
}
}
+impl IOInterface for ConsoleIO {}
+
impl BaseIO for ConsoleIO {
fn authentications(
&self,
diff --git a/crates/shirabe/src/io/io_interface.rs b/crates/shirabe/src/io/io_interface.rs
index 1d97700..aac1488 100644
--- a/crates/shirabe/src/io/io_interface.rs
+++ b/crates/shirabe/src/io/io_interface.rs
@@ -2,8 +2,9 @@
use crate::config::Config;
use indexmap::IndexMap;
-use shirabe_external_packages::psr::log::LoggerInterface;
use shirabe_php_shim::PhpMixed;
+use std::cell::RefCell;
+use std::rc::Rc;
pub const QUIET: i64 = 1;
pub const NORMAL: i64 = 2;
@@ -11,7 +12,18 @@ pub const VERBOSE: i64 = 4;
pub const VERY_VERBOSE: i64 = 8;
pub const DEBUG: i64 = 16;
-pub trait IOInterface: LoggerInterface + std::fmt::Debug {
+// In PHP this is `IOInterface extends LoggerInterface`. Shirabe does not
+// integrate with the PHP runtime, so there is no need for a separate
+// `LoggerInterface` entity on the Rust side: the LoggerInterface methods that
+// Composer actually invokes through an IO are folded directly into this trait
+// (each is annotated as originating from LoggerInterface).
+//
+// On the Rust side the interface is split into an immutable part (`&self`
+// methods, below) and a mutable part (`IOInterfaceMutable`, the `&mut self`
+// methods). The shared handle `Rc<RefCell<dyn IOInterface>>` implements only
+// `IOInterfaceImmutable`, so the mutating methods are reachable only via
+// `io.borrow_mut()` — enforced at compile time rather than at runtime.
+pub trait IOInterfaceImmutable: std::fmt::Debug {
fn is_interactive(&self) -> bool;
fn is_verbose(&self) -> bool;
@@ -112,6 +124,19 @@ pub trait IOInterface: LoggerInterface + std::fmt::Debug {
fn get_authentication(&self, repository_name: &str) -> IndexMap<String, Option<String>>;
+ // From PHP `LoggerInterface` (which `IOInterface` extends). Only the
+ // variants Composer actually calls through an IO are kept.
+ fn error(&self, message: &str, context: &[(&str, &str)]);
+
+ fn warning(&self, message: &str, context: &[(&str, &str)]);
+
+ fn debug(&self, message: &str, context: &[(&str, &str)]);
+}
+
+// The `&mut self` part of PHP `IOInterface`. The shared handle does NOT
+// implement this trait, so these methods can only be reached through
+// `io.borrow_mut()`.
+pub trait IOInterfaceMutable {
fn set_authentication(
&mut self,
repository_name: String,
@@ -120,8 +145,190 @@ pub trait IOInterface: LoggerInterface + std::fmt::Debug {
);
fn load_configuration(&mut self, config: &mut Config) -> anyhow::Result<()>;
+}
+
+// PHP `IOInterface`. This is the type used for the shared trait object
+// `dyn IOInterface`; its vtable carries both the immutable and mutable methods.
+pub trait IOInterface: IOInterfaceImmutable + IOInterfaceMutable {}
+
+// Shared-ownership handle for a PHP IO instance (reference semantics). It
+// exposes only the immutable surface; mutating methods (`set_authentication`,
+// `load_configuration`) are reached via `io.borrow_mut()`. Because the handle
+// does not implement `IOInterfaceMutable`, calling those directly on the handle
+// is a compile error rather than a runtime panic.
+impl IOInterfaceImmutable for Rc<RefCell<dyn IOInterface>> {
+ fn is_interactive(&self) -> bool {
+ self.borrow().is_interactive()
+ }
+
+ fn is_verbose(&self) -> bool {
+ self.borrow().is_verbose()
+ }
+
+ fn is_very_verbose(&self) -> bool {
+ self.borrow().is_very_verbose()
+ }
+
+ fn is_debug(&self) -> bool {
+ self.borrow().is_debug()
+ }
+
+ fn is_decorated(&self) -> bool {
+ self.borrow().is_decorated()
+ }
+
+ fn write(&self, message: &str) {
+ self.borrow().write(message)
+ }
+
+ fn write2(&self, message: &str, newline: bool) {
+ self.borrow().write2(message, newline)
+ }
+
+ fn write_no_newline(&self, message: &str) {
+ self.borrow().write_no_newline(message)
+ }
+
+ fn write3(&self, message: &str, newline: bool, verbosity: i64) {
+ self.borrow().write3(message, newline, verbosity)
+ }
+
+ fn write_error(&self, message: &str) {
+ self.borrow().write_error(message)
+ }
+
+ fn write_error2(&self, message: &str, newline: bool) {
+ self.borrow().write_error2(message, newline)
+ }
+
+ fn write_error_no_newline(&self, message: &str) {
+ self.borrow().write_error_no_newline(message)
+ }
+
+ fn write_error3(&self, message: &str, newline: bool, verbosity: i64) {
+ self.borrow().write_error3(message, newline, verbosity)
+ }
+
+ fn write_raw(&self, message: &str) {
+ self.borrow().write_raw(message)
+ }
+
+ fn write_raw2(&self, message: &str, newline: bool) {
+ self.borrow().write_raw2(message, newline)
+ }
+
+ fn write_raw3(&self, message: &str, newline: bool, verbosity: i64) {
+ self.borrow().write_raw3(message, newline, verbosity)
+ }
+
+ fn write_error_raw(&self, message: &str) {
+ self.borrow().write_error_raw(message)
+ }
+
+ fn write_error_raw2(&self, message: &str, newline: bool) {
+ self.borrow().write_error_raw2(message, newline)
+ }
+
+ fn write_error_raw3(&self, message: &str, newline: bool, verbosity: i64) {
+ self.borrow().write_error_raw3(message, newline, verbosity)
+ }
+
+ fn overwrite(&self, message: &str) {
+ self.borrow().overwrite(message)
+ }
+
+ fn overwrite2(&self, message: &str, newline: bool) {
+ self.borrow().overwrite2(message, newline)
+ }
+
+ fn overwrite3(&self, message: &str, newline: bool, size: Option<i64>) {
+ self.borrow().overwrite3(message, newline, size)
+ }
+
+ fn overwrite4(&self, message: &str, newline: bool, size: Option<i64>, verbosity: i64) {
+ self.borrow().overwrite4(message, newline, size, verbosity)
+ }
+
+ fn overwrite_error(&self, message: &str) {
+ self.borrow().overwrite_error(message)
+ }
+
+ fn overwrite_error2(&self, message: &str, newline: bool) {
+ self.borrow().overwrite_error2(message, newline)
+ }
+
+ fn overwrite_error3(&self, message: &str, newline: bool, size: Option<i64>) {
+ self.borrow().overwrite_error3(message, newline, size)
+ }
+
+ fn overwrite_error4(&self, message: &str, newline: bool, size: Option<i64>, verbosity: i64) {
+ self.borrow()
+ .overwrite_error4(message, newline, size, verbosity)
+ }
+
+ fn ask(&self, question: String, default: PhpMixed) -> PhpMixed {
+ self.borrow().ask(question, default)
+ }
+
+ fn ask_confirmation(&self, question: String, default: bool) -> bool {
+ self.borrow().ask_confirmation(question, default)
+ }
+
+ fn ask_and_validate(
+ &self,
+ question: String,
+ validator: Box<dyn Fn(PhpMixed) -> PhpMixed>,
+ attempts: Option<i64>,
+ default: PhpMixed,
+ ) -> PhpMixed {
+ self.borrow()
+ .ask_and_validate(question, validator, attempts, default)
+ }
+
+ fn ask_and_hide_answer(&self, question: String) -> Option<String> {
+ self.borrow().ask_and_hide_answer(question)
+ }
+
+ fn select(
+ &self,
+ question: String,
+ choices: Vec<String>,
+ default: PhpMixed,
+ attempts: PhpMixed,
+ error_message: String,
+ multiselect: bool,
+ ) -> PhpMixed {
+ self.borrow().select(
+ question,
+ choices,
+ default,
+ attempts,
+ error_message,
+ multiselect,
+ )
+ }
+
+ fn get_authentications(&self) -> IndexMap<String, IndexMap<String, Option<String>>> {
+ self.borrow().get_authentications()
+ }
+
+ fn has_authentication(&self, repository_name: &str) -> bool {
+ self.borrow().has_authentication(repository_name)
+ }
+
+ fn get_authentication(&self, repository_name: &str) -> IndexMap<String, Option<String>> {
+ self.borrow().get_authentication(repository_name)
+ }
+
+ fn error(&self, message: &str, context: &[(&str, &str)]) {
+ self.borrow().error(message, context)
+ }
+
+ fn warning(&self, message: &str, context: &[(&str, &str)]) {
+ self.borrow().warning(message, context)
+ }
- fn clone_box(&self) -> Box<dyn IOInterface> {
- todo!()
+ fn debug(&self, message: &str, context: &[(&str, &str)]) {
+ self.borrow().debug(message, context)
}
}
diff --git a/crates/shirabe/src/io/null_io.rs b/crates/shirabe/src/io/null_io.rs
index e3cfdcf..b0e11f1 100644
--- a/crates/shirabe/src/io/null_io.rs
+++ b/crates/shirabe/src/io/null_io.rs
@@ -2,7 +2,8 @@
use crate::io::BaseIO;
use crate::io::IOInterface;
-use shirabe_external_packages::psr::log::LoggerInterface;
+use crate::io::IOInterfaceImmutable;
+use crate::io::IOInterfaceMutable;
use shirabe_php_shim::PhpMixed;
#[derive(Debug)]
@@ -18,7 +19,7 @@ impl NullIO {
}
}
-impl IOInterface for NullIO {
+impl IOInterfaceImmutable for NullIO {
fn is_interactive(&self) -> bool {
false
}
@@ -109,6 +110,20 @@ impl IOInterface for NullIO {
<Self as BaseIO>::get_authentication(self, repository_name)
}
+ fn error(&self, _message: &str, _context: &[(&str, &str)]) {
+ todo!()
+ }
+
+ fn warning(&self, _message: &str, _context: &[(&str, &str)]) {
+ todo!()
+ }
+
+ fn debug(&self, _message: &str, _context: &[(&str, &str)]) {
+ todo!()
+ }
+}
+
+impl IOInterfaceMutable for NullIO {
fn set_authentication(
&mut self,
repository_name: String,
@@ -123,6 +138,8 @@ impl IOInterface for NullIO {
}
}
+impl IOInterface for NullIO {}
+
impl BaseIO for NullIO {
fn authentications(
&self,
@@ -136,41 +153,3 @@ impl BaseIO for NullIO {
&mut self.authentications
}
}
-
-impl LoggerInterface for NullIO {
- fn emergency(&self, message: &str, context: &[(&str, &str)]) {
- todo!()
- }
-
- fn alert(&self, message: &str, context: &[(&str, &str)]) {
- todo!()
- }
-
- fn critical(&self, message: &str, context: &[(&str, &str)]) {
- todo!()
- }
-
- fn error(&self, message: &str, context: &[(&str, &str)]) {
- todo!()
- }
-
- fn warning(&self, message: &str, context: &[(&str, &str)]) {
- todo!()
- }
-
- fn notice(&self, message: &str, context: &[(&str, &str)]) {
- todo!()
- }
-
- fn info(&self, message: &str, context: &[(&str, &str)]) {
- todo!()
- }
-
- fn debug(&self, message: &str, context: &[(&str, &str)]) {
- todo!()
- }
-
- fn log(&self, level: &str, message: &str, context: &[(&str, &str)]) {
- todo!()
- }
-}
diff --git a/crates/shirabe/src/json/json_file.rs b/crates/shirabe/src/json/json_file.rs
index 3340cae..2450b0a 100644
--- a/crates/shirabe/src/json/json_file.rs
+++ b/crates/shirabe/src/json/json_file.rs
@@ -19,6 +19,7 @@ use shirabe_php_shim::{
use crate::downloader::TransportException;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::json::JsonValidationException;
use crate::util::Filesystem;
use crate::util::HttpDownloader;
@@ -31,7 +32,7 @@ pub struct JsonFile {
/// @var ?HttpDownloader
http_downloader: Option<std::rc::Rc<std::cell::RefCell<HttpDownloader>>>,
/// @var ?IOInterface
- io: Option<Box<dyn IOInterface>>,
+ io: Option<std::rc::Rc<std::cell::RefCell<dyn IOInterface>>>,
/// @var string
indent: String,
}
@@ -69,7 +70,7 @@ impl JsonFile {
pub fn new(
path: String,
http_downloader: Option<std::rc::Rc<std::cell::RefCell<HttpDownloader>>>,
- io: Option<Box<dyn IOInterface>>,
+ io: Option<std::rc::Rc<std::cell::RefCell<dyn IOInterface>>>,
) -> Result<Self> {
if http_downloader.is_none() && Preg::is_match(r"{^https?://}i", &path).unwrap_or(false) {
return Err(InvalidArgumentException {
diff --git a/crates/shirabe/src/package/loader/root_package_loader.rs b/crates/shirabe/src/package/loader/root_package_loader.rs
index e235e31..1b4d155 100644
--- a/crates/shirabe/src/package/loader/root_package_loader.rs
+++ b/crates/shirabe/src/package/loader/root_package_loader.rs
@@ -8,6 +8,7 @@ use shirabe_php_shim::{
use crate::config::Config;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::package::CompletePackageInterface;
use crate::package::PackageInterface;
use crate::package::RootAliasPackage;
@@ -30,7 +31,7 @@ pub struct RootPackageLoader {
manager: std::rc::Rc<std::cell::RefCell<RepositoryManager>>,
config: std::rc::Rc<std::cell::RefCell<Config>>,
version_guesser: VersionGuesser,
- io: Option<Box<dyn IOInterface>>,
+ io: Option<std::rc::Rc<std::cell::RefCell<dyn IOInterface>>>,
}
impl RootPackageLoader {
@@ -39,17 +40,17 @@ impl RootPackageLoader {
config: std::rc::Rc<std::cell::RefCell<Config>>,
parser: Option<VersionParser>,
version_guesser: Option<VersionGuesser>,
- io: Option<Box<dyn IOInterface>>,
+ io: Option<std::rc::Rc<std::cell::RefCell<dyn IOInterface>>>,
) -> Self {
let inner = ArrayLoader::new(parser, true);
let version_guesser = version_guesser.unwrap_or_else(|| {
- let mut process_executor = ProcessExecutor::new(io.as_deref().map(|i| i.clone_box()));
+ let mut process_executor = ProcessExecutor::new(io.clone());
process_executor.enable_async();
VersionGuesser::new(
config.clone(),
std::rc::Rc::new(std::cell::RefCell::new(process_executor)),
inner.version_parser.clone(),
- io.as_ref().map(|i| i.clone_box()),
+ io.clone(),
)
});
Self {
diff --git a/crates/shirabe/src/package/locker.rs b/crates/shirabe/src/package/locker.rs
index bdeb391..8ba2cc2 100644
--- a/crates/shirabe/src/package/locker.rs
+++ b/crates/shirabe/src/package/locker.rs
@@ -60,7 +60,7 @@ pub struct Locker {
impl Locker {
/// Initializes packages locker.
pub fn new(
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
lock_file: JsonFile,
installation_manager: std::rc::Rc<std::cell::RefCell<InstallationManager>>,
composer_file_contents: &str,
diff --git a/crates/shirabe/src/package/version/version_guesser.rs b/crates/shirabe/src/package/version/version_guesser.rs
index 47054a4..c7ffd65 100644
--- a/crates/shirabe/src/package/version/version_guesser.rs
+++ b/crates/shirabe/src/package/version/version_guesser.rs
@@ -37,7 +37,7 @@ pub struct VersionGuesser {
version_parser: VersionParser,
/// @var IOInterface|null
- io: Option<Box<dyn IOInterface>>,
+ io: Option<std::rc::Rc<std::cell::RefCell<dyn IOInterface>>>,
}
/// PHP: @phpstan-type Version array{version, commit, pretty_version, feature_version?, feature_pretty_version?}
@@ -55,7 +55,7 @@ impl VersionGuesser {
config: std::rc::Rc<std::cell::RefCell<Config>>,
process: std::rc::Rc<std::cell::RefCell<ProcessExecutor>>,
version_parser: VersionParser,
- io: Option<Box<dyn IOInterface>>,
+ io: Option<std::rc::Rc<std::cell::RefCell<dyn IOInterface>>>,
) -> Self {
Self {
config,
@@ -284,7 +284,7 @@ impl VersionGuesser {
GitUtil::check_for_repo_ownership_error(
&self.process.borrow().get_error_output(),
path,
- self.io.as_deref(),
+ self.io.clone(),
);
if version.is_none() || is_detached {
diff --git a/crates/shirabe/src/platform/hhvm_detector.rs b/crates/shirabe/src/platform/hhvm_detector.rs
index 736b4b2..3566f1f 100644
--- a/crates/shirabe/src/platform/hhvm_detector.rs
+++ b/crates/shirabe/src/platform/hhvm_detector.rs
@@ -51,7 +51,7 @@ impl HhvmDetector {
let hhvm_path = finder.find("hhvm", None, &[]);
if let Some(hhvm_path) = hhvm_path {
let executor = self.process_executor.get_or_insert_with(|| {
- std::rc::Rc::new(std::cell::RefCell::new(ProcessExecutor::new(())))
+ std::rc::Rc::new(std::cell::RefCell::new(ProcessExecutor::new(None)))
});
let mut version_output = shirabe_php_shim::PhpMixed::Null;
let cmd = shirabe_php_shim::PhpMixed::List(
diff --git a/crates/shirabe/src/plugin/plugin_manager.rs b/crates/shirabe/src/plugin/plugin_manager.rs
index ddde387..a03fcaa 100644
--- a/crates/shirabe/src/plugin/plugin_manager.rs
+++ b/crates/shirabe/src/plugin/plugin_manager.rs
@@ -21,6 +21,7 @@ use crate::composer::{ComposerHandle, ComposerWeakHandle};
use crate::event_dispatcher::EventSubscriberInterface;
use crate::installer::InstallerInterface;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::package::CompletePackage;
use crate::package::Link;
use crate::package::Locker;
@@ -51,7 +52,7 @@ pub enum DisablePlugins {
#[derive(Debug)]
pub struct PluginManager {
pub(crate) composer: ComposerWeakHandle,
- pub(crate) io: Box<dyn IOInterface>,
+ pub(crate) io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
pub(crate) global_composer: Option<PartialComposerHandle>,
pub(crate) version_parser: VersionParser,
pub(crate) disable_plugins: DisablePlugins,
@@ -72,7 +73,7 @@ static mut CLASS_COUNTER: i64 = 0;
impl PluginManager {
pub fn new(
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
composer: ComposerWeakHandle,
global_composer: Option<PartialComposerHandle>,
disable_plugins: DisablePlugins,
@@ -475,7 +476,7 @@ impl PluginManager {
String::new()
}
));
- plugin.activate(&self.composer_full(), &*self.io);
+ plugin.activate(&self.composer_full(), &*self.io.borrow());
// TODO(plugin): if plugin is EventSubscriberInterface, hook into the event dispatcher
// The PHP code calls $this->composer->getEventDispatcher()->addSubscriber($plugin);
@@ -502,7 +503,7 @@ impl PluginManager {
self.io
.write_error(&format!("Unloading plugin {}", get_class_obj(plugin)));
let mut removed = self.plugins.remove(index);
- removed.deactivate(&self.composer_full(), &*self.io);
+ removed.deactivate(&self.composer_full(), &*self.io.borrow());
// TODO(plugin): remove_listener accepts any callable/object in PHP; here we have
// a plugin instance and need to translate to a Callable, which is not portable
@@ -515,7 +516,7 @@ impl PluginManager {
// TODO(plugin): plugin uninstall hook
self.io
.write_error(&format!("Uninstalling plugin {}", get_class_obj(plugin)));
- plugin.uninstall(&self.composer_full(), &*self.io);
+ plugin.uninstall(&self.composer_full(), &*self.io.borrow());
}
fn load_repository(
diff --git a/crates/shirabe/src/repository/artifact_repository.rs b/crates/shirabe/src/repository/artifact_repository.rs
index eff8fef..1509de3 100644
--- a/crates/shirabe/src/repository/artifact_repository.rs
+++ b/crates/shirabe/src/repository/artifact_repository.rs
@@ -9,6 +9,7 @@ use shirabe_php_shim::{
};
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::json::JsonFile;
use crate::package::BasePackage;
use crate::package::loader::ArrayLoader;
@@ -24,7 +25,7 @@ pub struct ArtifactRepository {
pub(crate) loader: Box<dyn LoaderInterface>,
pub(crate) lookup: String,
pub(crate) repo_config: IndexMap<String, PhpMixed>,
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
}
impl std::fmt::Debug for ArtifactRepository {
@@ -39,7 +40,7 @@ impl std::fmt::Debug for ArtifactRepository {
impl ArtifactRepository {
pub fn new(
repo_config: IndexMap<String, PhpMixed>,
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
) -> anyhow::Result<Self> {
if !extension_loaded("zip") {
return Err(RuntimeException {
diff --git a/crates/shirabe/src/repository/composer_repository.rs b/crates/shirabe/src/repository/composer_repository.rs
index 5c16f8e..d055e59 100644
--- a/crates/shirabe/src/repository/composer_repository.rs
+++ b/crates/shirabe/src/repository/composer_repository.rs
@@ -21,6 +21,7 @@ use crate::config::Config;
use crate::downloader::TransportException;
use crate::event_dispatcher::EventDispatcher;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::json::JsonFile;
use crate::package::BasePackageHandle;
use crate::package::PackageInterface;
@@ -84,7 +85,7 @@ pub struct ComposerRepository {
url: String,
/// non-empty-string
base_url: String,
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
http_downloader: std::rc::Rc<std::cell::RefCell<HttpDownloader>>,
r#loop: std::rc::Rc<std::cell::RefCell<Loop>>,
pub(crate) cache: Cache,
@@ -141,7 +142,7 @@ impl ConfigurableRepositoryInterface for ComposerRepository {
impl ComposerRepository {
pub fn new(
mut repo_config: IndexMap<String, PhpMixed>,
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: &Config,
http_downloader: std::rc::Rc<std::cell::RefCell<HttpDownloader>>,
event_dispatcher: Option<std::rc::Rc<std::cell::RefCell<EventDispatcher>>>,
@@ -258,10 +259,11 @@ impl ComposerRepository {
let base_url = base_url_trimmed.trim_end_matches('/').to_string();
assert!(!base_url.is_empty());
- // TODO(phase-b): Cache::new expects Box<dyn IOInterface> but io is also stored in self.io;
+ // TODO(phase-b): Cache::new expects std::rc::Rc<std::cell::RefCell<dyn IOInterface>> but io is also stored in self.io;
// need shared ownership (Rc) for IOInterface. Using todo!() placeholder.
- let cache: Cache =
- todo!("Cache::new requires Box<dyn IOInterface> but io is also moved into self.io");
+ let cache: Cache = todo!(
+ "Cache::new requires std::rc::Rc<std::cell::RefCell<dyn IOInterface>> but io is also moved into self.io"
+ );
let version_parser = VersionParser::new();
let loader = ArrayLoader::new(Some(version_parser.clone()), true);
@@ -2930,7 +2932,7 @@ impl ComposerRepository {
.as_array()
.map(|a| a.iter().map(|(k, v)| (k.clone(), (**v).clone())).collect())
.unwrap_or_default();
- HttpDownloader::output_warnings(&*self.io, &self.url, &data_local);
+ HttpDownloader::output_warnings(&*self.io.borrow(), &self.url, &data_local);
if let Some(ck) = cache_key_owned.as_ref() {
if !ck.is_empty() && !self.cache.is_read_only() {
@@ -3127,7 +3129,7 @@ impl ComposerRepository {
.as_array()
.map(|a| a.iter().map(|(k, v)| (k.clone(), (**v).clone())).collect())
.unwrap_or_default();
- HttpDownloader::output_warnings(&*self.io, &self.url, &data);
+ HttpDownloader::output_warnings(&*self.io.borrow(), &self.url, &data);
let last_modified_date = response.get_header("last-modified");
response.collect();
@@ -3305,7 +3307,7 @@ impl ComposerRepository {
.as_array()
.map(|a| a.iter().map(|(k, v)| (k.clone(), (**v).clone())).collect())
.unwrap_or_default();
- HttpDownloader::output_warnings(self.io.as_ref(), &self.url, &data);
+ HttpDownloader::output_warnings(&*self.io.borrow(), &self.url, &data);
let last_modified_date = response.get_header("last-modified");
response.collect();
diff --git a/crates/shirabe/src/repository/path_repository.rs b/crates/shirabe/src/repository/path_repository.rs
index 8d9965e..51acff0 100644
--- a/crates/shirabe/src/repository/path_repository.rs
+++ b/crates/shirabe/src/repository/path_repository.rs
@@ -44,7 +44,7 @@ impl ConfigurableRepositoryInterface for PathRepository {
impl PathRepository {
pub fn new(
repo_config: IndexMap<String, PhpMixed>,
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: std::rc::Rc<std::cell::RefCell<Config>>,
http_downloader: Option<std::rc::Rc<std::cell::RefCell<HttpDownloader>>>,
dispatcher: Option<std::rc::Rc<std::cell::RefCell<EventDispatcher>>>,
@@ -67,14 +67,14 @@ impl PathRepository {
let url = Platform::expand_path(&url_str);
let process = process.unwrap_or_else(|| {
std::rc::Rc::new(std::cell::RefCell::new(ProcessExecutor::new(Some(
- io.clone_box(),
+ io.clone(),
))))
});
let version_guesser = VersionGuesser::new(
config,
process.clone(),
VersionParser::new(),
- Some(io.clone_box()),
+ Some(io.clone()),
);
let mut options = repo_config
.get("options")
diff --git a/crates/shirabe/src/repository/repository_factory.rs b/crates/shirabe/src/repository/repository_factory.rs
index 0f2e6b2..908704c 100644
--- a/crates/shirabe/src/repository/repository_factory.rs
+++ b/crates/shirabe/src/repository/repository_factory.rs
@@ -21,7 +21,7 @@ pub struct RepositoryFactory;
impl RepositoryFactory {
pub fn config_from_string(
- io: &dyn IOInterface,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: &std::rc::Rc<std::cell::RefCell<Config>>,
repository: &str,
allow_filesystem: bool,
@@ -42,9 +42,9 @@ impl RepositoryFactory {
let mut json = JsonFile::new(
repository.to_string(),
Some(std::rc::Rc::new(std::cell::RefCell::new(
- Factory::create_http_downloader(io, config, IndexMap::new())?,
+ Factory::create_http_downloader(io.clone(), config, IndexMap::new())?,
))),
- Some(io.clone_box()),
+ Some(io.clone()),
)?;
let data = json.read()?;
let has_packages = data.get("packages").map_or(false, |v| !v.is_null());
@@ -97,18 +97,19 @@ impl RepositoryFactory {
}
pub fn from_string(
- io: &dyn IOInterface,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: &std::rc::Rc<std::cell::RefCell<Config>>,
repository: &str,
allow_filesystem: bool,
rm: Option<&mut RepositoryManager>,
) -> anyhow::Result<Box<dyn RepositoryInterface>> {
- let repo_config = Self::config_from_string(io, config, repository, allow_filesystem)?;
+ let repo_config =
+ Self::config_from_string(io.clone(), config, repository, allow_filesystem)?;
Self::create_repo(io, config, repo_config, rm)
}
pub fn create_repo(
- io: &dyn IOInterface,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: &std::rc::Rc<std::cell::RefCell<Config>>,
repo_config: IndexMap<String, PhpMixed>,
rm: Option<&mut RepositoryManager>,
@@ -141,7 +142,7 @@ impl RepositoryFactory {
}
pub fn default_repos(
- io: Option<&dyn IOInterface>,
+ io: Option<std::rc::Rc<std::cell::RefCell<dyn IOInterface>>>,
config: Option<std::rc::Rc<std::cell::RefCell<Config>>>,
rm: Option<&mut RepositoryManager>,
) -> anyhow::Result<IndexMap<String, Box<dyn RepositoryInterface>>> {
@@ -149,7 +150,7 @@ impl RepositoryFactory {
Some(c) => c,
None => std::rc::Rc::new(std::cell::RefCell::new(Factory::create_config(None, None)?)),
};
- if let Some(_io) = io {
+ if let Some(_io) = &io {
// TODO(phase-b): IOInterface::load_configuration requires &mut self, but this
// function takes &dyn IOInterface. Wider refactor needed; skip for now.
}
@@ -164,7 +165,7 @@ impl RepositoryFactory {
code: 0,
})?;
owned_rm = Self::manager(
- io,
+ io.clone(),
&config,
Some(std::rc::Rc::new(std::cell::RefCell::new(
Factory::create_http_downloader(io, &config, IndexMap::new())?,
@@ -181,7 +182,7 @@ impl RepositoryFactory {
}
pub fn manager(
- io: &dyn IOInterface,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: &std::rc::Rc<std::cell::RefCell<Config>>,
http_downloader: Option<std::rc::Rc<std::cell::RefCell<HttpDownloader>>>,
event_dispatcher: Option<std::rc::Rc<std::cell::RefCell<EventDispatcher>>>,
@@ -190,7 +191,7 @@ impl RepositoryFactory {
let http_downloader = match http_downloader {
Some(h) => h,
None => std::rc::Rc::new(std::cell::RefCell::new(Factory::create_http_downloader(
- io,
+ io.clone(),
config,
IndexMap::new(),
)?)),
@@ -198,7 +199,7 @@ impl RepositoryFactory {
let process = match process {
Some(p) => p,
None => {
- let mut p = ProcessExecutor::new(io);
+ let mut p = ProcessExecutor::new(Some(io.clone()));
p.enable_async();
std::rc::Rc::new(std::cell::RefCell::new(p))
}
@@ -231,14 +232,15 @@ impl RepositoryFactory {
}
pub fn default_repos_with_default_manager(
- io: &mut dyn IOInterface,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
) -> anyhow::Result<IndexMap<String, Box<dyn RepositoryInterface>>> {
let config = std::rc::Rc::new(std::cell::RefCell::new(Factory::create_config(
- Some(io),
+ Some(io.clone()),
None,
)?));
- let mut manager = Self::manager(io, &config, None, None, None)?;
- io.load_configuration(&mut *config.borrow_mut())?;
+ let mut manager = Self::manager(io.clone(), &config, None, None, None)?;
+ io.borrow_mut()
+ .load_configuration(&mut *config.borrow_mut())?;
Self::default_repos(Some(io), Some(config), Some(&mut manager))
}
diff --git a/crates/shirabe/src/repository/repository_manager.rs b/crates/shirabe/src/repository/repository_manager.rs
index f432d6e..72c3643 100644
--- a/crates/shirabe/src/repository/repository_manager.rs
+++ b/crates/shirabe/src/repository/repository_manager.rs
@@ -7,6 +7,7 @@ use shirabe_semver::constraint::AnyConstraint;
use crate::config::Config;
use crate::event_dispatcher::EventDispatcher;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::package::PackageInterfaceHandle;
use crate::repository::FilterRepository;
use crate::repository::InstalledRepositoryInterface;
@@ -19,7 +20,7 @@ pub struct RepositoryManager {
local_repository: Option<Box<dyn InstalledRepositoryInterface>>,
repositories: Vec<Box<dyn RepositoryInterface>>,
repository_classes: IndexMap<String, String>,
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: std::rc::Rc<std::cell::RefCell<Config>>,
http_downloader: std::rc::Rc<std::cell::RefCell<HttpDownloader>>,
event_dispatcher: Option<std::rc::Rc<std::cell::RefCell<EventDispatcher>>>,
@@ -28,19 +29,22 @@ pub struct RepositoryManager {
impl RepositoryManager {
pub fn new(
- io: &dyn IOInterface,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: std::rc::Rc<std::cell::RefCell<Config>>,
http_downloader: std::rc::Rc<std::cell::RefCell<HttpDownloader>>,
event_dispatcher: Option<std::rc::Rc<std::cell::RefCell<EventDispatcher>>>,
process: Option<std::rc::Rc<std::cell::RefCell<ProcessExecutor>>>,
) -> Self {
- let process = process
- .unwrap_or_else(|| std::rc::Rc::new(std::cell::RefCell::new(ProcessExecutor::new(io))));
+ let process = process.unwrap_or_else(|| {
+ std::rc::Rc::new(std::cell::RefCell::new(ProcessExecutor::new(Some(
+ io.clone(),
+ ))))
+ });
Self {
local_repository: None,
repositories: vec![],
repository_classes: IndexMap::new(),
- io: io.clone_box(),
+ io,
config,
http_downloader,
event_dispatcher,
diff --git a/crates/shirabe/src/repository/repository_set.rs b/crates/shirabe/src/repository/repository_set.rs
index 1c9c4a3..3a81eda 100644
--- a/crates/shirabe/src/repository/repository_set.rs
+++ b/crates/shirabe/src/repository/repository_set.rs
@@ -456,7 +456,7 @@ impl RepositorySet {
pub fn create_pool(
&mut self,
request: Request,
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
event_dispatcher: Option<std::rc::Rc<std::cell::RefCell<EventDispatcher>>>,
pool_optimizer: Option<PoolOptimizer>,
ignored_types: Vec<String>,
@@ -609,7 +609,7 @@ impl RepositorySet {
self.create_pool(
request,
- Box::new(NullIO::new()),
+ std::rc::Rc::new(std::cell::RefCell::new(NullIO::new())),
None,
None,
vec![],
diff --git a/crates/shirabe/src/repository/vcs/forgejo_driver.rs b/crates/shirabe/src/repository/vcs/forgejo_driver.rs
index 72fd6af..ccd0c16 100644
--- a/crates/shirabe/src/repository/vcs/forgejo_driver.rs
+++ b/crates/shirabe/src/repository/vcs/forgejo_driver.rs
@@ -12,6 +12,7 @@ use crate::cache::Cache;
use crate::config::Config;
use crate::downloader::TransportException;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::json::JsonFile;
use crate::repository::vcs::GitDriver;
use crate::repository::vcs::VcsDriverBase;
@@ -51,7 +52,7 @@ impl ForgejoDriver {
self.forgejo_url = Some(forgejo_url);
self.inner.cache = Some(Cache::new(
- self.inner.io.clone_box(),
+ self.inner.io.clone(),
&cache_dir,
None,
None,
diff --git a/crates/shirabe/src/repository/vcs/fossil_driver.rs b/crates/shirabe/src/repository/vcs/fossil_driver.rs
index 4982d17..207a138 100644
--- a/crates/shirabe/src/repository/vcs/fossil_driver.rs
+++ b/crates/shirabe/src/repository/vcs/fossil_driver.rs
@@ -9,6 +9,7 @@ use shirabe_php_shim::{PhpMixed, RuntimeException, dirname, is_dir, is_file, is_
use crate::cache::Cache;
use crate::config::Config;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::repository::vcs::VcsDriverBase;
use crate::util::Filesystem;
use crate::util::ProcessExecutor;
@@ -31,7 +32,7 @@ impl FossilDriver {
// Ensure we are allowed to use this URL by config.
self.inner.config.borrow_mut().prohibit_url_by_config(
&self.inner.url,
- Some(&*self.inner.io),
+ Some(&*self.inner.io.borrow()),
&indexmap::IndexMap::new(),
)?;
@@ -289,7 +290,12 @@ impl FossilDriver {
Ok(self.branches.clone().unwrap_or_default())
}
- pub fn supports(io: &dyn IOInterface, config: &Config, url: &str, deep: bool) -> bool {
+ pub fn supports(
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
+ config: &Config,
+ url: &str,
+ deep: bool,
+ ) -> bool {
if Preg::is_match(
r"#(^(?:https?|ssh)://(?:[^@]@)?(?:chiselapp\.com|fossil\.))#i",
url,
@@ -310,7 +316,7 @@ impl FossilDriver {
return false;
}
- let mut process = ProcessExecutor::new(io);
+ let mut process = ProcessExecutor::new(Some(io));
let mut output = String::new();
if process.execute_args(
&["fossil", "info"].map(|s| s.to_string()).to_vec(),
diff --git a/crates/shirabe/src/repository/vcs/git_bitbucket_driver.rs b/crates/shirabe/src/repository/vcs/git_bitbucket_driver.rs
index 19f0246..53e49fc 100644
--- a/crates/shirabe/src/repository/vcs/git_bitbucket_driver.rs
+++ b/crates/shirabe/src/repository/vcs/git_bitbucket_driver.rs
@@ -15,6 +15,7 @@ use crate::cache::Cache;
use crate::config::Config;
use crate::downloader::TransportException;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::json::JsonFile;
use crate::repository::vcs::GitDriver;
use crate::repository::vcs::VcsDriverBase;
@@ -80,7 +81,7 @@ impl GitBitbucketDriver {
self.repository = m.get(&CaptureKey::ByIndex(2)).cloned().unwrap_or_default();
self.inner.origin_url = "bitbucket.org".to_string();
self.inner.cache = Some(Cache::new(
- self.inner.io.clone_box(),
+ self.inner.io.clone(),
&implode(
"/",
&[
@@ -693,7 +694,7 @@ impl GitBitbucketDriver {
Err(e) => {
// TODO(phase-b): only handle TransportException
let mut bitbucket_util = Bitbucket::new(
- self.inner.io.clone_box(),
+ self.inner.io.clone(),
self.inner.config.clone(),
Some(self.inner.process.clone()),
Some(self.inner.http_downloader.clone()),
diff --git a/crates/shirabe/src/repository/vcs/git_driver.rs b/crates/shirabe/src/repository/vcs/git_driver.rs
index 69b16b6..665e2fb 100644
--- a/crates/shirabe/src/repository/vcs/git_driver.rs
+++ b/crates/shirabe/src/repository/vcs/git_driver.rs
@@ -13,6 +13,7 @@ use shirabe_php_shim::{
use crate::cache::Cache;
use crate::config::Config;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::repository::vcs::VcsDriverBase;
use crate::util::Filesystem;
use crate::util::Git as GitUtil;
@@ -31,7 +32,7 @@ pub struct GitDriver {
impl GitDriver {
pub fn new(
repo_config: IndexMap<String, shirabe_php_shim::PhpMixed>,
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: std::rc::Rc<std::cell::RefCell<Config>>,
http_downloader: std::rc::Rc<std::cell::RefCell<crate::util::HttpDownloader>>,
process: std::rc::Rc<std::cell::RefCell<ProcessExecutor>>,
@@ -117,7 +118,7 @@ impl GitDriver {
}
let mut git_util = GitUtil::new(
- self.inner.io.clone_box(),
+ self.inner.io.clone(),
self.inner.config.clone(),
self.inner.process.clone(),
std::rc::Rc::new(std::cell::RefCell::new(Filesystem::new(None))),
@@ -154,7 +155,7 @@ impl GitDriver {
.unwrap_or("")
.to_string();
self.inner.cache = Some(Cache::new(
- self.inner.io.clone_box(),
+ self.inner.io.clone(),
&format!(
"{}/{}",
cache_repo_dir,
@@ -183,7 +184,7 @@ impl GitDriver {
self.root_identifier = Some("master".to_string());
let mut git_util = GitUtil::new(
- self.inner.io.clone_box(),
+ self.inner.io.clone(),
self.inner.config.clone(),
self.inner.process.clone(),
std::rc::Rc::new(std::cell::RefCell::new(Filesystem::new(None))),
@@ -399,7 +400,7 @@ impl GitDriver {
}
pub fn supports(
- io: &dyn IOInterface,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
_config: &Config,
url: &str,
deep: bool,
@@ -419,7 +420,9 @@ impl GitDriver {
return Ok(false);
}
- let process = std::rc::Rc::new(std::cell::RefCell::new(ProcessExecutor::new(io)));
+ let process = std::rc::Rc::new(std::cell::RefCell::new(ProcessExecutor::new(Some(
+ io.clone(),
+ ))));
let mut output = String::new();
if process.borrow_mut().execute_args(
&["git".to_string(), "tag".to_string()],
@@ -432,7 +435,7 @@ impl GitDriver {
GitUtil::check_for_repo_ownership_error(
&process.borrow().get_error_output(),
&url,
- Some(io),
+ Some(io.clone()),
)?;
}
@@ -440,7 +443,9 @@ impl GitDriver {
return Ok(false);
}
- let process = std::rc::Rc::new(std::cell::RefCell::new(ProcessExecutor::new(io)));
+ let process = std::rc::Rc::new(std::cell::RefCell::new(ProcessExecutor::new(Some(
+ io.clone(),
+ ))));
// TODO(phase-b): supports() takes &Config; GitUtil now needs Rc<RefCell<Config>>.
// Skipping clean Rc construction since we cannot reconstruct one from a borrowed &Config.
let _ = _config;
@@ -449,7 +454,7 @@ impl GitDriver {
));
#[allow(unreachable_code)]
let mut git_util = GitUtil::new(
- io.clone_box(),
+ io.clone(),
todo!(),
process.clone(),
std::rc::Rc::new(std::cell::RefCell::new(Filesystem::new(None))),
diff --git a/crates/shirabe/src/repository/vcs/github_driver.rs b/crates/shirabe/src/repository/vcs/github_driver.rs
index 6c8d495..5f8266c 100644
--- a/crates/shirabe/src/repository/vcs/github_driver.rs
+++ b/crates/shirabe/src/repository/vcs/github_driver.rs
@@ -15,6 +15,7 @@ use crate::cache::Cache;
use crate::config::Config;
use crate::downloader::TransportException;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::json::JsonFile;
use crate::repository::vcs::GitDriver;
use crate::repository::vcs::VcsDriverBase;
@@ -88,7 +89,7 @@ impl GitHubDriver {
self.inner.origin_url = "github.com".to_string();
}
self.inner.cache = Some(Cache::new(
- self.inner.io.clone_box(),
+ self.inner.io.clone(),
&format!(
"{}/{}/{}/{}",
self.inner
@@ -1015,7 +1016,7 @@ impl GitHubDriver {
Ok(r) => Ok(r),
Err(e) => {
let mut git_hub_util = GitHub::new(
- self.inner.io.clone_box(),
+ self.inner.io.clone(),
self.inner.config.clone(),
Some(self.inner.process.clone()),
Some(self.inner.http_downloader.clone()),
@@ -1294,7 +1295,7 @@ impl GitHubDriver {
repo_config.insert("url".to_string(), PhpMixed::String(url.to_string()));
let mut git_driver = GitDriver::new(
repo_config,
- self.inner.io.clone_box(),
+ self.inner.io.clone(),
self.inner.config.clone(),
self.inner.http_downloader.clone(),
self.inner.process.clone(),
diff --git a/crates/shirabe/src/repository/vcs/gitlab_driver.rs b/crates/shirabe/src/repository/vcs/gitlab_driver.rs
index 8a24b7d..e31eb67 100644
--- a/crates/shirabe/src/repository/vcs/gitlab_driver.rs
+++ b/crates/shirabe/src/repository/vcs/gitlab_driver.rs
@@ -15,6 +15,7 @@ use crate::cache::Cache;
use crate::config::Config;
use crate::downloader::TransportException;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::json::JsonFile;
use crate::repository::vcs::GitDriver;
use crate::repository::vcs::VcsDriverBase;
@@ -183,7 +184,7 @@ impl GitLabDriver {
.unwrap_or_default();
self.inner.cache = Some(Cache::new(
- self.inner.io.clone_box(),
+ self.inner.io.clone(),
&format!(
"{}/{}/{}/{}",
self.inner
@@ -768,7 +769,7 @@ impl GitLabDriver {
repo_config.insert("url".to_string(), PhpMixed::String(url.to_string()));
let mut git_driver = GitDriver::new(
repo_config,
- self.inner.io.clone_box(),
+ self.inner.io.clone(),
self.inner.config.clone(),
self.inner.http_downloader.clone(),
self.inner.process.clone(),
@@ -885,7 +886,7 @@ impl GitLabDriver {
}
Err(e) => {
let mut git_lab_util = GitLab::new(
- self.inner.io.clone_box(),
+ self.inner.io.clone(),
self.inner.config.clone(),
Some(self.inner.process.clone()),
Some(self.inner.http_downloader.clone()),
diff --git a/crates/shirabe/src/repository/vcs/hg_driver.rs b/crates/shirabe/src/repository/vcs/hg_driver.rs
index 8f40d2a..ab3bd0c 100644
--- a/crates/shirabe/src/repository/vcs/hg_driver.rs
+++ b/crates/shirabe/src/repository/vcs/hg_driver.rs
@@ -3,6 +3,7 @@
use crate::cache::Cache;
use crate::config::Config;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::io::io_interface;
use crate::repository::vcs::VcsDriverBase;
use crate::util::Filesystem;
@@ -61,12 +62,12 @@ impl HgDriver {
self.inner.config.borrow_mut().prohibit_url_by_config(
&self.inner.url,
- Some(&*self.inner.io),
+ Some(&*self.inner.io.borrow()),
&indexmap::IndexMap::new(),
)?;
let hg_utils = HgUtils::new(
- &*self.inner.io,
+ self.inner.io.clone(),
&*self.inner.config.borrow(),
&self.inner.process,
);
@@ -308,7 +309,12 @@ impl HgDriver {
Ok(self.branches.clone().unwrap_or_default())
}
- pub fn supports(io: &dyn IOInterface, config: &Config, url: &str, deep: bool) -> bool {
+ pub fn supports(
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
+ config: &Config,
+ url: &str,
+ deep: bool,
+ ) -> bool {
if Preg::is_match(
r"#(^(?:https?|ssh)://(?:[^@]+@)?bitbucket.org|https://(?:.*?)\.kilnhg.com)#i",
url,
@@ -324,7 +330,7 @@ impl HgDriver {
return false;
}
- let mut process = crate::util::ProcessExecutor::new(io);
+ let mut process = crate::util::ProcessExecutor::new(Some(io.clone()));
let mut output = String::new();
if process.execute_args(
&["hg", "summary"].map(|s| s.to_string()).to_vec(),
@@ -340,7 +346,7 @@ impl HgDriver {
return false;
}
- let mut process = crate::util::ProcessExecutor::new(io);
+ let mut process = crate::util::ProcessExecutor::new(Some(io));
let mut ignored = String::new();
let exit = process.execute_args(
&["hg", "identify", "--", url]
diff --git a/crates/shirabe/src/repository/vcs/perforce_driver.rs b/crates/shirabe/src/repository/vcs/perforce_driver.rs
index 35da517..03948b3 100644
--- a/crates/shirabe/src/repository/vcs/perforce_driver.rs
+++ b/crates/shirabe/src/repository/vcs/perforce_driver.rs
@@ -77,7 +77,7 @@ impl PerforceDriver {
self.inner.url.clone(),
repo_dir,
self.inner.process.clone(),
- self.inner.io.clone_box(),
+ self.inner.io.clone(),
));
Ok(())
@@ -167,9 +167,14 @@ impl PerforceDriver {
.into())
}
- pub fn supports(io: &dyn IOInterface, _config: &Config, url: &str, deep: bool) -> bool {
+ pub fn supports(
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
+ _config: &Config,
+ url: &str,
+ deep: bool,
+ ) -> bool {
if deep || Preg::is_match(r"#\b(perforce|p4)\b#i", url).unwrap_or(false) {
- return Perforce::check_server_exists(url, &mut ProcessExecutor::new(io));
+ return Perforce::check_server_exists(url, &mut ProcessExecutor::new(Some(io)));
}
false
}
diff --git a/crates/shirabe/src/repository/vcs/svn_driver.rs b/crates/shirabe/src/repository/vcs/svn_driver.rs
index a6ca9c1..a793340 100644
--- a/crates/shirabe/src/repository/vcs/svn_driver.rs
+++ b/crates/shirabe/src/repository/vcs/svn_driver.rs
@@ -468,7 +468,12 @@ impl SvnDriver {
self.branches.as_ref().unwrap()
}
- pub fn supports(io: &dyn IOInterface, _config: &Config, url: &str, deep: bool) -> bool {
+ pub fn supports(
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
+ _config: &Config,
+ url: &str,
+ deep: bool,
+ ) -> bool {
let url = Self::normalize_url(url);
if Preg::is_match(r"#(^svn://|^svn\+ssh://|svn\.)#i", &url).unwrap_or(false) {
return true;
@@ -479,7 +484,7 @@ impl SvnDriver {
return false;
}
- let mut process = ProcessExecutor::new(io);
+ let mut process = ProcessExecutor::new(Some(io));
let mut ignored_output = String::new();
let exit = process.execute_args(
&[
diff --git a/crates/shirabe/src/repository/vcs/vcs_driver.rs b/crates/shirabe/src/repository/vcs/vcs_driver.rs
index 71476b9..15dd722 100644
--- a/crates/shirabe/src/repository/vcs/vcs_driver.rs
+++ b/crates/shirabe/src/repository/vcs/vcs_driver.rs
@@ -23,7 +23,7 @@ pub struct VcsDriverBase {
pub url: String,
pub origin_url: String,
pub repo_config: IndexMap<String, PhpMixed>,
- pub io: Box<dyn IOInterface>,
+ pub io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
pub config: std::rc::Rc<std::cell::RefCell<Config>>,
pub process: std::rc::Rc<std::cell::RefCell<ProcessExecutor>>,
pub http_downloader: std::rc::Rc<std::cell::RefCell<HttpDownloader>>,
@@ -34,7 +34,7 @@ pub struct VcsDriverBase {
impl VcsDriverBase {
pub fn new(
repo_config: IndexMap<String, PhpMixed>,
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: std::rc::Rc<std::cell::RefCell<Config>>,
http_downloader: std::rc::Rc<std::cell::RefCell<HttpDownloader>>,
process: std::rc::Rc<std::cell::RefCell<ProcessExecutor>>,
diff --git a/crates/shirabe/src/repository/vcs_repository.rs b/crates/shirabe/src/repository/vcs_repository.rs
index a256fb8..804ba51 100644
--- a/crates/shirabe/src/repository/vcs_repository.rs
+++ b/crates/shirabe/src/repository/vcs_repository.rs
@@ -15,6 +15,7 @@ use crate::config::Config;
use crate::downloader::TransportException;
use crate::event_dispatcher::EventDispatcher;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::package::loader::ArrayLoader;
use crate::package::loader::InvalidPackageException;
use crate::package::loader::LoaderInterface;
@@ -43,7 +44,7 @@ pub struct VcsRepository {
/// @var bool
pub(crate) is_very_verbose: bool,
/// @var IOInterface
- pub(crate) io: Box<dyn IOInterface>,
+ pub(crate) io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
/// @var Config
pub(crate) config: std::rc::Rc<std::cell::RefCell<Config>>,
/// @var VersionParser
@@ -87,7 +88,7 @@ impl VcsRepository {
/// @param array<string, class-string<VcsDriverInterface>>|null $drivers
pub fn new(
mut repo_config: IndexMap<String, PhpMixed>,
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: std::rc::Rc<std::cell::RefCell<Config>>,
http_downloader: std::rc::Rc<std::cell::RefCell<HttpDownloader>>,
dispatcher: Option<std::rc::Rc<std::cell::RefCell<EventDispatcher>>>,
@@ -158,7 +159,7 @@ impl VcsRepository {
let is_very_verbose = io.is_very_verbose();
let process_executor = process.unwrap_or_else(|| {
std::rc::Rc::new(std::cell::RefCell::new(ProcessExecutor::new(Some(
- io.clone_box(),
+ io.clone(),
))))
});
diff --git a/crates/shirabe/src/script/event.rs b/crates/shirabe/src/script/event.rs
index 1bd37dd..60557b0 100644
--- a/crates/shirabe/src/script/event.rs
+++ b/crates/shirabe/src/script/event.rs
@@ -10,7 +10,7 @@ use shirabe_php_shim::PhpMixed;
pub struct Event {
inner: BaseEvent,
composer: ComposerWeakHandle,
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
dev_mode: bool,
originating_event: Option<Box<BaseEvent>>,
}
@@ -19,7 +19,7 @@ impl Event {
pub fn new(
name: String,
composer: ComposerWeakHandle,
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
dev_mode: bool,
args: Vec<String>,
flags: IndexMap<String, PhpMixed>,
@@ -37,8 +37,8 @@ impl Event {
&self.composer
}
- pub fn get_io(&self) -> &dyn IOInterface {
- self.io.as_ref()
+ pub fn get_io(&self) -> std::rc::Rc<std::cell::RefCell<dyn IOInterface>> {
+ self.io.clone()
}
pub fn is_dev_mode(&self) -> bool {
diff --git a/crates/shirabe/src/util/auth_helper.rs b/crates/shirabe/src/util/auth_helper.rs
index 908839e..3471a54 100644
--- a/crates/shirabe/src/util/auth_helper.rs
+++ b/crates/shirabe/src/util/auth_helper.rs
@@ -13,13 +13,14 @@ use shirabe_php_shim::{
use crate::config::Config;
use crate::downloader::TransportException;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::util::Bitbucket;
use crate::util::GitHub;
use crate::util::GitLab;
#[derive(Debug)]
pub struct AuthHelper {
- pub(crate) io: Box<dyn IOInterface>,
+ pub(crate) io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
pub(crate) config: std::rc::Rc<std::cell::RefCell<Config>>,
/// @var array<string, string> Map of origins to message displayed
displayed_origin_authentications: IndexMap<String, String>,
@@ -41,7 +42,10 @@ pub enum StoreAuth {
}
impl AuthHelper {
- pub fn new(io: Box<dyn IOInterface>, config: std::rc::Rc<std::cell::RefCell<Config>>) -> Self {
+ pub fn new(
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
+ config: std::rc::Rc<std::cell::RefCell<Config>>,
+ ) -> Self {
Self {
io,
config,
@@ -339,7 +343,7 @@ impl AuthHelper {
let access_token =
bitbucket_util.request_token(&origin, &username, &password)?;
if !access_token.is_empty() {
- self.io.set_authentication(
+ self.io.borrow_mut().set_authentication(
origin.clone(),
"x-token-auth".to_string(),
Some(access_token),
@@ -452,7 +456,7 @@ impl AuthHelper {
);
let username = self.io.ask(" Username: ".to_string(), PhpMixed::Null);
let password = self.io.ask_and_hide_answer(" Password: ".to_string());
- self.io.set_authentication(
+ self.io.borrow_mut().set_authentication(
origin.to_string(),
username.as_string().unwrap_or("").to_string(),
password,
diff --git a/crates/shirabe/src/util/bitbucket.rs b/crates/shirabe/src/util/bitbucket.rs
index 1708447..67ae575 100644
--- a/crates/shirabe/src/util/bitbucket.rs
+++ b/crates/shirabe/src/util/bitbucket.rs
@@ -8,6 +8,7 @@ use crate::config::Config;
use crate::downloader::TransportException;
use crate::factory::Factory;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::util::HttpDownloader;
use crate::util::ProcessExecutor;
@@ -17,7 +18,7 @@ fn transport_error_code(err: &anyhow::Error) -> Option<i64> {
#[derive(Debug)]
pub struct Bitbucket {
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: std::rc::Rc<std::cell::RefCell<Config>>,
process: std::rc::Rc<std::cell::RefCell<ProcessExecutor>>,
http_downloader: std::rc::Rc<std::cell::RefCell<HttpDownloader>>,
@@ -30,7 +31,7 @@ impl Bitbucket {
"https://bitbucket.org/site/oauth2/access_token";
pub fn new(
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: std::rc::Rc<std::cell::RefCell<Config>>,
process: Option<std::rc::Rc<std::cell::RefCell<ProcessExecutor>>>,
http_downloader: Option<std::rc::Rc<std::cell::RefCell<HttpDownloader>>>,
@@ -38,13 +39,13 @@ impl Bitbucket {
) -> anyhow::Result<Self> {
let process = process.unwrap_or_else(|| {
std::rc::Rc::new(std::cell::RefCell::new(ProcessExecutor::new(Some(
- io.clone_box(),
+ io.clone(),
))))
});
let http_downloader = match http_downloader {
Some(h) => h,
None => std::rc::Rc::new(std::cell::RefCell::new(Factory::create_http_downloader(
- &*io,
+ io.clone(),
&config,
IndexMap::new(),
)?)),
@@ -88,7 +89,7 @@ impl Bitbucket {
== 0
{
let output_str = output.as_string().unwrap_or("").trim().to_string();
- self.io.set_authentication(
+ self.io.borrow_mut().set_authentication(
origin_url.to_string(),
"x-token-auth".to_string(),
Some(output_str),
@@ -292,7 +293,7 @@ impl Bitbucket {
return Ok(false);
}
- self.io.set_authentication(
+ self.io.borrow_mut().set_authentication(
origin_url.to_string(),
consumer_key.clone(),
Some(consumer_secret.clone()),
@@ -338,7 +339,7 @@ impl Bitbucket {
.unwrap_or_default());
}
- self.io.set_authentication(
+ self.io.borrow_mut().set_authentication(
origin_url.to_string(),
consumer_key.to_string(),
Some(consumer_secret.to_string()),
diff --git a/crates/shirabe/src/util/config_validator.rs b/crates/shirabe/src/util/config_validator.rs
index ee78c26..47b4968 100644
--- a/crates/shirabe/src/util/config_validator.rs
+++ b/crates/shirabe/src/util/config_validator.rs
@@ -15,13 +15,13 @@ use shirabe_php_shim::PhpMixed;
#[derive(Debug)]
pub struct ConfigValidator {
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
}
impl ConfigValidator {
pub const CHECK_VERSION: i64 = 1;
- pub fn new(io: Box<dyn IOInterface>) -> Self {
+ pub fn new(io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>) -> Self {
Self { io }
}
@@ -39,7 +39,7 @@ impl ConfigValidator {
let mut lax_valid = false;
let mut manifest: Option<IndexMap<String, PhpMixed>> = None;
- // TODO(phase-b): io type mismatch (&dyn IOInterface vs Box<dyn IOInterface>)
+ // TODO(phase-b): io type mismatch (&dyn IOInterface vs std::rc::Rc<std::cell::RefCell<dyn IOInterface>>)
let mut json =
JsonFile::new(file.to_string(), None, None).expect("config file path is always local");
let schema_result: anyhow::Result<()> = (|| -> anyhow::Result<()> {
diff --git a/crates/shirabe/src/util/filesystem.rs b/crates/shirabe/src/util/filesystem.rs
index 73f21d6..ef3d307 100644
--- a/crates/shirabe/src/util/filesystem.rs
+++ b/crates/shirabe/src/util/filesystem.rs
@@ -819,7 +819,7 @@ impl Filesystem {
pub(crate) fn get_process(&mut self) -> std::cell::RefMut<'_, ProcessExecutor> {
if self.process_executor.is_none() {
self.process_executor = Some(std::rc::Rc::new(std::cell::RefCell::new(
- ProcessExecutor::new(()),
+ ProcessExecutor::new(None),
)));
}
diff --git a/crates/shirabe/src/util/forgejo.rs b/crates/shirabe/src/util/forgejo.rs
index 0e1d52d..4db5815 100644
--- a/crates/shirabe/src/util/forgejo.rs
+++ b/crates/shirabe/src/util/forgejo.rs
@@ -3,19 +3,20 @@
use crate::config::Config;
use crate::downloader::TransportException;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::io::io_interface;
use crate::util::HttpDownloader;
#[derive(Debug)]
pub struct Forgejo {
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: std::rc::Rc<std::cell::RefCell<Config>>,
http_downloader: std::rc::Rc<std::cell::RefCell<HttpDownloader>>,
}
impl Forgejo {
pub fn new(
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: std::rc::Rc<std::cell::RefCell<Config>>,
http_downloader: std::rc::Rc<std::cell::RefCell<HttpDownloader>>,
) -> Self {
@@ -107,7 +108,7 @@ impl Forgejo {
return Ok(Ok(false));
}
- self.io.set_authentication(
+ self.io.borrow_mut().set_authentication(
origin_url.to_string(),
username.clone(),
Some(token.clone()),
diff --git a/crates/shirabe/src/util/git.rs b/crates/shirabe/src/util/git.rs
index f1b71f9..3be37f6 100644
--- a/crates/shirabe/src/util/git.rs
+++ b/crates/shirabe/src/util/git.rs
@@ -15,6 +15,7 @@ use shirabe_php_shim::{
use crate::config::Config;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::util::Bitbucket;
use crate::util::Filesystem;
use crate::util::GitHub;
@@ -27,7 +28,7 @@ use crate::util::{AuthHelper, StoreAuth};
#[derive(Debug)]
pub struct Git {
- pub(crate) io: Box<dyn IOInterface>,
+ pub(crate) io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
pub(crate) config: std::rc::Rc<std::cell::RefCell<Config>>,
pub(crate) process: std::rc::Rc<std::cell::RefCell<ProcessExecutor>>,
pub(crate) filesystem: std::rc::Rc<std::cell::RefCell<Filesystem>>,
@@ -39,7 +40,7 @@ static VERSION: Mutex<Option<Option<String>>> = Mutex::new(None);
impl Git {
pub fn new(
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: std::rc::Rc<std::cell::RefCell<Config>>,
process: std::rc::Rc<std::cell::RefCell<ProcessExecutor>>,
fs: std::rc::Rc<std::cell::RefCell<Filesystem>>,
@@ -57,7 +58,7 @@ impl Git {
pub fn check_for_repo_ownership_error(
output: &str,
path: &str,
- io: Option<&dyn IOInterface>,
+ io: Option<std::rc::Rc<std::cell::RefCell<dyn IOInterface>>>,
) -> Result<()> {
if str_contains(output, "fatal: detected dubious ownership") {
let msg = format!(
@@ -147,11 +148,9 @@ impl Git {
let mut last_command: PhpMixed = PhpMixed::String(String::new());
// Ensure we are allowed to use this URL by config
- self.config.borrow_mut().prohibit_url_by_config(
- url,
- Some(self.io.as_ref()),
- &IndexMap::new(),
- )?;
+ self.config
+ .borrow_mut()
+ .prohibit_url_by_config(url, Some(&*self.io.borrow()), &IndexMap::new())?;
let orig_cwd: Option<String> = if initial_clone {
cwd.map(|s| s.to_string())
@@ -238,7 +237,7 @@ impl Git {
{
let m3 = m.get(&CaptureKey::ByIndex(3)).cloned().unwrap_or_default();
if !self.io.has_authentication(&m3) {
- self.io.set_authentication(
+ self.io.borrow_mut().set_authentication(
m3.clone(),
rawurldecode(&m.get(&CaptureKey::ByIndex(1)).cloned().unwrap_or_default()),
Some(rawurldecode(
@@ -386,7 +385,7 @@ impl Git {
let m2 = m.get(&CaptureKey::ByIndex(2)).cloned().unwrap_or_default();
if !self.io.has_authentication(&m1) {
let mut git_hub_util = GitHub::new(
- self.io.clone_box(),
+ self.io.clone(),
self.config.clone(),
Some(self.process.clone()),
self.http_downloader.clone(),
@@ -448,7 +447,7 @@ impl Git {
} {
// bitbucket either through oauth or app password, with fallback to ssh.
let mut bitbucket_util = Bitbucket::new(
- self.io.clone_box(),
+ self.io.clone(),
self.config.clone(),
Some(self.process.clone()),
self.http_downloader.clone(),
@@ -467,7 +466,7 @@ impl Git {
if !bitbucket_util.authorize_oauth(&domain) && self.io.is_interactive() {
bitbucket_util.authorize_oauth_interactively(&domain, Some(message));
let access_token = bitbucket_util.get_token();
- self.io.set_authentication(
+ self.io.borrow_mut().set_authentication(
domain.clone(),
"x-token-auth".to_string(),
Some(access_token),
@@ -521,7 +520,7 @@ impl Git {
let access_token =
bitbucket_util.request_token(&domain, &username, &password)?;
if !access_token.is_empty() {
- self.io.set_authentication(
+ self.io.borrow_mut().set_authentication(
domain.clone(),
"x-token-auth".to_string(),
Some(access_token),
@@ -613,7 +612,7 @@ impl Git {
if !self.io.has_authentication(&m2) {
let mut git_lab_util = GitLab::new(
- self.io.clone_box(),
+ self.io.clone(),
self.config.clone(),
Some(self.process.clone()),
self.http_downloader.clone(),
@@ -765,10 +764,12 @@ impl Git {
command_output.as_deref_mut(),
) == 0
{
- self.io
- .set_authentication(m2.clone(), username, Some(password));
- let mut auth_helper =
- AuthHelper::new(self.io.clone_box(), self.config.clone());
+ self.io.borrow_mut().set_authentication(
+ m2.clone(),
+ username,
+ Some(password),
+ );
+ let mut auth_helper = AuthHelper::new(self.io.clone(), self.config.clone());
let store_auth_enum = match &store_auth {
PhpMixed::String(s) if s == "prompt" => StoreAuth::Prompt,
PhpMixed::Bool(b) => StoreAuth::Bool(*b),
diff --git a/crates/shirabe/src/util/github.rs b/crates/shirabe/src/util/github.rs
index f8a592e..c87a83f 100644
--- a/crates/shirabe/src/util/github.rs
+++ b/crates/shirabe/src/util/github.rs
@@ -9,12 +9,13 @@ use crate::config::Config;
use crate::downloader::TransportException;
use crate::factory::Factory;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::util::HttpDownloader;
use crate::util::ProcessExecutor;
#[derive(Debug)]
pub struct GitHub {
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: std::rc::Rc<std::cell::RefCell<Config>>,
process: std::rc::Rc<std::cell::RefCell<ProcessExecutor>>,
http_downloader: std::rc::Rc<std::cell::RefCell<HttpDownloader>>,
@@ -25,18 +26,20 @@ impl GitHub {
r"{^([a-f0-9]{12,}|gh[a-z]_[a-zA-Z0-9_]+|github_pat_[a-zA-Z0-9_]+)$}";
pub fn new(
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: std::rc::Rc<std::cell::RefCell<Config>>,
process: Option<std::rc::Rc<std::cell::RefCell<ProcessExecutor>>>,
http_downloader: Option<std::rc::Rc<std::cell::RefCell<HttpDownloader>>>,
) -> anyhow::Result<Self> {
let process = process.unwrap_or_else(|| {
- std::rc::Rc::new(std::cell::RefCell::new(ProcessExecutor::new(&*io)))
+ std::rc::Rc::new(std::cell::RefCell::new(ProcessExecutor::new(Some(
+ io.clone(),
+ ))))
});
let http_downloader = match http_downloader {
Some(h) => h,
None => std::rc::Rc::new(std::cell::RefCell::new(Factory::create_http_downloader(
- &*io,
+ io.clone(),
&config,
IndexMap::new(),
)?)),
@@ -71,7 +74,7 @@ impl GitHub {
(),
) == 0
{
- self.io.set_authentication(
+ self.io.borrow_mut().set_authentication(
origin_url.to_string(),
output.trim().to_string(),
Some("x-oauth-basic".to_string()),
@@ -216,7 +219,7 @@ impl GitHub {
return Ok(false);
}
- self.io.set_authentication(
+ self.io.borrow_mut().set_authentication(
origin_url.to_string(),
token.clone(),
Some("x-oauth-basic".to_string()),
diff --git a/crates/shirabe/src/util/gitlab.rs b/crates/shirabe/src/util/gitlab.rs
index 88563db..d42f1cf 100644
--- a/crates/shirabe/src/util/gitlab.rs
+++ b/crates/shirabe/src/util/gitlab.rs
@@ -9,12 +9,13 @@ use crate::config::Config;
use crate::downloader::TransportException;
use crate::factory::Factory;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::util::HttpDownloader;
use crate::util::ProcessExecutor;
#[derive(Debug)]
pub struct GitLab {
- pub(crate) io: Box<dyn IOInterface>,
+ pub(crate) io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
pub(crate) config: std::rc::Rc<std::cell::RefCell<Config>>,
pub(crate) process: std::rc::Rc<std::cell::RefCell<ProcessExecutor>>,
pub(crate) http_downloader: std::rc::Rc<std::cell::RefCell<HttpDownloader>>,
@@ -22,18 +23,20 @@ pub struct GitLab {
impl GitLab {
pub fn new(
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: std::rc::Rc<std::cell::RefCell<Config>>,
process: Option<std::rc::Rc<std::cell::RefCell<ProcessExecutor>>>,
http_downloader: Option<std::rc::Rc<std::cell::RefCell<HttpDownloader>>>,
) -> anyhow::Result<Self> {
let process = process.unwrap_or_else(|| {
- std::rc::Rc::new(std::cell::RefCell::new(ProcessExecutor::new(&*io)))
+ std::rc::Rc::new(std::cell::RefCell::new(ProcessExecutor::new(Some(
+ io.clone(),
+ ))))
});
let http_downloader = match http_downloader {
Some(h) => h,
None => std::rc::Rc::new(std::cell::RefCell::new(Factory::create_http_downloader(
- &*io,
+ io.clone(),
&config,
IndexMap::new(),
)?)),
@@ -76,7 +79,7 @@ impl GitLab {
(),
) == 0
{
- self.io.set_authentication(
+ self.io.borrow_mut().set_authentication(
origin_url.to_string(),
output.trim().to_string(),
Some("oauth2".to_string()),
@@ -106,7 +109,7 @@ impl GitLab {
(),
) == 0
{
- self.io.set_authentication(
+ self.io.borrow_mut().set_authentication(
origin_url.to_string(),
token_user.trim().to_string(),
Some(token_password.trim().to_string()),
@@ -154,11 +157,17 @@ impl GitLab {
// 'gitlab-ci-token' to be stored as password. Detect cases where this is reversed
// and automatically resolve it.
if ["private-token", "gitlab-ci-token", "oauth2"].contains(&username.as_str()) {
- self.io
- .set_authentication(origin_url.to_string(), password, Some(username));
+ self.io.borrow_mut().set_authentication(
+ origin_url.to_string(),
+ password,
+ Some(username),
+ );
} else {
- self.io
- .set_authentication(origin_url.to_string(), username, Some(password));
+ self.io.borrow_mut().set_authentication(
+ origin_url.to_string(),
+ username,
+ Some(password),
+ );
}
return true;
@@ -311,7 +320,7 @@ impl GitLab {
.unwrap_or("")
.to_string();
- self.io.set_authentication(
+ self.io.borrow_mut().set_authentication(
origin_url.to_string(),
access_token.clone(),
Some("oauth2".to_string()),
@@ -391,7 +400,7 @@ impl GitLab {
.unwrap_or("")
.to_string();
- self.io.set_authentication(
+ self.io.borrow_mut().set_authentication(
origin_url.to_string(),
access_token.clone(),
Some("oauth2".to_string()),
diff --git a/crates/shirabe/src/util/hg.rs b/crates/shirabe/src/util/hg.rs
index b6bdd04..47e80e2 100644
--- a/crates/shirabe/src/util/hg.rs
+++ b/crates/shirabe/src/util/hg.rs
@@ -2,6 +2,7 @@
use crate::config::Config;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::util::ProcessExecutor;
use crate::util::Url;
use anyhow::Result;
@@ -13,14 +14,14 @@ static VERSION: OnceLock<Option<String>> = OnceLock::new();
#[derive(Debug)]
pub struct Hg {
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: std::rc::Rc<std::cell::RefCell<Config>>,
process: std::rc::Rc<std::cell::RefCell<ProcessExecutor>>,
}
impl Hg {
pub fn new(
- io: &dyn IOInterface,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: &Config,
process: &std::rc::Rc<std::cell::RefCell<ProcessExecutor>>,
) -> Self {
@@ -35,7 +36,7 @@ impl Hg {
) -> Result<()> {
self.config.borrow_mut().prohibit_url_by_config(
&url,
- Some(&*self.io),
+ Some(&*self.io.borrow()),
&indexmap::IndexMap::new(),
)?;
diff --git a/crates/shirabe/src/util/http/curl_downloader.rs b/crates/shirabe/src/util/http/curl_downloader.rs
index c3a1227..87ea8ef 100644
--- a/crates/shirabe/src/util/http/curl_downloader.rs
+++ b/crates/shirabe/src/util/http/curl_downloader.rs
@@ -29,6 +29,7 @@ use crate::config::Config;
use crate::downloader::MaxFileSizeExceededException;
use crate::downloader::TransportException;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::util::HttpDownloader;
use crate::util::Platform;
use crate::util::StreamContextFactory;
@@ -48,7 +49,7 @@ pub struct CurlDownloader {
/// @var Job[]
jobs: IndexMap<i64, IndexMap<String, PhpMixed>>,
/// @var IOInterface
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
/// @var Config
config: std::rc::Rc<std::cell::RefCell<Config>>,
/// @var AuthHelper
@@ -122,7 +123,7 @@ static TIMEOUT_WARNING: AtomicBool = AtomicBool::new(false);
impl CurlDownloader {
/// @param mixed[] $options
pub fn new(
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: std::rc::Rc<std::cell::RefCell<Config>>,
_options: IndexMap<String, PhpMixed>,
_disable_tls: bool,
@@ -340,7 +341,7 @@ impl CurlDownloader {
{
self.config
.borrow_mut()
- .prohibit_url_by_config(url, Some(&*self.io), &options)?;
+ .prohibit_url_by_config(url, Some(&*self.io.borrow()), &options)?;
}
let curl_handle = curl_init();
@@ -1184,7 +1185,7 @@ impl CurlDownloader {
== Some("application/json")
{
HttpDownloader::output_warnings(
- &*self.io,
+ &*self.io.borrow(),
job.get("origin").and_then(|v| v.as_string()).unwrap_or(""),
&match json_decode(response_ref.inner.get_body().unwrap_or(""), true)? {
PhpMixed::Array(a) => a.into_iter().map(|(k, v)| (k, *v)).collect(),
diff --git a/crates/shirabe/src/util/http_downloader.rs b/crates/shirabe/src/util/http_downloader.rs
index 77d35b1..610bd3a 100644
--- a/crates/shirabe/src/util/http_downloader.rs
+++ b/crates/shirabe/src/util/http_downloader.rs
@@ -32,7 +32,7 @@ use crate::util::http::Response;
#[derive(Debug)]
pub struct HttpDownloader {
/// @var IOInterface
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
/// @var Config
config: std::rc::Rc<std::cell::RefCell<Config>>,
/// @var array<Job>
@@ -103,7 +103,7 @@ impl HttpDownloader {
/// @param Config $config The config
/// @param mixed[] $options The options
pub fn new(
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: std::rc::Rc<std::cell::RefCell<Config>>,
options: IndexMap<String, PhpMixed>,
disable_tls: bool,
@@ -115,8 +115,7 @@ impl HttpDownloader {
// The cafile option can be set via config.json
let mut self_options: IndexMap<String, PhpMixed> = IndexMap::new();
if disable_tls == false {
- self_options =
- StreamContextFactory::get_tls_defaults(&options, Some(&*io)).unwrap_or_default();
+ self_options = StreamContextFactory::get_tls_defaults(&options, ()).unwrap_or_default();
}
// handle the other externally set options normally.
@@ -124,7 +123,7 @@ impl HttpDownloader {
let curl = if Self::is_curl_enabled() {
Some(CurlDownloader::new(
- io.clone_box(),
+ io.clone(),
config.clone(),
options.clone(),
disable_tls,
@@ -134,7 +133,7 @@ impl HttpDownloader {
};
let rfs = Some(RemoteFilesystem::new(
- io.clone_box(),
+ io.clone(),
config.clone(),
options.clone(),
disable_tls,
@@ -317,7 +316,7 @@ impl HttpDownloader {
)
.unwrap_or(false)
{
- self.io.set_authentication(
+ self.io.borrow_mut().set_authentication(
origin.clone(),
rawurldecode(
m.get(&CaptureKey::ByIndex(1))
diff --git a/crates/shirabe/src/util/perforce.rs b/crates/shirabe/src/util/perforce.rs
index 10c426f..cd384fc 100644
--- a/crates/shirabe/src/util/perforce.rs
+++ b/crates/shirabe/src/util/perforce.rs
@@ -12,6 +12,7 @@ use shirabe_php_shim::{
};
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::util::Filesystem;
use crate::util::Platform;
use crate::util::ProcessExecutor;
@@ -33,7 +34,7 @@ pub struct Perforce {
pub(crate) unique_perforce_client_name: String,
pub(crate) windows_flag: bool,
pub(crate) command_result: String,
- pub(crate) io: Box<dyn IOInterface>,
+ pub(crate) io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
pub(crate) filesystem: Option<std::rc::Rc<std::cell::RefCell<Filesystem>>>,
}
@@ -45,7 +46,7 @@ impl Perforce {
path: String,
process: std::rc::Rc<std::cell::RefCell<ProcessExecutor>>,
is_windows: bool,
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
) -> Self {
let mut this = Self {
path: String::new(),
@@ -76,7 +77,7 @@ impl Perforce {
port: String,
path: String,
process: std::rc::Rc<std::cell::RefCell<ProcessExecutor>>,
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
) -> Self {
Self::new(repo_config, port, path, process, Platform::is_windows(), io)
}
diff --git a/crates/shirabe/src/util/process_executor.rs b/crates/shirabe/src/util/process_executor.rs
index 74fc30c..36025ea 100644
--- a/crates/shirabe/src/util/process_executor.rs
+++ b/crates/shirabe/src/util/process_executor.rs
@@ -19,6 +19,7 @@ use shirabe_php_shim::{
};
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::util::GitHub;
use crate::util::Platform;
@@ -34,7 +35,7 @@ pub struct ProcessExecutor {
/// @var string
pub(crate) error_output: String,
/// @var ?IOInterface
- pub(crate) io: Option<Box<dyn IOInterface>>,
+ pub(crate) io: Option<std::rc::Rc<std::cell::RefCell<dyn IOInterface>>>,
/// @phpstan-var array<int, array<string, mixed>>
jobs: IndexMap<i64, Job>,
/// @var int
@@ -87,11 +88,11 @@ impl ProcessExecutor {
const GIT_CMDS_NEED_GIT_DIR: &'static [&'static [&'static str]] =
&[&["show"], &["log"], &["branch"], &["remote", "set-url"]];
- pub fn new<I: IntoProcessExecutorIo>(io: I) -> Self {
+ pub fn new(io: Option<std::rc::Rc<std::cell::RefCell<dyn IOInterface>>>) -> Self {
let mut this = Self {
capture_output: false,
error_output: String::new(),
- io: io.into_process_executor_io(),
+ io,
jobs: IndexMap::new(),
running_jobs: 0,
max_jobs: 10,
@@ -270,7 +271,7 @@ impl ProcessExecutor {
})
};
- let io_for_signal = self.io.as_ref().map(|b| &**b as *const dyn IOInterface);
+ let io_for_signal = self.io.clone();
let signal_handler = SignalHandler::create(
vec![
SignalHandler::SIGINT.to_string(),
@@ -278,8 +279,7 @@ impl ProcessExecutor {
SignalHandler::SIGHUP.to_string(),
],
Box::new(move |signal: String, _h: &SignalHandler| {
- if let Some(io_ptr) = io_for_signal {
- let io = unsafe { &*io_ptr };
+ if let Some(io) = &io_for_signal {
io.write_error(&format!(
"Received {}, aborting when child process is done",
signal
@@ -1085,45 +1085,6 @@ impl ToTimeoutSeconds for PhpMixed {
}
}
-/// Phase B helper: accept various IO forms for `ProcessExecutor::new`.
-/// Note: clones the IO via `clone_box` for borrow forms; this is incidental
-/// to Phase B — PHP class semantics should use Rc, but that requires broader
-/// refactor. TODO(phase-b): switch to shared ownership when call sites are
-/// stabilized.
-pub trait IntoProcessExecutorIo {
- fn into_process_executor_io(self) -> Option<Box<dyn IOInterface>>;
-}
-
-impl IntoProcessExecutorIo for Option<Box<dyn IOInterface>> {
- fn into_process_executor_io(self) -> Option<Box<dyn IOInterface>> {
- self
- }
-}
-
-impl IntoProcessExecutorIo for Box<dyn IOInterface> {
- fn into_process_executor_io(self) -> Option<Box<dyn IOInterface>> {
- Some(self)
- }
-}
-
-impl IntoProcessExecutorIo for () {
- fn into_process_executor_io(self) -> Option<Box<dyn IOInterface>> {
- None
- }
-}
-
-impl IntoProcessExecutorIo for &dyn IOInterface {
- fn into_process_executor_io(self) -> Option<Box<dyn IOInterface>> {
- Some(self.clone_box())
- }
-}
-
-impl IntoProcessExecutorIo for &mut dyn IOInterface {
- fn into_process_executor_io(self) -> Option<Box<dyn IOInterface>> {
- Some(self.clone_box())
- }
-}
-
// Suppress unused-import warnings.
#[allow(dead_code)]
const _USE_PARITY: () = {
diff --git a/crates/shirabe/src/util/remote_filesystem.rs b/crates/shirabe/src/util/remote_filesystem.rs
index 2e77fe8..8d50fa4 100644
--- a/crates/shirabe/src/util/remote_filesystem.rs
+++ b/crates/shirabe/src/util/remote_filesystem.rs
@@ -16,6 +16,7 @@ use crate::config::Config;
use crate::downloader::MaxFileSizeExceededException;
use crate::downloader::TransportException;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::util::AuthHelper;
use crate::util::HttpDownloader;
use crate::util::Platform;
@@ -34,7 +35,7 @@ pub enum GetResult {
#[derive(Debug)]
pub struct RemoteFilesystem {
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: std::rc::Rc<std::cell::RefCell<Config>>,
scheme: String,
bytes_max: i64,
@@ -56,7 +57,7 @@ pub struct RemoteFilesystem {
impl RemoteFilesystem {
pub fn new(
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: std::rc::Rc<std::cell::RefCell<Config>>,
options: IndexMap<String, PhpMixed>,
disable_tls: bool,
@@ -64,8 +65,7 @@ impl RemoteFilesystem {
) -> Self {
let (computed_options, disable_tls_set) = if !disable_tls {
(
- // TODO(phase-b): logger is None placeholder; should pass `&*io` if a Logger view is available.
- StreamContextFactory::get_tls_defaults(&options, None)
+ StreamContextFactory::get_tls_defaults(&options, ())
.unwrap_or_else(|_| IndexMap::new()),
false,
)
@@ -75,7 +75,7 @@ impl RemoteFilesystem {
let merged = array_replace_recursive(computed_options, options);
let auth_helper =
- auth_helper.unwrap_or_else(|| AuthHelper::new(io.clone_box(), config.clone()));
+ auth_helper.unwrap_or_else(|| AuthHelper::new(io.clone(), config.clone()));
Self {
io,
config,
@@ -292,7 +292,7 @@ impl RemoteFilesystem {
{
let _ = self.config.borrow_mut().prohibit_url_by_config(
&file_url,
- Some(&*self.io),
+ Some(&*self.io.borrow()),
&indexmap::IndexMap::new(),
);
}
@@ -337,7 +337,7 @@ impl RemoteFilesystem {
PhpMixed::Array(m) => m.into_iter().map(|(k, v)| (k, *v)).collect(),
_ => IndexMap::new(),
};
- let _ = HttpDownloader::output_warnings(&*self.io, origin_url, &parsed_map);
+ let _ = HttpDownloader::output_warnings(&*self.io.borrow(), origin_url, &parsed_map);
}
if [401_i64, 403].contains(&code) && retry_auth_failure {
diff --git a/crates/shirabe/src/util/stream_context_factory.rs b/crates/shirabe/src/util/stream_context_factory.rs
index 48949c8..488d807 100644
--- a/crates/shirabe/src/util/stream_context_factory.rs
+++ b/crates/shirabe/src/util/stream_context_factory.rs
@@ -2,7 +2,6 @@
use indexmap::IndexMap;
use shirabe_external_packages::composer::ca_bundle::CaBundle;
-use shirabe_external_packages::psr::log::LoggerInterface;
use shirabe_php_shim::{
HHVM_VERSION, PHP_MAJOR_VERSION, PHP_MINOR_VERSION, PHP_RELEASE_VERSION, PhpMixed,
RuntimeException, array_replace_recursive, curl_version, extension_loaded, function_exists,
@@ -239,7 +238,9 @@ impl StreamContextFactory {
pub fn get_tls_defaults(
options: &IndexMap<String, PhpMixed>,
- logger: Option<&dyn LoggerInterface>,
+ // `logger` was a PSR LoggerInterface; CaBundle is slated for removal so
+ // it is now an unused `()` placeholder.
+ logger: (),
) -> anyhow::Result<IndexMap<String, PhpMixed>, TransportException> {
let ciphers = [
"ECDHE-RSA-AES128-GCM-SHA256",
diff --git a/crates/shirabe/src/util/svn.rs b/crates/shirabe/src/util/svn.rs
index aa81f0f..737e75d 100644
--- a/crates/shirabe/src/util/svn.rs
+++ b/crates/shirabe/src/util/svn.rs
@@ -13,6 +13,7 @@ use shirabe_php_shim::{
use crate::config::Config;
use crate::io::IOInterface;
+use crate::io::IOInterfaceImmutable;
use crate::util::Platform;
use crate::util::ProcessExecutor;
@@ -29,7 +30,7 @@ pub struct Svn {
/// @var bool
pub(crate) has_auth: Option<bool>,
/// @var IOInterface
- pub(crate) io: Box<dyn IOInterface>,
+ pub(crate) io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
/// @var string
pub(crate) url: String,
/// @var bool
@@ -50,12 +51,14 @@ impl Svn {
pub fn new(
url: String,
- io: Box<dyn IOInterface>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
config: std::rc::Rc<std::cell::RefCell<Config>>,
process: Option<std::rc::Rc<std::cell::RefCell<ProcessExecutor>>>,
) -> Self {
let process = process.unwrap_or_else(|| {
- std::rc::Rc::new(std::cell::RefCell::new(ProcessExecutor::new(&*io)))
+ std::rc::Rc::new(std::cell::RefCell::new(ProcessExecutor::new(Some(
+ io.clone(),
+ ))))
});
Self {
url,
@@ -95,7 +98,7 @@ impl Svn {
// Ensure we are allowed to use this URL by config
self.config.borrow_mut().prohibit_url_by_config(
url,
- Some(&*self.io),
+ Some(&*self.io.borrow()),
&indexmap::IndexMap::new(),
)?;