From dce39c9a846701a066ba789fa805fd5de1e96b74 Mon Sep 17 00:00:00 2001 From: Valentin Haudiquet Date: Thu, 19 Feb 2026 15:36:08 +0100 Subject: [PATCH] deb: allow adding multiple ppas for deps --- src/deb/local.rs | 92 ++++++++++++++++++++++++++---------------------- src/deb/mod.rs | 2 +- src/main.rs | 13 +++++-- 3 files changed, 61 insertions(+), 46 deletions(-) diff --git a/src/deb/local.rs b/src/deb/local.rs index d8d5fd5..f5382d9 100644 --- a/src/deb/local.rs +++ b/src/deb/local.rs @@ -18,7 +18,7 @@ pub async fn build( series: &str, build_root: &str, cross: bool, - ppa: Option<&str>, + ppa: Option<&[&str]>, inject_packages: Option<&[&str]>, ) -> Result<(), Box> { // Environment @@ -58,47 +58,53 @@ pub async fn build( let mut sources = apt::sources::load(None)?; let mut modified = false; + let mut added_ppas: Vec<(&str, &str)> = Vec::new(); - // Add PPA repository if specified - if let Some(ppa_str) = ppa { - // PPA format: user/ppa_name - let parts: Vec<&str> = ppa_str.split('/').collect(); - if parts.len() == 2 { - let base_url = crate::package_info::ppa_to_base_url(parts[0], parts[1]); + // Add PPA repositories if specified + if let Some(ppas) = ppa { + for ppa_str in ppas { + // PPA format: user/ppa_name + let parts: Vec<&str> = ppa_str.split('/').collect(); + if parts.len() == 2 { + let base_url = crate::package_info::ppa_to_base_url(parts[0], parts[1]); - // Add new PPA source if not found - if !sources.iter().any(|s| s.uri.contains(&base_url)) { - // Get host and target architectures - let host_arch = crate::get_current_arch(); - let target_arch = arch; + // Add new PPA source if not found + if !sources.iter().any(|s| s.uri.contains(&base_url)) { + // Get host and target architectures + let host_arch = crate::get_current_arch(); + let target_arch = arch; - // Create architectures list with both host and target if different - let mut architectures = vec![host_arch.clone()]; - if host_arch != *target_arch { - architectures.push(target_arch.to_string()); + // Create architectures list with both host and target if different + let mut architectures = vec![host_arch.clone()]; + if host_arch != *target_arch { + architectures.push(target_arch.to_string()); + } + + // Create suite list with all Ubuntu series + let suites = vec![format!("{}", series)]; + + let new_source = crate::apt::sources::SourceEntry { + enabled: true, + components: vec!["main".to_string()], + architectures: architectures.clone(), + suite: suites, + uri: base_url, + }; + sources.push(new_source); + modified = true; + added_ppas.push((parts[0], parts[1])); + log::info!( + "Added PPA: {} for series {} with architectures {:?}", + ppa_str, + series, + architectures + ); } - - // Create suite list with all Ubuntu series - let suites = vec![format!("{}", series)]; - - let new_source = crate::apt::sources::SourceEntry { - enabled: true, - components: vec!["main".to_string()], - architectures: architectures.clone(), - suite: suites, - uri: base_url, - }; - sources.push(new_source); - modified = true; - log::info!( - "Added PPA: {} for series {} with architectures {:?}", - ppa_str, - series, - architectures + } else { + return Err( + format!("Invalid PPA format: '{}'. Expected: user/ppa_name", ppa_str).into(), ); } - } else { - return Err("Invalid PPA format. Expected: user/ppa_name".into()); } } @@ -113,14 +119,14 @@ pub async fn build( if modified { apt::sources::save_legacy(None, sources, "/etc/apt/sources.list")?; - // Download and import PPA key if we added a PPA - if let Some(ppa_str) = ppa { - let parts: Vec<&str> = ppa_str.split('/').collect(); - if parts.len() == 2 - && let Err(e) = - crate::apt::keyring::download_trust_ppa_key(None, parts[0], parts[1]).await + // Download and import PPA keys for all added PPAs + for (user, ppa_name) in added_ppas { + if let Err(e) = crate::apt::keyring::download_trust_ppa_key(None, user, ppa_name).await { - warn!("Failed to download PPA key for {}: {}", ppa_str, e); + warn!( + "Failed to download PPA key for {}/{}: {}", + user, ppa_name, e + ); } } } diff --git a/src/deb/mod.rs b/src/deb/mod.rs index 605e248..380f6d5 100644 --- a/src/deb/mod.rs +++ b/src/deb/mod.rs @@ -23,7 +23,7 @@ pub async fn build_binary_package( cwd: Option<&Path>, cross: bool, mode: Option, - ppa: Option<&str>, + ppa: Option<&[&str]>, inject_packages: Option<&[&str]>, ) -> Result<(), Box> { let cwd = cwd.unwrap_or_else(|| Path::new(".")); diff --git a/src/main.rs b/src/main.rs index 390b9e7..f43ad7a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -54,7 +54,8 @@ fn main() { .about("Build the source package into binary package (.deb)") .arg(arg!(-s --series "Target distribution series").required(false)) .arg(arg!(-a --arch "Target architecture").required(false)) - .arg(arg!(--ppa "Build the package adding a specific PPA for dependencies").required(false)) + .arg(arg!(--ppa "Build the package adding a specific PPA for dependencies (can be specified multiple times)") + .long_help("Build the package adding a specific PPA for dependencies. Can be specified multiple times.").required(false).action(clap::ArgAction::Append)) .arg(arg!(--inject "Inject a package into the build environment (can be specified multiple times)") .long_help("Inject a package into the build environment before build-dep. Can be a .deb file path, a package name from the archive, or a package from a previously added PPA. Can be specified multiple times.").required(false).action(clap::ArgAction::Append)) .arg(arg!(--cross "Cross-compile for target architecture (instead of qemu-binfmt)") @@ -162,7 +163,15 @@ fn main() { let series = sub_matches.get_one::("series").map(|s| s.as_str()); let arch = sub_matches.get_one::("arch").map(|s| s.as_str()); let cross = sub_matches.get_one::("cross").unwrap_or(&false); - let ppa = sub_matches.get_one::("ppa").map(|s| s.as_str()); + let ppa: Vec<&str> = sub_matches + .get_many::("ppa") + .map(|v| v.map(|s| s.as_str()).collect()) + .unwrap_or_default(); + let ppa = if ppa.is_empty() { + None + } else { + Some(ppa.as_slice()) + }; let inject_packages: Vec<&str> = sub_matches .get_many::("inject") .map(|v| v.map(|s| s.as_str()).collect())