aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-07-20 23:30:19 +0900
committernsfisis <nsfisis@gmail.com>2026-07-20 23:30:19 +0900
commit641451481bcff596a7db52b5f2bcbeaddbeb1681 (patch)
tree364e24bf182efe755f6ece9278aafc0ac99b578a
parent2862d2da275a672f22485f5d1db3550248b20251 (diff)
downloadphp-shirabe-641451481bcff596a7db52b5f2bcbeaddbeb1681.tar.gz
php-shirabe-641451481bcff596a7db52b5f2bcbeaddbeb1681.tar.zst
php-shirabe-641451481bcff596a7db52b5f2bcbeaddbeb1681.zip
perf(composer-repository): avoid redundant clones when checking security advisories
get_security_advisories cloned each package's full metadata blob (hundreds of versions for popular packages) just to peek at its "security-advisories" field. Same pattern already fixed in load_async_packages by 2862d2da; move ownership through pattern matches and IndexMap::shift_remove instead. Measured with laravel/laravel create-project: response processing in the security-advisories metadata branch drops ~80% (236ms -> 48ms), and the whole run_security_advisory_filter phase drops from ~420-500ms to ~250-270ms. End-to-end, shirabe now matches or edges out upstream Composer (6.57s vs 6.85s in this run) instead of trailing by ~1.2s.
-rw-r--r--crates/shirabe/src/repository/composer_repository.rs35
1 files changed, 17 insertions, 18 deletions
diff --git a/crates/shirabe/src/repository/composer_repository.rs b/crates/shirabe/src/repository/composer_repository.rs
index ab83ace2..66d530c4 100644
--- a/crates/shirabe/src/repository/composer_repository.rs
+++ b/crates/shirabe/src/repository/composer_repository.rs
@@ -996,31 +996,30 @@ impl ComposerRepository {
let spec = spec?;
// [$response] = $spec;
- let response = spec
- .as_list()
- .and_then(|l| l.first())
- .cloned()
- .unwrap_or(PhpMixed::Null);
- let response_arr = match response.as_array() {
- Some(a) => a.clone(),
- None => continue,
+ let response = match spec {
+ PhpMixed::List(mut l) if !l.is_empty() => l.remove(0),
+ _ => PhpMixed::Null,
};
- let sec_advs_arr = match response_arr.get("security-advisories") {
- Some(PhpMixed::List(l)) => l.clone(),
- Some(PhpMixed::Array(a)) => a.values().cloned().collect(),
+ // Takes ownership out of response instead of cloning: response is local to this
+ // iteration's own package metadata and is not read again afterwards.
+ let mut response_arr = match response {
+ PhpMixed::Array(a) => a,
+ _ => continue,
+ };
+ let sec_advs_arr = match response_arr.shift_remove("security-advisories") {
+ Some(PhpMixed::List(l)) => l,
+ Some(PhpMixed::Array(a)) => a.into_values().collect(),
_ => continue,
};
names_found.insert(name.clone(), true);
if !sec_advs_arr.is_empty() {
let mut entries: Vec<AnySecurityAdvisory> = Vec::new();
- for data_mixed in sec_advs_arr.iter() {
- if let Some(data) = data_mixed.as_array() {
- let data_map: IndexMap<String, PhpMixed> =
- data.iter().map(|(k, v)| (k.clone(), v.clone())).collect();
- if let Some(adv) = create(&data_map, &name, &package_constraint_map)? {
- entries.push(adv);
- }
+ for data_mixed in sec_advs_arr.into_iter() {
+ if let PhpMixed::Array(data_map) = data_mixed
+ && let Some(adv) = create(&data_map, &name, &package_constraint_map)?
+ {
+ entries.push(adv);
}
}
advisories.insert(name.clone(), entries);