diff --git a/README.md b/README.md index 64ae9bc..392fc8e 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ Options: -d, --dist Target package distribution (debian, ubuntu) -v, --version Target package version -a, --arch Target architecture (amd64, arm64, riscv64, ...) + -p, --pocket Target distribution pocket (updates, security, proposed, ...) --ppa Do the action in/for a specific PPA ``` diff --git a/src/deb/cross.rs b/src/deb/cross.rs index 5612461..3ddfe63 100644 --- a/src/deb/cross.rs +++ b/src/deb/cross.rs @@ -38,6 +38,7 @@ pub fn setup_environment( pub fn ensure_repositories( arch: &str, series: &str, + pocket: Option<&str>, ctx: Arc, ) -> Result<(), Box> { let local_arch = crate::get_current_arch(); @@ -74,12 +75,19 @@ pub fn ensure_repositories( } // Ensure all suites (pockets) are enabled, excluding 'proposed' - let required_suites = [ + // unless explicitly requested through the 'pocket' option + let mut required_suites = vec![ series.to_string(), format!("{}-updates", series), format!("{}-backports", series), format!("{}-security", series), ]; + if let Some(p) = pocket { + let pocket_suite = format!("{series}-{p}"); + if !required_suites.contains(&pocket_suite) { + required_suites.push(pocket_suite); + } + } for suite in required_suites { if !source.suite.contains(&suite) { source.suite.push(suite); @@ -95,6 +103,18 @@ pub fn ensure_repositories( if !has_ports { // Add ports repository for the target architecture + let mut ports_suites = vec![ + format!("{series}"), + format!("{series}-updates"), + format!("{series}-backports"), + format!("{series}-security"), + ]; + if let Some(p) = pocket { + let pocket_suite = format!("{series}-{p}"); + if !ports_suites.contains(&pocket_suite) { + ports_suites.push(pocket_suite); + } + } let ports_entry = crate::apt::sources::SourceEntry { enabled: true, components: vec![ @@ -105,12 +125,7 @@ pub fn ensure_repositories( ], architectures: vec![arch.to_string()], uri: "http://ports.ubuntu.com/ubuntu-ports".to_string(), - suite: vec![ - format!("{series}"), - format!("{series}-updates"), - format!("{series}-backports"), - format!("{series}-security"), - ], + suite: ports_suites, }; sources.push(ports_entry); } diff --git a/src/deb/local.rs b/src/deb/local.rs index 9c5480f..02c98ce 100644 --- a/src/deb/local.rs +++ b/src/deb/local.rs @@ -17,6 +17,7 @@ pub async fn build( version: &str, arch: &str, series: &str, + pocket: Option<&str>, build_root: &str, cross: bool, ppa: Option<&[&str]>, @@ -53,7 +54,7 @@ pub async fn build( if cross { log::debug!("Setting up environment for local cross build..."); cross::setup_environment(&mut env, arch, ctx.clone())?; - cross::ensure_repositories(arch, series, ctx.clone())?; + cross::ensure_repositories(arch, series, pocket, ctx.clone())?; } let mut sources = apt::sources::load(Some(ctx.clone()))?; @@ -116,6 +117,19 @@ pub async fn build( } } + // Enable the requested pocket on archive sources, so build-dependencies + // are resolved from that pocket + if let Some(pocket_name) = pocket { + let pocket_suite = format!("{series}-{pocket_name}"); + log::info!("Enabling pocket '{}' for build dependencies", pocket_suite); + for source in &mut sources { + if crate::deb::is_archive_source(&source.uri) && !source.suite.contains(&pocket_suite) { + source.suite.push(pocket_suite.clone()); + modified = true; + } + } + } + if modified { apt::sources::save_legacy(Some(ctx.clone()), sources, "/etc/apt/sources.list")?; diff --git a/src/deb/mod.rs b/src/deb/mod.rs index 1efa7ed..e502559 100644 --- a/src/deb/mod.rs +++ b/src/deb/mod.rs @@ -19,6 +19,7 @@ pub enum BuildMode { pub async fn build_binary_package( arch: Option<&str>, series: Option<&str>, + pocket: Option<&str>, cwd: Option<&Path>, cross: bool, mode: Option, @@ -99,6 +100,7 @@ pub async fn build_binary_package( &version, arch, series, + pocket, &build_root, cross, ppa, @@ -107,7 +109,7 @@ pub async fn build_binary_package( ) .await? } - }; + } // Retrieve produced .deb files let remote_files = build_ctx.list_files(Path::new(&build_root))?; @@ -256,6 +258,15 @@ fn find_dsc_file( Ok(dsc_path) } +/// Check whether an apt source URI points to a distribution archive +/// (as opposed to a PPA or another third-party repository) +pub(crate) fn is_archive_source(uri: &str) -> bool { + uri.contains("archive.ubuntu.com") + || uri.contains("security.ubuntu.com") + || uri.contains("ports.ubuntu.com") + || uri.contains("deb.debian.org") +} + #[cfg(test)] mod tests { use super::*; @@ -303,6 +314,7 @@ mod tests { crate::deb::build_binary_package( arch, Some(series), + None, Some(&cwd), cross, None, diff --git a/src/main.rs b/src/main.rs index e0093f9..ed3fea1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -50,6 +50,7 @@ fn main() { .arg(arg!(-v --version "Target package version").required(false)) .arg(arg!(--archive "Only use the archive to download package source, not git").required(false)) .arg(arg!(--ppa "Download the package from a specific PPA").required(false)) + .arg(arg!(-p --pocket "Target package distribution pocket (updates, security, proposed)").required(false)) .arg(arg!( "Target package")), ) .subcommand( @@ -65,6 +66,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!(-p --pocket "Build against dependencies from a specific distribution pocket (updates, security, proposed)").required(false) + .long_help("Build against dependencies from a specific distribution pocket (e.g. updates, security, proposed).\nThe '-' suite will be enabled on archive sources when resolving build-dependencies.")) .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)") @@ -130,6 +133,10 @@ fn main() { let dist = sub_matches.get_one::("dist").map(|s| s.as_str()); let version = sub_matches.get_one::("version").map(|s| s.as_str()); let ppa = sub_matches.get_one::("ppa").map(|s| s.as_str()); + let pocket = sub_matches + .get_one::("pocket") + .map(|s| s.as_str()) + .unwrap_or(""); let archive = sub_matches.get_one::("archive").unwrap_or(&false); let (pb, progress_callback) = ui::create_progress_bar(&multi); @@ -151,7 +158,7 @@ fn main() { package, version, series, - "", + pocket, dist, base_url.as_deref(), Some(&progress_callback), @@ -251,6 +258,7 @@ fn main() { Some(("deb", sub_matches)) => { let cwd = current_dir_or_exit(); let series = sub_matches.get_one::("series").map(|s| s.as_str()); + let pocket = sub_matches.get_one::("pocket").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: Vec<&str> = sub_matches @@ -281,6 +289,7 @@ fn main() { pkh::deb::build_binary_package( arch, series, + pocket, Some(cwd.as_path()), *cross, mode,