aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/src/repository/vcs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/shirabe/src/repository/vcs')
-rw-r--r--crates/shirabe/src/repository/vcs/forgejo_driver.rs46
-rw-r--r--crates/shirabe/src/repository/vcs/fossil_driver.rs58
-rw-r--r--crates/shirabe/src/repository/vcs/git_bitbucket_driver.rs46
-rw-r--r--crates/shirabe/src/repository/vcs/git_driver.rs108
-rw-r--r--crates/shirabe/src/repository/vcs/github_driver.rs202
-rw-r--r--crates/shirabe/src/repository/vcs/gitlab_driver.rs165
-rw-r--r--crates/shirabe/src/repository/vcs/hg_driver.rs55
-rw-r--r--crates/shirabe/src/repository/vcs/perforce_driver.rs1
-rw-r--r--crates/shirabe/src/repository/vcs/svn_driver.rs132
-rw-r--r--crates/shirabe/src/repository/vcs/vcs_driver.rs65
-rw-r--r--crates/shirabe/src/repository/vcs/vcs_driver_interface.rs2
11 files changed, 569 insertions, 311 deletions
diff --git a/crates/shirabe/src/repository/vcs/forgejo_driver.rs b/crates/shirabe/src/repository/vcs/forgejo_driver.rs
index 2efbfb7..179f2db 100644
--- a/crates/shirabe/src/repository/vcs/forgejo_driver.rs
+++ b/crates/shirabe/src/repository/vcs/forgejo_driver.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_php_shim::{
PhpMixed, RuntimeException, base64_decode, explode, extension_loaded, urlencode,
};
@@ -15,6 +15,7 @@ use crate::io::io_interface::IOInterface;
use crate::json::json_file::JsonFile;
use crate::repository::vcs::git_driver::GitDriver;
use crate::repository::vcs::vcs_driver::VcsDriverBase;
+use crate::repository::vcs::vcs_driver_interface::VcsDriverInterface;
use crate::util::forgejo::Forgejo;
use crate::util::forgejo_repository_data::ForgejoRepositoryData;
use crate::util::forgejo_url::ForgejoUrl;
@@ -39,6 +40,7 @@ impl ForgejoDriver {
"{}/{}/{}/{}",
self.inner
.config
+ .borrow_mut()
.get("cache-repo-dir")
.as_string()
.unwrap_or(""),
@@ -53,6 +55,7 @@ impl ForgejoDriver {
c.set_read_only(
self.inner
.config
+ .borrow_mut()
.get("cache-read-only")
.as_bool()
.unwrap_or(false),
@@ -313,7 +316,7 @@ impl ForgejoDriver {
identifier: &str,
) -> Result<Option<IndexMap<String, PhpMixed>>> {
if let Some(ref mut git_driver) = self.git_driver {
- return git_driver.inner.get_composer_information(identifier);
+ return git_driver.get_composer_information(identifier);
}
if !self.inner.info_cache.contains_key(identifier) {
@@ -321,7 +324,12 @@ impl ForgejoDriver {
if let Some(res) = self.inner.cache.as_ref().and_then(|c| c.read(identifier)) {
JsonFile::parse_json(&res, None)?
} else {
- let c = self.inner.get_base_composer_information(identifier)?;
+ let file_content = self.get_file_content("composer.json", identifier)?;
+ let c = VcsDriverBase::finish_base_composer_information(
+ identifier,
+ file_content,
+ || self.get_change_date(identifier),
+ )?;
if self.inner.should_cache(identifier) {
if let Some(ref composer_map) = c {
let encoded = JsonFile::encode_with_options(
@@ -338,7 +346,10 @@ impl ForgejoDriver {
c
}
} else {
- self.inner.get_base_composer_information(identifier)?
+ let file_content = self.get_file_content("composer.json", identifier)?;
+ VcsDriverBase::finish_base_composer_information(identifier, file_content, || {
+ self.get_change_date(identifier)
+ })?
};
let mut composer = composer;
@@ -484,11 +495,11 @@ impl ForgejoDriver {
}
if !extension_loaded("openssl") {
- io.write_error(
- PhpMixed::String(format!(
+ io.write_error3(
+ &format!(
"Skipping Forgejo driver for {} because the OpenSSL PHP extension is missing.",
url
- )),
+ ),
true,
io_interface::VERBOSE,
);
@@ -510,7 +521,7 @@ impl ForgejoDriver {
todo!("clone io for GitDriver setup"),
self.inner.config.clone(),
self.inner.http_downloader.clone(),
- self.inner.process.clone(),
+ std::rc::Rc::clone(&self.inner.process),
),
tags: None,
branches: None,
@@ -556,8 +567,11 @@ impl ForgejoDriver {
let links = explode(",", &header);
for link in links {
- if let Some(m) = Preg::match_strict_groups(r#"{<(.+?)>; *rel="next"}"#, &link) {
- if let Some(url) = m.get("1") {
+ let mut m: IndexMap<CaptureKey, String> = IndexMap::new();
+ if Preg::match_strict_groups3(r#"{<(.+?)>; *rel="next"}"#, &link, Some(&mut m))
+ .unwrap_or(false)
+ {
+ if let Some(url) = m.get(&CaptureKey::ByIndex(1)) {
return Some(url.clone());
}
}
@@ -650,14 +664,10 @@ impl ForgejoDriver {
Ok(()) => Ok(true),
Err(e) => {
self.git_driver = None;
- self.inner.io.write_error(
- PhpMixed::String(format!(
- "<error>Failed to clone the {} repository, try running in interactive mode so that you can enter your Forgejo credentials</error>",
- ssh_url
- )),
- true,
- io_interface::NORMAL,
- );
+ self.inner.io.write_error3(&format!(
+ "<error>Failed to clone the {} repository, try running in interactive mode so that you can enter your Forgejo credentials</error>",
+ ssh_url
+ ), true, io_interface::NORMAL);
Err(e)
}
}
diff --git a/crates/shirabe/src/repository/vcs/fossil_driver.rs b/crates/shirabe/src/repository/vcs/fossil_driver.rs
index a765c4c..f0c3468 100644
--- a/crates/shirabe/src/repository/vcs/fossil_driver.rs
+++ b/crates/shirabe/src/repository/vcs/fossil_driver.rs
@@ -29,9 +29,11 @@ impl FossilDriver {
self.check_fossil()?;
// Ensure we are allowed to use this URL by config.
- self.inner
- .config
- .prohibit_url_by_config(&self.inner.url, &*self.inner.io)?;
+ self.inner.config.borrow_mut().prohibit_url_by_config(
+ &self.inner.url,
+ Some(&*self.inner.io),
+ &indexmap::IndexMap::new(),
+ )?;
// Only if url points to a locally accessible directory, assume it's the checkout directory.
// Otherwise, it should be something fossil can clone from.
@@ -41,6 +43,7 @@ impl FossilDriver {
let cache_repo_dir = self
.inner
.config
+ .borrow_mut()
.get("cache-repo-dir")
.as_string()
.unwrap_or("")
@@ -48,6 +51,7 @@ impl FossilDriver {
let cache_vcs_dir = self
.inner
.config
+ .borrow_mut()
.get("cache-vcs-dir")
.as_string()
.unwrap_or("")
@@ -60,7 +64,7 @@ impl FossilDriver {
.into());
}
- let local_name = Preg::replace(r"{[^a-z0-9]}i", "-", self.inner.url.clone());
+ let local_name = Preg::replace(r"{[^a-z0-9]}i", "-", &self.inner.url);
self.repo_file = Some(format!("{}/{}.fossil", cache_repo_dir, local_name));
self.checkout_dir = format!("{}/{}/", cache_vcs_dir, local_name);
@@ -75,7 +79,7 @@ impl FossilDriver {
pub(crate) fn check_fossil(&self) -> anyhow::Result<()> {
let mut ignored_output = String::new();
- if self.inner.process.execute(
+ if self.inner.process.borrow_mut().execute_args(
&["fossil", "version"].map(|s| s.to_string()).to_vec(),
&mut ignored_output,
None,
@@ -84,7 +88,7 @@ impl FossilDriver {
return Err(RuntimeException {
message: format!(
"fossil was not found, check that it is installed and in your PATH env.\n\n{}",
- self.inner.process.get_error_output()
+ self.inner.process.borrow().get_error_output()
),
code: 0,
}
@@ -115,27 +119,23 @@ impl FossilDriver {
// update the repo if it is a valid fossil repository
if is_file(&repo_file)
&& is_dir(&self.checkout_dir)
- && self.inner.process.execute(
+ && self.inner.process.borrow_mut().execute_args(
&["fossil", "info"].map(|s| s.to_string()).to_vec(),
&mut String::new(),
Some(self.checkout_dir.clone()),
) == 0
{
- if self.inner.process.execute(
+ if self.inner.process.borrow_mut().execute_args(
&["fossil", "pull"].map(|s| s.to_string()).to_vec(),
&mut String::new(),
Some(self.checkout_dir.clone()),
) != 0
{
- self.inner.io.write_error(
- PhpMixed::String(format!(
- "<error>Failed to update {}, package information from this repository may be outdated ({})</error>",
- self.inner.url,
- self.inner.process.get_error_output()
- )),
- true,
- io_interface::NORMAL,
- );
+ self.inner.io.write_error3(&format!(
+ "<error>Failed to update {}, package information from this repository may be outdated ({})</error>",
+ self.inner.url,
+ self.inner.process.borrow().get_error_output()
+ ), true, io_interface::NORMAL);
}
} else {
// clean up directory and do a fresh clone into it
@@ -144,7 +144,7 @@ impl FossilDriver {
fs.ensure_directory_exists(&self.checkout_dir)?;
let mut output = String::new();
- if self.inner.process.execute(
+ if self.inner.process.borrow_mut().execute_args(
&["fossil", "clone", "--", &self.inner.url, &repo_file]
.map(|s| s.to_string())
.to_vec(),
@@ -152,7 +152,7 @@ impl FossilDriver {
None,
) != 0
{
- let output = self.inner.process.get_error_output();
+ let output = self.inner.process.borrow().get_error_output();
return Err(RuntimeException {
message: format!(
"Failed to clone {} to repository {}\n\n{}",
@@ -163,7 +163,7 @@ impl FossilDriver {
.into());
}
- if self.inner.process.execute(
+ if self.inner.process.borrow_mut().execute_args(
&["fossil", "open", "--nested", "--", &repo_file]
.map(|s| s.to_string())
.to_vec(),
@@ -171,7 +171,7 @@ impl FossilDriver {
Some(self.checkout_dir.clone()),
) != 0
{
- let output = self.inner.process.get_error_output();
+ let output = self.inner.process.borrow().get_error_output();
return Err(RuntimeException {
message: format!(
"Failed to open repository {} in {}\n\n{}",
@@ -222,7 +222,7 @@ impl FossilDriver {
}
let mut content = String::new();
- self.inner.process.execute(
+ self.inner.process.borrow_mut().execute_args(
&["fossil", "cat", "-r", identifier, "--", file]
.map(|s| s.to_string())
.to_vec(),
@@ -239,7 +239,7 @@ impl FossilDriver {
pub fn get_change_date(&self, _identifier: &str) -> anyhow::Result<Option<DateTime<Utc>>> {
let mut output = String::new();
- self.inner.process.execute(
+ self.inner.process.borrow_mut().execute_args(
&["fossil", "finfo", "-b", "-n", "1", "composer.json"]
.map(|s| s.to_string())
.to_vec(),
@@ -257,12 +257,12 @@ impl FossilDriver {
if self.tags.is_none() {
let mut tags: IndexMap<String, String> = IndexMap::new();
let mut output = String::new();
- self.inner.process.execute(
+ self.inner.process.borrow_mut().execute_args(
&["fossil", "tag", "list"].map(|s| s.to_string()).to_vec(),
&mut output,
Some(self.checkout_dir.clone()),
);
- for tag in self.inner.process.split_lines(&output) {
+ for tag in self.inner.process.borrow().split_lines(&output) {
tags.insert(tag.clone(), tag);
}
self.tags = Some(tags);
@@ -274,13 +274,13 @@ impl FossilDriver {
if self.branches.is_none() {
let mut branches: IndexMap<String, String> = IndexMap::new();
let mut output = String::new();
- self.inner.process.execute(
+ self.inner.process.borrow_mut().execute_args(
&["fossil", "branch", "list"].map(|s| s.to_string()).to_vec(),
&mut output,
Some(self.checkout_dir.clone()),
);
- for branch in self.inner.process.split_lines(&output) {
- let branch = Preg::replace(r"/^\*/", "", branch.trim().to_string());
+ for branch in self.inner.process.borrow().split_lines(&output) {
+ let branch = Preg::replace(r"/^\*/", "", &branch.trim());
let branch = branch.trim().to_string();
branches.insert(branch.clone(), branch);
}
@@ -312,7 +312,7 @@ impl FossilDriver {
let process = ProcessExecutor::new(io);
let mut output = String::new();
- if process.execute(
+ if process.execute_args(
&["fossil", "info"].map(|s| s.to_string()).to_vec(),
&mut output,
Some(url),
diff --git a/crates/shirabe/src/repository/vcs/git_bitbucket_driver.rs b/crates/shirabe/src/repository/vcs/git_bitbucket_driver.rs
index 05e7c61..689c0e8 100644
--- a/crates/shirabe/src/repository/vcs/git_bitbucket_driver.rs
+++ b/crates/shirabe/src/repository/vcs/git_bitbucket_driver.rs
@@ -4,7 +4,7 @@ use crate::io::io_interface;
use anyhow::Result;
use chrono::{DateTime, Utc};
use indexmap::IndexMap;
-use shirabe_external_packages::composer::pcre::preg::Preg;
+use shirabe_external_packages::composer::pcre::preg::{CaptureKey, Preg};
use shirabe_php_shim::{
InvalidArgumentException, LogicException, PhpMixed, RuntimeException, array_key_exists,
array_search_mixed, extension_loaded, http_build_query_mixed, implode, in_array, is_array,
@@ -58,11 +58,14 @@ pub struct GitBitbucketDriver {
impl GitBitbucketDriver {
/// @inheritDoc
pub fn initialize(&mut self) -> Result<()> {
- let matched = Preg::is_match_strict_groups(
+ let mut m: indexmap::IndexMap<CaptureKey, String> = indexmap::IndexMap::new();
+ if !Preg::is_match_strict_groups3(
r"#^https?://bitbucket\.org/([^/]+)/([^/]+?)(?:\.git|/?)?$#i",
&self.inner.url,
- );
- if matched.is_none() {
+ Some(&mut m),
+ )
+ .unwrap_or(false)
+ {
return Err(InvalidArgumentException {
message: sprintf(
"The Bitbucket repository URL %s is invalid. It must be the HTTPS URL of a Bitbucket repository.",
@@ -72,10 +75,9 @@ impl GitBitbucketDriver {
}
.into());
}
- let m = matched.unwrap();
- self.owner = m.get(1).cloned().unwrap_or_default();
- self.repository = m.get(2).cloned().unwrap_or_default();
+ self.owner = m.get(&CaptureKey::ByIndex(1)).cloned().unwrap_or_default();
+ self.repository = m.get(&CaptureKey::ByIndex(2)).cloned().unwrap_or_default();
self.inner.origin_url = "bitbucket.org".to_string();
self.inner.cache = Some(Cache::new(
&*self.inner.io,
@@ -84,6 +86,7 @@ impl GitBitbucketDriver {
&[
self.inner
.config
+ .borrow_mut()
.get("cache-repo-dir")
.as_string()
.unwrap_or("")
@@ -98,6 +101,7 @@ impl GitBitbucketDriver {
self.inner.cache.as_mut().unwrap().set_read_only(
self.inner
.config
+ .borrow_mut()
.get("cache-read-only")
.as_bool()
.unwrap_or(false),
@@ -236,7 +240,12 @@ impl GitBitbucketDriver {
} {
// composer already set above
} else {
- composer = self.inner.get_base_composer_information(identifier)?;
+ let file_content = self.get_file_content("composer.json", identifier)?;
+ composer = VcsDriverBase::finish_base_composer_information(
+ identifier,
+ file_content,
+ || self.get_change_date(identifier),
+ )?;
if self.inner.should_cache(identifier) {
self.inner.cache.as_ref().unwrap().write(
@@ -664,16 +673,17 @@ impl GitBitbucketDriver {
url: &str,
fetching_repo_data: bool,
) -> Result<Response> {
- match self.inner.get_contents(url, false) {
+ match self.inner.get_contents(url) {
Ok(r) => Ok(r),
Err(e) => {
// TODO(phase-b): only handle TransportException
- let bitbucket_util = Bitbucket::new(
- &*self.inner.io,
- &self.inner.config,
- Some(self.inner.process.clone()),
- Some(self.inner.http_downloader.clone()),
- );
+ let mut bitbucket_util = Bitbucket::new(
+ self.inner.io.clone_box(),
+ std::rc::Rc::clone(&self.inner.config),
+ Some(std::rc::Rc::clone(&self.inner.process)),
+ Some(std::rc::Rc::clone(&self.inner.http_downloader)),
+ None,
+ )?;
if let Some(te) = e.downcast_ref::<TransportException>() {
let code = te.get_code();
@@ -693,7 +703,7 @@ impl GitBitbucketDriver {
if !self.inner.io.has_authentication(&self.inner.origin_url)
&& bitbucket_util.authorize_oauth(&self.inner.origin_url)
{
- return self.inner.get_contents(url, false);
+ return self.inner.get_contents(url);
}
if !self.inner.io.is_interactive() && fetching_repo_data {
@@ -833,7 +843,9 @@ impl GitBitbucketDriver {
if !Preg::is_match(
r"#^https?://bitbucket\.org/([^/]+)/([^/]+?)(\.git|/?)?$#i",
url,
- ) {
+ )
+ .unwrap_or(false)
+ {
return false;
}
diff --git a/crates/shirabe/src/repository/vcs/git_driver.rs b/crates/shirabe/src/repository/vcs/git_driver.rs
index 33474b1..07836bf 100644
--- a/crates/shirabe/src/repository/vcs/git_driver.rs
+++ b/crates/shirabe/src/repository/vcs/git_driver.rs
@@ -4,7 +4,7 @@ use crate::io::io_interface;
use chrono::TimeZone;
use chrono::{DateTime, Utc};
use indexmap::IndexMap;
-use shirabe_external_packages::composer::pcre::preg::Preg;
+use shirabe_external_packages::composer::pcre::preg::{CaptureKey, Preg};
use shirabe_php_shim::{
InvalidArgumentException, RuntimeException, dirname, is_dir, is_writable, realpath,
sys_get_temp_dir,
@@ -32,7 +32,7 @@ impl GitDriver {
pub fn initialize(&mut self) -> anyhow::Result<()> {
let cache_url;
if Filesystem::is_local_path(&self.inner.url) {
- self.inner.url = Preg::replace(r"{[\\/]\.git/?$}", "", self.inner.url.clone())?;
+ self.inner.url = Preg::replace(r"{[\\/]\.git/?$}", "", &self.inner.url)?;
if !is_dir(&self.inner.url) {
return Err(RuntimeException {
message: format!(
@@ -49,6 +49,7 @@ impl GitDriver {
let cache_vcs_dir = self
.inner
.config
+ .borrow_mut()
.get("cache-vcs-dir")
.as_string()
.unwrap_or("")
@@ -97,9 +98,9 @@ impl GitDriver {
let git_util = GitUtil::new(
&*self.inner.io,
- &self.inner.config,
- &self.inner.process,
- &Filesystem::new(None),
+ std::rc::Rc::clone(&self.inner.config),
+ std::rc::Rc::clone(&self.inner.process),
+ std::rc::Rc::new(std::cell::RefCell::new(Filesystem::new(None))),
);
if !git_util.sync_mirror(&self.inner.url, &self.repo_dir)? {
if !is_dir(&self.repo_dir) {
@@ -112,14 +113,10 @@ impl GitDriver {
}
.into());
}
- self.inner.io.write_error(
- shirabe_php_shim::PhpMixed::String(format!(
- "<error>Failed to update {}, package information from this repository may be outdated</error>",
- self.inner.url
- )),
- true,
- io_interface::NORMAL,
- );
+ self.inner.io.write_error3(shirabe_php_shim::PhpMixed::String(format!(
+ "<error>Failed to update {}, package information from this repository may be outdated</error>",
+ self.inner.url
+ )), true, io_interface::NORMAL);
}
cache_url = self.inner.url.clone();
@@ -131,6 +128,7 @@ impl GitDriver {
let cache_repo_dir = self
.inner
.config
+ .borrow_mut()
.get("cache-repo-dir")
.as_string()
.unwrap_or("")
@@ -147,6 +145,7 @@ impl GitDriver {
c.set_read_only(
self.inner
.config
+ .borrow_mut()
.get("cache-read-only")
.as_bool()
.unwrap_or(false),
@@ -162,9 +161,9 @@ impl GitDriver {
let git_util = GitUtil::new(
&*self.inner.io,
- &self.inner.config,
- &self.inner.process,
- &Filesystem::new(None),
+ std::rc::Rc::clone(&self.inner.config),
+ std::rc::Rc::clone(&self.inner.process),
+ std::rc::Rc::new(std::cell::RefCell::new(Filesystem::new(None))),
);
if !Filesystem::is_local_path(&self.inner.url) {
let default_branch =
@@ -176,7 +175,7 @@ impl GitDriver {
}
let mut output = String::new();
- self.inner.process.execute(
+ self.inner.process.borrow_mut().execute_args(
&[
"git".to_string(),
"branch".to_string(),
@@ -185,12 +184,15 @@ impl GitDriver {
&mut output,
Some(self.repo_dir.clone()),
);
- let branches = self.inner.process.split_lines(&output);
+ let branches = self.inner.process.borrow().split_lines(&output);
if !branches.contains(&"* master".to_string()) {
for branch in &branches {
if !branch.is_empty() {
- if let Some(caps) = Preg::match_strict_groups(r"{^\* +(\S+)}", branch) {
- if let Some(name) = caps.get("1") {
+ let mut caps: IndexMap<CaptureKey, String> = IndexMap::new();
+ if Preg::match_strict_groups3(r"{^\* +(\S+)}", branch, Some(&mut caps))
+ .unwrap_or(false)
+ {
+ if let Some(name) = caps.get(&CaptureKey::ByIndex(1)) {
self.root_identifier = Some(name.clone());
break;
}
@@ -236,7 +238,7 @@ impl GitDriver {
}
let mut content = String::new();
- self.inner.process.execute(
+ self.inner.process.borrow_mut().execute_args(
&[
"git".to_string(),
"show".to_string(),
@@ -274,9 +276,11 @@ impl GitDriver {
],
);
let mut output = String::new();
- self.inner
- .process
- .execute(&command, &mut output, Some(self.repo_dir.clone()));
+ self.inner.process.borrow_mut().execute_args(
+ &command,
+ &mut output,
+ Some(self.repo_dir.clone()),
+ );
let timestamp_str = GitUtil::parse_rev_list_output(&output, &self.inner.process);
let timestamp: i64 = timestamp_str.trim().parse().unwrap_or(0);
@@ -288,7 +292,7 @@ impl GitDriver {
self.tags = Some(IndexMap::new());
let mut output = String::new();
- self.inner.process.execute(
+ self.inner.process.borrow_mut().execute_args(
&[
"git".to_string(),
"show-ref".to_string(),
@@ -298,13 +302,20 @@ impl GitDriver {
&mut output,
Some(self.repo_dir.clone()),
);
- for tag in self.inner.process.split_lines(&output) {
+ for tag in self.inner.process.borrow().split_lines(&output) {
if !tag.is_empty() {
- if let Some(caps) = Preg::match_strict_groups(
+ let mut caps: IndexMap<CaptureKey, String> = IndexMap::new();
+ if Preg::match_strict_groups3(
r"{^([a-f0-9]{40}) refs/tags/(\S+?)(\^\{\})?$}",
&tag,
- ) {
- if let (Some(hash), Some(name)) = (caps.get("1"), caps.get("2")) {
+ Some(&mut caps),
+ )
+ .unwrap_or(false)
+ {
+ if let (Some(hash), Some(name)) = (
+ caps.get(&CaptureKey::ByIndex(1)),
+ caps.get(&CaptureKey::ByIndex(2)),
+ ) {
self.tags
.as_mut()
.unwrap()
@@ -323,7 +334,7 @@ impl GitDriver {
let mut branches = IndexMap::new();
let mut output = String::new();
- self.inner.process.execute(
+ self.inner.process.borrow_mut().execute_args(
&[
"git".to_string(),
"branch".to_string(),
@@ -334,15 +345,22 @@ impl GitDriver {
&mut output,
Some(self.repo_dir.clone()),
);
- for branch in self.inner.process.split_lines(&output) {
+ for branch in self.inner.process.borrow().split_lines(&output) {
if !branch.is_empty()
&& !Preg::is_match(r"{^ *[^/]+/HEAD }", &branch).unwrap_or(false)
{
- if let Some(caps) = Preg::match_strict_groups(
+ let mut caps: IndexMap<CaptureKey, String> = IndexMap::new();
+ if Preg::match_strict_groups3(
r"{^(?:\* )? *(\S+) *([a-f0-9]+)(?: .*)?$}",
&branch,
- ) {
- if let (Some(name), Some(hash)) = (caps.get("1"), caps.get("2")) {
+ Some(&mut caps),
+ )
+ .unwrap_or(false)
+ {
+ if let (Some(name), Some(hash)) = (
+ caps.get(&CaptureKey::ByIndex(1)),
+ caps.get(&CaptureKey::ByIndex(2)),
+ ) {
if !name.starts_with('-') {
branches.insert(name.clone(), hash.clone());
}
@@ -378,9 +396,9 @@ impl GitDriver {
return Ok(false);
}
- let process = ProcessExecutor::new(io);
+ let process = std::rc::Rc::new(std::cell::RefCell::new(ProcessExecutor::new(io)));
let mut output = String::new();
- if process.execute(
+ if process.borrow_mut().execute_args(
&["git".to_string(), "tag".to_string()],
&mut output,
Some(url.clone()),
@@ -388,15 +406,27 @@ impl GitDriver {
{
return Ok(true);
}
- GitUtil::check_for_repo_ownership_error(&process.get_error_output(), &url);
+ GitUtil::check_for_repo_ownership_error(&process.borrow().get_error_output(), &url);
}
if !deep {
return Ok(false);
}
- let process = ProcessExecutor::new(io);
- let git_util = GitUtil::new(io, _config, &process, &Filesystem::new(None));
+ let process = std::rc::Rc::new(std::cell::RefCell::new(ProcessExecutor::new(io)));
+ // TODO(phase-b): supports() takes &Config; GitUtil now needs Rc<RefCell<Config>>.
+ // Skipping clean Rc construction since we cannot reconstruct one from a borrowed &Config.
+ let _ = _config;
+ return Err(anyhow::anyhow!(
+ "GitDriver::supports requires Rc<RefCell<Config>>: not yet ported"
+ ));
+ #[allow(unreachable_code)]
+ let git_util = GitUtil::new(
+ io.clone_box(),
+ todo!(),
+ std::rc::Rc::clone(&process),
+ std::rc::Rc::new(std::cell::RefCell::new(Filesystem::new(None))),
+ );
GitUtil::clean_env(&process);
let result = git_util.run_commands(
diff --git a/crates/shirabe/src/repository/vcs/github_driver.rs b/crates/shirabe/src/repository/vcs/github_driver.rs
index 7bf15bf..93bfcdb 100644
--- a/crates/shirabe/src/repository/vcs/github_driver.rs
+++ b/crates/shirabe/src/repository/vcs/github_driver.rs
@@ -4,7 +4,7 @@ use crate::io::io_interface;
use anyhow::Result;
use chrono::{DateTime, Utc};
use indexmap::IndexMap;
-use shirabe_external_packages::composer::pcre::preg::Preg;
+use shirabe_external_packages::composer::pcre::preg::{CaptureKey, Preg};
use shirabe_php_shim::{
InvalidArgumentException, PhpMixed, RuntimeException, array_diff, array_key_exists, array_map,
array_search_mixed, base64_decode, basename, count, empty, explode, extension_loaded, in_array,
@@ -18,6 +18,7 @@ use crate::io::io_interface::IOInterface;
use crate::json::json_file::JsonFile;
use crate::repository::vcs::git_driver::GitDriver;
use crate::repository::vcs::vcs_driver::VcsDriverBase;
+use crate::repository::vcs::vcs_driver_interface::VcsDriverInterface;
use crate::util::github::GitHub;
use crate::util::http::response::Response;
@@ -45,31 +46,43 @@ pub struct GitHubDriver {
impl GitHubDriver {
pub fn initialize(&mut self) -> Result<()> {
- let match_ = match Preg::is_match_strict_groups(
+ let mut match_: IndexMap<CaptureKey, String> = IndexMap::new();
+ if !Preg::is_match_strict_groups3(
r"#^(?:(?:https?|git)://([^/]+)/|git@([^:]+):/?)([^/]+)/([^/]+?)(?:\.git|/)?$#",
&self.inner.url,
- ) {
- Some(m) => m,
- None => {
- return Err(InvalidArgumentException {
- message: sprintf(
- "The GitHub repository URL %s is invalid.",
- &[PhpMixed::String(self.inner.url.clone())],
- ),
- code: 0,
- }
- .into());
+ Some(&mut match_),
+ )
+ .unwrap_or(false)
+ {
+ return Err(InvalidArgumentException {
+ message: sprintf(
+ "The GitHub repository URL %s is invalid.",
+ &[PhpMixed::String(self.inner.url.clone())],
+ ),
+ code: 0,
}
- };
+ .into());
+ }
- self.owner = match_.get(3).cloned().unwrap_or_default();
- self.repository = match_.get(4).cloned().unwrap_or_default();
+ self.owner = match_
+ .get(&CaptureKey::ByIndex(3))
+ .cloned()
+ .unwrap_or_default();
+ self.repository = match_
+ .get(&CaptureKey::ByIndex(4))
+ .cloned()
+ .unwrap_or_default();
self.inner.origin_url = strtolower(
&match_
- .get(1)
+ .get(&CaptureKey::ByIndex(1))
.cloned()
.filter(|s| !s.is_empty())
- .unwrap_or_else(|| match_.get(2).cloned().unwrap_or_default()),
+ .unwrap_or_else(|| {
+ match_
+ .get(&CaptureKey::ByIndex(2))
+ .cloned()
+ .unwrap_or_default()
+ }),
);
if self.inner.origin_url == "www.github.com" {
self.inner.origin_url = "github.com".to_string();
@@ -80,6 +93,7 @@ impl GitHubDriver {
"{}/{}/{}/{}",
self.inner
.config
+ .borrow_mut()
.get("cache-repo-dir")
.as_string()
.unwrap_or(""),
@@ -95,6 +109,7 @@ impl GitHubDriver {
c.set_read_only(
self.inner
.config
+ .borrow_mut()
.get("cache-read-only")
.as_bool()
.unwrap_or(false),
@@ -111,7 +126,13 @@ impl GitHubDriver {
self.allow_git_fallback = false;
}
- if self.inner.config.get("use-github-api").as_bool() == Some(false)
+ if self
+ .inner
+ .config
+ .borrow_mut()
+ .get("use-github-api")
+ .as_bool()
+ == Some(false)
|| self
.inner
.repo_config
@@ -230,7 +251,12 @@ impl GitHubDriver {
.unwrap_or_default();
JsonFile::parse_json(&res, None)?
} else {
- let composer = self.inner.get_base_composer_information(identifier)?;
+ let file_content = self.get_file_content("composer.json", identifier)?;
+ let composer = VcsDriverBase::finish_base_composer_information(
+ identifier,
+ file_content,
+ || self.get_change_date(identifier),
+ )?;
if self.inner.should_cache(identifier) {
if let Some(ref composer_map) = composer {
@@ -384,7 +410,7 @@ impl GitHubDriver {
] {
let mut options: IndexMap<String, PhpMixed> = IndexMap::new();
options.insert("retry-auth-failure".to_string(), PhpMixed::Bool(false));
- let response = self.inner.http_downloader.get(
+ let response = self.inner.http_downloader.borrow_mut().get(
file_url,
&PhpMixed::Array(options.into_iter().map(|(k, v)| (k, Box::new(v))).collect()),
);
@@ -436,20 +462,26 @@ impl GitHubDriver {
let mut result: Vec<IndexMap<String, PhpMixed>> = vec![];
let mut key: Option<String> = None;
- for line in Preg::split(r"{\r?\n}", &funding) {
+ for line in Preg::split(r"{\r?\n}", &funding).unwrap_or_default() {
let line = trim(&line, None);
- if let Some(m) = Preg::is_match_strict_groups(r"{^(\w+)\s*:\s*(.+)$}", &line) {
- let g1 = m.get(1).cloned().unwrap_or_default();
- let g2 = m.get(2).cloned().unwrap_or_default();
+ let mut m: IndexMap<CaptureKey, String> = IndexMap::new();
+ if Preg::is_match_strict_groups3(r"{^(\w+)\s*:\s*(.+)$}", &line, Some(&mut m))
+ .unwrap_or(false)
+ {
+ let g1 = m.get(&CaptureKey::ByIndex(1)).cloned().unwrap_or_default();
+ let g2 = m.get(&CaptureKey::ByIndex(2)).cloned().unwrap_or_default();
if g2 == "[" {
key = Some(g1);
continue;
}
- if let Some(m2) = Preg::is_match_strict_groups(r"{^\[(.*?)\](?:\s*#.*)?$}", &g2) {
- let inner = m2.get(1).cloned().unwrap_or_default();
+ let mut m2: IndexMap<CaptureKey, String> = IndexMap::new();
+ if Preg::is_match_strict_groups3(r"{^\[(.*?)\](?:\s*#.*)?$}", &g2, Some(&mut m2))
+ .unwrap_or(false)
+ {
+ let inner = m2.get(&CaptureKey::ByIndex(1)).cloned().unwrap_or_default();
for item in array_map(
|s: &String| trim(s, None),
- &Preg::split(r#"{[\'\"]?\s*,\s*[\'\"]?}"#, &inner),
+ &Preg::split(r#"{[\'\"]?\s*,\s*[\'\"]?}"#, &inner).unwrap_or_default(),
) {
let mut entry = IndexMap::new();
entry.insert("type".to_string(), PhpMixed::String(g1.clone()));
@@ -459,30 +491,40 @@ impl GitHubDriver {
);
result.push(entry);
}
- } else if let Some(m2) =
- Preg::is_match_strict_groups(r"{^([^#].*?)(?:\s+#.*)?$}", &g2)
+ } else if Preg::is_match_strict_groups3(
+ r"{^([^#].*?)(?:\s+#.*)?$}",
+ &g2,
+ Some(&mut m2),
+ )
+ .unwrap_or(false)
{
let mut entry = IndexMap::new();
entry.insert("type".to_string(), PhpMixed::String(g1.clone()));
entry.insert(
"url".to_string(),
PhpMixed::String(trim(
- &m2.get(1).cloned().unwrap_or_default(),
+ &m2.get(&CaptureKey::ByIndex(1)).cloned().unwrap_or_default(),
Some("\"' "),
)),
);
result.push(entry);
}
key = None;
- } else if let Some(m) = Preg::is_match_strict_groups(r"{^(\w+)\s*:\s*#\s*$}", &line) {
- key = Some(m.get(1).cloned().unwrap_or_default());
- } else if key.is_some()
- && (Preg::is_match_strict_groups(r"{^-\s*(.+)(?:\s+#.*)?$}", &line).is_some()
- || Preg::is_match_strict_groups(r"{^(.+),(?:\s*#.*)?$}", &line).is_some())
+ } else if Preg::is_match_strict_groups3(r"{^(\w+)\s*:\s*#\s*$}", &line, Some(&mut m))
+ .unwrap_or(false)
{
- let m = Preg::is_match_strict_groups(r"{^-\s*(.+)(?:\s+#.*)?$}", &line)
- .or_else(|| Preg::is_match_strict_groups(r"{^(.+),(?:\s*#.*)?$}", &line))
- .unwrap();
+ key = Some(m.get(&CaptureKey::ByIndex(1)).cloned().unwrap_or_default());
+ } else if key.is_some() && {
+ let mut tmp: IndexMap<CaptureKey, String> = IndexMap::new();
+ Preg::is_match_strict_groups3(r"{^-\s*(.+)(?:\s+#.*)?$}", &line, Some(&mut m))
+ .unwrap_or(false)
+ || Preg::is_match_strict_groups3(r"{^(.+),(?:\s*#.*)?$}", &line, Some(&mut tmp))
+ .unwrap_or(false)
+ && {
+ m = tmp;
+ true
+ }
+ } {
let mut entry = IndexMap::new();
entry.insert(
"type".to_string(),
@@ -490,7 +532,10 @@ impl GitHubDriver {
);
entry.insert(
"url".to_string(),
- PhpMixed::String(trim(&m.get(1).cloned().unwrap_or_default(), Some("\"' "))),
+ PhpMixed::String(trim(
+ &m.get(&CaptureKey::ByIndex(1)).cloned().unwrap_or_default(),
+ Some("\"' "),
+ )),
);
result.push(entry);
} else if key.is_some() && line == "]" {
@@ -623,11 +668,11 @@ impl GitHubDriver {
continue;
}
- self.inner.io.write_error(
- PhpMixed::String(format!(
+ self.inner.io.write_error3(
+ &format!(
"<warning>Funding URL {} not in a supported format.</warning>",
item_url
- )),
+ ),
true,
io_interface::NORMAL,
);
@@ -874,21 +919,31 @@ impl GitHubDriver {
}
pub fn supports(io: &dyn IOInterface, config: &Config, url: &str, _deep: bool) -> bool {
- let matches = match Preg::is_match_strict_groups(
+ let mut matches: IndexMap<CaptureKey, String> = IndexMap::new();
+ if !Preg::is_match_strict_groups3(
r"#^((?:https?|git)://([^/]+)/|git@([^:]+):/?)([^/]+)/([^/]+?)(?:\.git|/)?$#",
url,
- ) {
- Some(m) => m,
- None => return false,
- };
+ Some(&mut matches),
+ )
+ .unwrap_or(false)
+ {
+ return false;
+ }
let origin_url = matches
- .get(2)
+ .get(&CaptureKey::ByIndex(2))
.cloned()
.filter(|s| !s.is_empty())
- .unwrap_or_else(|| matches.get(3).cloned().unwrap_or_default());
+ .unwrap_or_else(|| {
+ matches
+ .get(&CaptureKey::ByIndex(3))
+ .cloned()
+ .unwrap_or_default()
+ });
if !in_array(
- PhpMixed::String(strtolower(&Preg::replace(r"{^www\.}i", "", origin_url))),
+ PhpMixed::String(strtolower(
+ &Preg::replace(r"{^www\.}i", "", &origin_url).unwrap_or_default(),
+ )),
&config.get("github-domains"),
false,
) {
@@ -896,11 +951,11 @@ impl GitHubDriver {
}
if !extension_loaded("openssl") {
- io.write_error(
- PhpMixed::String(format!(
+ io.write_error3(
+ &format!(
"Skipping GitHub driver for {} because the OpenSSL PHP extension is missing.",
url
- )),
+ ),
true,
io_interface::VERBOSE,
);
@@ -945,11 +1000,11 @@ impl GitHubDriver {
Ok(r) => Ok(r),
Err(e) => {
let mut git_hub_util = GitHub::new(
- self.inner.io.as_ref(),
- &self.inner.config,
- &self.inner.process,
- &self.inner.http_downloader,
- );
+ self.inner.io.clone_box(),
+ std::rc::Rc::clone(&self.inner.config),
+ Some(std::rc::Rc::clone(&self.inner.process)),
+ Some(std::rc::Rc::clone(&self.inner.http_downloader)),
+ )?;
match e.code {
401 | 404 => {
@@ -1057,11 +1112,11 @@ impl GitHubDriver {
if !self.inner.io.has_authentication(&self.inner.origin_url) {
if !self.inner.io.is_interactive() {
- self.inner.io.write_error(
- PhpMixed::String(format!(
+ self.inner.io.write_error3(
+ &format!(
"<error>GitHub API limit exhausted. Failed to get metadata for the {} repository, try running in interactive mode so that you can enter your GitHub credentials to increase the API limit</error>",
self.inner.url
- )),
+ ),
true,
io_interface::NORMAL,
);
@@ -1083,14 +1138,14 @@ impl GitHubDriver {
let rate_limit = git_hub_util.get_rate_limit(
e.get_headers().map(|h| h.as_slice()).unwrap_or(&[]),
);
- self.inner.io.write_error(
- PhpMixed::String(sprintf(
+ self.inner.io.write_error3(
+ &sprintf(
"<error>GitHub API limit (%d calls/hr) is exhausted. You are already authorized so you have to wait until %s before doing more requests</error>",
&[
rate_limit.get("limit").cloned().unwrap_or(PhpMixed::Null),
rate_limit.get("reset").cloned().unwrap_or(PhpMixed::Null),
],
- )),
+ ),
true,
io_interface::NORMAL,
);
@@ -1206,11 +1261,11 @@ impl GitHubDriver {
Err(setup_err) => {
self.git_driver = None;
- self.inner.io.write_error(
- PhpMixed::String(format!(
+ self.inner.io.write_error3(
+ &format!(
"<error>Failed to clone the {} repository, try running in interactive mode so that you can enter your GitHub credentials</error>",
self.generate_ssh_url()
- )),
+ ),
true,
io_interface::NORMAL,
);
@@ -1233,8 +1288,8 @@ impl GitHubDriver {
repo_config,
self.inner.io.clone(),
self.inner.config.clone(),
- self.inner.http_downloader.clone(),
- self.inner.process.clone(),
+ std::rc::Rc::clone(&self.inner.http_downloader),
+ std::rc::Rc::clone(&self.inner.process),
);
git_driver.initialize()?;
self.git_driver = Some(git_driver);
@@ -1249,8 +1304,11 @@ impl GitHubDriver {
let links = explode(",", &header);
for link in &links {
- if let Some(m) = Preg::is_match_strict_groups(r#"{<(.+?)>; *rel="next"}"#, link) {
- return Some(m.get(1).cloned().unwrap_or_default());
+ let mut m: IndexMap<CaptureKey, String> = IndexMap::new();
+ if Preg::is_match_strict_groups3(r#"{<(.+?)>; *rel="next"}"#, link, Some(&mut m))
+ .unwrap_or(false)
+ {
+ return Some(m.get(&CaptureKey::ByIndex(1)).cloned().unwrap_or_default());
}
}
diff --git a/crates/shirabe/src/repository/vcs/gitlab_driver.rs b/crates/shirabe/src/repository/vcs/gitlab_driver.rs
index dea1bf6..e00bbf8 100644
--- a/crates/shirabe/src/repository/vcs/gitlab_driver.rs
+++ b/crates/shirabe/src/repository/vcs/gitlab_driver.rs
@@ -4,7 +4,7 @@ use crate::io::io_interface;
use anyhow::Result;
use chrono::{DateTime, Utc};
use indexmap::IndexMap;
-use shirabe_external_packages::composer::pcre::preg::Preg;
+use shirabe_external_packages::composer::pcre::preg::{CaptureKey, Preg};
use shirabe_php_shim::{
InvalidArgumentException, LogicException, PhpMixed, RuntimeException, array_search_mixed,
array_shift, ctype_alnum, empty, explode, extension_loaded, implode, in_array, is_array,
@@ -18,6 +18,7 @@ use crate::io::io_interface::IOInterface;
use crate::json::json_file::JsonFile;
use crate::repository::vcs::git_driver::GitDriver;
use crate::repository::vcs::vcs_driver::VcsDriverBase;
+use crate::repository::vcs::vcs_driver_interface::VcsDriverInterface;
use crate::util::gitlab::GitLab;
use crate::util::http::response::Response;
use crate::util::http_downloader::HttpDownloader;
@@ -57,30 +58,43 @@ impl GitLabDriver {
///
/// SSH urls use https by default. Set "secure-http": false on the repository config to use http instead.
pub fn initialize(&mut self) -> Result<()> {
- let match_ = match Preg::is_match_strict_groups(Self::URL_REGEX, &self.inner.url) {
- Some(m) => m,
- None => {
- return Err(InvalidArgumentException {
- message: sprintf(
- "The GitLab repository URL %s is invalid. It must be the HTTP URL of a GitLab project.",
- &[PhpMixed::String(self.inner.url.clone())],
- ),
- code: 0,
- }
- .into());
+ let mut match_: IndexMap<CaptureKey, String> = IndexMap::new();
+ if !Preg::is_match_strict_groups3(Self::URL_REGEX, &self.inner.url, Some(&mut match_))
+ .unwrap_or(false)
+ {
+ return Err(InvalidArgumentException {
+ message: sprintf(
+ "The GitLab repository URL %s is invalid. It must be the HTTP URL of a GitLab project.",
+ &[PhpMixed::String(self.inner.url.clone())],
+ ),
+ code: 0,
}
- };
+ .into());
+ }
let guessed_domain = match_
- .get("domain")
+ .get(&CaptureKey::ByName("domain".to_string()))
.cloned()
.filter(|s| !s.is_empty())
- .unwrap_or_else(|| match_.get("domain2").cloned().unwrap_or_default());
- let configured_domains = self.inner.config.get("gitlab-domains");
- let mut url_parts: Vec<String> =
- explode("/", &match_.get("parts").cloned().unwrap_or_default());
+ .unwrap_or_else(|| {
+ match_
+ .get(&CaptureKey::ByName("domain2".to_string()))
+ .cloned()
+ .unwrap_or_default()
+ });
+ let configured_domains = self.inner.config.borrow_mut().get("gitlab-domains");
+ let mut url_parts: Vec<String> = explode(
+ "/",
+ &match_
+ .get(&CaptureKey::ByName("parts".to_string()))
+ .cloned()
+ .unwrap_or_default(),
+ );
- let scheme_match = match_.get("scheme").cloned().unwrap_or_default();
+ let scheme_match = match_
+ .get(&CaptureKey::ByName("scheme".to_string()))
+ .cloned()
+ .unwrap_or_default();
self.scheme = if in_array(
PhpMixed::String(scheme_match.clone()),
&PhpMixed::List(vec![
@@ -101,7 +115,7 @@ impl GitLabDriver {
} else {
"https".to_string()
};
- let port = match_.get("port").cloned();
+ let port = match_.get(&CaptureKey::ByName("port".to_string())).cloned();
let origin = Self::determine_origin(
&configured_domains,
guessed_domain,
@@ -123,7 +137,7 @@ impl GitLabDriver {
};
self.inner.origin_url = origin;
- let protocol_value = self.inner.config.get("gitlab-protocol");
+ let protocol_value = self.inner.config.borrow_mut().get("gitlab-protocol");
if let Some(protocol) = protocol_value
.as_string()
.filter(|_| is_string(&protocol_value))
@@ -161,8 +175,12 @@ impl GitLabDriver {
self.repository = Preg::replace(
r"#(\.git)$#",
"",
- match_.get("repo").cloned().unwrap_or_default(),
- );
+ &match_
+ .get(&CaptureKey::ByName("repo".to_string()))
+ .cloned()
+ .unwrap_or_default(),
+ )
+ .unwrap_or_default();
self.inner.cache = Some(Cache::new(
self.inner.io.as_ref(),
@@ -170,6 +188,7 @@ impl GitLabDriver {
"{}/{}/{}/{}",
self.inner
.config
+ .borrow_mut()
.get("cache-repo-dir")
.as_string()
.unwrap_or(""),
@@ -185,6 +204,7 @@ impl GitLabDriver {
c.set_read_only(
self.inner
.config
+ .borrow_mut()
.get("cache-read-only")
.as_bool()
.unwrap_or(false),
@@ -200,7 +220,10 @@ impl GitLabDriver {
/// Mainly useful for tests.
///
/// @internal
- pub fn set_http_downloader(&mut self, http_downloader: HttpDownloader) {
+ pub fn set_http_downloader(
+ &mut self,
+ http_downloader: std::rc::Rc<std::cell::RefCell<HttpDownloader>>,
+ ) {
self.inner.http_downloader = http_downloader;
}
@@ -229,7 +252,12 @@ impl GitLabDriver {
.unwrap_or_default();
JsonFile::parse_json(&res, None)?
} else {
- let composer = self.inner.get_base_composer_information(identifier)?;
+ let file_content = self.get_file_content("composer.json", identifier)?;
+ let composer = VcsDriverBase::finish_base_composer_information(
+ identifier,
+ file_content,
+ || self.get_change_date(identifier),
+ )?;
if self.inner.should_cache(identifier) {
if let Some(ref composer_map) = composer {
@@ -679,11 +707,11 @@ impl GitLabDriver {
Err(e) => {
self.git_driver = None;
- self.inner.io.write_error(
- PhpMixed::String(format!(
+ self.inner.io.write_error3(
+ &format!(
"<error>Failed to clone the {} repository, try running in interactive mode so that you can enter your credentials</error>",
url
- )),
+ ),
true,
io_interface::NORMAL,
);
@@ -721,8 +749,8 @@ impl GitLabDriver {
repo_config,
self.inner.io.clone(),
self.inner.config.clone(),
- self.inner.http_downloader.clone(),
- self.inner.process.clone(),
+ std::rc::Rc::clone(&self.inner.http_downloader),
+ std::rc::Rc::clone(&self.inner.process),
);
git_driver.initialize()?;
self.git_driver = Some(git_driver);
@@ -780,11 +808,8 @@ impl GitLabDriver {
}
if !more_than_guest_access {
- self.inner.io.write_error(
- PhpMixed::String(
- "<warning>GitLab token with Guest or Planner only access detected</warning>"
- .to_string(),
- ),
+ self.inner.io.write_error3(
+ "<warning>GitLab token with Guest or Planner only access detected</warning>",
true,
io_interface::NORMAL,
);
@@ -840,11 +865,11 @@ impl GitLabDriver {
}
Err(e) => {
let mut git_lab_util = GitLab::new(
- self.inner.io.as_ref(),
- &self.inner.config,
- &self.inner.process,
- &self.inner.http_downloader,
- );
+ self.inner.io.clone_box(),
+ std::rc::Rc::clone(&self.inner.config),
+ Some(std::rc::Rc::clone(&self.inner.process)),
+ Some(std::rc::Rc::clone(&self.inner.http_downloader)),
+ )?;
match e.code {
401 | 404 => {
@@ -882,11 +907,11 @@ impl GitLabDriver {
.unwrap()
.unwrap());
}
- self.inner.io.write_error(
- PhpMixed::String(format!(
+ self.inner.io.write_error3(
+ &format!(
"<warning>Failed to download {}/{}:{}</warning>",
self.namespace, self.repository, e.message
- )),
+ ),
true,
io_interface::NORMAL,
);
@@ -938,25 +963,39 @@ impl GitLabDriver {
/// Uses the config `gitlab-domains` to see if the driver supports the url for the
/// repository given.
pub fn supports(io: &dyn IOInterface, config: &Config, url: &str, _deep: bool) -> bool {
- let match_ = match Preg::is_match_strict_groups(Self::URL_REGEX, url) {
- Some(m) => m,
- None => return false,
- };
+ let mut match_: IndexMap<CaptureKey, String> = IndexMap::new();
+ if !Preg::is_match_strict_groups3(Self::URL_REGEX, url, Some(&mut match_)).unwrap_or(false)
+ {
+ return false;
+ }
- let scheme = match_.get("scheme").cloned().unwrap_or_default();
+ let scheme = match_
+ .get(&CaptureKey::ByName("scheme".to_string()))
+ .cloned()
+ .unwrap_or_default();
let guessed_domain = match_
- .get("domain")
+ .get(&CaptureKey::ByName("domain".to_string()))
.cloned()
.filter(|s| !s.is_empty())
- .unwrap_or_else(|| match_.get("domain2").cloned().unwrap_or_default());
- let mut url_parts: Vec<String> =
- explode("/", &match_.get("parts").cloned().unwrap_or_default());
+ .unwrap_or_else(|| {
+ match_
+ .get(&CaptureKey::ByName("domain2".to_string()))
+ .cloned()
+ .unwrap_or_default()
+ });
+ let mut url_parts: Vec<String> = explode(
+ "/",
+ &match_
+ .get(&CaptureKey::ByName("parts".to_string()))
+ .cloned()
+ .unwrap_or_default(),
+ );
if Self::determine_origin(
&config.get("gitlab-domains"),
guessed_domain,
&mut url_parts,
- match_.get("port").cloned(),
+ match_.get(&CaptureKey::ByName("port".to_string())).cloned(),
)
.is_none()
{
@@ -964,11 +1003,11 @@ impl GitLabDriver {
}
if scheme == "https" && !extension_loaded("openssl") {
- io.write_error(
- PhpMixed::String(format!(
+ io.write_error3(
+ &format!(
"Skipping GitLab driver for {} because the OpenSSL PHP extension is missing.",
url
- )),
+ ),
true,
io_interface::VERBOSE,
);
@@ -993,8 +1032,16 @@ impl GitLabDriver {
let links = explode(",", &header);
for link in &links {
- if let Some(match_) = Preg::is_match_strict_groups(r#"{<(.+?)>; *rel="next"}"#, link) {
- return Some(match_.get(1).cloned().unwrap_or_default());
+ let mut match_: IndexMap<CaptureKey, String> = IndexMap::new();
+ if Preg::is_match_strict_groups3(r#"{<(.+?)>; *rel="next"}"#, link, Some(&mut match_))
+ .unwrap_or(false)
+ {
+ return Some(
+ match_
+ .get(&CaptureKey::ByIndex(1))
+ .cloned()
+ .unwrap_or_default(),
+ );
}
}
@@ -1048,7 +1095,7 @@ impl GitLabDriver {
false,
) || (port_number.is_some()
&& in_array(
- PhpMixed::String(Preg::replace(r"{:\d+}", "", guessed_domain.clone())),
+ PhpMixed::String(Preg::replace(r"{:\d+}", "", &guessed_domain)),
configured_domains,
false,
))
diff --git a/crates/shirabe/src/repository/vcs/hg_driver.rs b/crates/shirabe/src/repository/vcs/hg_driver.rs
index 68393ed..f7c0c16 100644
--- a/crates/shirabe/src/repository/vcs/hg_driver.rs
+++ b/crates/shirabe/src/repository/vcs/hg_driver.rs
@@ -30,6 +30,7 @@ impl HgDriver {
let cache_vcs_dir = self
.inner
.config
+ .borrow_mut()
.get("cache-vcs-dir")
.as_string()
.unwrap_or("")
@@ -58,30 +59,32 @@ impl HgDriver {
}.into());
}
- self.inner
- .config
- .prohibit_url_by_config(&self.inner.url, &*self.inner.io)?;
+ self.inner.config.borrow_mut().prohibit_url_by_config(
+ &self.inner.url,
+ Some(&*self.inner.io),
+ &indexmap::IndexMap::new(),
+ )?;
- 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,
+ );
if is_dir(&self.repo_dir)
- && self.inner.process.execute(
+ && self.inner.process.borrow_mut().execute_args(
&["hg", "summary"].map(|s| s.to_string()).to_vec(),
&mut String::new(),
Some(self.repo_dir.clone()),
) == 0
{
- if self.inner.process.execute(
+ if self.inner.process.borrow_mut().execute_args(
&["hg", "pull"].map(|s| s.to_string()).to_vec(),
&mut String::new(),
Some(self.repo_dir.clone()),
) != 0
{
- self.inner.io.write_error(
- format!("<error>Failed to update {}, package information from this repository may be outdated ({})</error>", self.inner.url, self.inner.process.get_error_output()).into(),
- true,
- crate::io::io_interface::NORMAL,
- );
+ self.inner.io.write_error3(format!("<error>Failed to update {}, package information from this repository may be outdated ({})</error>", self.inner.url, self.inner.process.borrow().get_error_output()).into(), true, crate::io::io_interface::NORMAL);
}
} else {
let fs2 = Filesystem::new(None);
@@ -112,14 +115,14 @@ impl HgDriver {
pub fn get_root_identifier(&mut self) -> anyhow::Result<String> {
if self.root_identifier.is_none() {
let mut output = String::new();
- self.inner.process.execute(
+ self.inner.process.borrow_mut().execute_args(
&["hg", "tip", "--template", "{node}"]
.map(|s| s.to_string())
.to_vec(),
&mut output,
Some(self.repo_dir.clone()),
);
- let lines = self.inner.process.split_lines(&output);
+ let lines = self.inner.process.borrow().split_lines(&output);
self.root_identifier = lines.into_iter().next();
}
@@ -163,9 +166,11 @@ impl HgDriver {
file.to_string(),
];
let mut content = String::new();
- self.inner
- .process
- .execute(&resource, &mut content, Some(self.repo_dir.clone()));
+ self.inner.process.borrow_mut().execute_args(
+ &resource,
+ &mut content,
+ Some(self.repo_dir.clone()),
+ );
if content.trim().is_empty() {
return Ok(None);
@@ -187,7 +192,7 @@ impl HgDriver {
}
let mut output = String::new();
- self.inner.process.execute(
+ self.inner.process.borrow_mut().execute_args(
&[
"hg",
"log",
@@ -210,12 +215,12 @@ impl HgDriver {
if self.tags.is_none() {
let mut tags: IndexMap<String, String> = IndexMap::new();
let mut output = String::new();
- self.inner.process.execute(
+ self.inner.process.borrow_mut().execute_args(
&["hg", "tags"].map(|s| s.to_string()).to_vec(),
&mut output,
Some(self.repo_dir.clone()),
);
- for tag in self.inner.process.split_lines(&output) {
+ for tag in self.inner.process.borrow().split_lines(&output) {
if !tag.is_empty() {
if let Some(m) = Preg::match_(r"^([^\s]+)\s+\d+:(.*)$", &tag) {
tags.insert(
@@ -239,12 +244,12 @@ impl HgDriver {
let mut bookmarks: IndexMap<String, String> = IndexMap::new();
let mut output = String::new();
- self.inner.process.execute(
+ self.inner.process.borrow_mut().execute_args(
&["hg", "branches"].map(|s| s.to_string()).to_vec(),
&mut output,
Some(self.repo_dir.clone()),
);
- for branch in self.inner.process.split_lines(&output) {
+ for branch in self.inner.process.borrow().split_lines(&output) {
if !branch.is_empty() {
if let Some(m) = Preg::match_(r"^([^\s]+)\s+\d+:([a-f0-9]+)", &branch) {
let name = m.get("1").cloned().unwrap_or_default();
@@ -256,12 +261,12 @@ impl HgDriver {
}
output.clear();
- self.inner.process.execute(
+ self.inner.process.borrow_mut().execute_args(
&["hg", "bookmarks"].map(|s| s.to_string()).to_vec(),
&mut output,
Some(self.repo_dir.clone()),
);
- for branch in self.inner.process.split_lines(&output) {
+ for branch in self.inner.process.borrow().split_lines(&output) {
if !branch.is_empty() {
if let Some(m) = Preg::match_(r"^(?:[\s*]*)([^\s]+)\s+\d+:(.*)$", &branch) {
let name = m.get("1").cloned().unwrap_or_default();
@@ -298,7 +303,7 @@ impl HgDriver {
let process = crate::util::process_executor::ProcessExecutor::new(io);
let mut output = String::new();
- if process.execute(
+ if process.execute_args(
&["hg", "summary"].map(|s| s.to_string()).to_vec(),
&mut output,
Some(url),
@@ -314,7 +319,7 @@ impl HgDriver {
let process = crate::util::process_executor::ProcessExecutor::new(io);
let mut ignored = String::new();
- let exit = process.execute(
+ let exit = process.execute_args(
&["hg", "identify", "--", url]
.map(|s| s.to_string())
.to_vec(),
diff --git a/crates/shirabe/src/repository/vcs/perforce_driver.rs b/crates/shirabe/src/repository/vcs/perforce_driver.rs
index ee09dee..e3aa868 100644
--- a/crates/shirabe/src/repository/vcs/perforce_driver.rs
+++ b/crates/shirabe/src/repository/vcs/perforce_driver.rs
@@ -59,6 +59,7 @@ impl PerforceDriver {
let cache_vcs_dir = self
.inner
.config
+ .borrow_mut()
.get("cache-vcs-dir")
.as_string()
.unwrap_or("")
diff --git a/crates/shirabe/src/repository/vcs/svn_driver.rs b/crates/shirabe/src/repository/vcs/svn_driver.rs
index 2e649df..8218563 100644
--- a/crates/shirabe/src/repository/vcs/svn_driver.rs
+++ b/crates/shirabe/src/repository/vcs/svn_driver.rs
@@ -3,7 +3,7 @@
use anyhow::Result;
use chrono::{DateTime, TimeZone, Utc};
use indexmap::IndexMap;
-use shirabe_external_packages::composer::pcre::preg::Preg;
+use shirabe_external_packages::composer::pcre::preg::{CaptureKey, Preg};
use shirabe_php_shim::{
JSON_UNESCAPED_SLASHES, JSON_UNESCAPED_UNICODE, PhpMixed, RuntimeException, array_key_exists,
is_array, max, sprintf, stripos, strrpos, strtr, substr, trim,
@@ -90,6 +90,7 @@ impl SvnDriver {
"{}/{}",
self.inner
.config
+ .borrow_mut()
.get("cache-repo-dir")
.as_string()
.unwrap_or(""),
@@ -102,6 +103,7 @@ impl SvnDriver {
self.inner.cache.as_mut().unwrap().set_read_only(
self.inner
.config
+ .borrow_mut()
.get("cache-read-only")
.as_bool()
.unwrap_or(false),
@@ -135,7 +137,10 @@ impl SvnDriver {
}
pub(crate) fn should_cache(&self, identifier: &str) -> bool {
- self.inner.cache.is_some() && Preg::is_match(r"{@\d+$}", identifier)
+ self.inner.cache.is_some()
+ && Preg::is_match(r"{@\d+$}", identifier)
+ .unwrap_or(false)
+ .unwrap_or(false)
}
pub fn get_composer_information(
@@ -170,22 +175,30 @@ impl SvnDriver {
}
// TODO(phase-b): use anyhow::Result<Result<T, E>> to model PHP try/catch
- let composer: Option<IndexMap<String, PhpMixed>> =
- match self.inner.get_base_composer_information(identifier) {
- Ok(c) => c,
- Err(e) => {
- // TODO(phase-b): downcast to TransportException
- let _te: &TransportException = todo!("downcast e to TransportException");
- let message = e.to_string();
- if stripos(&message, "path not found").is_none()
- && stripos(&message, "svn: warning: W160013").is_none()
- {
- return Err(e);
- }
- // remember a not-existent composer.json
- None
+ let base_result =
+ self.get_file_content("composer.json", identifier)
+ .and_then(|file_content| {
+ VcsDriverBase::finish_base_composer_information(
+ identifier,
+ file_content,
+ || self.get_change_date(identifier),
+ )
+ });
+ let composer: Option<IndexMap<String, PhpMixed>> = match base_result {
+ Ok(c) => c,
+ Err(e) => {
+ // TODO(phase-b): downcast to TransportException
+ let _te: &TransportException = todo!("downcast e to TransportException");
+ let message = e.to_string();
+ if stripos(&message, "path not found").is_none()
+ && stripos(&message, "svn: warning: W160013").is_none()
+ {
+ return Err(e);
}
- };
+ // remember a not-existent composer.json
+ None
+ }
+ };
if self.should_cache(identifier) {
let encoded = JsonFile::encode(
@@ -282,12 +295,17 @@ impl SvnDriver {
vec!["svn".to_string(), "info".to_string()],
&format!("{}{}{}", self.base_url, path, rev),
)?;
- for line in self.inner.process.split_lines(&output) {
+ for line in self.inner.process.borrow().split_lines(&output) {
if !line.is_empty() {
- if let Some(m) =
- Preg::is_match_strict_groups(r"{^Last Changed Date: ([^(]+)}", &line)
+ let mut m: IndexMap<CaptureKey, String> = IndexMap::new();
+ if Preg::is_match_strict_groups3(
+ r"{^Last Changed Date: ([^(]+)}",
+ &line,
+ Some(&mut m),
+ )
+ .unwrap_or(false)
{
- let date_str = m.get(1).cloned().unwrap_or_default();
+ let date_str = m.get(&CaptureKey::ByIndex(1)).cloned().unwrap_or_default();
// PHP: new \DateTimeImmutable($match[1], new \DateTimeZone('UTC'))
return Ok(Utc
.datetime_from_str(date_str.trim(), "%Y-%m-%d %H:%M:%S %z")
@@ -313,15 +331,23 @@ impl SvnDriver {
.unwrap_or_default();
if !output.is_empty() {
let mut last_rev: i64 = 0;
- for line in self.inner.process.split_lines(&output) {
+ for line in self.inner.process.borrow().split_lines(&output) {
let line = trim(&line, None);
if !line.is_empty() {
- if let Some(m) =
- Preg::is_match_strict_groups(r"{^\s*(\S+).*?(\S+)\s*$}", &line)
+ let mut m: IndexMap<CaptureKey, String> = IndexMap::new();
+ if Preg::is_match_strict_groups3(
+ r"{^\s*(\S+).*?(\S+)\s*$}",
+ &line,
+ Some(&mut m),
+ )
+ .unwrap_or(false)
{
- let rev: i64 =
- m.get(1).map(|s| s.parse().unwrap_or(0)).unwrap_or(0);
- let path = m.get(2).cloned().unwrap_or_default();
+ let rev: i64 = m
+ .get(&CaptureKey::ByIndex(1))
+ .and_then(|s| s.parse().ok())
+ .unwrap_or(0);
+ let path =
+ m.get(&CaptureKey::ByIndex(2)).cloned().unwrap_or_default();
if path == "./" {
last_rev = rev;
} else {
@@ -360,14 +386,22 @@ impl SvnDriver {
)
.unwrap_or_default();
if !output.is_empty() {
- for line in self.inner.process.split_lines(&output) {
+ for line in self.inner.process.borrow().split_lines(&output) {
let line = trim(&line, None);
if !line.is_empty() {
- if let Some(m) =
- Preg::is_match_strict_groups(r"{^\s*(\S+).*?(\S+)\s*$}", &line)
+ let mut m: IndexMap<CaptureKey, String> = IndexMap::new();
+ if Preg::is_match_strict_groups3(
+ r"{^\s*(\S+).*?(\S+)\s*$}",
+ &line,
+ Some(&mut m),
+ )
+ .unwrap_or(false)
{
- let rev: i64 = m.get(1).map(|s| s.parse().unwrap_or(0)).unwrap_or(0);
- let path = m.get(2).cloned().unwrap_or_default();
+ let rev: i64 = m
+ .get(&CaptureKey::ByIndex(1))
+ .and_then(|s| s.parse().ok())
+ .unwrap_or(0);
+ let path = m.get(&CaptureKey::ByIndex(2)).cloned().unwrap_or_default();
if path == "./" {
let identifier = self.build_identifier(
&format!("/{}", self.trunk_path.clone().unwrap_or_default()),
@@ -393,15 +427,28 @@ impl SvnDriver {
.unwrap_or_default();
if !output.is_empty() {
let mut last_rev: i64 = 0;
- for line in self.inner.process.split_lines(&trim(&output, None)) {
+ for line in self
+ .inner
+ .process
+ .borrow()
+ .split_lines(&trim(&output, None))
+ {
let line = trim(&line, None);
if !line.is_empty() {
- if let Some(m) =
- Preg::is_match_strict_groups(r"{^\s*(\S+).*?(\S+)\s*$}", &line)
+ let mut m: IndexMap<CaptureKey, String> = IndexMap::new();
+ if Preg::is_match_strict_groups3(
+ r"{^\s*(\S+).*?(\S+)\s*$}",
+ &line,
+ Some(&mut m),
+ )
+ .unwrap_or(false)
{
- let rev: i64 =
- m.get(1).map(|s| s.parse().unwrap_or(0)).unwrap_or(0);
- let path = m.get(2).cloned().unwrap_or_default();
+ let rev: i64 = m
+ .get(&CaptureKey::ByIndex(1))
+ .and_then(|s| s.parse().ok())
+ .unwrap_or(0);
+ let path =
+ m.get(&CaptureKey::ByIndex(2)).cloned().unwrap_or_default();
if path == "./" {
last_rev = rev;
} else {
@@ -426,7 +473,10 @@ impl SvnDriver {
pub fn supports(io: &dyn IOInterface, _config: &Config, url: &str, deep: bool) -> bool {
let url = Self::normalize_url(url);
- if Preg::is_match(r"#(^svn://|^svn\+ssh://|svn\.)#i", &url) {
+ if Preg::is_match(r"#(^svn://|^svn\+ssh://|svn\.)#i", &url)
+ .unwrap_or(false)
+ .unwrap_or(false)
+ {
return true;
}
@@ -437,7 +487,7 @@ impl SvnDriver {
let mut process = ProcessExecutor::new(io);
let mut ignored_output = String::new();
- let exit = process.execute(
+ let exit = process.execute_args(
&[
"svn".to_string(),
"info".to_string(),
@@ -516,7 +566,7 @@ impl SvnDriver {
message: format!(
"Failed to load {}, svn was not found, check that it is installed and in your PATH env.\n\n{}",
self.inner.url,
- self.inner.process.get_error_output(),
+ self.inner.process.borrow().get_error_output(),
),
code: 0,
}
diff --git a/crates/shirabe/src/repository/vcs/vcs_driver.rs b/crates/shirabe/src/repository/vcs/vcs_driver.rs
index 162792e..e356a6f 100644
--- a/crates/shirabe/src/repository/vcs/vcs_driver.rs
+++ b/crates/shirabe/src/repository/vcs/vcs_driver.rs
@@ -1,5 +1,6 @@
//! ref: composer/src/Composer/Repository/Vcs/VcsDriver.php
+use chrono::{DateTime, Utc};
use indexmap::IndexMap;
use shirabe_external_packages::composer::pcre::preg::Preg;
use shirabe_php_shim::{
@@ -23,9 +24,9 @@ pub struct VcsDriverBase {
pub origin_url: String,
pub repo_config: IndexMap<String, PhpMixed>,
pub io: Box<dyn IOInterface>,
- pub config: Config,
- pub process: ProcessExecutor,
- pub http_downloader: HttpDownloader,
+ pub config: std::rc::Rc<std::cell::RefCell<Config>>,
+ pub process: std::rc::Rc<std::cell::RefCell<ProcessExecutor>>,
+ pub http_downloader: std::rc::Rc<std::cell::RefCell<HttpDownloader>>,
pub info_cache: IndexMap<String, Option<IndexMap<String, PhpMixed>>>,
pub cache: Option<Cache>,
}
@@ -34,9 +35,9 @@ impl VcsDriverBase {
pub fn new(
repo_config: IndexMap<String, PhpMixed>,
io: Box<dyn IOInterface>,
- config: Config,
- http_downloader: HttpDownloader,
- process: ProcessExecutor,
+ config: std::rc::Rc<std::cell::RefCell<Config>>,
+ http_downloader: std::rc::Rc<std::cell::RefCell<HttpDownloader>>,
+ process: std::rc::Rc<std::cell::RefCell<ProcessExecutor>>,
) -> Self {
let url = repo_config
.get("url")
@@ -74,7 +75,52 @@ impl VcsDriverBase {
.get("options")
.cloned()
.unwrap_or(PhpMixed::Array(IndexMap::new()));
- self.http_downloader.get(url, &options)
+ self.http_downloader.borrow_mut().get(url, &options)
+ }
+
+ // Helper for concrete drivers: produces the same value as the trait default
+ // `get_base_composer_information`, but receives a pre-fetched composer.json
+ // body and a lazy change-date callback. Concrete drivers in the Rust port
+ // wrap `VcsDriverBase` as `self.inner` instead of inheriting from it, so
+ // they cannot dispatch back into a base method that calls `get_file_content`
+ // / `get_change_date` hooks; the caller threads those calls in itself.
+ pub fn finish_base_composer_information(
+ identifier: &str,
+ composer_file_content: Option<String>,
+ change_date: impl FnOnce() -> anyhow::Result<Option<DateTime<Utc>>>,
+ ) -> anyhow::Result<Option<IndexMap<String, PhpMixed>>> {
+ let content = match composer_file_content {
+ None => return Ok(None),
+ Some(c) if c.is_empty() => return Ok(None),
+ Some(c) => c,
+ };
+
+ let parsed = JsonFile::parse_json(
+ Some(&content),
+ Some(&format!("{}:composer.json", identifier)),
+ )?;
+
+ let array = match parsed {
+ PhpMixed::Array(a) if !a.is_empty() => a,
+ _ => return Ok(None),
+ };
+
+ // PHP arrays own their nested values; the Rust representation wraps them
+ // in Box<PhpMixed>. Unbox the outer level so callers can mutate keys.
+ let mut composer: IndexMap<String, PhpMixed> =
+ array.into_iter().map(|(k, v)| (k, *v)).collect();
+
+ if !composer.contains_key("time")
+ || composer
+ .get("time")
+ .map_or(true, |v| v.as_string().map_or(true, |s| s.is_empty()))
+ {
+ if let Some(d) = change_date()? {
+ composer.insert("time".to_string(), PhpMixed::String(d.to_rfc3339()));
+ }
+ }
+
+ Ok(Some(composer))
}
}
@@ -93,8 +139,7 @@ pub trait VcsDriver: VcsDriverInterface {
fn config_mut(&mut self) -> &mut Config;
fn process(&self) -> &ProcessExecutor;
fn process_mut(&mut self) -> &mut ProcessExecutor;
- fn http_downloader(&self) -> &HttpDownloader;
- fn http_downloader_mut(&mut self) -> &mut HttpDownloader;
+ fn http_downloader(&self) -> &std::rc::Rc<std::cell::RefCell<HttpDownloader>>;
fn info_cache(&self) -> &IndexMap<String, Option<IndexMap<String, PhpMixed>>>;
fn info_cache_mut(&mut self) -> &mut IndexMap<String, Option<IndexMap<String, PhpMixed>>>;
fn cache(&self) -> Option<&Cache>;
@@ -195,7 +240,7 @@ pub trait VcsDriver: VcsDriverInterface {
.get("options")
.cloned()
.unwrap_or(PhpMixed::Array(IndexMap::new()));
- self.http_downloader().get(url, &options)
+ self.http_downloader().borrow_mut().get(url, &options)
}
fn cleanup(&self) {}
diff --git a/crates/shirabe/src/repository/vcs/vcs_driver_interface.rs b/crates/shirabe/src/repository/vcs/vcs_driver_interface.rs
index 5b15c2c..236b9b4 100644
--- a/crates/shirabe/src/repository/vcs/vcs_driver_interface.rs
+++ b/crates/shirabe/src/repository/vcs/vcs_driver_interface.rs
@@ -6,7 +6,7 @@ use chrono::{DateTime, Utc};
use indexmap::IndexMap;
use shirabe_php_shim::PhpMixed;
-pub trait VcsDriverInterface {
+pub trait VcsDriverInterface: std::fmt::Debug {
fn initialize(&mut self) -> anyhow::Result<()>;
fn get_composer_information(