deb,quirks: scope deb entries per series with an entry list
One deb block per package cannot express two series needing different rules. Make pull and deb lists of entries, each with its own series scope: every matching entry applies, in file order, so a stonking entry can carry its own dependency rules next to the resolute one. Thread the series through find_package_directory for the package_directory lookup, which keeps its deb-then-pull fallback.
This commit is contained in:
+27
-23
@@ -1,10 +1,12 @@
|
||||
# Quirks configuration for package-specific workarounds
|
||||
# This file defines package-specific quirks that are applied during pull and deb operations
|
||||
#
|
||||
# Entries can be scoped with `series`: an empty list applies to every
|
||||
# series, otherwise only the listed ones. Packaging workarounds should
|
||||
# carry the series they were verified against so they can be dropped once
|
||||
# the upstream packaging catches up.
|
||||
# `pull` and `deb` hold one entry per scope: several entries can carry
|
||||
# different `series` lists, and every matching entry applies in file
|
||||
# order. Entries can be scoped with `series`: an empty list applies to
|
||||
# every series, otherwise only the listed ones. Packaging workarounds
|
||||
# should carry the series they were verified against so they can be
|
||||
# dropped once the upstream packaging catches up.
|
||||
|
||||
quirks:
|
||||
|
||||
@@ -15,29 +17,31 @@ quirks:
|
||||
# until the control is fixed upstream.
|
||||
linux:
|
||||
deb:
|
||||
series: [resolute]
|
||||
dependencies:
|
||||
replace:
|
||||
llvm-21-dev: llvm-21-dev:native <!stage1>
|
||||
- series: [resolute]
|
||||
dependencies:
|
||||
replace:
|
||||
llvm-21-dev: llvm-21-dev:native <!stage1>
|
||||
linux-riscv:
|
||||
deb:
|
||||
series: [resolute]
|
||||
dependencies:
|
||||
replace:
|
||||
llvm-21-dev: llvm-21-dev:native <!stage1>
|
||||
- series: [resolute]
|
||||
dependencies:
|
||||
replace:
|
||||
llvm-21-dev: llvm-21-dev:native <!stage1>
|
||||
|
||||
# Add more packages and their quirks as needed
|
||||
# example-package:
|
||||
# pull:
|
||||
# method: archive
|
||||
# - series: [noble]
|
||||
# package_directory:
|
||||
# - linux-main
|
||||
# deb:
|
||||
# series: [noble]
|
||||
# dependencies:
|
||||
# replace:
|
||||
# old-dep: new-dep (>= 2) [linux-any]
|
||||
# inject:
|
||||
# - missing-dep
|
||||
# drop:
|
||||
# - broken-dep
|
||||
# parameters:
|
||||
# key: value
|
||||
# - series: [resolute]
|
||||
# dependencies:
|
||||
# replace:
|
||||
# llvm-21-dev: llvm-21-dev:native <!stage1>
|
||||
# - series: [stonking]
|
||||
# dependencies:
|
||||
# replace:
|
||||
# llvm-22-dev: llvm-22-dev:native <!stage1>
|
||||
# parameters:
|
||||
# key: value
|
||||
|
||||
+2
-1
@@ -231,9 +231,10 @@ pub async fn build(
|
||||
return Err("Could not install essential packages for the build".into());
|
||||
}
|
||||
|
||||
// Find the actual package directory
|
||||
// Find the actual package directory
|
||||
let package_dir =
|
||||
crate::deb::find_package_directory(Path::new(build_root), package, version, &ctx)?;
|
||||
crate::deb::find_package_directory(Path::new(build_root), package, version, series, &ctx)?;
|
||||
let package_dir_str = package_dir
|
||||
.to_str()
|
||||
.ok_or("Invalid package directory path")?;
|
||||
|
||||
+10
-4
@@ -337,10 +337,11 @@ pub(crate) fn find_package_directory(
|
||||
parent_dir: &Path,
|
||||
package: &str,
|
||||
version: &str,
|
||||
series: &str,
|
||||
ctx: &context::Context,
|
||||
) -> Result<PathBuf, Box<dyn Error>> {
|
||||
// Check quirks first for custom package directories
|
||||
let custom_dirs = crate::quirks::get_package_directories(package);
|
||||
let custom_dirs = crate::quirks::get_package_directories(package, series);
|
||||
for custom_dir in custom_dirs {
|
||||
let package_dir = parent_dir.join(&custom_dir);
|
||||
if ctx.exists(&package_dir)? && ctx.exists(&package_dir.join("debian"))? {
|
||||
@@ -533,9 +534,14 @@ mod tests {
|
||||
let ctx = Arc::new(Context::new(crate::context::ContextConfig::Local).unwrap());
|
||||
|
||||
// Change directory to the package directory
|
||||
let cwd =
|
||||
crate::deb::find_package_directory(cwd, package, &package_info.stanza.version, &ctx)
|
||||
.expect("Cannot find package directory");
|
||||
let cwd = crate::deb::find_package_directory(
|
||||
cwd,
|
||||
package,
|
||||
&package_info.stanza.version,
|
||||
series,
|
||||
&ctx,
|
||||
)
|
||||
.expect("Cannot find package directory");
|
||||
log::debug!("Package directory: {}", cwd.display());
|
||||
|
||||
log::info!("Starting binary package build...");
|
||||
|
||||
+55
-36
@@ -57,15 +57,19 @@ pub struct OperationQuirks {
|
||||
}
|
||||
|
||||
/// Quirks for a specific package
|
||||
///
|
||||
/// `pull` and `deb` hold one entry per scope: an operation can carry
|
||||
/// several entries with different `series` lists; every matching entry
|
||||
/// applies, in file order.
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct PackageQuirks {
|
||||
/// Quirks to apply during pull operation
|
||||
#[serde(default)]
|
||||
pub pull: Option<OperationQuirks>,
|
||||
pub pull: Vec<OperationQuirks>,
|
||||
|
||||
/// Quirks to apply during deb operation
|
||||
#[serde(default)]
|
||||
pub deb: Option<OperationQuirks>,
|
||||
pub deb: Vec<OperationQuirks>,
|
||||
}
|
||||
|
||||
/// Top-level quirks configuration
|
||||
@@ -102,49 +106,64 @@ fn entry_applies_to_series(quirks: &OperationQuirks, series: &str) -> bool {
|
||||
|
||||
/// Get the build-dependency resolution rules of a package for a series
|
||||
///
|
||||
/// Every deb entry whose series list matches contributes its rules; the
|
||||
/// returned rules apply in file order.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `package` - The package name
|
||||
/// * `series` - The distribution series (e.g. "resolute")
|
||||
///
|
||||
/// # Returns
|
||||
/// * `Option<DependencyQuirks>` - The rules, or None when the package has
|
||||
/// no deb entry or the entry does not apply to the series
|
||||
pub fn get_deb_dependency_quirks(package: &str, series: &str) -> Option<DependencyQuirks> {
|
||||
let quirks = get_package_quirks(&QUIRKS_DATA, package)?;
|
||||
let deb = quirks.deb.as_ref()?;
|
||||
if entry_applies_to_series(deb, series) {
|
||||
deb.dependencies.clone()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
/// * `Vec<DependencyQuirks>` - The matching rules, empty when the package
|
||||
/// has no deb entry or none applies to the series
|
||||
pub fn get_deb_dependency_quirks(package: &str, series: &str) -> Vec<DependencyQuirks> {
|
||||
let Some(quirks) = get_package_quirks(&QUIRKS_DATA, package) else {
|
||||
return Vec::new();
|
||||
};
|
||||
quirks
|
||||
.deb
|
||||
.iter()
|
||||
.filter(|deb| entry_applies_to_series(deb, series))
|
||||
.filter_map(|deb| deb.dependencies.clone())
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Get package directories from quirks configuration
|
||||
///
|
||||
/// This function returns the list of custom package directories to try
|
||||
/// when looking for the package source directory.
|
||||
/// when looking for the package source directory: every matching deb
|
||||
/// entry contributes its directories, falling back to the pull entries
|
||||
/// when no deb entry carries any.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `package` - The package name
|
||||
/// * `series` - The distribution series (e.g. "resolute")
|
||||
///
|
||||
/// # Returns
|
||||
/// * `Vec<String>` - List of package directories to try, or empty vector if none
|
||||
pub fn get_package_directories(package: &str) -> Vec<String> {
|
||||
if let Some(quirks) = get_package_quirks(&QUIRKS_DATA, package) {
|
||||
// Check deb quirks first, then pull quirks
|
||||
if let Some(deb_quirks) = &quirks.deb
|
||||
&& !deb_quirks.package_directory.is_empty()
|
||||
pub fn get_package_directories(package: &str, series: &str) -> Vec<String> {
|
||||
let Some(quirks) = get_package_quirks(&QUIRKS_DATA, package) else {
|
||||
return Vec::new();
|
||||
};
|
||||
|
||||
let mut directories = Vec::new();
|
||||
for deb in quirks
|
||||
.deb
|
||||
.iter()
|
||||
.filter(|q| entry_applies_to_series(q, series))
|
||||
{
|
||||
directories.extend(deb.package_directory.iter().cloned());
|
||||
}
|
||||
if directories.is_empty() {
|
||||
for pull in quirks
|
||||
.pull
|
||||
.iter()
|
||||
.filter(|q| entry_applies_to_series(q, series))
|
||||
{
|
||||
return deb_quirks.package_directory.clone();
|
||||
}
|
||||
if let Some(pull_quirks) = &quirks.pull
|
||||
&& !pull_quirks.package_directory.is_empty()
|
||||
{
|
||||
return pull_quirks.package_directory.clone();
|
||||
directories.extend(pull.package_directory.iter().cloned());
|
||||
}
|
||||
}
|
||||
|
||||
Vec::new()
|
||||
directories
|
||||
}
|
||||
|
||||
/// Apply the dependency quirks of `package` in `series` to parsed
|
||||
@@ -160,10 +179,10 @@ pub fn apply_dependency_quirks(
|
||||
clauses: &mut Vec<Vec<PkgRelation>>,
|
||||
opts: &ParseOpts,
|
||||
) -> Result<(), String> {
|
||||
let Some(deps) = get_deb_dependency_quirks(package, series) else {
|
||||
return Ok(());
|
||||
};
|
||||
apply_rules(clauses, &deps, opts)
|
||||
for deps in get_deb_dependency_quirks(package, series) {
|
||||
apply_rules(clauses, &deps, opts)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Apply one set of dependency rules to parsed clauses.
|
||||
@@ -236,8 +255,8 @@ mod tests {
|
||||
fn test_unknown_package_has_no_quirks() {
|
||||
// A package absent from quirks.yml has no dependency rules nor
|
||||
// custom directories, and must not panic
|
||||
assert!(get_deb_dependency_quirks("not-in-quirks", "resolute").is_none());
|
||||
assert!(get_package_directories("not-in-quirks").is_empty());
|
||||
assert!(get_deb_dependency_quirks("not-in-quirks", "resolute").is_empty());
|
||||
assert!(get_package_directories("not-in-quirks", "resolute").is_empty());
|
||||
}
|
||||
|
||||
/// The linux dependency quirks are scoped to the series they were
|
||||
@@ -245,13 +264,13 @@ mod tests {
|
||||
#[test]
|
||||
fn linux_dependency_quirks_are_series_scoped() {
|
||||
for package in ["linux", "linux-riscv"] {
|
||||
let deps =
|
||||
get_deb_dependency_quirks(package, "resolute").expect("the resolute entry applies");
|
||||
let rules = get_deb_dependency_quirks(package, "resolute");
|
||||
assert_eq!(rules.len(), 1, "the resolute entry applies");
|
||||
assert_eq!(
|
||||
deps.replace.get("llvm-21-dev").map(String::as_str),
|
||||
rules[0].replace.get("llvm-21-dev").map(String::as_str),
|
||||
Some("llvm-21-dev:native <!stage1>")
|
||||
);
|
||||
assert!(get_deb_dependency_quirks(package, "noble").is_none());
|
||||
assert!(get_deb_dependency_quirks(package, "noble").is_empty());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user