aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/src/downloader
diff options
context:
space:
mode:
Diffstat (limited to 'crates/shirabe/src/downloader')
-rw-r--r--crates/shirabe/src/downloader/archive_downloader.rs26
-rw-r--r--crates/shirabe/src/downloader/download_manager.rs36
-rw-r--r--crates/shirabe/src/downloader/downloader_interface.rs30
-rw-r--r--crates/shirabe/src/downloader/file_downloader.rs87
-rw-r--r--crates/shirabe/src/downloader/fossil_downloader.rs28
-rw-r--r--crates/shirabe/src/downloader/git_downloader.rs348
-rw-r--r--crates/shirabe/src/downloader/gzip_downloader.rs12
-rw-r--r--crates/shirabe/src/downloader/hg_downloader.rs30
-rw-r--r--crates/shirabe/src/downloader/path_downloader.rs103
-rw-r--r--crates/shirabe/src/downloader/perforce_downloader.rs2
-rw-r--r--crates/shirabe/src/downloader/phar_downloader.rs8
-rw-r--r--crates/shirabe/src/downloader/rar_downloader.rs12
-rw-r--r--crates/shirabe/src/downloader/svn_downloader.rs96
-rw-r--r--crates/shirabe/src/downloader/tar_downloader.rs8
-rw-r--r--crates/shirabe/src/downloader/transport_exception.rs6
-rw-r--r--crates/shirabe/src/downloader/vcs_downloader.rs97
-rw-r--r--crates/shirabe/src/downloader/xz_downloader.rs12
-rw-r--r--crates/shirabe/src/downloader/zip_downloader.rs24
18 files changed, 564 insertions, 401 deletions
diff --git a/crates/shirabe/src/downloader/archive_downloader.rs b/crates/shirabe/src/downloader/archive_downloader.rs
index 02cd8a9..937add0 100644
--- a/crates/shirabe/src/downloader/archive_downloader.rs
+++ b/crates/shirabe/src/downloader/archive_downloader.rs
@@ -69,7 +69,7 @@ pub trait ArchiveDownloader {
));
}
- let vendor_dir = self.inner().config.get("vendor-dir");
+ let vendor_dir = self.inner().config.borrow_mut().get("vendor-dir");
// clean up the target directory, unless it contains the vendor dir, as the vendor dir contains
// the archive to be extracted. This is the case when installing with create-project in the current directory
@@ -77,15 +77,20 @@ pub trait ArchiveDownloader {
if !self
.inner()
.filesystem
+ .borrow()
.normalize_path(&vendor_dir)
.contains(
&self
.inner()
.filesystem
+ .borrow()
.normalize_path(&format!("{}{}", path, DIRECTORY_SEPARATOR)),
)
{
- self.inner_mut().filesystem.empty_directory(path);
+ self.inner_mut()
+ .filesystem
+ .borrow_mut()
+ .empty_directory(path);
}
let temporary_dir;
@@ -105,6 +110,7 @@ pub trait ArchiveDownloader {
self.inner_mut()
.filesystem
+ .borrow_mut()
.ensure_directory_exists(&temporary_dir);
let file_name = self.inner().get_file_name(package, path);
@@ -115,9 +121,9 @@ pub trait ArchiveDownloader {
self.inner_mut().clear_last_cache_write(package);
// clean up
- filesystem.remove_directory(&temporary_dir);
+ filesystem.borrow_mut().remove_directory(&temporary_dir);
if is_dir(path) && realpath(path) != Platform::get_cwd(false).unwrap_or_default() {
- filesystem.remove_directory(path);
+ filesystem.borrow_mut().remove_directory(path);
}
self.inner_mut()
.remove_cleanup_path(package, &temporary_dir);
@@ -138,7 +144,7 @@ pub trait ArchiveDownloader {
Ok(promise.then(
Box::new(move || -> Result<Box<dyn PromiseInterface>> {
if file_exists(&file_name) {
- filesystem.unlink(&file_name);
+ filesystem.borrow_mut().unlink(&file_name);
}
let get_folder_content = |dir: &str| -> Vec<std::path::PathBuf> {
@@ -177,7 +183,7 @@ pub trait ArchiveDownloader {
&format!("{}/{}", to, file_basename),
)?;
} else {
- filesystem.rename(&file, &format!("{}/{}", to, file_basename));
+ filesystem.borrow_mut().rename(&file, &format!("{}/{}", to, file_basename));
}
}
@@ -187,8 +193,8 @@ pub trait ArchiveDownloader {
let mut rename_as_one = false;
if !file_exists(path) {
rename_as_one = true;
- } else if filesystem.is_dir_empty(path) {
- match filesystem.remove_directory_php(path) {
+ } else if filesystem.borrow().is_dir_empty(path) {
+ match filesystem.borrow_mut().remove_directory_php(path) {
Ok(true) => {
rename_as_one = true;
}
@@ -210,7 +216,7 @@ pub trait ArchiveDownloader {
} else {
temporary_dir.clone()
};
- filesystem.rename(&extracted_dir, path);
+ filesystem.borrow_mut().rename(&extracted_dir, path);
} else {
// only one dir in the archive, extract its contents out of it
let from = if single_dir_at_top_level {
@@ -222,7 +228,7 @@ pub trait ArchiveDownloader {
rename_recursively.as_ref().unwrap()(&from, path)?;
}
- let promise = filesystem.remove_directory_async(&temporary_dir);
+ let promise = filesystem.borrow_mut().remove_directory_async(&temporary_dir);
Ok(promise.then(
Box::new(move || -> Result<()> {
diff --git a/crates/shirabe/src/downloader/download_manager.rs b/crates/shirabe/src/downloader/download_manager.rs
index db3484e..ea2ee1e 100644
--- a/crates/shirabe/src/downloader/download_manager.rs
+++ b/crates/shirabe/src/downloader/download_manager.rs
@@ -29,7 +29,7 @@ pub struct DownloadManager {
/// @var array<string, string>
package_preferences: IndexMap<String, String>,
/// @var Filesystem
- filesystem: Filesystem,
+ filesystem: std::rc::Rc<std::cell::RefCell<Filesystem>>,
/// @var array<string, DownloaderInterface>
downloaders: IndexMap<String, Box<dyn DownloaderInterface>>,
}
@@ -43,9 +43,10 @@ impl DownloadManager {
pub fn new(
io: Box<dyn IOInterface>,
prefer_source: bool,
- filesystem: Option<Filesystem>,
+ filesystem: Option<std::rc::Rc<std::cell::RefCell<Filesystem>>>,
) -> Self {
- let filesystem = filesystem.unwrap_or_else(|| Filesystem::new(None));
+ let filesystem = filesystem
+ .unwrap_or_else(|| std::rc::Rc::new(std::cell::RefCell::new(Filesystem::new(None))));
Self {
io,
prefer_source,
@@ -202,6 +203,7 @@ impl DownloadManager {
) -> Result<Box<dyn PromiseInterface>> {
let target_dir = self.normalize_target_dir(target_dir);
self.filesystem
+ .borrow_mut()
.ensure_directory_exists(&dirname(&target_dir));
let mut sources = self.get_available_sources(package, prev_package)?;
@@ -217,11 +219,11 @@ impl DownloadManager {
}
};
if retry_state {
- self.io.write_error(
- PhpMixed::String(format!(
+ self.io.write_error3(
+ &format!(
" <warning>Now trying to download from {}</warning>",
source,
- )),
+ ),
true,
io_interface::NORMAL,
);
@@ -237,7 +239,7 @@ impl DownloadManager {
};
// TODO(phase-b): use anyhow::Result<Result<T, E>> to model PHP try/catch
- let result = match downloader.download(package, &target_dir, prev_package) {
+ let result = match downloader.download3(package, &target_dir, prev_package) {
Ok(r) => r,
Err(e) => {
// PHP closure handleError: rethrow if not RuntimeException or if IrrecoverableDownloadException
@@ -250,13 +252,13 @@ impl DownloadManager {
return Err(e);
}
- self.io.write_error(
- PhpMixed::String(format!(
+ self.io.write_error3(
+ &format!(
" <warning>Failed to download {} from {}: {}</warning>",
package.get_pretty_name(),
source,
e,
- )),
+ ),
true,
io_interface::NORMAL,
);
@@ -316,7 +318,7 @@ impl DownloadManager {
) -> Result<Box<dyn PromiseInterface>> {
let target_dir = self.normalize_target_dir(target_dir);
if let Some(downloader) = self.get_downloader_for_package(package)? {
- return downloader.install(package, &target_dir);
+ return downloader.install2(package, &target_dir);
}
Ok(shirabe_external_packages::react::promise::resolve(None))
@@ -347,7 +349,7 @@ impl DownloadManager {
// if we have a downloader present before, but not after, the package became a metapackage and its files should be removed
if downloader.is_none() {
- return initial_downloader.unwrap().remove(initial, &target_dir);
+ return initial_downloader.unwrap().remove2(initial, &target_dir);
}
let initial_type = self.get_downloader_type(initial_downloader.unwrap());
@@ -362,8 +364,8 @@ impl DownloadManager {
if !self.io.is_interactive() {
return Err(e);
}
- self.io.write_error(
- PhpMixed::String(format!("<error> Update failed ({})</error>", e,)),
+ self.io.write_error3(
+ &format!("<error> Update failed ({})</error>", e,),
true,
io_interface::NORMAL,
);
@@ -379,7 +381,7 @@ impl DownloadManager {
// if downloader type changed, or update failed and user asks for reinstall,
// we wipe the dir and do a new install instead of updating it
- let promise = initial_downloader.unwrap().remove(initial, &target_dir)?;
+ let promise = initial_downloader.unwrap().remove2(initial, &target_dir)?;
let target_dir_owned = target_dir.clone();
// TODO(phase-b): capture self and target into the closure
@@ -402,7 +404,7 @@ impl DownloadManager {
) -> Result<Box<dyn PromiseInterface>> {
let target_dir = self.normalize_target_dir(target_dir);
if let Some(downloader) = self.get_downloader_for_package(package)? {
- return downloader.remove(package, &target_dir);
+ return downloader.remove2(package, &target_dir);
}
Ok(shirabe_external_packages::react::promise::resolve(None))
@@ -442,7 +444,7 @@ impl DownloadManager {
"{{^{}$}}i",
str_replace("\\*", ".*", &preg_quote(pattern, None)),
);
- if Preg::is_match(&pattern_regex, package.get_name()) {
+ if Preg::is_match(&pattern_regex, package.get_name()).unwrap_or(false) {
if "dist" == preference || (!package.is_dev() && "auto" == preference) {
return "dist".to_string();
}
diff --git a/crates/shirabe/src/downloader/downloader_interface.rs b/crates/shirabe/src/downloader/downloader_interface.rs
index 6662799..b72d80e 100644
--- a/crates/shirabe/src/downloader/downloader_interface.rs
+++ b/crates/shirabe/src/downloader/downloader_interface.rs
@@ -4,7 +4,7 @@ use shirabe_external_packages::react::promise::promise_interface::PromiseInterfa
use crate::package::package_interface::PackageInterface;
-pub trait DownloaderInterface {
+pub trait DownloaderInterface: std::fmt::Debug {
fn get_installation_source(&self) -> String;
fn download(
@@ -15,6 +15,16 @@ pub trait DownloaderInterface {
output: bool,
) -> anyhow::Result<Box<dyn PromiseInterface>>;
+ /// Convenience for the PHP default `$output = true` overload.
+ fn download3(
+ &self,
+ package: &dyn PackageInterface,
+ path: &str,
+ prev_package: Option<&dyn PackageInterface>,
+ ) -> anyhow::Result<Box<dyn PromiseInterface>> {
+ self.download(package, path, prev_package, true)
+ }
+
fn prepare(
&self,
r#type: &str,
@@ -30,6 +40,15 @@ pub trait DownloaderInterface {
output: bool,
) -> anyhow::Result<Box<dyn PromiseInterface>>;
+ /// Convenience for the PHP default `$output = true` overload.
+ fn install2(
+ &self,
+ package: &dyn PackageInterface,
+ path: &str,
+ ) -> anyhow::Result<Box<dyn PromiseInterface>> {
+ self.install(package, path, true)
+ }
+
fn update(
&self,
initial: &dyn PackageInterface,
@@ -44,6 +63,15 @@ pub trait DownloaderInterface {
output: bool,
) -> anyhow::Result<Box<dyn PromiseInterface>>;
+ /// Convenience for the PHP default `$output = true` overload.
+ fn remove2(
+ &self,
+ package: &dyn PackageInterface,
+ path: &str,
+ ) -> anyhow::Result<Box<dyn PromiseInterface>> {
+ self.remove(package, path, true)
+ }
+
fn cleanup(
&self,
r#type: &str,
diff --git a/crates/shirabe/src/downloader/file_downloader.rs b/crates/shirabe/src/downloader/file_downloader.rs
index 85e43fc..c814baa 100644
--- a/crates/shirabe/src/downloader/file_downloader.rs
+++ b/crates/shirabe/src/downloader/file_downloader.rs
@@ -59,17 +59,17 @@ pub struct FileDownloader {
/// @var IOInterface
pub(crate) io: Box<dyn IOInterface>,
/// @var Config
- pub(crate) config: Config,
+ pub(crate) config: std::rc::Rc<std::cell::RefCell<Config>>,
/// @var HttpDownloader
- pub(crate) http_downloader: HttpDownloader,
+ pub(crate) http_downloader: std::rc::Rc<std::cell::RefCell<HttpDownloader>>,
/// @var Filesystem
- pub(crate) filesystem: Filesystem,
+ pub(crate) filesystem: std::rc::Rc<std::cell::RefCell<Filesystem>>,
/// @var ?Cache
pub(crate) cache: Option<Cache>,
/// @var ?EventDispatcher
pub(crate) event_dispatcher: Option<EventDispatcher>,
/// @var ProcessExecutor
- pub(crate) process: ProcessExecutor,
+ pub(crate) process: std::rc::Rc<std::cell::RefCell<ProcessExecutor>>,
/// @var array<string, string> Map of package name to cache key
last_cache_writes: IndexMap<String, String>,
/// @var array<string, string[]> Map of package name to list of paths
@@ -80,15 +80,23 @@ impl FileDownloader {
/// Constructor.
pub fn new(
io: Box<dyn IOInterface>,
- config: Config,
- http_downloader: HttpDownloader,
+ config: std::rc::Rc<std::cell::RefCell<Config>>,
+ http_downloader: std::rc::Rc<std::cell::RefCell<HttpDownloader>>,
event_dispatcher: Option<EventDispatcher>,
cache: Option<Cache>,
- filesystem: Option<Filesystem>,
- process: Option<ProcessExecutor>,
+ filesystem: Option<std::rc::Rc<std::cell::RefCell<Filesystem>>>,
+ process: Option<std::rc::Rc<std::cell::RefCell<ProcessExecutor>>>,
) -> Self {
- let process = process.unwrap_or_else(|| ProcessExecutor::new(Some(Box::new(&*io)), None));
- let filesystem = filesystem.unwrap_or_else(|| Filesystem::new(Some(process.clone())));
+ let process = process.unwrap_or_else(|| {
+ std::rc::Rc::new(std::cell::RefCell::new(ProcessExecutor::new(Some(
+ Box::new(&*io),
+ ))))
+ });
+ let filesystem = filesystem.unwrap_or_else(|| {
+ std::rc::Rc::new(std::cell::RefCell::new(Filesystem::new(Some(
+ std::rc::Rc::clone(&process),
+ ))))
+ });
let mut this = Self {
io,
@@ -106,8 +114,16 @@ impl FileDownloader {
// PHP: writeError('Running cache garbage collection', true, io_interface::VERY_VERBOSE)
this.io.write_error("Running cache garbage collection");
this.cache.as_mut().unwrap().gc(
- this.config.get("cache-files-ttl").as_int().unwrap_or(0),
- this.config.get("cache-files-maxsize").as_int().unwrap_or(0),
+ this.config
+ .borrow_mut()
+ .get("cache-files-ttl")
+ .as_int()
+ .unwrap_or(0),
+ this.config
+ .borrow_mut()
+ .get("cache-files-maxsize")
+ .as_int()
+ .unwrap_or(0),
);
}
@@ -168,9 +184,11 @@ impl DownloaderInterface for FileDownloader {
debug_assert!(urls.len() > 0);
let file_name = self.get_file_name(package, path);
- self.filesystem.ensure_directory_exists(path)?;
+ self.filesystem.borrow_mut().ensure_directory_exists(path)?;
let dir_of_file = shirabe_php_shim::dirname(&file_name, 1);
- self.filesystem.ensure_directory_exists(&dir_of_file)?;
+ self.filesystem
+ .borrow_mut()
+ .ensure_directory_exists(&dir_of_file)?;
// TODO(plugin): inline closures rely on captured $accept/$reject/$urls/$retries. In Rust
// we'd need a struct holding shared state — left as a phase-b refactor.
@@ -204,11 +222,12 @@ impl DownloaderInterface for FileDownloader {
) -> Result<Box<dyn PromiseInterface>> {
let file_name = self.get_file_name(package, path);
if file_exists(&file_name) {
- self.filesystem.unlink(&file_name)?;
+ self.filesystem.borrow_mut().unlink(&file_name)?;
}
let vendor_dir = self
.config
+ .borrow_mut()
.get("vendor-dir")
.as_string()
.unwrap_or("")
@@ -232,16 +251,16 @@ impl DownloaderInterface for FileDownloader {
.cloned()
{
for path_to_clean in &paths {
- self.filesystem.remove(path_to_clean)?;
+ self.filesystem.borrow_mut().remove(path_to_clean)?;
}
}
for dir in &dirs_to_clean_up {
if is_dir(dir)
- && self.filesystem.is_dir_empty(dir)?
+ && self.filesystem.borrow_mut().is_dir_empty(dir)?
&& realpath(dir).as_deref() != Some(&Platform::get_cwd(false).unwrap_or_default())
{
- self.filesystem.remove_directory_php(dir)?;
+ self.filesystem.borrow_mut().remove_directory_php(dir)?;
}
}
@@ -262,6 +281,7 @@ impl DownloaderInterface for FileDownloader {
let vendor_dir = self
.config
+ .borrow_mut()
.get("vendor-dir")
.as_string()
.unwrap_or("")
@@ -271,16 +291,17 @@ impl DownloaderInterface for FileDownloader {
// the file to be installed. This is the case when installing with create-project in the current directory
// but in that case we ensure the directory is empty already in ProjectInstaller so no need to empty it here.
if false == {
- let normalized_vendor = self.filesystem.normalize_path(&vendor_dir);
+ let normalized_vendor = self.filesystem.borrow_mut().normalize_path(&vendor_dir);
let normalized_path = self
.filesystem
+ .borrow()
.normalize_path(&format!("{}{}", path, DIRECTORY_SEPARATOR));
strpos(&normalized_vendor, &normalized_path).is_some()
} {
- self.filesystem.empty_directory(path, true)?;
+ self.filesystem.borrow_mut().empty_directory(path, true)?;
}
- self.filesystem.ensure_directory_exists(path)?;
- self.filesystem.rename(
+ self.filesystem.borrow_mut().ensure_directory_exists(path)?;
+ self.filesystem.borrow_mut().rename(
&self.get_file_name(package, path),
&format!(
"{}/{}",
@@ -338,7 +359,7 @@ impl DownloaderInterface for FileDownloader {
UninstallOperation::format(package, false)
));
}
- let _promise = self.filesystem.remove_directory_async(path)?;
+ let _promise = self.filesystem.borrow_mut().remove_directory_async(path)?;
// TODO(phase-b): chain `.then(|result| if !result { throw RuntimeException })`
let _ = path;
@@ -357,7 +378,7 @@ impl ChangeReportInterface for FileDownloader {
// TODO(phase-b): swap self.io to NullIO and restore — needs a take/swap helper
let mut null_io = NullIO::new();
- null_io.load_configuration(&self.config);
+ null_io.load_configuration(&mut *self.config.borrow_mut())?;
let mut e: Option<anyhow::Error> = None;
let mut output: String = String::new();
@@ -365,7 +386,8 @@ impl ChangeReportInterface for FileDownloader {
let result: Result<()> = (|| -> Result<()> {
if is_dir(&format!("{}_compare", target_dir)) {
self.filesystem
- .remove_directory(&format!("{}_compare", target_dir), false)?;
+ .borrow_mut()
+ .remove_directory(&format!("{}_compare", target_dir))?;
}
let promise =
@@ -377,7 +399,7 @@ impl ChangeReportInterface for FileDownloader {
PhpMixed::Null
})),
);
- self.http_downloader.wait()?;
+ self.http_downloader.borrow_mut().wait()?;
if e.is_some() {
return Err(e.unwrap());
}
@@ -389,7 +411,7 @@ impl ChangeReportInterface for FileDownloader {
PhpMixed::Null
})),
);
- self.process.wait()?;
+ self.process.borrow_mut().wait()?;
if e.is_some() {
return Err(e.unwrap());
}
@@ -400,6 +422,7 @@ impl ChangeReportInterface for FileDownloader {
comparer.do_compare();
output = comparer.get_changed_as_string(true, false);
self.filesystem
+ .borrow_mut()
.remove_directory(&format!("{}_compare", target_dir))?;
Ok(())
})();
@@ -491,7 +514,11 @@ impl FileDownloader {
rtrim(
&format!(
"{}/composer/tmp-{}.{}",
- self.config.get("vendor-dir").as_string().unwrap_or(""),
+ self.config
+ .borrow_mut()
+ .get("vendor-dir")
+ .as_string()
+ .unwrap_or(""),
hash(
"md5",
&format!("{}{}", package, spl_object_hash(&PhpMixed::Null))
@@ -525,10 +552,10 @@ impl FileDownloader {
let mut url = url.to_string();
if package.get_dist_reference().is_some() {
url = UrlUtil::update_dist_reference(
- &self.config,
+ &*self.config.borrow(),
&url,
package.get_dist_reference().unwrap(),
- )?;
+ );
}
Ok(url)
diff --git a/crates/shirabe/src/downloader/fossil_downloader.rs b/crates/shirabe/src/downloader/fossil_downloader.rs
index 5314e10..53b4315 100644
--- a/crates/shirabe/src/downloader/fossil_downloader.rs
+++ b/crates/shirabe/src/downloader/fossil_downloader.rs
@@ -29,9 +29,11 @@ impl FossilDownloader {
path: String,
url: String,
) -> Result<Box<dyn PromiseInterface>> {
- self.inner
- .config
- .prohibit_url_by_config(&url, &self.inner.io)?;
+ self.inner.config.borrow_mut().prohibit_url_by_config(
+ &url,
+ Some(&self.inner.io),
+ &indexmap::IndexMap::new(),
+ )?;
let repo_file = format!("{}.fossil", path);
let real_path = shirabe_php_shim::realpath(&path);
@@ -85,9 +87,11 @@ impl FossilDownloader {
path: String,
url: String,
) -> Result<Box<dyn PromiseInterface>> {
- self.inner
- .config
- .prohibit_url_by_config(&url, &self.inner.io)?;
+ self.inner.config.borrow_mut().prohibit_url_by_config(
+ &url,
+ Some(&self.inner.io),
+ &indexmap::IndexMap::new(),
+ )?;
self.inner.io.write_error(&format!(
" Updating to {}",
@@ -135,7 +139,7 @@ impl FossilDownloader {
}
let mut output = String::new();
- self.inner.process.execute(
+ self.inner.process.borrow_mut().execute_args(
&["fossil".to_string(), "changes".to_string()],
&mut output,
shirabe_php_shim::realpath(&path),
@@ -196,12 +200,18 @@ impl FossilDownloader {
cwd: Option<String>,
output: &mut String,
) -> Result<()> {
- if self.inner.process.execute(&command, output, cwd) != 0 {
+ if self
+ .inner
+ .process
+ .borrow_mut()
+ .execute(&command, output, cwd)
+ != 0
+ {
return Err(RuntimeException {
message: format!(
"Failed to execute {}\n\n{}",
command.join(" "),
- self.inner.process.get_error_output()
+ self.inner.process.borrow().get_error_output()
),
code: 0,
}
diff --git a/crates/shirabe/src/downloader/git_downloader.rs b/crates/shirabe/src/downloader/git_downloader.rs
index fb41b0c..d451727 100644
--- a/crates/shirabe/src/downloader/git_downloader.rs
+++ b/crates/shirabe/src/downloader/git_downloader.rs
@@ -3,7 +3,7 @@
use crate::io::io_interface;
use anyhow::Result;
use indexmap::IndexMap;
-use shirabe_external_packages::composer::pcre::preg::Preg;
+use shirabe_external_packages::composer::pcre::preg::{CaptureKey, Preg};
use shirabe_external_packages::react::promise;
use shirabe_external_packages::react::promise::promise_interface::PromiseInterface;
use shirabe_php_shim::{
@@ -38,12 +38,17 @@ pub struct GitDownloader {
impl GitDownloader {
pub fn new(
io: Box<dyn IOInterface>,
- config: Config,
- process: Option<ProcessExecutor>,
- fs: Option<Filesystem>,
+ 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, &inner.config, &inner.process, &inner.filesystem);
+ let git_util = GitUtil::new(
+ inner.io.clone_box(),
+ std::rc::Rc::clone(&inner.config),
+ std::rc::Rc::clone(&inner.process),
+ std::rc::Rc::clone(&inner.filesystem),
+ );
Self {
inner,
has_stashed_changes: IndexMap::new(),
@@ -71,10 +76,11 @@ impl GitDownloader {
"{}/{}/",
self.inner
.config
+ .borrow_mut()
.get("cache-vcs-dir")
.as_string()
.unwrap_or(""),
- Preg::replace(r"{[^a-z0-9.]}i", "-", Url::sanitize(url.to_string())),
+ Preg::replace(r"{[^a-z0-9.]}i", "-", &Url::sanitize(url.to_string()))?,
);
let git_version = GitUtil::get_version(&self.inner.process);
@@ -83,20 +89,20 @@ impl GitDownloader {
&& version_compare(git_version.as_deref().unwrap_or(""), "2.3.0-rc0", ">=")
&& Cache::is_usable(&cache_path)
{
- self.inner.io.write_error(
- PhpMixed::String(format!(
+ self.inner.io.write_error3(
+ &format!(
" - Syncing <info>{}</info> (<comment>{}</comment>) into cache",
package.get_name(),
package.get_full_pretty_version(),
- )),
+ ),
true,
io_interface::NORMAL,
);
- self.inner.io.write_error(
- PhpMixed::String(sprintf(
+ self.inner.io.write_error3(
+ &sprintf(
" Cloning to cache at %s",
&[PhpMixed::String(cache_path.clone())],
- )),
+ ),
true,
io_interface::DEBUG,
);
@@ -136,10 +142,11 @@ impl GitDownloader {
"{}/{}/",
self.inner
.config
+ .borrow_mut()
.get("cache-vcs-dir")
.as_string()
.unwrap_or(""),
- Preg::replace(r"{[^a-z0-9.]}i", "-", Url::sanitize(url.to_string())),
+ Preg::replace(r"{[^a-z0-9.]}i", "-", &Url::sanitize(url.to_string()))?,
);
let r#ref = package.get_source_reference().unwrap_or("").to_string();
@@ -252,7 +259,8 @@ impl GitDownloader {
self.inner.io.write_error3(&msg, true, io_interface::NORMAL);
- self.git_util.run_commands(commands, url, &path, true);
+ self.git_util
+ .run_commands(commands, url, Some(&path), true, None)?;
let source_url = package.get_source_url();
if url != source_url.unwrap_or("") && source_url.is_some() {
@@ -299,10 +307,11 @@ impl GitDownloader {
"{}/{}/",
self.inner
.config
+ .borrow_mut()
.get("cache-vcs-dir")
.as_string()
.unwrap_or(""),
- Preg::replace(r"{[^a-z0-9.]}i", "-", Url::sanitize(url.to_string())),
+ Preg::replace(r"{[^a-z0-9.]}i", "-", &Url::sanitize(url.to_string()))?,
);
let r#ref = target.get_source_reference().unwrap_or("").to_string();
@@ -335,7 +344,7 @@ impl GitDownloader {
self.inner.io.write_error3(&msg, true, io_interface::NORMAL);
let mut output = String::new();
- if self.inner.process.execute(
+ if self.inner.process.borrow_mut().execute_args(
&vec![
"git".to_string(),
"rev-parse".to_string(),
@@ -369,7 +378,8 @@ impl GitDownloader {
],
];
- self.git_util.run_commands(commands, url, &path, false);
+ self.git_util
+ .run_commands(commands, url, Some(&path), false, None)?;
}
let command = vec![
@@ -380,7 +390,8 @@ impl GitDownloader {
"--".to_string(),
"%sanitizedUrl%".to_string(),
];
- self.git_util.run_commands(vec![command], url, &path, false);
+ self.git_util
+ .run_commands(vec![command], url, Some(&path), false, None)?;
if let Some(new_ref) =
self.update_to_commit(target, &path, &r#ref, target.get_pretty_version())?
@@ -395,18 +406,35 @@ impl GitDownloader {
let mut update_origin_url = false;
let mut output = String::new();
- if self.inner.process.execute(
+ if self.inner.process.borrow_mut().execute_args(
&vec!["git".to_string(), "remote".to_string(), "-v".to_string()],
&mut output,
Some(path.clone()),
) == 0
{
- let origin_match = Preg::is_match_strict_groups(r"{^origin\s+(?P<url>\S+)}m", &output);
- let composer_match =
- Preg::is_match_strict_groups(r"{^composer\s+(?P<url>\S+)}m", &output);
- if let (Some(origin_match), Some(composer_match)) = (origin_match, composer_match) {
- let origin_url = origin_match.get("url").cloned().unwrap_or_default();
- let composer_url = composer_match.get("url").cloned().unwrap_or_default();
+ let mut origin_match: IndexMap<CaptureKey, String> = IndexMap::new();
+ let mut composer_match: IndexMap<CaptureKey, String> = IndexMap::new();
+ if Preg::is_match3(
+ r"{^origin\s+(?P<url>\S+)}m",
+ &output,
+ Some(&mut origin_match),
+ )
+ .unwrap_or(false)
+ && Preg::is_match3(
+ r"{^composer\s+(?P<url>\S+)}m",
+ &output,
+ Some(&mut composer_match),
+ )
+ .unwrap_or(false)
+ {
+ let origin_url = origin_match
+ .get(&CaptureKey::ByName("url".to_string()))
+ .cloned()
+ .unwrap_or_default();
+ let composer_url = composer_match
+ .get(&CaptureKey::ByName("url".to_string()))
+ .cloned()
+ .unwrap_or_default();
if origin_url == composer_url
&& Some(composer_url.as_str()) != target.get_source_url()
{
@@ -434,11 +462,11 @@ impl GitDownloader {
"--untracked-files=no".to_string(),
];
let mut output = String::new();
- if self
- .inner
- .process
- .execute(&command, &mut output, Some(path.to_string()))
- != 0
+ if self.inner.process.borrow_mut().execute_args(
+ &command,
+ &mut output,
+ Some(path.to_string()),
+ ) != 0
{
// TODO(phase-b): cannot throw from &self / non-Result fn; bubble error via Result later
panic!(
@@ -446,7 +474,7 @@ impl GitDownloader {
format!(
"Failed to execute {}\n\n{}",
implode(" ", &command),
- self.inner.process.get_error_output(),
+ self.inner.process.borrow().get_error_output(),
)
);
}
@@ -481,7 +509,8 @@ impl GitDownloader {
if self
.inner
.process
- .execute(&command, &mut output, Some(path.clone()))
+ .borrow_mut()
+ .execute_args(&command, &mut output, Some(path.clone()))
!= 0
{
// TODO(phase-b): bubble error via Result later
@@ -490,26 +519,39 @@ impl GitDownloader {
format!(
"Failed to execute {}\n\n{}",
implode(" ", &command),
- self.inner.process.get_error_output(),
+ self.inner.process.borrow().get_error_output(),
)
);
}
let mut refs = trim(&output, None);
- let head_ref = match Preg::is_match_strict_groups(r"{^([a-f0-9]+) HEAD$}mi", &refs) {
- Some(m) => m.get(1).cloned().unwrap_or_default(),
+ let mut head_match: IndexMap<CaptureKey, String> = IndexMap::new();
+ if !Preg::is_match_strict_groups3(r"{^([a-f0-9]+) HEAD$}mi", &refs, Some(&mut head_match))
+ .unwrap_or(false)
+ {
// could not match the HEAD for some reason
- None => return None,
- };
+ return None;
+ }
+ let head_ref = head_match
+ .get(&CaptureKey::ByIndex(1))
+ .cloned()
+ .unwrap_or_default();
- let candidate_branches: Vec<String> = match Preg::is_match_all_strict_groups(
+ let mut branches_match: IndexMap<CaptureKey, Vec<String>> = IndexMap::new();
+ if !Preg::is_match_all_strict_groups3(
&format!("{{^{} refs/heads/(.+)$}}mi", preg_quote(&head_ref, None)),
&refs,
- ) {
- Some(m) => m.get(1).cloned().unwrap_or_default(),
+ Some(&mut branches_match),
+ )
+ .unwrap_or(false)
+ {
// not on a branch, we are either on a not-modified tag or some sort of detached head, so skip this
- None => return None,
- };
+ return None;
+ }
+ let candidate_branches: Vec<String> = branches_match
+ .get(&CaptureKey::ByIndex(1))
+ .cloned()
+ .unwrap_or_default();
// use the first match as branch name for now
let mut branch = candidate_branches[0].clone();
@@ -522,14 +564,19 @@ impl GitDownloader {
// try to find matching branch names in remote repos
for candidate in &candidate_branches {
- if let Some(m) = Preg::is_match_all_strict_groups(
+ let mut m: IndexMap<CaptureKey, Vec<String>> = IndexMap::new();
+ if Preg::is_match_all_strict_groups3(
&format!(
"{{^[a-f0-9]+ refs/remotes/((?:[^/]+)/{})$}}mi",
preg_quote(candidate, None)
),
&refs,
- ) {
- let matches: Vec<String> = m.get(1).cloned().unwrap_or_default();
+ Some(&mut m),
+ )
+ .unwrap_or(false)
+ {
+ let matches: Vec<String> =
+ m.get(&CaptureKey::ByIndex(1)).cloned().unwrap_or_default();
for match_ in matches {
branch = candidate.clone();
remote_branches.push(match_);
@@ -562,11 +609,11 @@ impl GitDownloader {
"--".to_string(),
];
let mut output = String::new();
- if self
- .inner
- .process
- .execute(&command, &mut output, Some(path.clone()))
- != 0
+ if self.inner.process.borrow_mut().execute_args(
+ &command,
+ &mut output,
+ Some(path.clone()),
+ ) != 0
{
// TODO(phase-b): bubble error via Result later
panic!(
@@ -574,7 +621,7 @@ impl GitDownloader {
format!(
"Failed to execute {}\n\n{}",
implode(" ", &command),
- self.inner.process.get_error_output(),
+ self.inner.process.borrow().get_error_output(),
)
);
}
@@ -593,7 +640,7 @@ impl GitDownloader {
// remotes and then try again as outdated remotes can sometimes cause false-positives
if unpushed_changes.is_some() && i == 0 {
let mut output = String::new();
- self.inner.process.execute(
+ self.inner.process.borrow_mut().execute_args(
&vec!["git".to_string(), "fetch".to_string(), "--all".to_string()],
&mut output,
Some(path.clone()),
@@ -607,11 +654,11 @@ impl GitDownloader {
"-d".to_string(),
];
let mut output = String::new();
- if self
- .inner
- .process
- .execute(&command, &mut output, Some(path.clone()))
- != 0
+ if self.inner.process.borrow_mut().execute_args(
+ &command,
+ &mut output,
+ Some(path.clone()),
+ ) != 0
{
// TODO(phase-b): bubble error via Result later
panic!(
@@ -619,7 +666,7 @@ impl GitDownloader {
format!(
"Failed to execute {}\n\n{}",
implode(" ", &command),
- self.inner.process.get_error_output(),
+ self.inner.process.borrow().get_error_output(),
)
);
}
@@ -647,7 +694,13 @@ impl GitDownloader {
let unpushed = self.get_unpushed_changes(package, &path);
if let Some(unpushed) = unpushed.as_deref() {
if self.inner.io.is_interactive()
- || self.inner.config.get("discard-changes").as_bool() != Some(true)
+ || self
+ .inner
+ .config
+ .borrow_mut()
+ .get("discard-changes")
+ .as_bool()
+ != Some(true)
{
return Err(RuntimeException {
message: format!(
@@ -666,7 +719,7 @@ impl GitDownloader {
};
if !self.inner.io.is_interactive() {
- let discard_changes = self.inner.config.get("discard-changes");
+ let discard_changes = self.inner.config.borrow_mut().get("discard-changes");
if discard_changes.as_bool() == Some(true) {
return self.discard_changes(&path);
}
@@ -685,16 +738,16 @@ impl GitDownloader {
|elem: &String| format!(" {}", elem),
&Preg::split(r"{\s*\r?\n\s*}", &changes),
);
- self.inner.io.write_error(
- PhpMixed::String(format!(
+ self.inner.io.write_error3(
+ &format!(
" <error>{} has modified files:</error>",
package.get_pretty_name()
- )),
+ ),
true,
io_interface::NORMAL,
);
let slice_end = 10_usize.min(changes.len());
- self.inner.io.write_error(
+ self.inner.io.write_error3(
PhpMixed::List(
changes[..slice_end]
.iter()
@@ -705,11 +758,11 @@ impl GitDownloader {
io_interface::NORMAL,
);
if (changes.len() as i64) > 10 {
- self.inner.io.write_error(
- PhpMixed::String(format!(
+ self.inner.io.write_error3(
+ &format!(
" <info>{} more files modified, choose \"v\" to view the full list</info>",
changes.len() as i64 - 10
- )),
+ ),
true,
io_interface::NORMAL,
);
@@ -751,7 +804,7 @@ impl GitDownloader {
.into());
}
Some("v") => {
- self.inner.io.write_error(
+ self.inner.io.write_error3(
PhpMixed::List(
changes
.iter()
@@ -773,7 +826,7 @@ impl GitDownloader {
if do_help {
// help:
- self.inner.io.write_error(
+ self.inner.io.write_error3(
PhpMixed::List(vec![
Box::new(PhpMixed::String(format!(
" y - discard changes and apply the {}",
@@ -792,20 +845,15 @@ impl GitDownloader {
io_interface::NORMAL,
);
if update {
- self.inner.io.write_error(
- PhpMixed::String(
- " s - stash changes and try to reapply them after the update"
- .to_string(),
- ),
+ self.inner.io.write_error3(
+ " s - stash changes and try to reapply them after the update",
true,
io_interface::NORMAL,
);
}
- self.inner.io.write_error(
- PhpMixed::String(" ? - print help".to_string()),
- true,
- io_interface::NORMAL,
- );
+ self.inner
+ .io
+ .write_error3(" ? - print help", true, io_interface::NORMAL);
}
}
@@ -821,13 +869,13 @@ impl GitDownloader {
.unwrap_or(false)
{
self.has_stashed_changes.shift_remove(&path);
- self.inner.io.write_error(
- PhpMixed::String(" <info>Re-applying stashed changes</info>".to_string()),
+ self.inner.io.write_error3(
+ " <info>Re-applying stashed changes</info>",
true,
io_interface::NORMAL,
);
let mut output = String::new();
- if self.inner.process.execute(
+ if self.inner.process.borrow_mut().execute_args(
&vec!["git".to_string(), "stash".to_string(), "pop".to_string()],
&mut output,
Some(path.clone()),
@@ -836,7 +884,7 @@ impl GitDownloader {
return Err(RuntimeException {
message: format!(
"Failed to apply stashed changes:\n\n{}",
- self.inner.process.get_error_output()
+ self.inner.process.borrow().get_error_output()
),
code: 0,
}
@@ -877,11 +925,7 @@ impl GitDownloader {
// If the non-existent branch is actually the name of a file, the file
// is checked out.
- let mut branch = Preg::replace(
- r"{(?:^dev-|(?:\.x)?-dev$)}i",
- "",
- pretty_version.to_string(),
- );
+ let mut branch = Preg::replace(r"{(?:^dev-|(?:\.x)?-dev$)}i", "", &pretty_version);
// Closure equivalent: $execute = function(array $command) use (&$output, $path) { ... };
// Inlined below at each call site.
@@ -889,7 +933,7 @@ impl GitDownloader {
let mut branches: Option<String> = None;
{
let mut output = String::new();
- if self.inner.process.execute(
+ if self.inner.process.borrow_mut().execute_args(
&vec!["git".to_string(), "branch".to_string(), "-r".to_string()],
&mut output,
Some(path.to_string()),
@@ -926,17 +970,18 @@ impl GitDownloader {
];
let mut output = String::new();
- let ok1 = self
- .inner
- .process
- .execute(&command1, &mut output, Some(path.to_string()))
- == 0;
+ let ok1 = self.inner.process.borrow_mut().execute_args(
+ &command1,
+ &mut output,
+ Some(path.to_string()),
+ ) == 0;
let ok2 = if ok1 {
let mut output = String::new();
- self.inner
- .process
- .execute(&command2, &mut output, Some(path.to_string()))
- == 0
+ self.inner.process.borrow_mut().execute_args(
+ &command2,
+ &mut output,
+ Some(path.to_string()),
+ ) == 0
} else {
false
};
@@ -986,26 +1031,28 @@ impl GitDownloader {
];
let mut output = String::new();
- let ok_command =
- self.inner
- .process
- .execute(&command, &mut output, Some(path.to_string()))
- == 0;
+ let ok_command = self.inner.process.borrow_mut().execute_args(
+ &command,
+ &mut output,
+ Some(path.to_string()),
+ ) == 0;
let ok_fallback = if !ok_command {
let mut output = String::new();
- self.inner
- .process
- .execute(&fallback_command, &mut output, Some(path.to_string()))
- == 0
+ self.inner.process.borrow_mut().execute_args(
+ &fallback_command,
+ &mut output,
+ Some(path.to_string()),
+ ) == 0
} else {
false
};
let ok_reset = if ok_command || ok_fallback {
let mut output = String::new();
- self.inner
- .process
- .execute(&reset_command, &mut output, Some(path.to_string()))
- == 0
+ self.inner.process.borrow_mut().execute_args(
+ &reset_command,
+ &mut output,
+ Some(path.to_string()),
+ ) == 0
} else {
false
};
@@ -1026,17 +1073,18 @@ impl GitDownloader {
];
{
let mut output = String::new();
- let ok1 = self
- .inner
- .process
- .execute(&command1, &mut output, Some(path.to_string()))
- == 0;
+ let ok1 = self.inner.process.borrow_mut().execute_args(
+ &command1,
+ &mut output,
+ Some(path.to_string()),
+ ) == 0;
let ok2 = if ok1 {
let mut output = String::new();
- self.inner
- .process
- .execute(&command2, &mut output, Some(path.to_string()))
- == 0
+ self.inner.process.borrow_mut().execute_args(
+ &command2,
+ &mut output,
+ Some(path.to_string()),
+ ) == 0
} else {
false
};
@@ -1048,12 +1096,12 @@ impl GitDownloader {
let mut exception_extra = String::new();
// reference was not found (prints "fatal: reference is not a tree: $ref")
- if strpos(self.inner.process.get_error_output(), reference).is_some() {
- self.inner.io.write_error(
- PhpMixed::String(format!(
+ if strpos(self.inner.process.borrow().get_error_output(), reference).is_some() {
+ self.inner.io.write_error3(
+ &format!(
" <warning>{} is gone (history was rewritten?)</warning>",
reference
- )),
+ ),
true,
io_interface::NORMAL,
);
@@ -1074,7 +1122,7 @@ impl GitDownloader {
message: Url::sanitize(format!(
"Failed to execute {}\n\n{}{}",
command,
- self.inner.process.get_error_output(),
+ self.inner.process.borrow().get_error_output(),
exception_extra,
)),
code: 0,
@@ -1084,7 +1132,7 @@ impl GitDownloader {
pub(crate) fn update_origin_url(&mut self, path: &str, url: &str) {
let mut output = String::new();
- self.inner.process.execute(
+ self.inner.process.borrow_mut().execute_args(
&vec![
"git".to_string(),
"remote".to_string(),
@@ -1101,17 +1149,30 @@ impl GitDownloader {
pub(crate) fn set_push_url(&mut self, path: &str, url: &str) {
// set push url for github projects
- if let Some(match_) = Preg::is_match_strict_groups(
+ let mut match_: IndexMap<CaptureKey, String> = IndexMap::new();
+ if Preg::is_match3(
&format!(
"{{^(?:https?|git)://{}/([^/]+)/([^/]+?)(?:\\.git)?$}}",
- GitUtil::get_github_domains_regex(&self.inner.config)
+ GitUtil::get_github_domains_regex(&*self.inner.config.borrow())
),
url,
- ) {
- let protocols = self.inner.config.get("github-protocols");
- let m1 = match_.get(1).cloned().unwrap_or_default();
- let m2 = match_.get(2).cloned().unwrap_or_default();
- let m3 = match_.get(3).cloned().unwrap_or_default();
+ Some(&mut match_),
+ )
+ .unwrap_or(false)
+ {
+ let protocols = self.inner.config.borrow_mut().get("github-protocols");
+ let m1 = match_
+ .get(&CaptureKey::ByIndex(1))
+ .cloned()
+ .unwrap_or_default();
+ let m2 = match_
+ .get(&CaptureKey::ByIndex(2))
+ .cloned()
+ .unwrap_or_default();
+ let m3 = match_
+ .get(&CaptureKey::ByIndex(3))
+ .cloned()
+ .unwrap_or_default();
let mut push_url = format!("git@{}:{}/{}.git", m1, m2, m3);
if !in_array(PhpMixed::String("ssh".to_string()), &protocols, true) {
push_url = format!("https://{}/{}/{}.git", m1, m2, m3);
@@ -1126,9 +1187,11 @@ impl GitDownloader {
push_url,
];
let mut ignored_output = String::new();
- self.inner
- .process
- .execute(&cmd, &mut ignored_output, Some(path.to_string()));
+ self.inner.process.borrow_mut().execute_args(
+ &cmd,
+ &mut ignored_output,
+ Some(path.to_string()),
+ );
}
}
@@ -1150,14 +1213,15 @@ impl GitDownloader {
if self
.inner
.process
- .execute(&command, &mut output, Some(path.clone()))
+ .borrow_mut()
+ .execute_args(&command, &mut output, Some(path.clone()))
!= 0
{
return Err(RuntimeException {
message: format!(
"Failed to execute {}\n\n{}",
implode(" ", &command),
- self.inner.process.get_error_output(),
+ self.inner.process.borrow().get_error_output(),
),
code: 0,
}
@@ -1172,7 +1236,7 @@ impl GitDownloader {
pub(crate) fn discard_changes(&mut self, path: &str) -> Result<Box<dyn PromiseInterface>> {
let path = self.normalize_path(path);
let mut output = String::new();
- if self.inner.process.execute(
+ if self.inner.process.borrow_mut().execute_args(
&vec!["git".to_string(), "clean".to_string(), "-df".to_string()],
&mut output,
Some(path.clone()),
@@ -1185,7 +1249,7 @@ impl GitDownloader {
.into());
}
let mut output = String::new();
- if self.inner.process.execute(
+ if self.inner.process.borrow_mut().execute_args(
&vec!["git".to_string(), "reset".to_string(), "--hard".to_string()],
&mut output,
Some(path.clone()),
@@ -1208,7 +1272,7 @@ impl GitDownloader {
pub(crate) fn stash_changes(&mut self, path: &str) -> Result<Box<dyn PromiseInterface>> {
let path = self.normalize_path(path);
let mut output = String::new();
- if self.inner.process.execute(
+ if self.inner.process.borrow_mut().execute_args(
&vec![
"git".to_string(),
"stash".to_string(),
@@ -1234,7 +1298,7 @@ impl GitDownloader {
pub(crate) fn view_diff(&mut self, path: &str) {
let path = self.normalize_path(path);
let mut output = String::new();
- if self.inner.process.execute(
+ if self.inner.process.borrow_mut().execute_args(
&vec!["git".to_string(), "diff".to_string(), "HEAD".to_string()],
&mut output,
Some(path.clone()),
diff --git a/crates/shirabe/src/downloader/gzip_downloader.rs b/crates/shirabe/src/downloader/gzip_downloader.rs
index 2a485de..4ee9d33 100644
--- a/crates/shirabe/src/downloader/gzip_downloader.rs
+++ b/crates/shirabe/src/downloader/gzip_downloader.rs
@@ -29,12 +29,12 @@ pub struct GzipDownloader {
impl GzipDownloader {
pub fn new(
io: Box<dyn IOInterface>,
- config: Config,
- http_downloader: HttpDownloader,
+ config: std::rc::Rc<std::cell::RefCell<Config>>,
+ http_downloader: std::rc::Rc<std::cell::RefCell<HttpDownloader>>,
event_dispatcher: Option<EventDispatcher>,
cache: Option<Cache>,
- filesystem: Filesystem,
- process: ProcessExecutor,
+ filesystem: std::rc::Rc<std::cell::RefCell<Filesystem>>,
+ process: std::rc::Rc<std::cell::RefCell<ProcessExecutor>>,
) -> Self {
Self {
inner: FileDownloader::new(
@@ -80,7 +80,7 @@ impl GzipDownloader {
];
let mut process_output = PhpMixed::Null;
- if self.inner.process.execute(
+ if self.inner.process.borrow_mut().execute(
PhpMixed::List(
command
.iter()
@@ -102,7 +102,7 @@ impl GzipDownloader {
let process_error = format!(
"Failed to execute {}\n\n{}",
implode(" ", &command),
- self.inner.process.get_error_output(),
+ self.inner.process.borrow().get_error_output(),
);
return Err(anyhow::anyhow!(RuntimeException {
message: process_error,
diff --git a/crates/shirabe/src/downloader/hg_downloader.rs b/crates/shirabe/src/downloader/hg_downloader.rs
index 1b4204f..161eb7e 100644
--- a/crates/shirabe/src/downloader/hg_downloader.rs
+++ b/crates/shirabe/src/downloader/hg_downloader.rs
@@ -37,7 +37,11 @@ impl HgDownloader {
path: String,
url: String,
) -> Result<Box<dyn PromiseInterface>> {
- let hg_utils = HgUtils::new(&self.inner.io, &self.inner.config, &self.inner.process);
+ let hg_utils = HgUtils::new(
+ &*self.inner.io,
+ &*self.inner.config.borrow(),
+ &self.inner.process,
+ );
let path_clone = path.clone();
let clone_command = move |url: String| -> Vec<String> {
@@ -58,7 +62,7 @@ impl HgDownloader {
package.get_source_reference().unwrap_or_default(),
];
let mut ignored_output = String::new();
- if self.inner.process.execute(
+ if self.inner.process.borrow_mut().execute_args(
&command,
&mut ignored_output,
shirabe_php_shim::realpath(&path),
@@ -68,7 +72,7 @@ impl HgDownloader {
message: format!(
"Failed to execute {}\n\n{}",
command.join(" "),
- self.inner.process.get_error_output()
+ self.inner.process.borrow().get_error_output()
),
code: 0,
}
@@ -85,7 +89,11 @@ impl HgDownloader {
path: String,
url: String,
) -> Result<Box<dyn PromiseInterface>> {
- let hg_utils = HgUtils::new(&self.inner.io, &self.inner.config, &self.inner.process);
+ let hg_utils = HgUtils::new(
+ &*self.inner.io,
+ &*self.inner.config.borrow(),
+ &self.inner.process,
+ );
let ref_ = target.get_source_reference().unwrap_or_default();
self.inner.io.write_error(&format!(
@@ -132,7 +140,7 @@ impl HgDownloader {
}
let mut output = String::new();
- self.inner.process.execute(
+ self.inner.process.borrow_mut().execute_args(
&["hg".to_string(), "st".to_string()],
&mut output,
shirabe_php_shim::realpath(&path),
@@ -163,17 +171,17 @@ impl HgDownloader {
];
let mut output = String::new();
- if self
- .inner
- .process
- .execute(&command, &mut output, shirabe_php_shim::realpath(&path))
- != 0
+ if self.inner.process.borrow_mut().execute_args(
+ &command,
+ &mut output,
+ shirabe_php_shim::realpath(&path),
+ ) != 0
{
return Err(RuntimeException {
message: format!(
"Failed to execute {}\n\n{}",
command.join(" "),
- self.inner.process.get_error_output()
+ self.inner.process.borrow().get_error_output()
),
code: 0,
}
diff --git a/crates/shirabe/src/downloader/path_downloader.rs b/crates/shirabe/src/downloader/path_downloader.rs
index a525df0..26795f3 100644
--- a/crates/shirabe/src/downloader/path_downloader.rs
+++ b/crates/shirabe/src/downloader/path_downloader.rs
@@ -117,12 +117,12 @@ impl PathDownloader {
if realpath(&path).as_deref() == Some(&real_url) {
if output {
let appendix = self.get_install_operation_appendix(package, &path)?;
- self.inner.io.write_error(
- PhpMixed::String(format!(
+ self.inner.io.write_error3(
+ &format!(
" - {}{}",
InstallOperation::format(package, false),
appendix
- )),
+ ),
true,
io_interface::NORMAL,
);
@@ -141,14 +141,11 @@ impl PathDownloader {
self.compute_allowed_strategies(&transport_options)?;
let symfony_filesystem = SymfonyFilesystem::new(None);
- self.inner.filesystem.remove_directory(&path);
+ self.inner.filesystem.borrow_mut().remove_directory(&path);
if output {
- self.inner.io.write_error(
- PhpMixed::String(format!(
- " - {}: ",
- InstallOperation::format(package, false)
- )),
+ self.inner.io.write_error3(
+ &format!(" - {}: ", InstallOperation::format(package, false)),
false,
io_interface::NORMAL,
);
@@ -160,18 +157,22 @@ impl PathDownloader {
if Platform::is_windows() {
// Implement symlinks as NTFS junctions on Windows
if output {
- self.inner.io.write_error(
- PhpMixed::String(format!("Junctioning from {}", url)),
+ self.inner.io.write_error3(
+ &format!("Junctioning from {}", url),
false,
io_interface::NORMAL,
);
}
- Ok(self.inner.filesystem.junction(&real_url, &path))
+ Ok(self
+ .inner
+ .filesystem
+ .borrow_mut()
+ .junction(&real_url, &path))
} else {
let path = path.trim_end_matches('/').to_string();
if output {
- self.inner.io.write_error(
- PhpMixed::String(format!("Symlinking from {}", url)),
+ self.inner.io.write_error3(
+ &format!("Symlinking from {}", url),
false,
io_interface::NORMAL,
);
@@ -181,17 +182,18 @@ impl PathDownloader {
.and_then(|v| v.as_bool())
.unwrap_or(false)
{
- let absolute_path = if !self.inner.filesystem.is_absolute_path(&path) {
- format!(
- "{}{}{}",
- Platform::get_cwd(false),
- DIRECTORY_SEPARATOR,
- path
- )
- } else {
- path.clone()
- };
- let shortest_path = self.inner.filesystem.find_shortest_path(
+ let absolute_path =
+ if !self.inner.filesystem.borrow_mut().is_absolute_path(&path) {
+ format!(
+ "{}{}{}",
+ Platform::get_cwd(false),
+ DIRECTORY_SEPARATOR,
+ path
+ )
+ } else {
+ path.clone()
+ };
+ let shortest_path = self.inner.filesystem.borrow_mut().find_shortest_path(
&absolute_path,
&real_url,
false,
@@ -209,16 +211,9 @@ impl PathDownloader {
Err(_e) => {
if allowed_strategies.contains(&Self::STRATEGY_MIRROR) {
if output {
- self.inner.io.write_error(
- PhpMixed::String("".to_string()),
- true,
- io_interface::NORMAL,
- );
- self.inner.io.write_error(
- PhpMixed::String(
- " <error>Symlink failed, fallback to use mirroring!</error>"
- .to_string(),
- ),
+ self.inner.io.write_error3("", true, io_interface::NORMAL);
+ self.inner.io.write_error3(
+ " <error>Symlink failed, fallback to use mirroring!</error>",
true,
io_interface::NORMAL,
);
@@ -241,15 +236,15 @@ impl PathDownloader {
// Fallback if symlink failed or if symlink is not allowed for the package
if Self::STRATEGY_MIRROR == current_strategy {
- let real_url = self.inner.filesystem.normalize_path(&real_url);
+ let real_url = self.inner.filesystem.borrow_mut().normalize_path(&real_url);
if output {
- self.inner.io.write_error(
- PhpMixed::String(format!(
+ self.inner.io.write_error3(
+ &format!(
"{}Mirroring from {}",
if is_fallback { " " } else { "" },
url
- )),
+ ),
false,
io_interface::NORMAL,
);
@@ -280,24 +275,24 @@ impl PathDownloader {
// process inadvertently locks the file the removal will fail, but it would fall back to recursive
// delete which is disastrous within a junction. So in that case we have no other real choice but
// to fail hard.
- if Platform::is_windows() && self.inner.filesystem.is_junction(&path) {
+ if Platform::is_windows() && self.inner.filesystem.borrow_mut().is_junction(&path) {
if output {
- self.inner.io.write_error(
- PhpMixed::String(format!(
+ self.inner.io.write_error3(
+ &format!(
" - {}, source is still present in {}",
UninstallOperation::format(package, false),
path
- )),
+ ),
true,
io_interface::NORMAL,
);
}
- if !self.inner.filesystem.remove_junction(&path) {
- self.inner.io.write_error(
- PhpMixed::String(format!(
+ if !self.inner.filesystem.borrow_mut().remove_junction(&path)? {
+ self.inner.io.write_error3(
+ &format!(
" <warning>Could not remove junction at {} - is another process locking it?</warning>",
path
- )),
+ ),
true,
io_interface::NORMAL,
);
@@ -339,12 +334,12 @@ impl PathDownloader {
};
if fs.normalize_path(&abs_path) == fs.normalize_path(&abs_dist_url) {
if output {
- self.inner.io.write_error(
- PhpMixed::String(format!(
+ self.inner.io.write_error3(
+ &format!(
" - {}, source is still present in {}",
UninstallOperation::format(package, false),
path
- )),
+ ),
true,
io_interface::NORMAL,
);
@@ -360,10 +355,10 @@ impl PathDownloader {
let path = Filesystem::trim_trailing_slash(path);
let parser = VersionParser::new();
let guesser = VersionGuesser::new(
- &self.inner.config,
- &self.inner.process,
- &parser,
- Some(&*self.inner.io),
+ std::rc::Rc::clone(&self.inner.config),
+ std::rc::Rc::clone(&self.inner.process),
+ parser.clone(),
+ Some(self.inner.io.clone_box()),
);
let dumper = ArrayDumper::new();
diff --git a/crates/shirabe/src/downloader/perforce_downloader.rs b/crates/shirabe/src/downloader/perforce_downloader.rs
index b10e27f..fe5e9e5 100644
--- a/crates/shirabe/src/downloader/perforce_downloader.rs
+++ b/crates/shirabe/src/downloader/perforce_downloader.rs
@@ -74,7 +74,7 @@ impl PerforceDownloader {
let repository = package.get_repository();
let repo_config: Option<IndexMap<String, PhpMixed>> = if let Some(repo) = repository {
- if let Some(vcs_repo) = (repo.as_any() as &dyn Any).downcast_ref::<VcsRepository>() {
+ if let Some(vcs_repo) = repo.as_any().downcast_ref::<VcsRepository>() {
Some(self.get_repo_config(vcs_repo))
} else {
None
diff --git a/crates/shirabe/src/downloader/phar_downloader.rs b/crates/shirabe/src/downloader/phar_downloader.rs
index 649841d..19777fb 100644
--- a/crates/shirabe/src/downloader/phar_downloader.rs
+++ b/crates/shirabe/src/downloader/phar_downloader.rs
@@ -25,12 +25,12 @@ pub struct PharDownloader {
impl PharDownloader {
pub fn new(
io: Box<dyn IOInterface>,
- config: Config,
- http_downloader: HttpDownloader,
+ config: std::rc::Rc<std::cell::RefCell<Config>>,
+ http_downloader: std::rc::Rc<std::cell::RefCell<HttpDownloader>>,
event_dispatcher: Option<EventDispatcher>,
cache: Option<Cache>,
- filesystem: Filesystem,
- process: ProcessExecutor,
+ filesystem: std::rc::Rc<std::cell::RefCell<Filesystem>>,
+ process: std::rc::Rc<std::cell::RefCell<ProcessExecutor>>,
) -> Self {
Self {
inner: FileDownloader::new(
diff --git a/crates/shirabe/src/downloader/rar_downloader.rs b/crates/shirabe/src/downloader/rar_downloader.rs
index 51feadb..afc2f12 100644
--- a/crates/shirabe/src/downloader/rar_downloader.rs
+++ b/crates/shirabe/src/downloader/rar_downloader.rs
@@ -28,12 +28,12 @@ pub struct RarDownloader {
impl RarDownloader {
pub fn new(
io: Box<dyn IOInterface>,
- config: Config,
- http_downloader: HttpDownloader,
+ config: std::rc::Rc<std::cell::RefCell<Config>>,
+ http_downloader: std::rc::Rc<std::cell::RefCell<HttpDownloader>>,
event_dispatcher: Option<EventDispatcher>,
cache: Option<Cache>,
- filesystem: Filesystem,
- process: ProcessExecutor,
+ filesystem: std::rc::Rc<std::cell::RefCell<Filesystem>>,
+ process: std::rc::Rc<std::cell::RefCell<ProcessExecutor>>,
) -> Self {
Self {
inner: FileDownloader::new(
@@ -67,7 +67,7 @@ impl RarDownloader {
];
let mut process_output = PhpMixed::Null;
- if self.inner.process.execute(
+ if self.inner.process.borrow_mut().execute(
PhpMixed::List(
command
.iter()
@@ -84,7 +84,7 @@ impl RarDownloader {
process_error = Some(format!(
"Failed to execute {}\n\n{}",
implode(" ", &command),
- self.inner.process.get_error_output(),
+ self.inner.process.borrow().get_error_output(),
));
}
diff --git a/crates/shirabe/src/downloader/svn_downloader.rs b/crates/shirabe/src/downloader/svn_downloader.rs
index eb4de65..c228379 100644
--- a/crates/shirabe/src/downloader/svn_downloader.rs
+++ b/crates/shirabe/src/downloader/svn_downloader.rs
@@ -1,7 +1,8 @@
//! ref: composer/src/Composer/Downloader/SvnDownloader.php
use crate::io::io_interface;
-use shirabe_external_packages::composer::pcre::preg::Preg;
+use indexmap::IndexMap;
+use shirabe_external_packages::composer::pcre::preg::{CaptureKey, Preg};
use shirabe_external_packages::react::promise;
use shirabe_external_packages::react::promise::promise_interface::PromiseInterface;
use shirabe_php_shim::{PhpMixed, RuntimeException, is_dir, version_compare};
@@ -29,9 +30,9 @@ impl SvnDownloader {
SvnUtil::clean_env();
let util = SvnUtil::new(
url,
- &*self.inner.io,
- &self.inner.config,
- &self.inner.process,
+ self.inner.io.clone_box(),
+ std::rc::Rc::clone(&self.inner.config),
+ Some(std::rc::Rc::clone(&self.inner.process)),
);
if util.binary_version().is_none() {
return Err(RuntimeException {
@@ -68,8 +69,8 @@ impl SvnDownloader {
}
}
- self.inner.io.write_error(
- PhpMixed::String(format!(" Checking out {}", package.get_source_reference())),
+ self.inner.io.write_error3(
+ &format!(" Checking out {}", package.get_source_reference()),
true,
io_interface::NORMAL,
);
@@ -108,17 +109,17 @@ impl SvnDownloader {
let util = SvnUtil::new(
url,
- &*self.inner.io,
- &self.inner.config,
- &self.inner.process,
+ self.inner.io.clone_box(),
+ std::rc::Rc::clone(&self.inner.config),
+ Some(std::rc::Rc::clone(&self.inner.process)),
);
let mut flags: Vec<String> = vec![];
if version_compare(&util.binary_version().unwrap_or_default(), "1.7.0", ">=") {
flags.push("--ignore-ancestry".to_string());
}
- self.inner.io.write_error(
- PhpMixed::String(format!(" Checking out {}", r#ref)),
+ self.inner.io.write_error3(
+ &format!(" Checking out {}", r#ref),
true,
io_interface::NORMAL,
);
@@ -142,7 +143,7 @@ impl SvnDownloader {
}
let mut output = String::new();
- self.inner.process.execute(
+ self.inner.process.borrow_mut().execute_args(
&["svn", "status", "--ignore-externals"]
.map(|s| s.to_string())
.to_vec(),
@@ -168,9 +169,9 @@ impl SvnDownloader {
) -> anyhow::Result<String> {
let mut util = SvnUtil::new(
base_url,
- &*self.inner.io,
- &self.inner.config,
- &self.inner.process,
+ self.inner.io.clone_box(),
+ std::rc::Rc::clone(&self.inner.config),
+ Some(std::rc::Rc::clone(&self.inner.process)),
);
util.set_cache_credentials(self.cache_credentials);
util.execute(command, url, cwd, path, self.inner.io.is_verbose())
@@ -195,7 +196,14 @@ impl SvnDownloader {
}
if !self.inner.io.is_interactive() {
- if self.inner.config.get("discard-changes").as_bool() == Some(true) {
+ if self
+ .inner
+ .config
+ .borrow_mut()
+ .get("discard-changes")
+ .as_bool()
+ == Some(true)
+ {
return self.discard_changes(path);
}
@@ -208,17 +216,17 @@ impl SvnDownloader {
.map(|elem| format!(" {}", elem))
.collect();
let count_changes = changes.len() as i64;
- self.inner.io.write_error(
- PhpMixed::String(format!(
+ self.inner.io.write_error3(
+ &format!(
" <error>{} has modified file{}:</error>",
package.get_pretty_name(),
if count_changes == 1 { "" } else { "s" }
- )),
+ ),
true,
io_interface::NORMAL,
);
let slice_end = 10_usize.min(changes.len());
- self.inner.io.write_error(
+ self.inner.io.write_error3(
PhpMixed::List(
changes[..slice_end]
.iter()
@@ -230,12 +238,12 @@ impl SvnDownloader {
);
if count_changes > 10 {
let remaining_changes = count_changes - 10;
- self.inner.io.write_error(
- PhpMixed::String(format!(
+ self.inner.io.write_error3(
+ &format!(
" <info>{} more file{} modified, choose \"v\" to view the full list</info>",
remaining_changes,
if remaining_changes == 1 { "" } else { "s" }
- )),
+ ),
true,
io_interface::NORMAL,
);
@@ -263,7 +271,7 @@ impl SvnDownloader {
.into());
}
Some("v") => {
- self.inner.io.write_error(
+ self.inner.io.write_error3(
PhpMixed::List(
changes
.iter()
@@ -275,7 +283,7 @@ impl SvnDownloader {
);
}
_ => {
- self.inner.io.write_error(
+ self.inner.io.write_error3(
PhpMixed::List(vec![
Box::new(PhpMixed::String(format!(
" y - discard changes and apply the {}",
@@ -317,17 +325,17 @@ impl SvnDownloader {
path.to_string(),
];
let mut output = String::new();
- if self
- .inner
- .process
- .execute(&command, &mut output, Some(path.to_string()))
- != 0
+ if self.inner.process.borrow_mut().execute_args(
+ &command,
+ &mut output,
+ Some(path.to_string()),
+ ) != 0
{
return Err(RuntimeException {
message: format!(
"Failed to execute {}\n\n{}",
command.join(" "),
- self.inner.process.get_error_output()
+ self.inner.process.borrow().get_error_output()
),
code: 0,
}
@@ -335,8 +343,14 @@ impl SvnDownloader {
}
let url_pattern = "#<url>(.*)</url>#";
- let base_url = if let Some(matches) = Preg::match_strict_groups(url_pattern, &output) {
- matches.get("1").cloned().unwrap_or_default()
+ let mut matches: IndexMap<CaptureKey, String> = IndexMap::new();
+ let base_url = if Preg::match_strict_groups3(url_pattern, &output, Some(&mut matches))
+ .unwrap_or(false)
+ {
+ matches
+ .get(&CaptureKey::ByIndex(1))
+ .cloned()
+ .unwrap_or_default()
} else {
return Err(RuntimeException {
message: format!("Unable to determine svn url for path {}", path),
@@ -346,8 +360,10 @@ impl SvnDownloader {
};
// strip paths from references and only keep the actual revision
- let from_revision = Preg::replace(r"{.*@(\d+)$}", "$1", from_reference.to_string());
- let to_revision = Preg::replace(r"{.*@(\d+)$}", "$1", to_reference.to_string());
+ let from_revision =
+ Preg::replace(r"{.*@(\d+)$}", "$1", &from_reference).unwrap_or_default();
+ let to_revision =
+ Preg::replace(r"{.*@(\d+)$}", "$1", &to_reference).unwrap_or_default();
let command = vec![
"svn".to_string(),
@@ -359,9 +375,9 @@ impl SvnDownloader {
let mut util = SvnUtil::new(
&base_url,
- &*self.inner.io,
- &self.inner.config,
- &self.inner.process,
+ self.inner.io.clone_box(),
+ std::rc::Rc::clone(&self.inner.config),
+ Some(std::rc::Rc::clone(&self.inner.process)),
);
util.set_cache_credentials(self.cache_credentials);
util.execute_local(command.clone(), path, None, self.inner.io.is_verbose())
@@ -382,7 +398,7 @@ impl SvnDownloader {
pub(crate) fn discard_changes(&self, path: &str) -> anyhow::Result<Box<dyn PromiseInterface>> {
let mut output = String::new();
- if self.inner.process.execute(
+ if self.inner.process.borrow_mut().execute_args(
&["svn", "revert", "-R", "."].map(|s| s.to_string()).to_vec(),
&mut output,
Some(path.to_string()),
@@ -391,7 +407,7 @@ impl SvnDownloader {
return Err(RuntimeException {
message: format!(
"Could not reset changes\n\n:{}",
- self.inner.process.get_error_output()
+ self.inner.process.borrow().get_error_output()
),
code: 0,
}
diff --git a/crates/shirabe/src/downloader/tar_downloader.rs b/crates/shirabe/src/downloader/tar_downloader.rs
index aaa7153..8fcf339 100644
--- a/crates/shirabe/src/downloader/tar_downloader.rs
+++ b/crates/shirabe/src/downloader/tar_downloader.rs
@@ -25,12 +25,12 @@ pub struct TarDownloader {
impl TarDownloader {
pub fn new(
io: Box<dyn IOInterface>,
- config: Config,
- http_downloader: HttpDownloader,
+ config: std::rc::Rc<std::cell::RefCell<Config>>,
+ http_downloader: std::rc::Rc<std::cell::RefCell<HttpDownloader>>,
event_dispatcher: Option<EventDispatcher>,
cache: Option<Cache>,
- filesystem: Filesystem,
- process: ProcessExecutor,
+ filesystem: std::rc::Rc<std::cell::RefCell<Filesystem>>,
+ process: std::rc::Rc<std::cell::RefCell<ProcessExecutor>>,
) -> Self {
Self {
inner: FileDownloader::new(
diff --git a/crates/shirabe/src/downloader/transport_exception.rs b/crates/shirabe/src/downloader/transport_exception.rs
index 382da01..9d5b352 100644
--- a/crates/shirabe/src/downloader/transport_exception.rs
+++ b/crates/shirabe/src/downloader/transport_exception.rs
@@ -24,6 +24,12 @@ impl TransportException {
}
}
+ /// PHP exposes ($message, $code = 0) — alias of `new` used at call sites where the
+ /// status/exception code is provided up-front.
+ pub fn new_with_code(message: String, code: i64) -> Self {
+ Self::new(message, code)
+ }
+
pub fn get_code(&self) -> i64 {
self.code
}
diff --git a/crates/shirabe/src/downloader/vcs_downloader.rs b/crates/shirabe/src/downloader/vcs_downloader.rs
index 346603a..39518e3 100644
--- a/crates/shirabe/src/downloader/vcs_downloader.rs
+++ b/crates/shirabe/src/downloader/vcs_downloader.rs
@@ -27,21 +27,24 @@ use crate::util::process_executor::ProcessExecutor;
#[derive(Debug)]
pub struct VcsDownloaderBase {
pub io: Box<dyn IOInterface>,
- pub config: Config,
- pub process: ProcessExecutor,
- pub filesystem: Filesystem,
+ 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>>,
pub has_cleaned_changes: IndexMap<String, bool>,
}
impl VcsDownloaderBase {
pub fn new(
io: Box<dyn IOInterface>,
- config: Config,
- process: Option<ProcessExecutor>,
- fs: Option<Filesystem>,
+ 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(|| ProcessExecutor::new(None, None));
- let filesystem = fs.unwrap_or_else(|| Filesystem::new(None));
+ 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 {
io,
config,
@@ -57,12 +60,12 @@ pub trait VcsDownloader:
{
fn io(&self) -> &dyn IOInterface;
fn io_mut(&mut self) -> &mut dyn IOInterface;
- fn config(&self) -> &Config;
- fn config_mut(&mut self) -> &mut Config;
- fn process(&self) -> &ProcessExecutor;
- fn process_mut(&mut self) -> &mut ProcessExecutor;
- fn filesystem(&self) -> &Filesystem;
- fn filesystem_mut(&mut self) -> &mut Filesystem;
+ fn config(&self) -> &std::rc::Rc<std::cell::RefCell<Config>>;
+ fn config_mut(&mut self) -> &mut std::rc::Rc<std::cell::RefCell<Config>>;
+ fn process(&self) -> &std::rc::Rc<std::cell::RefCell<ProcessExecutor>>;
+ fn process_mut(&mut self) -> &mut std::rc::Rc<std::cell::RefCell<ProcessExecutor>>;
+ fn filesystem(&self) -> &std::rc::Rc<std::cell::RefCell<Filesystem>>;
+ fn filesystem_mut(&mut self) -> &mut std::rc::Rc<std::cell::RefCell<Filesystem>>;
fn has_cleaned_changes(&self) -> &IndexMap<String, bool>;
fn has_cleaned_changes_mut(&mut self) -> &mut IndexMap<String, bool>;
@@ -136,8 +139,8 @@ pub trait VcsDownloader:
return Err(e);
}
if self.io().is_debug() {
- self.io_mut().write_error(
- PhpMixed::String(format!("Failed: [{}] {}", get_class(&e), e,)),
+ self.io_mut().write_error3(
+ &format!("Failed: [{}] {}", get_class(&e), e,),
true,
io_interface::NORMAL,
);
@@ -147,8 +150,8 @@ pub trait VcsDownloader:
.collect(),
)) > 0
{
- self.io_mut().write_error(
- PhpMixed::String(" Failed, trying the next URL".to_string()),
+ self.io_mut().write_error3(
+ " Failed, trying the next URL",
true,
io_interface::NORMAL,
);
@@ -180,7 +183,7 @@ pub trait VcsDownloader:
self.has_cleaned_changes_mut()
.insert(prev_package.unwrap().get_unique_name(), true);
} else if r#type == "install" {
- self.filesystem_mut().empty_directory(path);
+ self.filesystem_mut().borrow_mut().empty_directory(path);
} else if r#type == "uninstall" {
self.clean_changes(package, path, false)?;
}
@@ -227,11 +230,8 @@ pub trait VcsDownloader:
.into());
}
- self.io_mut().write_error(
- PhpMixed::String(format!(
- " - {}: ",
- InstallOperation::format(package, false)
- )),
+ self.io_mut().write_error3(
+ &format!(" - {}: ", InstallOperation::format(package, false)),
false,
io_interface::NORMAL,
);
@@ -250,8 +250,8 @@ pub trait VcsDownloader:
return Err(e);
}
if self.io().is_debug() {
- self.io_mut().write_error(
- PhpMixed::String(format!("Failed: [{}] {}", get_class(&e), e,)),
+ self.io_mut().write_error3(
+ &format!("Failed: [{}] {}", get_class(&e), e,),
true,
io_interface::NORMAL,
);
@@ -261,8 +261,8 @@ pub trait VcsDownloader:
.collect(),
)) > 0
{
- self.io_mut().write_error(
- PhpMixed::String(" Failed, trying the next URL".to_string()),
+ self.io_mut().write_error3(
+ " Failed, trying the next URL",
true,
io_interface::NORMAL,
);
@@ -299,11 +299,8 @@ pub trait VcsDownloader:
.into());
}
- self.io_mut().write_error(
- PhpMixed::String(format!(
- " - {}: ",
- UpdateOperation::format(initial, target, false),
- )),
+ self.io_mut().write_error3(
+ &format!(" - {}: ", UpdateOperation::format(initial, target, false),),
false,
io_interface::NORMAL,
);
@@ -328,8 +325,8 @@ pub trait VcsDownloader:
return Err(e);
}
if self.io().is_debug() {
- self.io_mut().write_error(
- PhpMixed::String(format!("Failed: [{}] {}", get_class(&e), e,)),
+ self.io_mut().write_error3(
+ &format!("Failed: [{}] {}", get_class(&e), e,),
true,
io_interface::NORMAL,
);
@@ -339,8 +336,8 @@ pub trait VcsDownloader:
.collect(),
)) > 0
{
- self.io_mut().write_error(
- PhpMixed::String(" Failed, trying the next URL".to_string()),
+ self.io_mut().write_error3(
+ " Failed, trying the next URL",
true,
io_interface::NORMAL,
);
@@ -379,11 +376,8 @@ pub trait VcsDownloader:
// escape angle brackets for proper output in the console
logs = str_replace("<", "\\<", &logs);
- self.io_mut().write_error(
- PhpMixed::String(format!(" {}", message)),
- true,
- io_interface::NORMAL,
- );
+ self.io_mut()
+ .write_error3(&format!(" {}", message), true, io_interface::NORMAL);
self.io_mut()
.write_error3(&logs, true, io_interface::NORMAL);
}
@@ -403,16 +397,16 @@ pub trait VcsDownloader:
package: &dyn PackageInterface,
path: &str,
) -> Result<Box<dyn PromiseInterface>> {
- self.io_mut().write_error(
- PhpMixed::String(format!(
- " - {}",
- UninstallOperation::format(package, false)
- )),
+ self.io_mut().write_error3(
+ &format!(" - {}", UninstallOperation::format(package, false)),
true,
io_interface::NORMAL,
);
- let promise = self.filesystem_mut().remove_directory_async(path);
+ let promise = self
+ .filesystem_mut()
+ .borrow_mut()
+ .remove_directory_async(path);
let path = path.to_string();
Ok(
@@ -432,7 +426,12 @@ pub trait VcsDownloader:
fn get_vcs_reference(&self, package: &dyn PackageInterface, path: &str) -> Option<String> {
let parser = VersionParser::new();
- let guesser = VersionGuesser::new(self.config(), self.process(), &parser, self.io());
+ let guesser = VersionGuesser::new(
+ std::rc::Rc::clone(self.config()),
+ std::rc::Rc::clone(self.process()),
+ parser.clone(),
+ Some(self.io().clone_box()),
+ );
let dumper = ArrayDumper::new();
let package_config = dumper.dump(package);
diff --git a/crates/shirabe/src/downloader/xz_downloader.rs b/crates/shirabe/src/downloader/xz_downloader.rs
index 61a7f14..99c29d3 100644
--- a/crates/shirabe/src/downloader/xz_downloader.rs
+++ b/crates/shirabe/src/downloader/xz_downloader.rs
@@ -24,12 +24,12 @@ pub struct XzDownloader {
impl XzDownloader {
pub fn new(
io: Box<dyn IOInterface>,
- config: Config,
- http_downloader: HttpDownloader,
+ config: std::rc::Rc<std::cell::RefCell<Config>>,
+ http_downloader: std::rc::Rc<std::cell::RefCell<HttpDownloader>>,
event_dispatcher: Option<EventDispatcher>,
cache: Option<Cache>,
- filesystem: Filesystem,
- process: ProcessExecutor,
+ filesystem: std::rc::Rc<std::cell::RefCell<Filesystem>>,
+ process: std::rc::Rc<std::cell::RefCell<ProcessExecutor>>,
) -> Self {
Self {
inner: FileDownloader::new(
@@ -54,7 +54,7 @@ impl XzDownloader {
let command = vec!["tar", "-xJf", file, "-C", path];
let mut ignored_output = PhpMixed::Null;
- if self.inner.process.execute(
+ if self.inner.process.borrow_mut().execute(
PhpMixed::List(
command
.iter()
@@ -71,7 +71,7 @@ impl XzDownloader {
let process_error = format!(
"Failed to execute {}\n\n{}",
command.join(" "),
- self.inner.process.get_error_output()
+ self.inner.process.borrow().get_error_output()
);
bail!(process_error);
diff --git a/crates/shirabe/src/downloader/zip_downloader.rs b/crates/shirabe/src/downloader/zip_downloader.rs
index 7f779c8..bfaf180 100644
--- a/crates/shirabe/src/downloader/zip_downloader.rs
+++ b/crates/shirabe/src/downloader/zip_downloader.rs
@@ -7,7 +7,7 @@ use crate::util::ini_helper::IniHelper;
use crate::util::platform::Platform;
use anyhow::Result;
use indexmap::IndexMap;
-use shirabe_external_packages::composer::pcre::preg::Preg;
+use shirabe_external_packages::composer::pcre::preg::{CaptureKey, Preg};
use shirabe_external_packages::react::promise::promise_interface::PromiseInterface;
use shirabe_external_packages::symfony::component::process::executable_finder::ExecutableFinder;
use shirabe_external_packages::symfony::component::process::process::Process;
@@ -164,9 +164,7 @@ impl ZipDownloader {
}
}
- self.inner
- .inner
- .download(package, path, prev_package, output)
+ self.inner.download(package, path, prev_package, output)
}
fn extract_with_system_unzip(
@@ -217,18 +215,23 @@ impl ZipDownloader {
let mut output = String::new();
if self
.inner
- .inner
.process
.execute(&[command_spec[1].as_str()], &mut output)
== 0
{
- if let Some(m) =
- Preg::is_match_strict_groups(r"^\s*7-Zip(?:\s\[64\])?\s([0-9.]+)", &output)
+ let mut m: IndexMap<CaptureKey, String> = IndexMap::new();
+ if Preg::is_match_strict_groups3(
+ r"^\s*7-Zip(?:\s\[64\])?\s([0-9.]+)",
+ &output,
+ Some(&mut m),
+ )
+ .unwrap_or(false)
{
- if version_compare(&m[1], "21.01", "<") {
+ let m1 = m.get(&CaptureKey::ByIndex(1)).cloned().unwrap_or_default();
+ if version_compare(&m1, "21.01", "<") {
self.inner.io.write_error(&format!(
" <warning>Unzipping using {} {} may result in incorrect file permissions. Install {} 21.01+ or unzip to ensure you get correct permissions.</warning>",
- executable, m[1], executable,
+ executable, m1, executable,
));
}
}
@@ -281,7 +284,6 @@ impl ZipDownloader {
io.write_error(&format!(
"Origin URL: {}",
self.inner
- .inner
.process_url(package, &package.get_dist_url().unwrap_or_default())
));
let headers = FileDownloader::response_headers.lock().unwrap();
@@ -297,7 +299,7 @@ impl ZipDownloader {
self.extract_with_zip_archive(package, file, path)
};
- match self.inner.process.execute_async(&command) {
+ match self.inner.process.borrow_mut().execute_async(&command) {
Ok(promise) => Ok(promise.then(
Box::new(move |process: Process| -> Result<()> {
if !process.is_successful() {