diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-05-26 20:04:02 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-05-26 20:04:02 +0900 |
| commit | f411daceacad66e0bd774fda7d3c5ef8533cc55c (patch) | |
| tree | eefb065e4d676a3f7031ca49bab21c773b00b134 /crates/shirabe/src/util | |
| parent | 1921f173ea219cb4b25847294d2d3fa465550fbb (diff) | |
| download | php-shirabe-f411daceacad66e0bd774fda7d3c5ef8533cc55c.tar.gz php-shirabe-f411daceacad66e0bd774fda7d3c5ef8533cc55c.tar.zst php-shirabe-f411daceacad66e0bd774fda7d3c5ef8533cc55c.zip | |
refactor(io): share IOInterface via Rc<RefCell<dyn _>> handle
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe/src/util')
| -rw-r--r-- | crates/shirabe/src/util/auth_helper.rs | 12 | ||||
| -rw-r--r-- | crates/shirabe/src/util/bitbucket.rs | 15 | ||||
| -rw-r--r-- | crates/shirabe/src/util/config_validator.rs | 6 | ||||
| -rw-r--r-- | crates/shirabe/src/util/filesystem.rs | 2 | ||||
| -rw-r--r-- | crates/shirabe/src/util/forgejo.rs | 7 | ||||
| -rw-r--r-- | crates/shirabe/src/util/git.rs | 37 | ||||
| -rw-r--r-- | crates/shirabe/src/util/github.rs | 15 | ||||
| -rw-r--r-- | crates/shirabe/src/util/gitlab.rs | 33 | ||||
| -rw-r--r-- | crates/shirabe/src/util/hg.rs | 7 | ||||
| -rw-r--r-- | crates/shirabe/src/util/http/curl_downloader.rs | 9 | ||||
| -rw-r--r-- | crates/shirabe/src/util/http_downloader.rs | 13 | ||||
| -rw-r--r-- | crates/shirabe/src/util/perforce.rs | 7 | ||||
| -rw-r--r-- | crates/shirabe/src/util/process_executor.rs | 51 | ||||
| -rw-r--r-- | crates/shirabe/src/util/remote_filesystem.rs | 14 | ||||
| -rw-r--r-- | crates/shirabe/src/util/stream_context_factory.rs | 5 | ||||
| -rw-r--r-- | crates/shirabe/src/util/svn.rs | 11 |
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(), )?; |
