diff --git a/crates/spk-cli/group2/src/cmd_ls_test.rs b/crates/spk-cli/group2/src/cmd_ls_test.rs index 7b96ea709..573888b3f 100644 --- a/crates/spk-cli/group2/src/cmd_ls_test.rs +++ b/crates/spk-cli/group2/src/cmd_ls_test.rs @@ -118,6 +118,8 @@ async fn test_ls_shows_remote_packages_with_host_default_filter() { remote_repo.publish_recipe(&recipe).await.unwrap(); let host_options = HOST_OPTIONS.get().unwrap(); let os_id = host_options.get(OptName::distro()).unwrap(); + + // Build with all matching host options let spec = spec!({"pkg": "my-pkg/1.0.0/BGSHW3CN", "build": { "options": @@ -140,7 +142,78 @@ async fn test_ls_shows_remote_packages_with_host_default_filter() { let mut opt = Opt::try_parse_from(["ls", "--host"]).unwrap(); opt.ls.run().await.unwrap(); - assert_ne!(opt.ls.output.vec.len(), 0); + assert_eq!(opt.ls.output.vec.len(), 1); +} + +/// `spk ls` is expected to list packages in the configured remote +/// repositories that match the default filter for the current host +#[tokio::test] +async fn test_ls_shows_remote_packages_with_host_default_filter_multiple_builds() { + let mut rt = spfs_runtime().await; + let remote_repo = spfsrepo().await; + + // Populate the "origin" repo with one package. + // The "local" repo is empty. + + rt.add_remote_repo( + "origin", + Remote::Address(RemoteAddress { + address: remote_repo.address().clone(), + }), + ) + .unwrap(); + + let recipe = recipe!({"pkg": "my-pkg/1.0.0"}); + remote_repo.publish_recipe(&recipe).await.unwrap(); + let host_options = HOST_OPTIONS.get().unwrap(); + let os_id = host_options.get(OptName::distro()).unwrap(); + + // Build with all matching host options + let spec = spec!({"pkg": "my-pkg/1.0.0/BGSHW3CN", + "build": { + "options": + [ + {"var": format!("{}/{}", OptName::distro(), host_options.get(OptName::distro()).unwrap()) }, + {"var": format!("{}/{}", OptName::os(), host_options.get(OptName::os()).unwrap()) }, + {"var": format!("{}/{}", OptName::arch(), host_options.get(OptName::arch()).unwrap()) }, + {"var": format!("{}/{}", os_id, host_options.get(os_id).unwrap()) } + ] + }}); + remote_repo + .publish_package( + &spec, + &vec![(Component::Run, empty_layer_digest())] + .into_iter() + .collect(), + ) + .await + .unwrap(); + + // Build with for another distro in its host options + let spec = spec!({"pkg": "my-pkg/1.0.0/2RGMWL2B", + "build": { + "options": + [ + {"var": format!("{}/{}", OptName::distro(), "test_distro") }, + {"var": format!("{}/{}", OptName::os(), host_options.get(OptName::os()).unwrap()) }, + {"var": format!("{}/{}", OptName::arch(), host_options.get(OptName::arch()).unwrap()) }, + {"var": format!("{}/{}", os_id, host_options.get(os_id).unwrap()) } + ] + }}); + remote_repo + .publish_package( + &spec, + &vec![(Component::Run, empty_layer_digest())] + .into_iter() + .collect(), + ) + .await + .unwrap(); + + let mut opt = Opt::try_parse_from(["ls", "--host"]).unwrap(); + opt.ls.run().await.unwrap(); + println!("Output: {:?}", opt.ls.output.vec); + assert_eq!(opt.ls.output.vec.len(), 1); } /// `spk ls` is expected to list packages in both the local and the configured diff --git a/crates/spk-schema/crates/foundation/src/option_map/filters.rs b/crates/spk-schema/crates/foundation/src/option_map/filters.rs index 4df249fff..b12ccabc7 100644 --- a/crates/spk-schema/crates/foundation/src/option_map/filters.rs +++ b/crates/spk-schema/crates/foundation/src/option_map/filters.rs @@ -12,18 +12,6 @@ pub struct OptFilter { pub value: String, } -impl OptFilter { - pub fn matches(&self, options: &OptionMap) -> bool { - if let Some(v) = options.get(&self.name) { - self.value == *v - } else { - // Not having an option with the filter's name is - // considered a match. - true - } - } -} - /// Constructs a list of filters from the current host's host options, /// if any. pub fn get_host_options_filters() -> Option> { diff --git a/crates/spk-schema/src/v0/spec.rs b/crates/spk-schema/src/v0/spec.rs index 498daffc3..71855d3d6 100644 --- a/crates/spk-schema/src/v0/spec.rs +++ b/crates/spk-schema/src/v0/spec.rs @@ -257,8 +257,19 @@ impl Package for Spec { fn matches_all_filters(&self, filter_by: &Option>) -> bool { if let Some(filters) = filter_by { let settings = self.option_values(); + for filter in filters { - if !filter.matches(&settings) { + if !settings.contains_key(&filter.name) { + // Not having an option with the filter's name is + // considered a match. + continue; + } + + let var_request = + VarRequest::new_with_value(filter.name.clone(), filter.value.clone()); + + let compat = self.check_satisfies_request(&var_request); + if !compat.is_ok() { return false; } } diff --git a/cspell.json b/cspell.json index e97522959..9e49f2127 100644 --- a/cspell.json +++ b/cspell.json @@ -592,6 +592,7 @@ "respecifying", "retpoline", "retryable", + "RGMWL", "rhelversion", "robinmap", "rootdata",