aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/src/repository/vcs
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-06-08 01:54:56 +0900
committernsfisis <nsfisis@gmail.com>2026-06-08 01:54:56 +0900
commit318ea948f5932dfa7942081a269d62fd7161a9bf (patch)
tree0fff2fe818f87a20dea89a51901f9e16071f2f53 /crates/shirabe/src/repository/vcs
parentf232d7f9d2936ef84bd904cacd21c12cb7012b34 (diff)
downloadphp-shirabe-318ea948f5932dfa7942081a269d62fd7161a9bf.tar.gz
php-shirabe-318ea948f5932dfa7942081a269d62fd7161a9bf.tar.zst
php-shirabe-318ea948f5932dfa7942081a269d62fd7161a9bf.zip
feat(phase-c): resolve reflection/downcast phase-b TODOs
Resolve category F phase-b TODOs (class-string, instanceof, get_class, method_exists, __FILE__, Reflection API, downcast). - VcsRepository: dispatch drivers through a VcsDriverKind enum (instantiate/supports/php_class_name) and add constructors to the concrete VCS drivers - repository downcasts via RepositoryInterfaceHandle::downcast_rc and as_any (init/show commands, vcs ValidatingArrayLoader) - BaseCommand::is_self_update_command override replaces an instanceof - Factory::create narrows PartialComposer to ComposerHandle via as_full - InstalledVersions gains set_self_dir/set_installed_is_local_dir, replacing Reflection-based static property mutation - ClassLoader::as_array_iter ports the PHP (array) cast - drop the unnecessary __FILE__ phar branch in self-update application get_class(command) reclassified TODO(plugin); buffer_io StreamableInputInterface downcast and the ValidatingArrayLoader trait redesign left as tracked TODOs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe/src/repository/vcs')
-rw-r--r--crates/shirabe/src/repository/vcs/forgejo_driver.rs17
-rw-r--r--crates/shirabe/src/repository/vcs/fossil_driver.rs17
-rw-r--r--crates/shirabe/src/repository/vcs/git_bitbucket_driver.rs26
-rw-r--r--crates/shirabe/src/repository/vcs/github_driver.rs24
-rw-r--r--crates/shirabe/src/repository/vcs/gitlab_driver.rs23
-rw-r--r--crates/shirabe/src/repository/vcs/hg_driver.rs16
-rw-r--r--crates/shirabe/src/repository/vcs/mod.rs131
-rw-r--r--crates/shirabe/src/repository/vcs/perforce_driver.rs15
-rw-r--r--crates/shirabe/src/repository/vcs/svn_driver.rs22
9 files changed, 291 insertions, 0 deletions
diff --git a/crates/shirabe/src/repository/vcs/forgejo_driver.rs b/crates/shirabe/src/repository/vcs/forgejo_driver.rs
index c93ee70..3c1366d 100644
--- a/crates/shirabe/src/repository/vcs/forgejo_driver.rs
+++ b/crates/shirabe/src/repository/vcs/forgejo_driver.rs
@@ -34,6 +34,23 @@ pub struct ForgejoDriver {
}
impl ForgejoDriver {
+ pub fn new(
+ repo_config: IndexMap<String, shirabe_php_shim::PhpMixed>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
+ config: std::rc::Rc<std::cell::RefCell<Config>>,
+ http_downloader: std::rc::Rc<std::cell::RefCell<crate::util::HttpDownloader>>,
+ process: std::rc::Rc<std::cell::RefCell<crate::util::ProcessExecutor>>,
+ ) -> Self {
+ Self {
+ inner: VcsDriverBase::new(repo_config, io, config, http_downloader, process),
+ forgejo_url: None,
+ repository_data: None,
+ git_driver: None,
+ tags: None,
+ branches: None,
+ }
+ }
+
pub fn initialize(&mut self) -> Result<()> {
let forgejo_url = ForgejoUrl::create(&self.inner.url)?;
self.inner.origin_url = forgejo_url.origin_url.clone();
diff --git a/crates/shirabe/src/repository/vcs/fossil_driver.rs b/crates/shirabe/src/repository/vcs/fossil_driver.rs
index 5b7ccc1..0ee20da 100644
--- a/crates/shirabe/src/repository/vcs/fossil_driver.rs
+++ b/crates/shirabe/src/repository/vcs/fossil_driver.rs
@@ -26,6 +26,23 @@ pub struct FossilDriver {
}
impl FossilDriver {
+ pub fn new(
+ repo_config: IndexMap<String, shirabe_php_shim::PhpMixed>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
+ config: std::rc::Rc<std::cell::RefCell<Config>>,
+ http_downloader: std::rc::Rc<std::cell::RefCell<crate::util::HttpDownloader>>,
+ process: std::rc::Rc<std::cell::RefCell<crate::util::ProcessExecutor>>,
+ ) -> Self {
+ Self {
+ inner: VcsDriverBase::new(repo_config, io, config, http_downloader, process),
+ tags: None,
+ branches: None,
+ root_identifier: None,
+ repo_file: None,
+ checkout_dir: String::new(),
+ }
+ }
+
pub fn initialize(&mut self) -> anyhow::Result<()> {
// Make sure fossil is installed and reachable.
self.check_fossil()?;
diff --git a/crates/shirabe/src/repository/vcs/git_bitbucket_driver.rs b/crates/shirabe/src/repository/vcs/git_bitbucket_driver.rs
index 2a8d374..3f0be13 100644
--- a/crates/shirabe/src/repository/vcs/git_bitbucket_driver.rs
+++ b/crates/shirabe/src/repository/vcs/git_bitbucket_driver.rs
@@ -58,6 +58,32 @@ pub struct GitBitbucketDriver {
}
impl GitBitbucketDriver {
+ pub fn new(
+ repo_config: IndexMap<String, shirabe_php_shim::PhpMixed>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
+ config: std::rc::Rc<std::cell::RefCell<Config>>,
+ http_downloader: std::rc::Rc<std::cell::RefCell<crate::util::HttpDownloader>>,
+ process: std::rc::Rc<std::cell::RefCell<crate::util::ProcessExecutor>>,
+ ) -> Self {
+ Self {
+ inner: VcsDriverBase::new(repo_config, io, config, http_downloader, process),
+ owner: String::new(),
+ repository: String::new(),
+ has_issues: false,
+ root_identifier: None,
+ tags: None,
+ branches: None,
+ branches_url: String::new(),
+ tags_url: String::new(),
+ home_url: String::new(),
+ website: String::new(),
+ clone_https_url: String::new(),
+ repo_data: IndexMap::new(),
+ fallback_driver: None,
+ vcs_type: None,
+ }
+ }
+
/// @inheritDoc
pub fn initialize(&mut self) -> Result<()> {
let mut m: indexmap::IndexMap<CaptureKey, String> = indexmap::IndexMap::new();
diff --git a/crates/shirabe/src/repository/vcs/github_driver.rs b/crates/shirabe/src/repository/vcs/github_driver.rs
index b3d5e05..6fc50ee 100644
--- a/crates/shirabe/src/repository/vcs/github_driver.rs
+++ b/crates/shirabe/src/repository/vcs/github_driver.rs
@@ -47,6 +47,30 @@ pub struct GitHubDriver {
}
impl GitHubDriver {
+ pub fn new(
+ repo_config: IndexMap<String, shirabe_php_shim::PhpMixed>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
+ config: std::rc::Rc<std::cell::RefCell<Config>>,
+ http_downloader: std::rc::Rc<std::cell::RefCell<crate::util::HttpDownloader>>,
+ process: std::rc::Rc<std::cell::RefCell<crate::util::ProcessExecutor>>,
+ ) -> Self {
+ Self {
+ inner: VcsDriverBase::new(repo_config, io, config, http_downloader, process),
+ owner: String::new(),
+ repository: String::new(),
+ tags: None,
+ branches: None,
+ root_identifier: String::new(),
+ repo_data: None,
+ has_issues: false,
+ is_private: false,
+ is_archived: false,
+ funding_info: None,
+ allow_git_fallback: true,
+ git_driver: None,
+ }
+ }
+
pub fn initialize(&mut self) -> Result<()> {
let mut match_: IndexMap<CaptureKey, String> = IndexMap::new();
if !Preg::is_match_strict_groups3(
diff --git a/crates/shirabe/src/repository/vcs/gitlab_driver.rs b/crates/shirabe/src/repository/vcs/gitlab_driver.rs
index 84a569f..84961f5 100644
--- a/crates/shirabe/src/repository/vcs/gitlab_driver.rs
+++ b/crates/shirabe/src/repository/vcs/gitlab_driver.rs
@@ -56,6 +56,29 @@ pub struct GitLabDriver {
impl GitLabDriver {
pub const URL_REGEX: &'static str = r##"#^(?:(?P<scheme>https?)://(?P<domain>.+?)(?::(?P<port>[0-9]+))?/|git@(?P<domain2>[^:]+):)(?P<parts>.+)/(?P<repo>[^/]+?)(?:\.git|/)?$#"##;
+ pub fn new(
+ repo_config: IndexMap<String, shirabe_php_shim::PhpMixed>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
+ config: std::rc::Rc<std::cell::RefCell<Config>>,
+ http_downloader: std::rc::Rc<std::cell::RefCell<crate::util::HttpDownloader>>,
+ process: std::rc::Rc<std::cell::RefCell<crate::util::ProcessExecutor>>,
+ ) -> Self {
+ Self {
+ inner: VcsDriverBase::new(repo_config, io, config, http_downloader, process),
+ scheme: String::new(),
+ namespace: String::new(),
+ repository: String::new(),
+ project: None,
+ commits: IndexMap::new(),
+ tags: None,
+ branches: None,
+ git_driver: None,
+ protocol: String::new(),
+ is_private: true,
+ has_nonstandard_origin: false,
+ }
+ }
+
/// Extracts information from the repository url.
///
/// SSH urls use https by default. Set "secure-http": false on the repository config to use http instead.
diff --git a/crates/shirabe/src/repository/vcs/hg_driver.rs b/crates/shirabe/src/repository/vcs/hg_driver.rs
index 1686f5d..c35a574 100644
--- a/crates/shirabe/src/repository/vcs/hg_driver.rs
+++ b/crates/shirabe/src/repository/vcs/hg_driver.rs
@@ -25,6 +25,22 @@ pub struct HgDriver {
}
impl HgDriver {
+ pub fn new(
+ repo_config: IndexMap<String, shirabe_php_shim::PhpMixed>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
+ config: std::rc::Rc<std::cell::RefCell<Config>>,
+ http_downloader: std::rc::Rc<std::cell::RefCell<crate::util::HttpDownloader>>,
+ process: std::rc::Rc<std::cell::RefCell<crate::util::ProcessExecutor>>,
+ ) -> Self {
+ Self {
+ inner: VcsDriverBase::new(repo_config, io, config, http_downloader, process),
+ tags: None,
+ branches: None,
+ root_identifier: None,
+ repo_dir: String::new(),
+ }
+ }
+
pub fn initialize(&mut self) -> anyhow::Result<()> {
if Filesystem::is_local_path(&self.inner.url) {
self.repo_dir = self.inner.url.clone();
diff --git a/crates/shirabe/src/repository/vcs/mod.rs b/crates/shirabe/src/repository/vcs/mod.rs
index 715d2e5..5c60e0a 100644
--- a/crates/shirabe/src/repository/vcs/mod.rs
+++ b/crates/shirabe/src/repository/vcs/mod.rs
@@ -21,3 +21,134 @@ pub use perforce_driver::*;
pub use svn_driver::*;
pub use vcs_driver::*;
pub use vcs_driver_interface::*;
+
+use crate::config::Config;
+use crate::io::IOInterface;
+use crate::util::{HttpDownloader, ProcessExecutor};
+use indexmap::IndexMap;
+use shirabe_php_shim::PhpMixed;
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum VcsDriverKind {
+ GitHub,
+ GitLab,
+ GitBitbucket,
+ Forgejo,
+ Git,
+ Hg,
+ Perforce,
+ Fossil,
+ Svn,
+}
+
+impl VcsDriverKind {
+ pub fn instantiate(
+ self,
+ repo_config: IndexMap<String, PhpMixed>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
+ config: std::rc::Rc<std::cell::RefCell<Config>>,
+ http_downloader: std::rc::Rc<std::cell::RefCell<HttpDownloader>>,
+ process: std::rc::Rc<std::cell::RefCell<ProcessExecutor>>,
+ ) -> Box<dyn VcsDriverInterface> {
+ match self {
+ VcsDriverKind::GitHub => Box::new(GitHubDriver::new(
+ repo_config,
+ io,
+ config,
+ http_downloader,
+ process,
+ )),
+ VcsDriverKind::GitLab => Box::new(GitLabDriver::new(
+ repo_config,
+ io,
+ config,
+ http_downloader,
+ process,
+ )),
+ VcsDriverKind::GitBitbucket => Box::new(GitBitbucketDriver::new(
+ repo_config,
+ io,
+ config,
+ http_downloader,
+ process,
+ )),
+ VcsDriverKind::Forgejo => Box::new(ForgejoDriver::new(
+ repo_config,
+ io,
+ config,
+ http_downloader,
+ process,
+ )),
+ VcsDriverKind::Git => Box::new(GitDriver::new(
+ repo_config,
+ io,
+ config,
+ http_downloader,
+ process,
+ )),
+ VcsDriverKind::Hg => Box::new(HgDriver::new(
+ repo_config,
+ io,
+ config,
+ http_downloader,
+ process,
+ )),
+ VcsDriverKind::Perforce => Box::new(PerforceDriver::new(
+ repo_config,
+ io,
+ config,
+ http_downloader,
+ process,
+ )),
+ VcsDriverKind::Fossil => Box::new(FossilDriver::new(
+ repo_config,
+ io,
+ config,
+ http_downloader,
+ process,
+ )),
+ VcsDriverKind::Svn => Box::new(SvnDriver::new(
+ repo_config,
+ io,
+ config,
+ http_downloader,
+ process,
+ )),
+ }
+ }
+
+ pub fn supports(
+ self,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
+ config: std::rc::Rc<std::cell::RefCell<Config>>,
+ url: &str,
+ deep: bool,
+ ) -> anyhow::Result<bool> {
+ match self {
+ VcsDriverKind::GitHub => GitHubDriver::supports(io, config, url, deep),
+ VcsDriverKind::GitLab => GitLabDriver::supports(io, config, url, deep),
+ VcsDriverKind::GitBitbucket => GitBitbucketDriver::supports(io, config, url, deep),
+ VcsDriverKind::Forgejo => ForgejoDriver::supports(io, config, url, deep),
+ VcsDriverKind::Git => GitDriver::supports(io, config, url, deep),
+ VcsDriverKind::Hg => HgDriver::supports(io, config, url, deep),
+ VcsDriverKind::Perforce => PerforceDriver::supports(io, config, url, deep),
+ VcsDriverKind::Fossil => FossilDriver::supports(io, config, url, deep),
+ VcsDriverKind::Svn => SvnDriver::supports(io, config, url, deep),
+ }
+ }
+
+ /// PHP fully-qualified `class-string`, used as the fallback driver name in `getRepoName()`.
+ pub fn php_class_name(self) -> &'static str {
+ match self {
+ VcsDriverKind::GitHub => "Composer\\Repository\\Vcs\\GitHubDriver",
+ VcsDriverKind::GitLab => "Composer\\Repository\\Vcs\\GitLabDriver",
+ VcsDriverKind::GitBitbucket => "Composer\\Repository\\Vcs\\GitBitbucketDriver",
+ VcsDriverKind::Forgejo => "Composer\\Repository\\Vcs\\ForgejoDriver",
+ VcsDriverKind::Git => "Composer\\Repository\\Vcs\\GitDriver",
+ VcsDriverKind::Hg => "Composer\\Repository\\Vcs\\HgDriver",
+ VcsDriverKind::Perforce => "Composer\\Repository\\Vcs\\PerforceDriver",
+ VcsDriverKind::Fossil => "Composer\\Repository\\Vcs\\FossilDriver",
+ VcsDriverKind::Svn => "Composer\\Repository\\Vcs\\SvnDriver",
+ }
+ }
+}
diff --git a/crates/shirabe/src/repository/vcs/perforce_driver.rs b/crates/shirabe/src/repository/vcs/perforce_driver.rs
index d653869..0fe0f6f 100644
--- a/crates/shirabe/src/repository/vcs/perforce_driver.rs
+++ b/crates/shirabe/src/repository/vcs/perforce_driver.rs
@@ -21,6 +21,21 @@ pub struct PerforceDriver {
}
impl PerforceDriver {
+ pub fn new(
+ repo_config: IndexMap<String, shirabe_php_shim::PhpMixed>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
+ config: std::rc::Rc<std::cell::RefCell<Config>>,
+ http_downloader: std::rc::Rc<std::cell::RefCell<crate::util::HttpDownloader>>,
+ process: std::rc::Rc<std::cell::RefCell<crate::util::ProcessExecutor>>,
+ ) -> Self {
+ Self {
+ inner: VcsDriverBase::new(repo_config, io, config, http_downloader, process),
+ depot: String::new(),
+ branch: String::new(),
+ perforce: None,
+ }
+ }
+
pub fn initialize(&mut self) -> anyhow::Result<()> {
self.depot = self
.inner
diff --git a/crates/shirabe/src/repository/vcs/svn_driver.rs b/crates/shirabe/src/repository/vcs/svn_driver.rs
index 9b2ea47..377d698 100644
--- a/crates/shirabe/src/repository/vcs/svn_driver.rs
+++ b/crates/shirabe/src/repository/vcs/svn_driver.rs
@@ -50,6 +50,28 @@ pub struct SvnDriver {
}
impl SvnDriver {
+ pub fn new(
+ repo_config: IndexMap<String, shirabe_php_shim::PhpMixed>,
+ io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
+ config: std::rc::Rc<std::cell::RefCell<Config>>,
+ http_downloader: std::rc::Rc<std::cell::RefCell<crate::util::HttpDownloader>>,
+ process: std::rc::Rc<std::cell::RefCell<crate::util::ProcessExecutor>>,
+ ) -> Self {
+ Self {
+ inner: VcsDriverBase::new(repo_config, io, config, http_downloader, process),
+ base_url: String::new(),
+ tags: None,
+ branches: None,
+ root_identifier: None,
+ trunk_path: Some("trunk".to_string()),
+ branches_path: "branches".to_string(),
+ tags_path: "tags".to_string(),
+ package_path: String::new(),
+ cache_credentials: true,
+ util: None,
+ }
+ }
+
pub fn initialize(&mut self) -> Result<()> {
let normalized = Self::normalize_url(&self.inner.url);
self.inner.url = normalized.trim_end_matches('/').to_string();