aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/src/package
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-05-31 21:34:47 +0900
committernsfisis <nsfisis@gmail.com>2026-06-01 01:45:00 +0900
commit20dbcf11b86cb03c451ba1d5cd9efe17b68fa66d (patch)
treed1fc3aaee3b2829d71f49581e1abc86ee62e525f /crates/shirabe/src/package
parent29df13733ae4acfd2b172bc9fd9ac9fd28efa013 (diff)
downloadphp-shirabe-20dbcf11b86cb03c451ba1d5cd9efe17b68fa66d.tar.gz
php-shirabe-20dbcf11b86cb03c451ba1d5cd9efe17b68fa66d.tar.zst
php-shirabe-20dbcf11b86cb03c451ba1d5cd9efe17b68fa66d.zip
fix(package): port every PHP clone operator to handle dup()HEADmain
Diffstat (limited to 'crates/shirabe/src/package')
-rw-r--r--crates/shirabe/src/package/alias_package.rs2
-rw-r--r--crates/shirabe/src/package/complete_alias_package.rs4
-rw-r--r--crates/shirabe/src/package/complete_package.rs2
-rw-r--r--crates/shirabe/src/package/handle.rs41
-rw-r--r--crates/shirabe/src/package/loader/root_package_loader.rs19
-rw-r--r--crates/shirabe/src/package/locker.rs3
-rw-r--r--crates/shirabe/src/package/package.rs2
-rw-r--r--crates/shirabe/src/package/root_alias_package.rs14
-rw-r--r--crates/shirabe/src/package/root_package.rs2
9 files changed, 64 insertions, 25 deletions
diff --git a/crates/shirabe/src/package/alias_package.rs b/crates/shirabe/src/package/alias_package.rs
index ff846a6..b4ddc70 100644
--- a/crates/shirabe/src/package/alias_package.rs
+++ b/crates/shirabe/src/package/alias_package.rs
@@ -13,7 +13,7 @@ use crate::package::PackageInterface;
use crate::package::version::VersionParser;
use crate::repository::RepositoryInterfaceHandle;
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub struct AliasPackage {
id: i64,
name: String,
diff --git a/crates/shirabe/src/package/complete_alias_package.rs b/crates/shirabe/src/package/complete_alias_package.rs
index 6a23bee..7720258 100644
--- a/crates/shirabe/src/package/complete_alias_package.rs
+++ b/crates/shirabe/src/package/complete_alias_package.rs
@@ -9,9 +9,9 @@ use crate::package::CompletePackageInterface;
use crate::package::PackageHandle;
use crate::package::handle::delegate_package_interface_to_inner;
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub struct CompleteAliasPackage {
- inner: AliasPackage,
+ pub(crate) inner: AliasPackage,
// overrides AliasPackage::alias_of with the more specific CompletePackage type
pub(crate) alias_of: CompletePackageHandle,
}
diff --git a/crates/shirabe/src/package/complete_package.rs b/crates/shirabe/src/package/complete_package.rs
index 55c7654..97669d8 100644
--- a/crates/shirabe/src/package/complete_package.rs
+++ b/crates/shirabe/src/package/complete_package.rs
@@ -6,7 +6,7 @@ use crate::package::PackageInterface;
use indexmap::IndexMap;
use shirabe_php_shim::PhpMixed;
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub struct CompletePackage {
pub(crate) inner: Package,
pub(crate) repositories: Vec<IndexMap<String, PhpMixed>>,
diff --git a/crates/shirabe/src/package/handle.rs b/crates/shirabe/src/package/handle.rs
index 746e2ce..aecc219 100644
--- a/crates/shirabe/src/package/handle.rs
+++ b/crates/shirabe/src/package/handle.rs
@@ -12,7 +12,7 @@ use crate::package::{
};
/// Any package type.
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub enum AnyPackage {
Package(Package),
CompletePackage(CompletePackage),
@@ -137,6 +137,36 @@ impl AnyPackage {
pub fn is_root_alias(&self) -> bool {
matches!(self, Self::RootAliasPackage(_))
}
+
+ /// PHP `clone $package`: fresh object identity. Matches PHP's shallow
+ /// clone for most types (scalars/arrays are copied, nested object
+ /// references — including `aliasOf` on alias variants — are shared),
+ /// except for RootAliasPackage where PHP's `__clone` hook explicitly
+ /// reseats `aliasOf` to a fresh clone.
+ pub fn dup(&self) -> Self {
+ match self {
+ Self::Package(p) => Self::Package(p.clone()),
+ Self::CompletePackage(p) => Self::CompletePackage(p.clone()),
+ Self::RootPackage(p) => Self::RootPackage(p.clone()),
+ Self::AliasPackage(p) => Self::AliasPackage(p.clone()),
+ Self::CompleteAliasPackage(p) => Self::CompleteAliasPackage(p.clone()),
+ Self::RootAliasPackage(p) => {
+ // PHP's RootAliasPackage overrides `__clone()`:
+ // $this->aliasOf = clone $this->aliasOf;
+ let new_alias_of_inner = p.alias_of.0.borrow().dup();
+ let new_alias_of_rc = Rc::new(RefCell::new(new_alias_of_inner));
+ let new_root = RootPackageHandle(new_alias_of_rc.clone());
+ let new_complete = CompletePackageHandle(new_alias_of_rc.clone());
+ let new_pkg = PackageHandle(new_alias_of_rc);
+
+ let mut cloned = p.clone();
+ cloned.alias_of = new_root;
+ cloned.inner.alias_of = new_complete;
+ cloned.inner.inner.alias_of = new_pkg;
+ Self::RootAliasPackage(cloned)
+ }
+ }
+ }
}
macro_rules! delegate_package_interface_to_inner {
@@ -1119,6 +1149,15 @@ macro_rules! impl_handle_common {
pub fn ptr_eq(&self, other: &Self) -> bool {
std::rc::Rc::ptr_eq(&self.0, &other.0)
}
+
+ /// PHP `clone $x`: fresh object identity. See [`AnyPackage::dup`]
+ /// for the per-variant semantics (including the RootAliasPackage
+ /// `__clone` hook).
+ pub fn dup(other: &Self) -> Self {
+ Self(std::rc::Rc::new(std::cell::RefCell::new(
+ other.0.borrow().dup(),
+ )))
+ }
}
impl PartialEq for $Handle {
diff --git a/crates/shirabe/src/package/loader/root_package_loader.rs b/crates/shirabe/src/package/loader/root_package_loader.rs
index 1b4d155..b31525f 100644
--- a/crates/shirabe/src/package/loader/root_package_loader.rs
+++ b/crates/shirabe/src/package/loader/root_package_loader.rs
@@ -11,8 +11,6 @@ use crate::io::IOInterface;
use crate::io::IOInterfaceImmutable;
use crate::package::CompletePackageInterface;
use crate::package::PackageInterface;
-use crate::package::RootAliasPackage;
-use crate::package::RootPackage;
use crate::package::RootPackageInterface;
use crate::package::loader::ArrayLoader;
use crate::package::loader::LoaderInterface;
@@ -194,19 +192,16 @@ impl RootPackageLoader {
Some("Composer\\Package\\RootPackage".to_string()),
)?;
- // TODO(phase-c): mutating the loaded RootPackage through a PackageInterfaceHandle
- // requires going through as_root_package() + a RefCell borrow; the inherent
- // RootPackage mutators used below are not yet reachable that way.
- let real_package: &mut RootPackage = {
- let _ = &mut package;
- todo!(
- "mutate RootPackage through PackageInterfaceHandle (as_root_package + borrow_mut)"
- )
+ let real_package = if let Some(alias) = package.as_root_alias_package() {
+ alias.get_alias_of()
+ } else {
+ package
+ .as_root_package()
+ .expect("Expecting a Composer\\Package\\RootPackage at this point")
};
if auto_versioned {
// TODO(phase-b): replace_version is an inherent method on Package, not exposed via trait.
- let _ = real_package;
todo!("replace_version is not accessible through RootPackage's embedded Package");
}
@@ -230,7 +225,7 @@ impl RootPackageLoader {
aliases = self.extract_aliases(&links, aliases);
stability_flags = Self::extract_stability_flags(
&links,
- real_package.get_minimum_stability(),
+ &real_package.get_minimum_stability(),
stability_flags,
);
references = Self::extract_references(&links, references);
diff --git a/crates/shirabe/src/package/locker.rs b/crates/shirabe/src/package/locker.rs
index 327f662..9e36255 100644
--- a/crates/shirabe/src/package/locker.rs
+++ b/crates/shirabe/src/package/locker.rs
@@ -951,8 +951,7 @@ impl Locker {
description: "Required (in require-dev)".to_string(),
});
}
- // TODO(phase-b): clone $package to a RootPackageRepository
- let root_repo = RootPackageRepository::new(todo!("phase-b: clone root package"));
+ let root_repo = RootPackageRepository::new(RootPackageInterfaceHandle::dup(&package));
for set in &sets {
let installed_repo = InstalledRepository::new(vec![/* set.repo, root_repo */]);
diff --git a/crates/shirabe/src/package/package.rs b/crates/shirabe/src/package/package.rs
index ba9e3f9..f573326 100644
--- a/crates/shirabe/src/package/package.rs
+++ b/crates/shirabe/src/package/package.rs
@@ -24,7 +24,7 @@ pub struct Mirror {
}
/// Core package definitions that are needed to resolve dependencies and install packages
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub struct Package {
id: i64,
name: String,
diff --git a/crates/shirabe/src/package/root_alias_package.rs b/crates/shirabe/src/package/root_alias_package.rs
index 7298c1f..67e123b 100644
--- a/crates/shirabe/src/package/root_alias_package.rs
+++ b/crates/shirabe/src/package/root_alias_package.rs
@@ -11,9 +11,9 @@ use crate::package::RootPackageHandle;
use crate::package::RootPackageInterface;
use crate::package::handle::delegate_package_interface_to_inner;
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub struct RootAliasPackage {
- inner: CompleteAliasPackage,
+ pub(crate) inner: CompleteAliasPackage,
// overrides CompleteAliasPackage::alias_of with the more specific RootPackage type
pub(crate) alias_of: RootPackageHandle,
}
@@ -83,8 +83,14 @@ impl RootPackageInterface for RootAliasPackage {
}
fn set_requires(&mut self, requires: Vec<Link>) {
- // TODO(phase-c): PHP re-derives the local links via
- // replaceSelfVersionDependencies before forwarding to aliasOf.
+ let replaced = self
+ .inner
+ .inner
+ .replace_self_version_dependencies(requires.clone(), Link::TYPE_REQUIRE);
+ self.inner.inner.requires = replaced
+ .into_iter()
+ .map(|l| (l.get_target().to_string(), l))
+ .collect();
self.alias_of.set_requires(requires);
}
diff --git a/crates/shirabe/src/package/root_package.rs b/crates/shirabe/src/package/root_package.rs
index 5a719de..9cedc1a 100644
--- a/crates/shirabe/src/package/root_package.rs
+++ b/crates/shirabe/src/package/root_package.rs
@@ -11,7 +11,7 @@ use crate::package::PackageInterface;
use crate::package::RootPackageInterface;
use crate::repository::RepositoryInterfaceHandle;
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub struct RootPackage {
inner: CompletePackage,
pub(crate) minimum_stability: String,