aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/src/util
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/util
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/util')
-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
16 files changed, 115 insertions, 129 deletions
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(),
)?;