Skip to content

Commit 79ad8fe

Browse files
authored
Adding auto_host_vars setting to package BuildSpec (#922)
Supports the 'auto_host_vars' field and the values: distro, arch, os, and none. The value determines which host os related options are automatically added to the package build's options. Signed-off-by: David Gilligan-Cook <[email protected]>
1 parent 3986bc2 commit 79ad8fe

File tree

15 files changed

+398
-27
lines changed

15 files changed

+398
-27
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/spk-build/src/build/binary_test.rs

+3
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ async fn test_empty_var_option_is_not_a_request() {
5353
r#"{
5454
pkg: mypackage/1.0.0,
5555
build: {
56+
host_compat: Any,
5657
options: [
5758
{var: something}
5859
]
@@ -831,11 +832,13 @@ async fn test_default_build_component() {
831832
"pkg": "mypkg/1.0.0",
832833
"sources": [],
833834
"build": {
835+
"host_compat": "Any",
834836
"options": [{"pkg": "somepkg/1.0.0"}],
835837
"script": "echo building...",
836838
},
837839
}
838840
);
841+
839842
let requirements = spec.get_build_requirements(&option_map! {}).unwrap();
840843
assert_eq!(requirements.len(), 1, "should have one build requirement");
841844
let req = requirements.get(0).unwrap();

crates/spk-cli/cmd-du/src/cmd_du_test.rs

+46-11
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,12 @@ async fn test_du_trivially_works() {
5555
.unwrap();
5656

5757
let spec = recipe!(
58-
{"pkg": "my-pkg/1.0.0", "build": {"script": "echo Hello World!"}}
58+
{ "pkg": "my-pkg/1.0.0",
59+
"build": {
60+
"auto_host_vars": "None",
61+
"script": "echo Hello World!"
62+
}
63+
}
5964
);
6065

6166
rt.tmprepo.publish_recipe(&spec).await.unwrap();
@@ -72,7 +77,7 @@ async fn test_du_trivially_works() {
7277

7378
let mut expected_output = vec![
7479
"2local/my-pkg/1.0.0/3I42H3S6/:build/spk/pkg/my-pkg/1.0.0/3I42H3S6/options.json",
75-
"160local/my-pkg/1.0.0/3I42H3S6/:build/spk/pkg/my-pkg/1.0.0/3I42H3S6/spec.yaml",
80+
"180local/my-pkg/1.0.0/3I42H3S6/:build/spk/pkg/my-pkg/1.0.0/3I42H3S6/spec.yaml",
7681
"0local/my-pkg/1.0.0/3I42H3S6/:build/spk/pkg/my-pkg/1.0.0/3I42H3S6/build.cmpt",
7782
"17local/my-pkg/1.0.0/3I42H3S6/:build/spk/pkg/my-pkg/1.0.0/3I42H3S6/build.sh",
7883
"0local/my-pkg/1.0.0/3I42H3S6/:run/spk/pkg/my-pkg/1.0.0/3I42H3S6/options.json",
@@ -204,7 +209,12 @@ async fn test_du_is_not_counting_links() {
204209
.unwrap();
205210

206211
let spec = recipe!(
207-
{"pkg": "my-pkg/1.0.0", "build": {"script": "echo Hello World!"}}
212+
{ "pkg": "my-pkg/1.0.0",
213+
"build": {
214+
"auto_host_vars": "None",
215+
"script": "echo Hello World!"
216+
}
217+
}
208218
);
209219

210220
rt.tmprepo.publish_recipe(&spec).await.unwrap();
@@ -242,7 +252,12 @@ async fn test_du_is_counting_links() {
242252
.unwrap();
243253

244254
let spec = recipe!(
245-
{"pkg": "my-pkg/1.0.0", "build": {"script": "echo Hello World!"}}
255+
{ "pkg": "my-pkg/1.0.0",
256+
"build": {
257+
"auto_host_vars": "None",
258+
"script": "echo Hello World!"
259+
}
260+
}
246261
);
247262

248263
rt.tmprepo.publish_recipe(&spec).await.unwrap();
@@ -328,7 +343,12 @@ async fn test_du_summarize_output_enabled() {
328343
.unwrap();
329344

330345
let spec = recipe!(
331-
{"pkg": "my-pkg/1.0.0", "build": {"script": "echo Hello World!"}}
346+
{ "pkg": "my-pkg/1.0.0",
347+
"build": {
348+
"auto_host_vars": "None",
349+
"script": "echo Hello World!"
350+
}
351+
}
332352
);
333353

334354
rt.tmprepo.publish_recipe(&spec).await.unwrap();
@@ -343,7 +363,7 @@ async fn test_du_summarize_output_enabled() {
343363
let mut opt = Opt::try_parse_from(["du", "local/my-pkg", "-s"]).unwrap();
344364
opt.du.run().await.unwrap();
345365

346-
let expected_output = format!("179local/my-pkg/{}", "".red());
366+
let expected_output = format!("199local/my-pkg/{}", "".red());
347367
let mut generated_output = opt.du.output.vec.lock().unwrap()[0].clone();
348368
generated_output.retain(|c| !c.is_whitespace());
349369

@@ -363,7 +383,12 @@ async fn test_du_summarize_output_is_not_enabled() {
363383
.unwrap();
364384

365385
let spec = recipe!(
366-
{"pkg": "my-pkg/1.0.0", "build": {"script": "echo Hello World!"}}
386+
{ "pkg": "my-pkg/1.0.0",
387+
"build": {
388+
"auto_host_vars": "None",
389+
"script": "echo Hello World!"
390+
}
391+
}
367392
);
368393

369394
rt.tmprepo.publish_recipe(&spec).await.unwrap();
@@ -382,7 +407,7 @@ async fn test_du_summarize_output_is_not_enabled() {
382407
"2local/my-pkg/1.0.0/3I42H3S6/:build/spk/pkg/my-pkg/1.0.0/3I42H3S6/options.json",
383408
"0local/my-pkg/1.0.0/3I42H3S6/:build/spk/pkg/my-pkg/1.0.0/3I42H3S6/build.cmpt",
384409
"17local/my-pkg/1.0.0/3I42H3S6/:build/spk/pkg/my-pkg/1.0.0/3I42H3S6/build.sh",
385-
"160local/my-pkg/1.0.0/3I42H3S6/:build/spk/pkg/my-pkg/1.0.0/3I42H3S6/spec.yaml",
410+
"180local/my-pkg/1.0.0/3I42H3S6/:build/spk/pkg/my-pkg/1.0.0/3I42H3S6/spec.yaml",
386411
"0local/my-pkg/1.0.0/3I42H3S6/:run/spk/pkg/my-pkg/1.0.0/3I42H3S6/spec.yaml",
387412
"0local/my-pkg/1.0.0/3I42H3S6/:run/spk/pkg/my-pkg/1.0.0/3I42H3S6/options.json",
388413
"0local/my-pkg/1.0.0/3I42H3S6/:run/spk/pkg/my-pkg/1.0.0/3I42H3S6/run.cmpt",
@@ -413,7 +438,12 @@ async fn test_deprecate_flag() {
413438
.unwrap();
414439

415440
let spec = recipe!(
416-
{"pkg": "my-pkg/1.0.0", "build": {"script": "echo Hello World!"}, "deprecated": true}
441+
{"pkg": "my-pkg/1.0.0",
442+
"build": {
443+
"auto_host_vars": "None",
444+
"script": "echo Hello World!"
445+
},
446+
"deprecated": true}
417447
);
418448

419449
rt.tmprepo.publish_recipe(&spec).await.unwrap();
@@ -440,7 +470,7 @@ async fn test_deprecate_flag() {
440470

441471
let mut opt_with_deprecate_flag = Opt::try_parse_from(["du", "local/my-pkg", "-ds"]).unwrap();
442472
opt_with_deprecate_flag.du.run().await.unwrap();
443-
let expected_output = format!("196local/my-pkg/{}", "DEPRECATED".red());
473+
let expected_output = format!("216local/my-pkg/{}", "DEPRECATED".red());
444474
let mut generated_output = opt_with_deprecate_flag.du.output.vec.lock().unwrap()[0].clone();
445475
generated_output.retain(|c| !c.is_whitespace());
446476
assert_eq!(expected_output, generated_output);
@@ -459,7 +489,12 @@ async fn test_human_readable_flag() {
459489
.unwrap();
460490

461491
let spec = recipe!(
462-
{"pkg": "my-pkg/1.0.0", "build": {"script": "echo Hello World!"}}
492+
{ "pkg": "my-pkg/1.0.0",
493+
"build": {
494+
"auto_host_vars": "None",
495+
"script": "echo Hello World!"
496+
}
497+
}
463498
);
464499

465500
rt.tmprepo.publish_recipe(&spec).await.unwrap();

crates/spk-cli/group2/src/cmd_new.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,23 @@ fn get_stub(name: &PkgNameBuf) -> String {
4444
4545
build:
4646
47+
# set which host related vars are added automatically to the built package:
48+
# - Distro: adds 'distro', 'arch', 'os' and '<distroname>' vars, so the package
49+
# can only be used on the same OS, CPU, and OS distribution version
50+
# (e.g. linux distro). This is the default.
51+
# - Arch: adds 'arch' and 'os' vars, so the package can be used anywhere that
52+
# has the same OS and CPU architecture (x86_64, i386)
53+
# - Os: adds 'os' var, so the package can be used anywhere that has the same
54+
# OS type (mac, linux, windows)
55+
# - None: adds no host vars, so package can be used on any OS and any architecture
56+
auto_host_vars: Distro
57+
4758
# options are all the inputs to the package build process, including
4859
# build-time dependencies
4960
options:
5061
# var options define environment/string values that affect the build.
5162
# The value is defined in the build environment as SPK_OPT_{{name}}
52-
- var: arch # rebuild if the arch changes
53-
- var: os # rebuild if the os changes
54-
- var: centos # rebuild if centos version changes
63+
# - var: somename/somvevalue
5564
5665
# pkg options request packages that need to be present
5766
# in the build environment. You can specify a version number

crates/spk-cli/group3/src/cmd_import_test.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ async fn test_archive_io() {
2121
.build_and_publish(option_map! {}, &*rt.tmprepo)
2222
.await
2323
.unwrap();
24+
let digest = spec.ident().build();
25+
2426
let filename = rt.tmpdir.path().join("archive.spk");
2527
filename.ensure();
2628
spk_storage::export_package(spec.ident().to_any(), &filename)
@@ -49,15 +51,15 @@ async fn test_archive_io() {
4951
"tags/spk/pkg".to_string(),
5052
"tags/spk/pkg/spk-archive-test".to_string(),
5153
"tags/spk/pkg/spk-archive-test/0.0.1".to_string(),
52-
"tags/spk/pkg/spk-archive-test/0.0.1/3I42H3S6".to_string(),
53-
"tags/spk/pkg/spk-archive-test/0.0.1/3I42H3S6.tag".to_string(),
54-
"tags/spk/pkg/spk-archive-test/0.0.1/3I42H3S6/build.tag".to_string(),
55-
"tags/spk/pkg/spk-archive-test/0.0.1/3I42H3S6/run.tag".to_string(),
54+
format!("tags/spk/pkg/spk-archive-test/0.0.1/{digest}"),
55+
format!("tags/spk/pkg/spk-archive-test/0.0.1/{digest}.tag"),
56+
format!("tags/spk/pkg/spk-archive-test/0.0.1/{digest}/build.tag"),
57+
format!("tags/spk/pkg/spk-archive-test/0.0.1/{digest}/run.tag"),
5658
"tags/spk/spec".to_string(),
5759
"tags/spk/spec/spk-archive-test".to_string(),
5860
"tags/spk/spec/spk-archive-test/0.0.1".to_string(),
5961
"tags/spk/spec/spk-archive-test/0.0.1.tag".to_string(),
60-
"tags/spk/spec/spk-archive-test/0.0.1/3I42H3S6.tag".to_string(),
62+
format!("tags/spk/spec/spk-archive-test/0.0.1/{digest}.tag"),
6163
]
6264
);
6365
let result = super::Import {

crates/spk-schema/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ spk-schema-foundation = { path = "./crates/foundation" }
3434
spk-schema-ident = { path = "./crates/ident" }
3535
spk-schema-validators = { path = "./crates/validators" }
3636
spk-schema-liquid = { path = "./crates/liquid" }
37+
strum = { workspace = true }
3738
sys-info = "0.9.0"
3839
tempfile = { workspace = true }
3940
thiserror = { workspace = true }

crates/spk-schema/crates/foundation/src/name/mod.rs

+34
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,12 @@ impl OptName {
177177
unsafe { Self::from_str("distro") }
178178
}
179179

180+
/// Fallback option used to identify an os with no distro name
181+
pub const fn unknown_distro() -> &'static Self {
182+
// Safety: from_str skips validation, but this is a known good value
183+
unsafe { Self::from_str("unknown_distro") }
184+
}
185+
180186
/// Validate the given string as an option name
181187
pub fn validate<S: AsRef<str> + ?Sized>(s: &S) -> Result<()> {
182188
validate_opt_name(s)
@@ -230,6 +236,34 @@ impl OptName {
230236
}
231237
}
232238

239+
impl OptNameBuf {
240+
/// Construct a valid OptNameBuf, invalid characters will be
241+
/// removed, the length will be padded or truncated, and uppercase
242+
/// letters will be lowercased to make a valid option name.
243+
pub fn new_lossy<S: AsRef<str>>(s: &S) -> OptNameBuf {
244+
if validate_opt_base_name(s).is_ok() {
245+
return unsafe { OptNameBuf::from_string(s.as_ref().to_string()) };
246+
}
247+
248+
let mut new_name: String = s
249+
.as_ref()
250+
.to_lowercase()
251+
.chars()
252+
.filter(|c| is_valid_opt_name_char(*c))
253+
.collect();
254+
255+
let length = new_name.len();
256+
if length < OptName::MIN_LEN {
257+
let difference = OptName::MIN_LEN - length;
258+
new_name += &"_".repeat(difference)
259+
} else if length > OptName::MAX_LEN {
260+
new_name.truncate(OptName::MAX_LEN)
261+
}
262+
263+
unsafe { OptNameBuf::from_string(new_name) }
264+
}
265+
}
266+
233267
/// Ensure that the provided string is a valid option name.
234268
///
235269
/// This is for checking option names with or without any leading

crates/spk-schema/crates/foundation/src/name/name_test.rs

+17
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,23 @@ fn test_opt_name_validation(#[case] input: &str) {
3535
super::validate_opt_name(input).unwrap();
3636
}
3737

38+
#[rstest]
39+
#[case("lowercase", "lowercase")]
40+
#[case("with-dashes", "with-dashes")]
41+
#[case("with_underscores", "with_underscores")]
42+
#[case("num000", "num000")]
43+
#[case("000-000", "000-000")]
44+
#[case("000_000", "000_000")]
45+
#[case("-----", "-----")]
46+
#[case("_____", "_____")]
47+
#[case("upperCase", "uppercase")]
48+
#[case("name!!", "name")]
49+
#[case("a", "a_")]
50+
fn test_opt_name_buf_new_lossy(#[case] input: &str, #[case] result: &str) {
51+
let opt_name = super::OptNameBuf::new_lossy(&String::from(input));
52+
assert_eq!(opt_name.base_name(), result);
53+
}
54+
3855
#[rstest]
3956
#[case("my_opt", None, "my_opt")]
4057
#[case("my-pkg.my_opt", Some("my-pkg"), "my_opt")]

0 commit comments

Comments
 (0)