aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/src/package
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-05-17 11:52:08 +0900
committernsfisis <nsfisis@gmail.com>2026-05-17 11:52:20 +0900
commit93a7671c98a9f022d757781f8fe583a2d55df07b (patch)
tree66ad0cef7ac58823262280a6bf94961c1d73f92a /crates/shirabe/src/package
parent35690acf83fa4473311a18e970ecd8156e1e6ac0 (diff)
downloadphp-shirabe-93a7671c98a9f022d757781f8fe583a2d55df07b.tar.gz
php-shirabe-93a7671c98a9f022d757781f8fe583a2d55df07b.tar.zst
php-shirabe-93a7671c98a9f022d757781f8fe583a2d55df07b.zip
refactor(shirabe): convert PHP abstract classes to Rust traits
PHP abstract classes are represented as traits to better align with Rust's type system.
Diffstat (limited to 'crates/shirabe/src/package')
-rw-r--r--crates/shirabe/src/package/archiver/base_exclude_filter.rs43
-rw-r--r--crates/shirabe/src/package/base_package.rs170
2 files changed, 76 insertions, 137 deletions
diff --git a/crates/shirabe/src/package/archiver/base_exclude_filter.rs b/crates/shirabe/src/package/archiver/base_exclude_filter.rs
index f20af20..6522d79 100644
--- a/crates/shirabe/src/package/archiver/base_exclude_filter.rs
+++ b/crates/shirabe/src/package/archiver/base_exclude_filter.rs
@@ -3,22 +3,16 @@
use shirabe_external_packages::composer::pcre::preg::Preg;
use shirabe_external_packages::symfony::component::finder::glob::Glob;
-#[derive(Debug)]
-pub struct BaseExcludeFilter {
- pub(crate) source_path: String,
- pub(crate) exclude_patterns: Vec<(String, bool, bool)>,
-}
-
-impl BaseExcludeFilter {
- pub fn new(source_path: String) -> Self {
- Self {
- source_path,
- exclude_patterns: vec![],
- }
- }
+pub trait BaseExcludeFilter {
+ fn source_path(&self) -> &str;
+ fn exclude_patterns(&self) -> &[(String, bool, bool)];
+ fn exclude_patterns_mut(&mut self) -> &mut Vec<(String, bool, bool)>;
- pub fn filter(&self, relative_path: &str, mut exclude: bool) -> bool {
- for (pattern, negate, strip_leading_slash) in &self.exclude_patterns {
+ /// Checks the given path against all exclude patterns in this filter
+ ///
+ /// Negated patterns overwrite exclude decisions of previous filters.
+ fn filter(&self, relative_path: &str, mut exclude: bool) -> bool {
+ for (pattern, negate, strip_leading_slash) in self.exclude_patterns() {
let path = if *strip_leading_slash {
&relative_path[1..]
} else {
@@ -36,30 +30,33 @@ impl BaseExcludeFilter {
exclude
}
- pub fn parse_lines<F>(&self, lines: Vec<String>, line_parser: F) -> Vec<(String, bool, bool)>
+ /// Processes a file containing exclude rules of different formats per line
+ fn parse_lines<F>(&self, lines: Vec<String>, line_parser: F) -> Vec<(String, bool, bool)>
where
F: Fn(&str) -> Option<(String, bool, bool)>,
{
lines
.into_iter()
.filter_map(|line| {
- let line = line.trim();
+ let line = line.trim().to_string();
if line.is_empty() || line.starts_with('#') {
return None;
}
- line_parser(line)
+ line_parser(&line)
})
.collect()
}
- pub fn generate_patterns(&self, rules: Vec<String>) -> Vec<(String, bool, bool)> {
+ /// Generates a set of exclude patterns for filter() from gitignore rules
+ fn generate_patterns(&self, rules: Vec<String>) -> Vec<(String, bool, bool)> {
rules
.into_iter()
.map(|rule| self.generate_pattern(&rule))
.collect()
}
- pub fn generate_pattern(&self, rule: &str) -> (String, bool, bool) {
+ /// Generates an exclude pattern for filter() from a gitignore rule
+ fn generate_pattern(&self, rule: &str) -> (String, bool, bool) {
let mut negate = false;
let mut pattern = String::new();
@@ -82,6 +79,10 @@ impl BaseExcludeFilter {
let glob_regex = Glob::to_regex(rule);
let rule_regex = &glob_regex[2..glob_regex.len() - 2];
- (format!("{}{}(?=$|/)", pattern, rule_regex), negate, false)
+ (
+ format!("{{{}{}(?=$|/)}}", pattern, rule_regex),
+ negate,
+ false,
+ )
}
}
diff --git a/crates/shirabe/src/package/base_package.rs b/crates/shirabe/src/package/base_package.rs
index 4cbd11c..eb6cc90 100644
--- a/crates/shirabe/src/package/base_package.rs
+++ b/crates/shirabe/src/package/base_package.rs
@@ -58,55 +58,43 @@ pub static SUPPORTED_LINK_TYPES: LazyLock<IndexMap<&'static str, SupportedLinkTy
pub static STABILITIES: LazyLock<IndexMap<&'static str, i64>> = LazyLock::new(|| {
let mut m = IndexMap::new();
- m.insert("stable", BasePackage::STABILITY_STABLE);
- m.insert("RC", BasePackage::STABILITY_RC);
- m.insert("beta", BasePackage::STABILITY_BETA);
- m.insert("alpha", BasePackage::STABILITY_ALPHA);
- m.insert("dev", BasePackage::STABILITY_DEV);
+ m.insert("stable", 0i64);
+ m.insert("RC", 5i64);
+ m.insert("beta", 10i64);
+ m.insert("alpha", 15i64);
+ m.insert("dev", 20i64);
m
});
-#[derive(Debug)]
-pub struct BasePackage {
- pub id: i64,
- pub(crate) name: String,
- pub(crate) pretty_name: String,
- pub(crate) repository: Option<Box<dyn RepositoryInterface>>,
-}
-
-impl std::fmt::Display for BasePackage {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(f, "{}", self.get_unique_name())
- }
-}
+pub trait BasePackage: PackageInterface + std::fmt::Display {
+ const STABILITY_STABLE: i64 = 0;
+ const STABILITY_RC: i64 = 5;
+ const STABILITY_BETA: i64 = 10;
+ const STABILITY_ALPHA: i64 = 15;
+ const STABILITY_DEV: i64 = 20;
-impl BasePackage {
- pub const STABILITY_STABLE: i64 = 0;
- pub const STABILITY_RC: i64 = 5;
- pub const STABILITY_BETA: i64 = 10;
- pub const STABILITY_ALPHA: i64 = 15;
- pub const STABILITY_DEV: i64 = 20;
+ fn id(&self) -> i64;
+ fn id_mut(&mut self) -> &mut i64;
+ fn name(&self) -> &str;
+ fn name_mut(&mut self) -> &mut String;
+ fn pretty_name(&self) -> &str;
+ fn pretty_name_mut(&mut self) -> &mut String;
+ fn repository_opt(&self) -> Option<&dyn RepositoryInterface>;
+ fn set_repository_box(&mut self, repository: Box<dyn RepositoryInterface>);
+ fn take_repository(&mut self) -> Option<Box<dyn RepositoryInterface>>;
- pub fn new(name: String) -> Self {
- let pretty_name = name.clone();
- let name = name.to_lowercase();
- Self {
- id: -1,
- name,
- pretty_name,
- repository: None,
- }
- }
+ fn as_any(&self) -> &dyn std::any::Any;
+ fn clone_box(&self) -> Box<dyn BasePackage>;
- pub fn get_name(&self) -> &str {
- &self.name
+ fn get_name(&self) -> &str {
+ self.name()
}
- pub fn get_pretty_name(&self) -> &str {
- &self.pretty_name
+ fn get_pretty_name(&self) -> &str {
+ self.pretty_name()
}
- pub fn get_names(&self, provides: bool) -> Vec<String> {
+ fn get_names(&self, provides: bool) -> Vec<String> {
let mut names: IndexMap<String, bool> = IndexMap::new();
names.insert(self.get_name().to_string(), true);
@@ -123,19 +111,16 @@ impl BasePackage {
names.into_keys().collect()
}
- pub fn set_id(&mut self, id: i64) {
- self.id = id;
+ fn set_id(&mut self, id: i64) {
+ *self.id_mut() = id;
}
- pub fn get_id(&self) -> i64 {
- self.id
+ fn get_id(&self) -> i64 {
+ self.id()
}
- pub fn set_repository(
- &mut self,
- repository: Box<dyn RepositoryInterface>,
- ) -> anyhow::Result<()> {
- if let Some(ref existing) = self.repository {
+ fn set_repository(&mut self, repository: Box<dyn RepositoryInterface>) -> anyhow::Result<()> {
+ if let Some(existing) = self.repository_opt() {
// TODO(phase-b): proper reference identity check before raising error
return Err(anyhow::anyhow!(LogicException {
message: format!(
@@ -147,40 +132,35 @@ impl BasePackage {
code: 0,
}));
}
- self.repository = Some(repository);
+ self.set_repository_box(repository);
Ok(())
}
- pub fn get_repository(&self) -> Option<&dyn RepositoryInterface> {
- self.repository.as_deref()
+ fn get_repository(&self) -> Option<&dyn RepositoryInterface> {
+ self.repository_opt()
}
- pub fn is_platform(&self) -> bool {
- self.repository
- .as_ref()
+ fn is_platform(&self) -> bool {
+ self.repository_opt()
.and_then(|r| r.as_any().downcast_ref::<PlatformRepository>())
.is_some()
}
- pub fn get_unique_name(&self) -> String {
+ fn get_unique_name(&self) -> String {
format!("{}-{}", self.get_name(), self.get_version())
}
- pub fn equals(&self, _package: &dyn PackageInterface) -> bool {
+ fn equals(&self, _package: &dyn PackageInterface) -> bool {
// TODO(phase-b): implement via reference identity (requires Rc/Arc)
// PHP uses === which is reference equality; unwraps AliasPackage on both sides
todo!("equals requires reference identity which needs Rc/Arc")
}
- pub fn get_pretty_string(&self) -> String {
+ fn get_pretty_string(&self) -> String {
format!("{} {}", self.get_pretty_name(), self.get_pretty_version())
}
- pub fn get_full_pretty_version(
- &self,
- truncate: bool,
- display_mode: i64,
- ) -> anyhow::Result<String> {
+ fn get_full_pretty_version(&self, truncate: bool, display_mode: i64) -> anyhow::Result<String> {
const DISPLAY_SOURCE_REF_IF_DEV: i64 = PackageInterface::DISPLAY_SOURCE_REF_IF_DEV;
const DISPLAY_SOURCE_REF: i64 = PackageInterface::DISPLAY_SOURCE_REF;
const DISPLAY_DIST_REF: i64 = PackageInterface::DISPLAY_DIST_REF;
@@ -224,75 +204,33 @@ impl BasePackage {
Ok(format!("{} {}", self.get_pretty_version(), reference))
}
- pub fn get_stability_priority(&self) -> i64 {
+ fn get_stability_priority(&self) -> i64 {
*STABILITIES
.get(self.get_stability())
.unwrap_or(&Self::STABILITY_STABLE)
}
- pub fn php_clone(&mut self) {
- self.repository = None;
- self.id = -1;
+ fn php_clone(&mut self) {
+ self.take_repository();
+ *self.id_mut() = -1;
}
- pub fn package_name_to_regexp(allow_pattern: &str, wrap: &str) -> String {
+ fn package_name_to_regexp(allow_pattern: &str, wrap: &str) -> String
+ where
+ Self: Sized,
+ {
let cleaned = preg_quote(allow_pattern, None).replace("\\*", ".*");
wrap.replace("%s", &cleaned)
}
- pub fn package_names_to_regexp(package_names: &[String], wrap: &str) -> String {
+ fn package_names_to_regexp(package_names: &[String], wrap: &str) -> String
+ where
+ Self: Sized,
+ {
let patterns: Vec<String> = package_names
.iter()
.map(|name| Self::package_name_to_regexp(name, "%s"))
.collect();
wrap.replace("%s", &patterns.join("|"))
}
-
- // Methods below are defined in Package/CompletePackage subclasses in PHP.
- // Called via $this polymorphism from BasePackage methods.
- // TODO(phase-b): resolve via trait dispatch or field access in concrete types.
-
- pub fn get_provides(&self) -> IndexMap<String, Link> {
- todo!("defined in Package subclass")
- }
-
- pub fn get_replaces(&self) -> IndexMap<String, Link> {
- todo!("defined in Package subclass")
- }
-
- pub fn get_version(&self) -> &str {
- todo!("defined in Package subclass")
- }
-
- pub fn get_pretty_version(&self) -> &str {
- todo!("defined in Package subclass")
- }
-
- pub fn is_dev(&self) -> bool {
- todo!("defined in Package subclass")
- }
-
- pub fn get_source_type(&self) -> Option<&str> {
- todo!("defined in Package subclass")
- }
-
- pub fn get_source_reference(&self) -> Option<&str> {
- todo!("defined in Package subclass")
- }
-
- pub fn get_dist_reference(&self) -> Option<&str> {
- todo!("defined in Package subclass")
- }
-
- pub fn get_stability(&self) -> &str {
- todo!("defined in Package subclass")
- }
-
- pub fn as_any(&self) -> &dyn std::any::Any {
- self
- }
-
- pub fn clone_box(&self) -> Box<BasePackage> {
- todo!("clone_box needs resolution in Phase B")
- }
}