From 28d9cf636e934a1532fa21f4f04b6e01c0d77415 Mon Sep 17 00:00:00 2001 From: J Robert Ray Date: Tue, 21 Apr 2026 14:08:18 -0700 Subject: [PATCH 1/2] Reformat with latest nightly Signed-off-by: J Robert Ray From 3d42ffc7d9e07fca1c80bb712e529e840c4efe3b Mon Sep 17 00:00:00 2001 From: J Robert Ray Date: Tue, 21 Apr 2026 12:40:19 -0700 Subject: [PATCH 2/2] Fix CLI --opt request option mapping Attach namespaced command-line options to parsed package requests as complete request options so required vars can be satisfied by matching builds. Add a regression test in flags_test to verify parse_request keeps matching options and filters unrelated options. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: J Robert Ray --- crates/spk-cli/common/src/flags.rs | 34 ++++++++++++++++++--- crates/spk-cli/common/src/flags_test.rs | 40 ++++++++++++++++++++++++- 2 files changed, 69 insertions(+), 5 deletions(-) diff --git a/crates/spk-cli/common/src/flags.rs b/crates/spk-cli/common/src/flags.rs index e0d9255d7..78e4cc47d 100644 --- a/crates/spk-cli/common/src/flags.rs +++ b/crates/spk-cli/common/src/flags.rs @@ -32,15 +32,25 @@ use spk_schema::ident::{ PinnableRequest, PinnedValue, PkgRequest, + PkgRequestOptionValue, + PkgRequestOptions, + PkgRequestWithOptions, RangeIdent, - RequestWithOptions, RequestedBy, VarRequest, parse_ident, }; use spk_schema::option_map::HOST_OPTIONS; -use spk_schema::{Recipe, SpecFileData, SpecRecipe, Template, TestStage, VariantExt}; -use spk_solve as solve; +use spk_schema::{ + Recipe, + RequestWithOptions, + SpecFileData, + SpecRecipe, + Template, + TestStage, + VariantExt, +}; +use spk_solve::{self as solve}; #[cfg(unix)] #[cfg(feature = "statsd")] use spk_solve::{SPK_RUN_TIME_METRIC, get_metrics_client}; @@ -673,7 +683,23 @@ impl Requests { if req.required_compat.is_none() { req.required_compat = Some(CompatRule::API); } - out.push(req.into()); + let mut pkg_request_options = PkgRequestOptions::default(); + for (opt_name, value) in options.iter() { + if let Some(ns) = opt_name.namespace() + && ns == req.pkg.name + { + pkg_request_options.insert( + opt_name.clone(), + // `--opt` from the command line apply to all requests + // equally therefore this value is `Complete`. + PkgRequestOptionValue::Complete(value.clone()), + ); + } + } + out.push(RequestWithOptions::Pkg(PkgRequestWithOptions { + pkg_request: req, + options: pkg_request_options, + })); Ok(out) } diff --git a/crates/spk-cli/common/src/flags_test.rs b/crates/spk-cli/common/src/flags_test.rs index 5f91d6c24..b0bd0fffb 100644 --- a/crates/spk-cli/common/src/flags_test.rs +++ b/crates/spk-cli/common/src/flags_test.rs @@ -3,9 +3,10 @@ // https://github.com/spkenv/spk use rstest::rstest; +use spk_schema::RequestWithOptions; use spk_schema::foundation::name::OptName; use spk_schema::foundation::option_map::OptionMap; -use spk_schema::ident::VarRequest; +use spk_schema::ident::{PkgRequestOptionValue, VarRequest}; use spk_schema::option_map::HOST_OPTIONS; use spk_solve::Solver; @@ -115,3 +116,40 @@ async fn test_get_solver_with_host_options( } } } + +#[tokio::test] +async fn test_parse_request_includes_matching_cli_options() { + let request_flags = crate::flags::Requests { + pre: false, + workspace: crate::flags::Workspace::default(), + }; + let options_flags = crate::flags::Options { + no_host: true, + options: vec![ + "mylib.namespace_style=major_minor".to_string(), + "other.namespace_style=ignored".to_string(), + ], + }; + let repos: &[std::sync::Arc] = &[]; + + let (request, extra_options) = request_flags + .parse_request("mylib", &options_flags, repos) + .await + .unwrap(); + + assert!(extra_options.is_empty()); + + let RequestWithOptions::Pkg(pkg_request) = request else { + panic!("expected package request"); + }; + + let matching_opt = OptName::new("mylib.namespace_style").unwrap().to_owned(); + assert_eq!( + pkg_request.options.get(&matching_opt), + Some(&PkgRequestOptionValue::Complete("major_minor".to_string())) + ); + assert_eq!(pkg_request.options.len(), 1); + + let unrelated_opt = OptName::new("other.namespace_style").unwrap().to_owned(); + assert!(!pkg_request.options.contains_key(&unrelated_opt)); +}