pub(in crate::cli::pipeline) fn sync_cargo_lock_path_versions(
content: &str,
versions: &std::collections::HashMap<String, String>,
) -> Option<String> {
let mut out = String::with_capacity(content.len());
let mut changed = false;
let mut block: Vec<&str> = Vec::new();
let mut in_package_block = false;
for line in content.lines() {
if line.trim() == "[[package]]" {
changed |= append_package_block(&mut block, &mut out, versions);
in_package_block = true;
block.push(line);
} else if in_package_block {
block.push(line);
} else {
out.push_str(line);
out.push('\n');
}
}
changed |= append_package_block(&mut block, &mut out, versions);
if !changed {
return None;
}
if !content.ends_with('\n') {
out.pop();
}
Some(out)
}
fn append_package_block(
block: &mut Vec<&str>,
out: &mut String,
versions: &std::collections::HashMap<String, String>,
) -> bool {
if block.is_empty() {
return false;
}
let mut changed = false;
let is_package = block.first().is_some_and(|l| l.trim() == "[[package]]");
let has_source = block.iter().any(|l| l.trim_start().starts_with("source = "));
let version = block.iter().find_map(|line| {
line.trim()
.strip_prefix("name = \"")
.and_then(|name| name.strip_suffix('"'))
.and_then(|name| versions.get(name))
});
for line in block.iter() {
if is_package
&& !has_source
&& line.trim_start().starts_with("version = ")
&& let Some(new_version) = version
{
let indent_len = line.len() - line.trim_start().len();
let indent = &line[..indent_len];
let rewritten = format!(r#"{indent}version = "{new_version}""#);
if rewritten != *line {
changed = true;
}
out.push_str(&rewritten);
} else {
out.push_str(line);
}
out.push('\n');
}
block.clear();
changed
}