pub mod apt;
pub mod build;
pub mod build_deps;
pub mod context;
#[cfg(feature = "dep-server")]
pub mod dep_server;
pub mod file_search;
pub mod fix_build;
pub mod fixers;
#[cfg(feature = "udd")]
pub mod udd;
pub mod upstream_deps;
use breezyshim::tree::{Path, Tree};
use crate::session::Session;
pub fn satisfy_build_deps(
session: &dyn Session,
tree: &dyn Tree,
debian_path: &Path,
) -> Result<(), apt::Error> {
let path = debian_path.join("control");
let f = tree.get_file_text(&path).unwrap();
let control: debian_control::Control = String::from_utf8(f).unwrap().parse().unwrap();
let apt_mgr = apt::AptManager::new(session, None);
apt_mgr.satisfy(build_dep_entries(&control))
}
pub fn satisfy_build_deps_from_control(
session: &dyn Session,
control_path: &std::path::Path,
) -> Result<(), Box<dyn std::error::Error>> {
let text = std::fs::read_to_string(control_path)?;
let control: debian_control::Control = text.parse()?;
let apt_mgr = apt::AptManager::new(session, None);
let deps = build_dep_entries(&control);
apt_mgr
.satisfy(deps)
.map_err(|e| format!("Failed to satisfy build dependencies: {:?}", e))?;
Ok(())
}
fn relation_entries(relations: &debian_control::lossless::relations::Relations) -> Vec<String> {
relations
.entries()
.map(|entry| {
let alternatives: Vec<debian_control::lossy::Relation> = entry.into();
alternatives
.iter()
.map(|relation| relation.to_string())
.collect::<Vec<_>>()
.join(" | ")
})
.collect()
}
fn build_dep_entries(control: &debian_control::Control) -> Vec<apt::SatisfyEntry> {
let Some(source) = control.source() else {
return vec![];
};
let mut deps = vec![];
for relations in source
.build_depends()
.iter()
.chain(source.build_depends_indep().iter())
.chain(source.build_depends_arch().iter())
{
for entry in relation_entries(relations) {
deps.push(apt::SatisfyEntry::Required(entry));
}
}
for relations in source
.build_conflicts()
.iter()
.chain(source.build_conflicts_indep().iter())
.chain(source.build_conflicts_arch().iter())
{
for entry in relation_entries(relations) {
deps.push(apt::SatisfyEntry::Conflict(entry));
}
}
deps
}
#[cfg(test)]
mod tests {
use super::*;
fn classify(entries: &[apt::SatisfyEntry]) -> (Vec<&str>, Vec<&str>) {
let mut required = vec![];
let mut conflicts = vec![];
for entry in entries {
match entry {
apt::SatisfyEntry::Required(s) => required.push(s.as_str()),
apt::SatisfyEntry::Conflict(s) => conflicts.push(s.as_str()),
}
}
(required, conflicts)
}
#[test]
fn test_build_dep_entries() {
let control: debian_control::Control = "Source: dulwich\n\
Build-Depends: debhelper-compat (= 13), dh-python\n\
Build-Depends-Indep: python3-sphinx\n\
Build-Conflicts: python3-broken\n\n\
Package: python3-dulwich\n\
Architecture: any\n"
.parse()
.unwrap();
let entries = build_dep_entries(&control);
let (required, conflicts) = classify(&entries);
assert_eq!(
required,
vec!["debhelper-compat (= 13)", "dh-python", "python3-sphinx"]
);
assert_eq!(conflicts, vec!["python3-broken"]);
}
#[test]
fn test_build_dep_entries_no_source() {
let control: debian_control::Control = "Package: python3-dulwich\nArchitecture: any\n"
.parse()
.unwrap();
assert!(build_dep_entries(&control).is_empty());
}
#[test]
fn test_build_dep_entries_strips_comments_and_continuations() {
let control_text = concat!(
"Source: rustc\n",
"Build-Depends: debhelper-compat (= 13),\n",
"# needed by some vendor crates\n",
" pkgconf:native,\n",
" libcurl4-openssl-dev | libcurl4-gnutls-dev,\n",
" git <!nocheck>\n",
"\n",
"Package: rustc\n",
"Architecture: any\n",
);
let control: debian_control::Control = control_text.parse().unwrap();
let entries = build_dep_entries(&control);
let (required, _) = classify(&entries);
assert_eq!(
required,
vec![
"debhelper-compat (= 13)",
"pkgconf:native",
"libcurl4-openssl-dev | libcurl4-gnutls-dev",
"git <!nocheck>",
]
);
}
}