fork: implement promote, sync diff, exclude/include, and merge with excludes

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I2d10e3f970784e84192cbca10caffe296a6a6964
This commit is contained in:
raf 2026-04-21 23:34:11 +03:00
commit 45d5f7e99b
Signed by: NotAShelf
GPG key ID: 29D95B64378DB4BF
4 changed files with 315 additions and 78 deletions

View file

@ -233,14 +233,17 @@ fn merge_lockfiles(
// Collect local project slugs for override detection
let mut local_slugs = std::collections::HashSet::new();
for project in &local.projects {
// Add all slugs from all platforms
for slug in project.slug.values() {
local_slugs.insert(slug.clone());
}
}
// Add parent projects that are NOT overridden by local
let parent_projects_count = parent.projects.len();
// Collect excluded slugs from local config
let excluded: std::collections::HashSet<_> =
local_config.excludes.iter().collect();
// Add parent projects that are NOT overridden by local and NOT excluded
let mut parent_kept = 0usize;
for parent_project in &parent.projects {
let is_overridden = parent_project
@ -248,53 +251,63 @@ fn merge_lockfiles(
.values()
.any(|slug| local_slugs.contains(slug));
if !is_overridden {
// Check if project has local config overrides
let mut project = parent_project.clone();
let is_excluded = parent_project
.slug
.values()
.any(|slug| excluded.contains(slug))
|| parent_project
.name
.values()
.any(|name| excluded.contains(name));
// Apply local config overrides if they exist
for (key, local_proj_cfg) in &local_config.projects {
// Match by slug, name, or pakku_id
let matches = project.slug.values().any(|s| s == key)
|| project.name.values().any(|n| n == key)
|| project.pakku_id.as_ref() == Some(key);
if matches {
if let Some(t) = local_proj_cfg.r#type {
project.r#type = t;
}
if let Some(s) = local_proj_cfg.side {
project.side = s;
}
if let Some(us) = local_proj_cfg.update_strategy {
project.update_strategy = us;
}
if let Some(r) = local_proj_cfg.redistributable {
project.redistributable = r;
}
if let Some(ref sp) = local_proj_cfg.subpath {
project.subpath = Some(sp.clone());
}
if let Some(ref aliases) = local_proj_cfg.aliases {
project.aliases = aliases.iter().cloned().collect();
}
if let Some(e) = local_proj_cfg.export {
project.export = e;
}
break;
}
}
merged.projects.push(project);
if is_overridden || is_excluded {
continue;
}
let mut project = parent_project.clone();
// Apply local config attribute overrides (side, type, etc.)
for (key, local_proj_cfg) in &local_config.projects {
let matches = project.slug.values().any(|s| s == key)
|| project.name.values().any(|n| n == key)
|| project.pakku_id.as_ref() == Some(key);
if matches {
if let Some(t) = local_proj_cfg.r#type {
project.r#type = t;
}
if let Some(s) = local_proj_cfg.side {
project.side = s;
}
if let Some(us) = local_proj_cfg.update_strategy {
project.update_strategy = us;
}
if let Some(r) = local_proj_cfg.redistributable {
project.redistributable = r;
}
if let Some(ref sp) = local_proj_cfg.subpath {
project.subpath = Some(sp.clone());
}
if let Some(ref aliases) = local_proj_cfg.aliases {
project.aliases = aliases.iter().cloned().collect();
}
if let Some(e) = local_proj_cfg.export {
project.export = e;
}
break;
}
}
merged.projects.push(project);
parent_kept += 1;
}
// Add all local projects
merged.projects.extend(local.projects.clone());
println!(
"Merged fork: {} parent projects + {} local projects = {} total projects",
parent_projects_count - local_config.projects.len(),
"Merged fork: {} parent + {} local = {} total projects",
parent_kept,
local.projects.len(),
merged.projects.len()
);