use makefile_lossless::{Makefile, Rule};
pub fn dh_invoke_add_with(line: &str, with_argument: &str) -> String {
if line.contains(with_argument) {
return line.to_owned();
}
if !line.contains(" --with") {
return format!("{} --with={}", line, with_argument);
}
lazy_regex::regex_replace!(
r"([ \t])--with([ =])([^ \t]+)",
line,
|_, head, _with, tail| format!("{}--with={},{}", head, with_argument, tail)
)
.to_string()
}
pub fn dh_invoke_get_with(line: &str) -> Vec<String> {
let mut ret = Vec::new();
for cap in lazy_regex::regex!("[ \t]--with[ =]([^ \t]+)").captures_iter(line) {
if let Some(m) = cap.get(1) {
ret.extend(m.as_str().split(',').map(|s| s.to_owned()));
}
}
ret
}
pub fn dh_invoke_drop_with(line: &str, with_argument: &str) -> String {
if !line.contains(with_argument) {
return line.to_owned();
}
let mut result = line.to_owned();
let escaped = regex::escape(with_argument);
if let Ok(re) = regex::Regex::new(&format!(r"[ \t]--with[ =]{}( .+|)$", escaped)) {
result = re.replace(&result, "$1").to_string();
}
if let Ok(re) = regex::Regex::new(&format!(r"([ \t])--with([ =]){},", escaped)) {
result = re.replace(&result, "${1}--with${2}").to_string();
}
if let Ok(re) = regex::Regex::new(&format!(r"([ \t])--with([ =])(.+),{}([ ,])", escaped)) {
result = re.replace(&result, "${1}--with${2}${3}${4}").to_string();
}
if let Ok(re) = regex::Regex::new(&format!(r"([ \t])--with([ =])(.+),{}$", escaped)) {
result = re.replace(&result, "${1}--with${2}${3}").to_string();
}
result
}
pub fn dh_invoke_drop_argument(line: &str, argument: &str) -> String {
if !line.contains(argument) {
return line.to_owned();
}
let mut result = line.to_owned();
let escaped = regex::escape(argument);
if let Ok(re) = regex::Regex::new(&format!(r"[ \t]+{}$", escaped)) {
result = re.replace(&result, "").to_string();
}
if let Ok(re) = regex::Regex::new(&format!(r"([ \t]){}[ \t]", escaped)) {
result = re.replace(&result, "$1").to_string();
}
result
}
pub fn dh_invoke_replace_argument(line: &str, old: &str, new: &str) -> String {
if !line.contains(old) {
return line.to_owned();
}
let mut result = line.to_owned();
let escaped = regex::escape(old);
if let Ok(re) = regex::Regex::new(&format!(r"([ \t]){}$", escaped)) {
result = re.replace(&result, format!("$1{}", new)).to_string();
}
if let Ok(re) = regex::Regex::new(&format!(r"([ \t]){}([ \t])", escaped)) {
result = re.replace(&result, format!("$1{}$2", new)).to_string();
}
result
}
pub fn check_cdbs(path: &std::path::Path) -> bool {
let Ok(contents) = std::fs::read(path) else {
return false;
};
for line in contents.split(|&b| b == b'\n') {
let trimmed = line.strip_prefix(b"-").unwrap_or(line);
if trimmed.starts_with(b"include /usr/share/cdbs/") {
return true;
}
}
false
}
pub fn discard_pointless_override(makefile: &mut Makefile, rule: &Rule) -> bool {
let Some(target) = rule.targets().find(|t| t.starts_with("override_")) else {
return false;
};
let command = &target["override_".len()..];
let effective_recipes: Vec<String> = rule
.recipes()
.filter(|line| !line.trim().is_empty())
.collect();
if effective_recipes.len() != 1 || effective_recipes[0].trim() != command {
return false;
}
if rule.prerequisites().next().is_some() {
return false;
}
let _ = makefile.remove_phony_target(&target);
rule.clone().remove().is_ok()
}
pub fn discard_pointless_overrides(makefile: &mut Makefile) -> usize {
let mut removed = 0;
let rules: Vec<Rule> = makefile.rules().collect();
for rule in rules {
if discard_pointless_override(makefile, &rule) {
removed += 1;
}
}
removed
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_dh_invoke_add_with() {
assert_eq!(dh_invoke_add_with("dh", "blah"), "dh --with=blah");
assert_eq!(
dh_invoke_add_with("dh --with=foo", "blah"),
"dh --with=blah,foo"
);
assert_eq!(
dh_invoke_add_with("dh --with=foo --other", "blah"),
"dh --with=blah,foo --other"
);
}
#[test]
fn test_dh_invoke_get_with() {
assert_eq!(dh_invoke_get_with("dh --with=blah --foo"), vec!["blah"]);
assert_eq!(dh_invoke_get_with("dh --with=blah"), vec!["blah"]);
assert_eq!(
dh_invoke_get_with("dh --with=blah,blie"),
vec!["blah", "blie"]
);
assert_eq!(dh_invoke_get_with("dh $@ --with python3"), vec!["python3"]);
assert_eq!(
dh_invoke_get_with("dh $@ --with foo,bar,baz"),
vec!["foo", "bar", "baz"]
);
}
#[test]
fn test_dh_invoke_drop_with() {
assert_eq!(dh_invoke_drop_with("dh --with=blah", "blah"), "dh");
assert_eq!(
dh_invoke_drop_with("dh --with=blah,foo", "blah"),
"dh --with=foo"
);
assert_eq!(
dh_invoke_drop_with("dh --with=blah,foo --other", "blah"),
"dh --with=foo --other"
);
assert_eq!(dh_invoke_drop_with("dh --with=blah", "blah"), "dh");
assert_eq!(
dh_invoke_drop_with("dh --with=foo,blah", "blah"),
"dh --with=foo"
);
assert_eq!(
dh_invoke_drop_with(
"dh $@ --verbose --with autoreconf,systemd,cme-upgrade",
"systemd"
),
"dh $@ --verbose --with autoreconf,cme-upgrade"
);
assert_eq!(
dh_invoke_drop_with(
"dh $@ --with gir,python3,sphinxdoc,systemd --without autoreconf --buildsystem=cmake",
"systemd"
),
"dh $@ --with gir,python3,sphinxdoc --without autoreconf --buildsystem=cmake"
);
assert_eq!(
dh_invoke_drop_with("dh $@ --with systemd", "systemd"),
"dh $@"
);
}
#[test]
fn test_dh_invoke_drop_argument() {
assert_eq!(
dh_invoke_drop_argument("dh $@ --foo --bar", "--foo"),
"dh $@ --bar"
);
assert_eq!(
dh_invoke_drop_argument("dh $@ --foo --bar", "--bar"),
"dh $@ --foo"
);
assert_eq!(dh_invoke_drop_argument("dh $@ --foo", "--foo"), "dh $@");
}
#[test]
fn test_dh_invoke_replace_argument() {
assert_eq!(
dh_invoke_replace_argument("dh $@ --foo", "--foo", "--bar"),
"dh $@ --bar"
);
assert_eq!(
dh_invoke_replace_argument("dh $@ --foo --baz", "--foo", "--bar"),
"dh $@ --bar --baz"
);
}
#[test]
fn test_discard_pointless_override() {
let makefile_text = r#"
override_dh_auto_build:
dh_auto_build
"#;
let mut makefile = makefile_text.parse::<Makefile>().unwrap();
let rules: Vec<Rule> = makefile.rules().collect();
assert_eq!(rules.len(), 1);
let removed = discard_pointless_override(&mut makefile, &rules[0]);
assert!(removed, "Should have removed the pointless override");
let remaining_rules: Vec<Rule> = makefile.rules().collect();
assert_eq!(remaining_rules.len(), 0, "Rule should be removed");
}
#[test]
fn test_discard_pointless_override_with_args() {
let makefile_text = r#"
override_dh_auto_build:
dh_auto_build --foo
"#;
let mut makefile = makefile_text.parse::<Makefile>().unwrap();
let rules: Vec<Rule> = makefile.rules().collect();
assert_eq!(rules.len(), 1);
let removed = discard_pointless_override(&mut makefile, &rules[0]);
assert!(!removed, "Should NOT remove override with arguments");
let remaining_rules: Vec<Rule> = makefile.rules().collect();
assert_eq!(remaining_rules.len(), 1, "Rule should remain");
}
#[test]
fn test_discard_pointless_override_with_comment() {
let makefile_text = r#"
override_dh_auto_build:
# This is a comment
dh_auto_build
"#;
let mut makefile = makefile_text.parse::<Makefile>().unwrap();
let rules: Vec<Rule> = makefile.rules().collect();
assert_eq!(rules.len(), 1);
let removed = discard_pointless_override(&mut makefile, &rules[0]);
assert!(
removed,
"Should remove - recipes() doesn't include comments"
);
}
#[test]
fn test_discard_pointless_override_not_override() {
let makefile_text = r#"
build:
dh_auto_build
"#;
let mut makefile = makefile_text.parse::<Makefile>().unwrap();
let rules: Vec<Rule> = makefile.rules().collect();
assert_eq!(rules.len(), 1);
let removed = discard_pointless_override(&mut makefile, &rules[0]);
assert!(!removed, "Should NOT remove non-override rules");
}
#[test]
fn test_discard_pointless_overrides() {
let makefile_text = r#"
override_dh_auto_build:
dh_auto_build
override_dh_auto_test:
dh_auto_test
override_dh_auto_install:
dh_auto_install --foo
"#;
let mut makefile = makefile_text.parse::<Makefile>().unwrap();
let initial_rules = makefile.rules().count();
assert_eq!(initial_rules, 3);
let removed = discard_pointless_overrides(&mut makefile);
assert_eq!(removed, 2, "Should remove 2 pointless overrides");
let remaining_rules: Vec<Rule> = makefile.rules().collect();
assert_eq!(remaining_rules.len(), 1, "Should have 1 rule remaining");
let targets: Vec<String> = remaining_rules[0].targets().collect();
assert_eq!(targets, vec!["override_dh_auto_install"]);
}
}