From 9b4b19cda21c84fa68496e1874a31044e099d742 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Wed, 29 Sep 2021 14:33:04 -0400 Subject: [PATCH] extensions: Add support for per-extension repos and modules While we support arch-specific extensions today, the state of repos and modules are global. Which means if a module-using extension is only available on one architecture (as is the case in RHEL8/OCP with the `av` module) then it's not possible to build on other architectures. The most powerful mechanism here is the `arch-include` design that we have in the treefile, but...since we already have an architecture filter per extension, it's easier to add repos and modules per extension. Note that the repos and modules are still *global* state, so we're not supporting actively conflicting extensions right now still. Closes: https://github.com/coreos/rpm-ostree/issues/3150 --- docs/extensions.md | 12 +++++++++++ rust/src/extensions.rs | 46 ++++++++++++++++++++++++++++++++++++++++++ rust/src/treefile.rs | 2 +- 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/docs/extensions.md b/docs/extensions.md index 9dbc6230..bc3d0d7b 100644 --- a/docs/extensions.md +++ b/docs/extensions.md @@ -55,6 +55,18 @@ extensions: packages: - strace - ltrace + # Optional additional repos (still added globally). + # The reason use per-extension `repos` and `modules` + # is that it more closely groups them (where relevant) + # and further these are only added after architecture conditionals + # apply, so one can use repositories that only exist + # on a particular architecture. + repos: + - sooper-repo + # Optional additional modules (this also affects global state) + modules: + enable: + - sooper:latest # Optional list of architectures on which this extension # is valid. These are RPM basearches. If omitted, # defaults to all architectures. diff --git a/rust/src/extensions.rs b/rust/src/extensions.rs index e667f886..df37b792 100644 --- a/rust/src/extensions.rs +++ b/rust/src/extensions.rs @@ -34,6 +34,10 @@ pub struct Extensions { pub struct Extension { packages: Vec, #[serde(skip_serializing_if = "Option::is_none")] + repos: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + modules: Option, + #[serde(skip_serializing_if = "Option::is_none")] architectures: Option>, #[serde(skip_serializing_if = "Option::is_none")] match_base_evr: Option, @@ -74,6 +78,14 @@ fn extensions_load_stream( .collect(); for (_, ext) in parsed.extensions.iter_mut() { + // Extend the global extension state with the per-extension repos and modules, + // after we've done architecture filtering. + if let Some(repos) = parsed.repos.as_mut() { + repos.extend(ext.repos.take().unwrap_or_default()); + } else { + parsed.repos = ext.repos.take(); + } + crate::treefile::merge_modules(&mut parsed.modules, &mut ext.modules); if ext.kind == ExtensionKind::OsExtension { for pkg in &ext.packages { if base_pkgs.contains_key(pkg.as_str()) { @@ -264,10 +276,17 @@ extensions: #[test] fn basearch_filter() { let buf = r###" +repos: + - baserepo +modules: + enable: + - virt:av extensions: bazboo: packages: - bazboo + repos: + - bazboo-repo architectures: - x86_64 dodo: @@ -276,13 +295,40 @@ extensions: - dada architectures: - s390x + foo: + modules: + enable: + - foo:stable + packages: + - foo + repos: + - foo-repo + architectures: + - ppc64le "###; let mut input = std::io::BufReader::new(buf.as_bytes()); let extensions = extensions_load_stream(&mut input, "x86_64", &base_rpmdb()).unwrap(); assert!(extensions.get_os_extension_packages() == vec!["bazboo"]); + assert_eq!(extensions.get_repos().len(), 2); + assert_eq!(extensions.get_repos()[1], "bazboo-repo"); + let modules = extensions.modules.unwrap(); + assert_eq!(modules.enable.unwrap(), vec!["virt:av"]); + assert!(modules.install.is_none()); + let mut input = std::io::BufReader::new(buf.as_bytes()); let extensions = extensions_load_stream(&mut input, "s390x", &base_rpmdb()).unwrap(); assert!(extensions.get_os_extension_packages() == vec!["dodo", "dada"]); + assert_eq!(extensions.get_repos().len(), 1); + assert_eq!(extensions.get_repos()[0], "baserepo"); + + let mut input = std::io::BufReader::new(buf.as_bytes()); + let extensions = extensions_load_stream(&mut input, "ppc64le", &base_rpmdb()).unwrap(); + assert_eq!(extensions.get_os_extension_packages(), vec!["foo"]); + assert_eq!(extensions.get_repos().len(), 2); + assert_eq!(extensions.get_repos()[1], "foo-repo"); + let modules = extensions.modules.unwrap(); + assert_eq!(modules.enable.unwrap(), vec!["foo:stable", "virt:av"]); + assert!(modules.install.is_none()); } #[test] diff --git a/rust/src/treefile.rs b/rust/src/treefile.rs index 2c9af278..9f6c6581 100644 --- a/rust/src/treefile.rs +++ b/rust/src/treefile.rs @@ -324,7 +324,7 @@ fn merge_hashset_field( } /// Merge modules fields. -fn merge_modules(dest: &mut Option, src: &mut Option) { +pub(crate) fn merge_modules(dest: &mut Option, src: &mut Option) { if let Some(mut srcv) = src.take() { if let Some(mut destv) = dest.take() { merge_vec_field(&mut destv.enable, &mut srcv.enable); -- 2.31.1