diff --git a/Cargo.lock b/Cargo.lock index 6bec7bc2..97ef6cbc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -320,6 +320,7 @@ dependencies = [ "blue-build-recipe", "blue-build-template", "blue-build-utils", + "bon", "clap", "clap-verbosity-flag", "clap_complete", @@ -339,7 +340,6 @@ dependencies = [ "serde_yaml 0.9.34+deprecated", "shadow-rs", "tempdir", - "typed-builder", "urlencoding", "users", ] @@ -350,6 +350,7 @@ version = "0.8.17" dependencies = [ "anyhow", "blue-build-utils", + "bon", "chrono", "clap", "colored", @@ -375,7 +376,6 @@ dependencies = [ "sigstore", "tempdir", "tokio", - "typed-builder", "users", "uuid", "zeroize", @@ -386,6 +386,7 @@ name = "blue-build-recipe" version = "0.8.17" dependencies = [ "blue-build-utils", + "bon", "colored", "indexmap 2.3.0", "log", @@ -394,7 +395,6 @@ dependencies = [ "serde", "serde_json", "serde_yaml 0.9.34+deprecated", - "typed-builder", ] [[package]] @@ -403,10 +403,10 @@ version = "0.8.17" dependencies = [ "blue-build-recipe", "blue-build-utils", + "bon", "colored", "log", "rinja", - "typed-builder", "uuid", ] @@ -417,6 +417,7 @@ dependencies = [ "atty", "base64 0.22.1", "blake2", + "bon", "chrono", "clap", "directories", @@ -430,10 +431,32 @@ dependencies = [ "serde_json", "serde_yaml 0.9.34+deprecated", "syntect", - "typed-builder", "which", ] +[[package]] +name = "bon" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97493a391b4b18ee918675fb8663e53646fd09321c58b46afa04e8ce2499c869" +dependencies = [ + "bon-macros", + "rustversion", +] + +[[package]] +name = "bon-macros" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2af3eac944c12cdf4423eab70d310da0a8e5851a18ffb192c0a5e3f7ae1663" +dependencies = [ + "darling", + "ident_case", + "proc-macro2", + "quote", + "syn 2.0.72", +] + [[package]] name = "bstr" version = "1.10.0" @@ -4573,26 +4596,6 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" -[[package]] -name = "typed-builder" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77739c880e00693faef3d65ea3aad725f196da38b22fdc7ea6ded6e1ce4d3add" -dependencies = [ - "typed-builder-macro", -] - -[[package]] -name = "typed-builder-macro" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f718dfaf347dcb5b983bfc87608144b0bad87970aebcbea5ce44d2a30c08e63" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.72", -] - [[package]] name = "typed-path" version = "0.9.1" diff --git a/Cargo.toml b/Cargo.toml index 83072745..0682bb92 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ categories = ["command-line-utilities"] version = "0.8.17" [workspace.dependencies] +bon = "2" chrono = "0.4" clap = "4" colored = "2" @@ -23,7 +24,6 @@ serde = { version = "1", features = ["derive"] } serde_json = "1" serde_yaml = "0.9" tempdir = "0.3" -typed-builder = "0.18" users = "0.11" uuid = { version = "1", features = ["v4"] } @@ -81,7 +81,7 @@ serde.workspace = true serde_json.workspace = true serde_yaml.workspace = true tempdir.workspace = true -typed-builder.workspace = true +bon.workspace = true users.workspace = true [features] diff --git a/process/Cargo.toml b/process/Cargo.toml index 58e1825f..faf90972 100644 --- a/process/Cargo.toml +++ b/process/Cargo.toml @@ -39,7 +39,7 @@ oci-distribution.workspace = true serde.workspace = true serde_json.workspace = true tempdir.workspace = true -typed-builder.workspace = true +bon.workspace = true users.workspace = true uuid.workspace = true diff --git a/process/drivers.rs b/process/drivers.rs index e1a57ebc..42b60165 100644 --- a/process/drivers.rs +++ b/process/drivers.rs @@ -13,6 +13,7 @@ use std::{ }; use blue_build_utils::constants::IMAGE_VERSION_LABEL; +use bon::Builder; use clap::Args; use log::{debug, info, trace}; use miette::{miette, Result}; @@ -21,7 +22,6 @@ use once_cell::sync::Lazy; use opts::{GenerateImageNameOpts, GenerateTagsOpts}; #[cfg(feature = "sigstore")] use sigstore_driver::SigstoreDriver; -use typed_builder::TypedBuilder; use uuid::Uuid; use self::{ @@ -82,29 +82,25 @@ static OS_VERSION: Lazy>> = Lazy::new(|| Mutex::new(H /// /// If the args are left uninitialized, the program will determine /// the best one available. -#[derive(Default, Clone, Copy, Debug, TypedBuilder, Args)] +#[derive(Default, Clone, Copy, Debug, Builder, Args)] pub struct DriverArgs { /// Select which driver to use to build /// your image. - #[builder(default)] #[arg(short = 'B', long)] build_driver: Option, /// Select which driver to use to inspect /// images. - #[builder(default)] #[arg(short = 'I', long)] inspect_driver: Option, /// Select which driver to use to sign /// images. - #[builder(default)] #[arg(short = 'S', long)] signing_driver: Option, /// Select which driver to use to run /// containers. - #[builder(default)] #[arg(short = 'R', long)] run_driver: Option, } diff --git a/process/drivers/docker_driver.rs b/process/drivers/docker_driver.rs index f6433ad8..047e7849 100644 --- a/process/drivers/docker_driver.rs +++ b/process/drivers/docker_driver.rs @@ -22,7 +22,10 @@ use serde::Deserialize; use tempdir::TempDir; use crate::{ - drivers::image_metadata::ImageMetadata, + drivers::{ + image_metadata::ImageMetadata, + opts::{RunOptsEnv, RunOptsVolume}, + }, logging::{CommandLogging, Logger}, signal_handler::{add_cid, remove_cid, ContainerId, ContainerRuntime}, }; @@ -321,7 +324,7 @@ impl InspectDriver for DockerDriver { let output = Self::run_output( &RunOpts::builder() .image(SKOPEO_IMAGE) - .args(string_vec!["inspect", url.clone()]) + .args(bon::vec!["inspect", &url]) .remove(true) .build(), ) @@ -379,13 +382,13 @@ fn docker_run(opts: &RunOpts, cid_file: &Path) -> Command { if opts.privileged => "--privileged", if opts.remove => "--rm", if opts.pull => "--pull=always", - for volume in opts.volumes => [ + for RunOptsVolume { path_or_vol_name, container_path } in opts.volumes.iter() => [ "--volume", - format!("{}:{}", volume.path_or_vol_name, volume.container_path), + format!("{path_or_vol_name}:{container_path}"), ], - for env in opts.env_vars => [ + for RunOptsEnv { key, value } in opts.env_vars.iter() => [ "--env", - format!("{}={}", env.key, env.value), + format!("{key}={value}"), ], |command| { match (opts.uid, opts.gid) { @@ -395,7 +398,7 @@ fn docker_run(opts: &RunOpts, cid_file: &Path) -> Command { } }, &*opts.image, - for opts.args, + for arg in opts.args.iter() => &**arg, ); trace!("{command:?}"); diff --git a/process/drivers/github_driver.rs b/process/drivers/github_driver.rs index 6bb3f341..ae27f97f 100644 --- a/process/drivers/github_driver.rs +++ b/process/drivers/github_driver.rs @@ -137,7 +137,7 @@ mod test { constants::{ GITHUB_EVENT_NAME, GITHUB_EVENT_PATH, GITHUB_REF_NAME, GITHUB_SHA, PR_EVENT_NUMBER, }, - cowstr_vec, string_vec, + string_vec, test_utils::set_env_var, }; use oci_distribution::Reference; @@ -230,7 +230,7 @@ mod test { )] #[case::default_branch_alt_tags( setup_default_branch, - Some(cowstr_vec![TEST_TAG_1, TEST_TAG_2]), + Some(bon::vec![TEST_TAG_1, TEST_TAG_2]), string_vec![ TEST_TAG_1, format!("{TEST_TAG_1}-40"), @@ -249,7 +249,7 @@ mod test { )] #[case::pr_branch_alt_tags( setup_pr_branch, - Some(cowstr_vec![TEST_TAG_1, TEST_TAG_2]), + Some(bon::vec![TEST_TAG_1, TEST_TAG_2]), string_vec![ format!("pr-12-{TEST_TAG_1}-40"), format!("{COMMIT_SHA}-{TEST_TAG_1}-40"), @@ -264,7 +264,7 @@ mod test { )] #[case::branch_alt_tags( setup_branch, - Some(cowstr_vec![TEST_TAG_1, TEST_TAG_2]), + Some(bon::vec![TEST_TAG_1, TEST_TAG_2]), string_vec![ format!("br-{BR_REF_NAME}-{TEST_TAG_1}-40"), format!("{COMMIT_SHA}-{TEST_TAG_1}-40"), @@ -284,7 +284,7 @@ mod test { let mut tags = GithubDriver::generate_tags( &GenerateTagsOpts::builder() .oci_ref(&oci_ref) - .alt_tags(alt_tags) + .maybe_alt_tags(alt_tags) .build(), ) .unwrap(); diff --git a/process/drivers/gitlab_driver.rs b/process/drivers/gitlab_driver.rs index deaefdd1..7cc52841 100644 --- a/process/drivers/gitlab_driver.rs +++ b/process/drivers/gitlab_driver.rs @@ -149,7 +149,7 @@ mod test { CI_PIPELINE_SOURCE, CI_PROJECT_NAME, CI_PROJECT_NAMESPACE, CI_REGISTRY, CI_SERVER_HOST, CI_SERVER_PROTOCOL, }, - cowstr_vec, string_vec, + string_vec, test_utils::set_env_var, }; use oci_distribution::Reference; @@ -238,7 +238,7 @@ mod test { )] #[case::default_branch_alt_tags( setup_default_branch, - Some(cowstr_vec![TEST_TAG_1, TEST_TAG_2]), + Some(bon::vec![TEST_TAG_1, TEST_TAG_2]), string_vec![ TEST_TAG_1, format!("{TEST_TAG_1}-40"), @@ -257,7 +257,7 @@ mod test { )] #[case::pr_branch_alt_tags( setup_mr_branch, - Some(cowstr_vec![TEST_TAG_1, TEST_TAG_2]), + Some(bon::vec![TEST_TAG_1, TEST_TAG_2]), string_vec![ format!("mr-12-{TEST_TAG_1}-40"), format!("{COMMIT_SHA}-{TEST_TAG_1}-40"), @@ -272,7 +272,7 @@ mod test { )] #[case::branch_alt_tags( setup_branch, - Some(cowstr_vec![TEST_TAG_1, TEST_TAG_2]), + Some(bon::vec![TEST_TAG_1, TEST_TAG_2]), string_vec![ format!("br-{BR_REF_NAME}-{TEST_TAG_1}-40"), format!("{COMMIT_SHA}-{TEST_TAG_1}-40"), @@ -292,7 +292,7 @@ mod test { let mut tags = GitlabDriver::generate_tags( &GenerateTagsOpts::builder() .oci_ref(&oci_ref) - .alt_tags(alt_tags) + .maybe_alt_tags(alt_tags) .build(), ) .unwrap(); diff --git a/process/drivers/opts/build.rs b/process/drivers/opts/build.rs index 3f4689da..2eff5230 100644 --- a/process/drivers/opts/build.rs +++ b/process/drivers/opts/build.rs @@ -1,65 +1,63 @@ use std::{borrow::Cow, path::Path}; -use typed_builder::TypedBuilder; +use bon::Builder; use super::CompressionType; /// Options for building -#[derive(Debug, Clone, TypedBuilder)] -pub struct BuildOpts<'a> { - #[builder(setter(into))] - pub image: Cow<'a, str>, +#[derive(Debug, Clone, Builder)] +pub struct BuildOpts<'scope> { + #[builder(into)] + pub image: Cow<'scope, str>, #[builder(default)] pub squash: bool, - #[builder(setter(into))] - pub containerfile: Cow<'a, Path>, + #[builder(into)] + pub containerfile: Cow<'scope, Path>, } -#[derive(Debug, Clone, TypedBuilder)] -pub struct TagOpts<'a> { - #[builder(setter(into))] - pub src_image: Cow<'a, str>, +#[derive(Debug, Clone, Builder)] +pub struct TagOpts<'scope> { + #[builder(into)] + pub src_image: Cow<'scope, str>, - #[builder(setter(into))] - pub dest_image: Cow<'a, str>, + #[builder(into)] + pub dest_image: Cow<'scope, str>, } -#[derive(Debug, Clone, TypedBuilder)] -pub struct PushOpts<'a> { - #[builder(setter(into))] - pub image: Cow<'a, str>, - - #[builder(default, setter(strip_option))] +#[derive(Debug, Clone, Builder)] +pub struct PushOpts<'scope> { + #[builder(into)] + pub image: Cow<'scope, str>, pub compression_type: Option, } /// Options for building, tagging, and pusing images. #[allow(clippy::struct_excessive_bools)] -#[derive(Debug, Clone, TypedBuilder)] -pub struct BuildTagPushOpts<'a> { +#[derive(Debug, Clone, Builder)] +pub struct BuildTagPushOpts<'scope> { /// The base image name. /// /// NOTE: This SHOULD NOT contain the tag of the image. /// /// NOTE: You cannot have this set with `archive_path` set. - #[builder(default, setter(into, strip_option))] - pub image: Option>, + #[builder(into)] + pub image: Option>, /// The path to the archive file. /// /// NOTE: You cannot have this set with image set. - #[builder(default, setter(into, strip_option))] - pub archive_path: Option>, + #[builder(into)] + pub archive_path: Option>, /// The path to the Containerfile to build. - #[builder(setter(into))] - pub containerfile: Cow<'a, Path>, + #[builder(into)] + pub containerfile: Cow<'scope, Path>, /// The list of tags for the image being built. - #[builder(default, setter(into))] - pub tags: Cow<'a, [String]>, + #[builder(default, into)] + pub tags: Vec>, /// Enable pushing the image. #[builder(default)] diff --git a/process/drivers/opts/ci.rs b/process/drivers/opts/ci.rs index a2e8407c..2a64dc9f 100644 --- a/process/drivers/opts/ci.rs +++ b/process/drivers/opts/ci.rs @@ -1,24 +1,24 @@ use std::borrow::Cow; +use bon::Builder; use oci_distribution::Reference; -use typed_builder::TypedBuilder; -#[derive(Debug, Clone, TypedBuilder)] +#[derive(Debug, Clone, Builder)] pub struct GenerateTagsOpts<'scope> { pub oci_ref: &'scope Reference, - #[builder(default, setter(into))] + #[builder(into)] pub alt_tags: Option>>, } -#[derive(Debug, Clone, TypedBuilder)] +#[derive(Debug, Clone, Builder)] pub struct GenerateImageNameOpts<'scope> { - #[builder(default, setter(into))] + #[builder(into)] pub name: Cow<'scope, str>, - #[builder(default, setter(into))] + #[builder(into)] pub registry: Option>, - #[builder(default, setter(into))] + #[builder(into)] pub registry_namespace: Option>, } diff --git a/process/drivers/opts/inspect.rs b/process/drivers/opts/inspect.rs index b92f51bf..95b0036e 100644 --- a/process/drivers/opts/inspect.rs +++ b/process/drivers/opts/inspect.rs @@ -1,12 +1,12 @@ use std::borrow::Cow; -use typed_builder::TypedBuilder; +use bon::Builder; -#[derive(Debug, Clone, TypedBuilder)] -pub struct GetMetadataOpts<'a> { - #[builder(setter(into))] - pub image: Cow<'a, str>, +#[derive(Debug, Clone, Builder)] +pub struct GetMetadataOpts<'scope> { + #[builder(into)] + pub image: Cow<'scope, str>, - #[builder(default, setter(into, strip_option))] - pub tag: Option>, + #[builder(into)] + pub tag: Option>, } diff --git a/process/drivers/opts/run.rs b/process/drivers/opts/run.rs index 6c0971a6..7b3a23f0 100644 --- a/process/drivers/opts/run.rs +++ b/process/drivers/opts/run.rs @@ -1,30 +1,23 @@ use std::borrow::Cow; -use typed_builder::TypedBuilder; +use bon::Builder; -#[derive(Debug, Clone, TypedBuilder)] +#[derive(Debug, Clone, Builder)] pub struct RunOpts<'scope> { - #[builder(setter(into))] + #[builder(into)] pub image: Cow<'scope, str>, - #[builder(default, setter(into))] - pub args: Cow<'scope, [String]>, + #[builder(default, into)] + pub args: Vec>, - #[builder(default, setter(into))] + #[builder(default, into)] pub env_vars: Vec>, - #[builder(default, setter(into))] + #[builder(default, into)] pub volumes: Vec>, - - #[builder(default, setter(strip_option))] pub uid: Option, - - #[builder(default, setter(strip_option))] pub gid: Option, - #[builder(default, setter(into))] - pub workdir: Cow<'scope, str>, - #[builder(default)] pub privileged: bool, @@ -35,12 +28,12 @@ pub struct RunOpts<'scope> { pub remove: bool, } -#[derive(Debug, Clone, TypedBuilder)] +#[derive(Debug, Clone, Builder)] pub struct RunOptsVolume<'scope> { - #[builder(setter(into))] + #[builder(into)] pub path_or_vol_name: Cow<'scope, str>, - #[builder(setter(into))] + #[builder(into)] pub container_path: Cow<'scope, str>, } @@ -48,7 +41,7 @@ pub struct RunOptsVolume<'scope> { macro_rules! run_volumes { ($($host:expr => $container:expr),+ $(,)?) => { { - vec![ + ::bon::vec![ $($crate::drivers::opts::RunOptsVolume::builder() .path_or_vol_name($host) .container_path($container) @@ -58,12 +51,12 @@ macro_rules! run_volumes { }; } -#[derive(Debug, Clone, TypedBuilder)] +#[derive(Debug, Clone, Builder)] pub struct RunOptsEnv<'scope> { - #[builder(setter(into))] + #[builder(into)] pub key: Cow<'scope, str>, - #[builder(setter(into))] + #[builder(into)] pub value: Cow<'scope, str>, } @@ -71,7 +64,7 @@ pub struct RunOptsEnv<'scope> { macro_rules! run_envs { ($($key:expr => $value:expr),+ $(,)?) => { { - vec![ + ::bon::vec![ $($crate::drivers::opts::RunOptsEnv::builder() .key($key) .value($value) diff --git a/process/drivers/opts/signing.rs b/process/drivers/opts/signing.rs index 77acc475..8a43e37f 100644 --- a/process/drivers/opts/signing.rs +++ b/process/drivers/opts/signing.rs @@ -4,8 +4,8 @@ use std::{ path::{Path, PathBuf}, }; +use bon::Builder; use miette::{IntoDiagnostic, Result}; -use typed_builder::TypedBuilder; use zeroize::{Zeroize, Zeroizing}; pub enum PrivateKey { @@ -13,6 +13,18 @@ pub enum PrivateKey { Path(PathBuf), } +impl std::fmt::Display for PrivateKey { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str( + match *self { + Self::Env(ref env) => format!("env://{env}"), + Self::Path(ref path) => format!("{}", path.display()), + } + .as_str(), + ) + } +} + pub trait PrivateKeyContents where T: Zeroize, @@ -40,39 +52,27 @@ impl PrivateKeyContents for PrivateKey { } } -impl std::fmt::Display for PrivateKey { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str( - match *self { - Self::Env(ref env) => format!("env://{env}"), - Self::Path(ref path) => format!("{}", path.display()), - } - .as_str(), - ) - } -} - -#[derive(Debug, Clone, TypedBuilder)] +#[derive(Debug, Clone, Builder)] pub struct GenerateKeyPairOpts<'scope> { - #[builder(setter(into, strip_option))] + #[builder(into)] pub dir: Option>, } -#[derive(Debug, Clone, TypedBuilder)] +#[derive(Debug, Clone, Builder)] pub struct CheckKeyPairOpts<'scope> { - #[builder(setter(into, strip_option))] + #[builder(into)] pub dir: Option>, } -#[derive(Debug, Clone, TypedBuilder)] +#[derive(Debug, Clone, Builder)] pub struct SignOpts<'scope> { - #[builder(setter(into))] + #[builder(into)] pub image: Cow<'scope, str>, - #[builder(default, setter(into, strip_option))] + #[builder(into)] pub key: Option>, - #[builder(default, setter(into, strip_option))] + #[builder(into)] pub dir: Option>, } @@ -85,22 +85,22 @@ pub enum VerifyType<'scope> { }, } -#[derive(Debug, Clone, TypedBuilder)] +#[derive(Debug, Clone, Builder)] pub struct VerifyOpts<'scope> { - #[builder(setter(into))] + #[builder(into)] pub image: Cow<'scope, str>, pub verify_type: VerifyType<'scope>, } -#[derive(Debug, Clone, TypedBuilder)] +#[derive(Debug, Clone, Builder)] pub struct SignVerifyOpts<'scope> { - #[builder(setter(into))] + #[builder(into)] pub image: Cow<'scope, str>, - #[builder(default, setter(into, strip_option))] + #[builder(into)] pub tag: Option>, - #[builder(default, setter(into, strip_option))] + #[builder(into)] pub dir: Option>, /// Enable retry logic for pushing. diff --git a/process/drivers/podman_driver.rs b/process/drivers/podman_driver.rs index 3405c6d6..37e6a68e 100644 --- a/process/drivers/podman_driver.rs +++ b/process/drivers/podman_driver.rs @@ -5,7 +5,7 @@ use std::{ time::Duration, }; -use blue_build_utils::{cmd, constants::SKOPEO_IMAGE, credentials::Credentials, string_vec}; +use blue_build_utils::{cmd, constants::SKOPEO_IMAGE, credentials::Credentials}; use colored::Colorize; use indicatif::{ProgressBar, ProgressStyle}; use log::{debug, error, info, trace, warn}; @@ -15,7 +15,10 @@ use serde::Deserialize; use tempdir::TempDir; use crate::{ - drivers::image_metadata::ImageMetadata, + drivers::{ + image_metadata::ImageMetadata, + opts::{RunOptsEnv, RunOptsVolume}, + }, logging::{CommandLogging, Logger}, signal_handler::{add_cid, remove_cid, ContainerId, ContainerRuntime}, }; @@ -198,7 +201,7 @@ impl InspectDriver for PodmanDriver { let output = Self::run_output( &RunOpts::builder() .image(SKOPEO_IMAGE) - .args(string_vec!["inspect", url.clone()]) + .args(bon::vec!["inspect", &url]) .remove(true) .build(), ) @@ -277,16 +280,16 @@ fn podman_run(opts: &RunOpts, cid_file: &Path) -> Command { ], if opts.remove => "--rm", if opts.pull => "--pull=always", - for volume in opts.volumes => [ + for RunOptsVolume { path_or_vol_name, container_path } in opts.volumes.iter() => [ "--volume", - format!("{}:{}", volume.path_or_vol_name, volume.container_path), + format!("{path_or_vol_name}:{container_path}"), ], - for env in opts.env_vars => [ + for RunOptsEnv { key, value } in opts.env_vars.iter() => [ "--env", - format!("{}={}", env.key, env.value), + format!("{key}={value}"), ], &*opts.image, - for opts.args, + for arg in opts.args.iter() => &**arg, ); trace!("{command:?}"); diff --git a/process/drivers/traits.rs b/process/drivers/traits.rs index 3f0db119..6075fe83 100644 --- a/process/drivers/traits.rs +++ b/process/drivers/traits.rs @@ -105,7 +105,7 @@ pub trait BuildDriver { let mut image_list = Vec::with_capacity(opts.tags.len()); - for tag in opts.tags.as_ref() { + for tag in &opts.tags { debug!("Tagging {} with {tag}", &full_image); let tagged_image = format!("{image}:{tag}"); diff --git a/process/logging.rs b/process/logging.rs index 03fb54fd..ec60e1d0 100644 --- a/process/logging.rs +++ b/process/logging.rs @@ -9,6 +9,7 @@ use std::{ time::Duration, }; +use bon::Builder; use chrono::Local; use colored::{control::ShouldColorize, ColoredString, Colorize}; use indicatif::{MultiProgress, ProgressBar}; @@ -31,7 +32,6 @@ use log4rs::{ use nu_ansi_term::Color; use once_cell::sync::Lazy; use rand::Rng; -use typed_builder::TypedBuilder; use crate::signal_handler::{add_pid, remove_pid}; @@ -258,9 +258,9 @@ impl CommandLogging for Command { } } -#[derive(Debug, TypedBuilder)] +#[derive(Debug, Builder)] struct CustomPatternEncoder { - #[builder(default, setter(into))] + #[builder(default, into)] filter_modules: Vec<(String, LevelFilter)>, } diff --git a/recipe/Cargo.toml b/recipe/Cargo.toml index a98c0b75..059042c0 100644 --- a/recipe/Cargo.toml +++ b/recipe/Cargo.toml @@ -19,7 +19,7 @@ indexmap.workspace = true serde.workspace = true serde_yaml.workspace = true serde_json.workspace = true -typed-builder.workspace = true +bon.workspace = true [features] default = [] diff --git a/recipe/src/akmods_info.rs b/recipe/src/akmods_info.rs index 3d5b11d4..f72fa822 100644 --- a/recipe/src/akmods_info.rs +++ b/recipe/src/akmods_info.rs @@ -1,7 +1,10 @@ -use typed_builder::TypedBuilder; +use bon::Builder; -#[derive(Debug, Clone, TypedBuilder, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Builder, PartialEq, Eq, Hash)] pub struct AkmodsInfo { + #[builder(into)] pub images: (String, String, Option), + + #[builder(into)] pub stage_name: String, } diff --git a/recipe/src/module.rs b/recipe/src/module.rs index b6166e0c..ddfb390b 100644 --- a/recipe/src/module.rs +++ b/recipe/src/module.rs @@ -1,23 +1,23 @@ use std::{borrow::Cow, path::PathBuf}; use blue_build_utils::syntax_highlighting::highlight_ser; +use bon::Builder; use colored::Colorize; use indexmap::IndexMap; use log::{trace, warn}; use miette::{bail, Result}; use serde::{Deserialize, Serialize}; use serde_yaml::Value; -use typed_builder::TypedBuilder; use crate::{AkmodsInfo, ModuleExt}; -#[derive(Serialize, Deserialize, Debug, Clone, TypedBuilder, Default)] +#[derive(Serialize, Deserialize, Debug, Clone, Builder, Default)] pub struct ModuleRequiredFields<'a> { - #[builder(default, setter(into))] + #[builder(into)] #[serde(rename = "type")] pub module_type: Cow<'a, str>, - #[builder(default, setter(into, strip_option))] + #[builder(into)] #[serde(skip_serializing_if = "Option::is_none")] pub source: Option>, @@ -26,7 +26,7 @@ pub struct ModuleRequiredFields<'a> { pub no_cache: bool, #[serde(flatten)] - #[builder(default, setter(into))] + #[builder(default, into)] pub config: IndexMap, } @@ -154,13 +154,12 @@ impl<'a> ModuleRequiredFields<'a> { } } -#[derive(Serialize, Deserialize, Debug, Clone, TypedBuilder, Default)] +#[derive(Serialize, Deserialize, Debug, Clone, Builder, Default)] pub struct Module<'a> { - #[builder(default, setter(strip_option))] #[serde(flatten, skip_serializing_if = "Option::is_none")] pub required_fields: Option>, - #[builder(default, setter(into, strip_option))] + #[builder(into)] #[serde(rename = "from-file", skip_serializing_if = "Option::is_none")] pub from_file: Option>, } diff --git a/recipe/src/module_ext.rs b/recipe/src/module_ext.rs index ab096555..2e45dab6 100644 --- a/recipe/src/module_ext.rs +++ b/recipe/src/module_ext.rs @@ -1,17 +1,17 @@ -use std::{borrow::Cow, collections::HashSet, fs, path::Path}; +use std::{collections::HashSet, fs, path::Path}; use blue_build_utils::constants::{CONFIG_PATH, RECIPE_PATH}; +use bon::Builder; use log::{trace, warn}; use miette::{Context, IntoDiagnostic, Result}; use serde::{Deserialize, Serialize}; -use typed_builder::TypedBuilder; use crate::{AkmodsInfo, Module}; -#[derive(Default, Serialize, Clone, Deserialize, Debug, TypedBuilder)] +#[derive(Default, Serialize, Clone, Deserialize, Debug, Builder)] pub struct ModuleExt<'a> { - #[builder(default, setter(into))] - pub modules: Cow<'a, [Module<'a>]>, + #[builder(default)] + pub modules: Vec>, } impl ModuleExt<'_> { diff --git a/recipe/src/recipe.rs b/recipe/src/recipe.rs index cbbc2479..4fe54ee5 100644 --- a/recipe/src/recipe.rs +++ b/recipe/src/recipe.rs @@ -1,13 +1,12 @@ use std::{borrow::Cow, fs, path::Path}; -use blue_build_utils::cowstr; +use bon::Builder; use indexmap::IndexMap; use log::{debug, trace}; use miette::{Context, IntoDiagnostic, Result}; use oci_distribution::Reference; use serde::{Deserialize, Serialize}; use serde_yaml::Value; -use typed_builder::TypedBuilder; use crate::{Module, ModuleExt, StagesExt}; @@ -17,33 +16,33 @@ use crate::{Module, ModuleExt, StagesExt}; /// This will contain information on the image and its /// base image to assist with building the Containerfile /// and tagging the image appropriately. -#[derive(Default, Serialize, Clone, Deserialize, Debug, TypedBuilder)] +#[derive(Default, Serialize, Clone, Deserialize, Debug, Builder)] pub struct Recipe<'a> { /// The name of the user's image. /// /// This will be set on the `org.opencontainers.image.title` label. - #[builder(setter(into))] + #[builder(into)] pub name: Cow<'a, str>, /// The description of the user's image. /// /// This will be set on the `org.opencontainers.image.description` label. - #[builder(setter(into))] + #[builder(into)] pub description: Cow<'a, str>, /// The base image from which to build the user's image. #[serde(alias = "base-image")] - #[builder(setter(into))] + #[builder(into)] pub base_image: Cow<'a, str>, /// The version/tag of the base image. #[serde(alias = "image-version")] - #[builder(setter(into))] + #[builder(into)] pub image_version: Cow<'a, str>, /// The version of `bluebuild` to install in the image #[serde(alias = "blue-build-tag", skip_serializing_if = "Option::is_none")] - #[builder(default, setter(into, strip_option))] + #[builder(into)] pub blue_build_tag: Option>, /// Alternate tags to the `latest` tag to add to the image. @@ -54,8 +53,8 @@ pub struct Recipe<'a> { /// /// Any user input will override the `latest` and timestamp tags. #[serde(alias = "alt-tags", skip_serializing_if = "Option::is_none")] - #[builder(default, setter(into, strip_option))] - alt_tags: Option>>, + #[builder(into)] + pub alt_tags: Option>, /// The stages extension of the recipe. /// @@ -75,7 +74,7 @@ pub struct Recipe<'a> { /// done in case we serialize the data to a yaml file /// so that we retain any unused information. #[serde(flatten)] - #[builder(setter(into))] + #[builder(into)] pub extra: IndexMap, } @@ -106,11 +105,11 @@ impl<'a> Recipe<'a> { .map_err(blue_build_utils::serde_yaml_err(&file)) .into_diagnostic()?; - recipe.modules_ext.modules = Module::get_modules(&recipe.modules_ext.modules, None)?.into(); + recipe.modules_ext.modules = Module::get_modules(&recipe.modules_ext.modules, None)?; #[cfg(feature = "stages")] if let Some(ref mut stages_ext) = recipe.stages_ext { - stages_ext.stages = crate::Stage::get_stages(&stages_ext.stages, None)?.into(); + stages_ext.stages = crate::Stage::get_stages(&stages_ext.stages, None)?; } #[cfg(not(feature = "stages"))] @@ -132,11 +131,4 @@ impl<'a> Recipe<'a> { .into_diagnostic() .with_context(|| format!("Unable to parse base image {base_image}")) } - - #[must_use] - pub fn alt_tags(&'a self) -> Option>> { - self.alt_tags - .as_ref() - .map(|tags| tags.iter().map(|tag| cowstr!(&**tag)).collect()) - } } diff --git a/recipe/src/stage.rs b/recipe/src/stage.rs index 23224f3e..dff8875b 100644 --- a/recipe/src/stage.rs +++ b/recipe/src/stage.rs @@ -1,33 +1,33 @@ use std::{borrow::Cow, path::PathBuf}; use blue_build_utils::syntax_highlighting::highlight_ser; +use bon::Builder; use colored::Colorize; use miette::{bail, Result}; use serde::{Deserialize, Serialize}; -use typed_builder::TypedBuilder; use crate::{Module, ModuleExt, StagesExt}; /// Contains the required fields for a stage. -#[derive(Serialize, Deserialize, Debug, Clone, TypedBuilder)] +#[derive(Serialize, Deserialize, Debug, Clone, Builder)] pub struct StageRequiredFields<'a> { /// The name of the stage. /// /// This can then be referenced in the `copy` /// module using the `from:` property. - #[builder(setter(into))] + #[builder(into)] pub name: Cow<'a, str>, /// The base image of the stage. /// /// This is set directly in a `FROM` instruction. - #[builder(setter(into))] + #[builder(into)] pub from: Cow<'a, str>, /// The shell to use in the stage. - #[builder(default, setter(into, strip_option))] + #[builder(into)] #[serde(skip_serializing_if = "Option::is_none")] - pub shell: Option]>>, + pub shell: Option>, /// The modules extension for the stage #[serde(flatten)] @@ -38,10 +38,9 @@ pub struct StageRequiredFields<'a> { /// /// A stage has its own list of modules to run which /// allows the user to reuse the modules thats provided to the main build. -#[derive(Serialize, Deserialize, Debug, Clone, TypedBuilder)] +#[derive(Serialize, Deserialize, Debug, Clone, Builder)] pub struct Stage<'a> { /// The requied fields for a stage. - #[builder(default, setter(strip_option))] #[serde(flatten, skip_serializing_if = "Option::is_none")] pub required_fields: Option>, @@ -82,7 +81,7 @@ pub struct Stage<'a> { /// snippets: /// - echo "Hello World!" /// ``` - #[builder(default, setter(into, strip_option))] + #[builder(into)] #[serde(rename = "from-file", skip_serializing_if = "Option::is_none")] pub from_file: Option>, } diff --git a/recipe/src/stages_ext.rs b/recipe/src/stages_ext.rs index be30ef8d..ae8ebd7a 100644 --- a/recipe/src/stages_ext.rs +++ b/recipe/src/stages_ext.rs @@ -1,17 +1,17 @@ -use std::{borrow::Cow, fs, path::Path}; +use std::{fs, path::Path}; use blue_build_utils::constants::{CONFIG_PATH, RECIPE_PATH}; +use bon::Builder; use log::warn; use miette::{Context, IntoDiagnostic, Result}; use serde::{Deserialize, Serialize}; -use typed_builder::TypedBuilder; use crate::{Module, Stage}; -#[derive(Default, Serialize, Clone, Deserialize, Debug, TypedBuilder)] +#[derive(Default, Serialize, Clone, Deserialize, Debug, Builder)] pub struct StagesExt<'a> { - #[builder(default, setter(into))] - pub stages: Cow<'a, [Stage<'a>]>, + #[builder(default)] + pub stages: Vec>, } impl<'a> StagesExt<'a> { @@ -41,8 +41,7 @@ impl<'a> StagesExt<'a> { .map_err(blue_build_utils::serde_yaml_err(&file)) .into_diagnostic()?; if let Some(ref mut rf) = stage.required_fields { - rf.modules_ext.modules = - Module::get_modules(&rf.modules_ext.modules, None)?.into(); + rf.modules_ext.modules = Module::get_modules(&rf.modules_ext.modules, None)?; } Ok(Self::builder().stages(vec![stage]).build()) }, @@ -52,10 +51,10 @@ impl<'a> StagesExt<'a> { for stage in &mut stages { if let Some(ref mut rf) = stage.required_fields { rf.modules_ext.modules = - Module::get_modules(&rf.modules_ext.modules, None)?.into(); + Module::get_modules(&rf.modules_ext.modules, None)?; } } - stages_ext.stages = stages.into(); + stages_ext.stages = stages; Ok(stages_ext) }, ) diff --git a/src/commands/bug_report.rs b/src/commands/bug_report.rs index 7c49d599..ebbe7787 100644 --- a/src/commands/bug_report.rs +++ b/src/commands/bug_report.rs @@ -4,6 +4,7 @@ use blue_build_utils::constants::{ BUG_REPORT_WARNING_MESSAGE, GITHUB_CHAR_LIMIT, LC_TERMINAL, LC_TERMINAL_VERSION, TERM_PROGRAM, TERM_PROGRAM_VERSION, UNKNOWN_SHELL, UNKNOWN_TERMINAL, UNKNOWN_VERSION, }; +use bon::Builder; use clap::Args; use clap_complete::Shell; use colored::Colorize; @@ -12,23 +13,21 @@ use log::{debug, error, trace}; use miette::{IntoDiagnostic, Result}; use requestty::question::{completions, Completions}; use std::time::Duration; -use typed_builder::TypedBuilder; use super::BlueBuildCommand; use crate::shadow; -#[derive(Default, Debug, Clone, TypedBuilder, Args)] +#[derive(Default, Debug, Clone, Builder, Args)] pub struct BugReportRecipe { recipe_dir: Option, recipe_path: Option, } -#[derive(Debug, Clone, Args, TypedBuilder)] +#[derive(Debug, Clone, Args, Builder)] pub struct BugReportCommand { /// Path to the recipe file #[arg(short, long)] - #[builder(default)] recipe_path: Option, } diff --git a/src/commands/build.rs b/src/commands/build.rs index 3ad437c3..8dd96b0f 100644 --- a/src/commands/build.rs +++ b/src/commands/build.rs @@ -22,30 +22,31 @@ use blue_build_utils::{ cowstr, credentials::{Credentials, CredentialsArgs}, string, + traits::CowCollecter, }; +use bon::Builder; use clap::Args; use colored::Colorize; use log::{info, trace, warn}; use miette::{bail, Context, IntoDiagnostic, Result}; -use typed_builder::TypedBuilder; use crate::commands::generate::GenerateCommand; use super::BlueBuildCommand; #[allow(clippy::struct_excessive_bools)] -#[derive(Debug, Clone, Args, TypedBuilder)] +#[derive(Debug, Clone, Args, Builder)] pub struct BuildCommand { /// The recipe file to build an image #[arg()] #[cfg(feature = "multi-recipe")] - #[builder(default, setter(into, strip_option))] + #[builder(into)] recipe: Option>, /// The recipe file to build an image #[arg()] #[cfg(not(feature = "multi-recipe"))] - #[builder(default, setter(into, strip_option))] + #[builder(into)] recipe: Option, /// Push the image with all the tags. @@ -85,14 +86,13 @@ pub struct BuildCommand { /// Archives the built image into a tarfile /// in the specified directory. #[arg(short, long)] - #[builder(default, setter(into, strip_option))] + #[builder(into)] archive: Option, /// The url path to your base /// project images. - #[arg(long, env = BB_REGISTRY_NAMESPACE)] - #[builder(default, setter(into, strip_option))] - #[arg(visible_alias("registry-path"))] + #[arg(long, env = BB_REGISTRY_NAMESPACE, visible_alias("registry-path"))] + #[builder(into)] registry_namespace: Option, /// Do not sign the image on push. @@ -260,7 +260,7 @@ impl BuildCommand { let tags = Driver::generate_tags( &GenerateTagsOpts::builder() .oci_ref(&recipe.base_image_ref()?) - .alt_tags(recipe.alt_tags()) + .maybe_alt_tags(recipe.alt_tags.as_ref().map(CowCollecter::to_cow_vec)) .build(), )?; let image_name = self.image_name(&recipe)?; @@ -279,7 +279,7 @@ impl BuildCommand { BuildTagPushOpts::builder() .image(&image_name) .containerfile(containerfile) - .tags(&tags) + .tags(tags.to_cow_vec()) .push(self.push) .retry_push(self.retry_push) .retry_count(self.retry_count) @@ -291,16 +291,14 @@ impl BuildCommand { let images = Driver::build_tag_push(&opts)?; if self.push && !self.no_sign { - let opts = SignVerifyOpts::builder() - .image(&image_name) - .retry_push(self.retry_push) - .retry_count(self.retry_count); - let opts = if let Some(tag) = tags.first() { - opts.tag(tag).build() - } else { - opts.build() - }; - Driver::sign_and_verify(&opts)?; + Driver::sign_and_verify( + &SignVerifyOpts::builder() + .image(&image_name) + .retry_push(self.retry_push) + .retry_count(self.retry_count) + .maybe_tag(tags.first()) + .build(), + )?; } Ok(images) @@ -310,8 +308,8 @@ impl BuildCommand { let image_name = Driver::generate_image_name( GenerateImageNameOpts::builder() .name(recipe.name.trim()) - .registry(self.credentials.registry.as_ref().map(|r| cowstr!(r))) - .registry_namespace(self.registry_namespace.as_ref().map(|r| cowstr!(r))) + .maybe_registry(self.credentials.registry.as_ref().map(|r| cowstr!(r))) + .maybe_registry_namespace(self.registry_namespace.as_ref().map(|r| cowstr!(r))) .build(), )?; diff --git a/src/commands/generate.rs b/src/commands/generate.rs index ef7a1a0f..24308e89 100644 --- a/src/commands/generate.rs +++ b/src/commands/generate.rs @@ -10,25 +10,25 @@ use blue_build_utils::{ constants::{CONFIG_PATH, RECIPE_FILE, RECIPE_PATH}, syntax_highlighting::{self, DefaultThemes}, }; +use bon::Builder; use clap::{crate_version, Args}; use log::{debug, info, trace, warn}; use miette::{IntoDiagnostic, Result}; -use typed_builder::TypedBuilder; use crate::shadow; use super::BlueBuildCommand; -#[derive(Debug, Clone, Args, TypedBuilder)] +#[derive(Debug, Clone, Args, Builder)] pub struct GenerateCommand { /// The recipe file to create a template from #[arg()] - #[builder(default, setter(into, strip_option))] + #[builder(into)] recipe: Option, /// File to output to instead of STDOUT #[arg(short, long)] - #[builder(default, setter(into, strip_option))] + #[builder(into)] output: Option, /// The registry domain the image will be published to. @@ -36,7 +36,7 @@ pub struct GenerateCommand { /// This is used for modules that need to know where /// the image is being published (i.e. the signing module). #[arg(long)] - #[builder(default, setter(into, strip_option))] + #[builder(into)] registry: Option, /// The registry namespace the image will be published to. @@ -44,7 +44,7 @@ pub struct GenerateCommand { /// This is used for modules that need to know where /// the image is being published (i.e. the signing module). #[arg(long)] - #[builder(default, setter(into, strip_option))] + #[builder(into)] registry_namespace: Option, /// Instead of creating a Containerfile, display @@ -61,7 +61,6 @@ pub struct GenerateCommand { /// /// The default is `mocha-dark`. #[arg(short = 't', long)] - #[builder(default, setter(strip_option))] syntax_theme: Option, #[clap(flatten)] diff --git a/src/commands/generate_iso.rs b/src/commands/generate_iso.rs index 29a103b0..9c84b827 100644 --- a/src/commands/generate_iso.rs +++ b/src/commands/generate_iso.rs @@ -4,12 +4,12 @@ use std::{ }; use blue_build_recipe::Recipe; -use blue_build_utils::{constants::ARCHIVE_SUFFIX, string_vec}; +use blue_build_utils::{constants::ARCHIVE_SUFFIX, string_vec, traits::CowCollecter}; +use bon::Builder; use clap::{Args, Subcommand, ValueEnum}; use miette::{bail, Context, IntoDiagnostic, Result}; use oci_distribution::Reference; use tempdir::TempDir; -use typed_builder::TypedBuilder; use blue_build_process_management::{ drivers::{opts::RunOpts, Driver, DriverArgs, RunDriver}, @@ -18,13 +18,14 @@ use blue_build_process_management::{ use super::{build::BuildCommand, BlueBuildCommand}; -#[derive(Clone, Debug, TypedBuilder, Args)] +#[derive(Clone, Debug, Builder, Args)] pub struct GenerateIsoCommand { #[command(subcommand)] command: GenIsoSubcommand, /// The directory to save the resulting ISO file. #[arg(short, long)] + #[builder(into)] output_dir: Option, /// The variant of the installer to use. @@ -52,6 +53,7 @@ pub struct GenerateIsoCommand { long, default_value = "https://github.com/ublue-os/bazzite/raw/main/secure_boot.der" )] + #[builder(into)] secure_boot_url: String, /// The enrollment password for the secure boot @@ -61,10 +63,12 @@ pub struct GenerateIsoCommand { /// It's recommended to change this if your base /// image is not from UBlue. #[arg(long, default_value = "universalblue")] + #[builder(into)] enrollment_password: String, /// The name of your ISO image file. #[arg(long)] + #[builder(into)] iso_name: Option, #[clap(flatten)] @@ -226,7 +230,7 @@ impl GenerateIsoCommand { .image("ghcr.io/jasonn3/build-container-installer") .privileged(true) .remove(true) - .args(&args) + .args(args.to_cow_vec()) .volumes(vols) .build(); diff --git a/src/commands/local.rs b/src/commands/local.rs index 46174043..62bb659a 100644 --- a/src/commands/local.rs +++ b/src/commands/local.rs @@ -9,17 +9,17 @@ use blue_build_utils::{ cmd, constants::{ARCHIVE_SUFFIX, LOCAL_BUILD}, }; +use bon::Builder; use clap::Args; use log::{debug, info, trace}; use miette::{bail, IntoDiagnostic, Result}; -use typed_builder::TypedBuilder; use users::{Users, UsersCache}; use crate::commands::build::BuildCommand; use super::BlueBuildCommand; -#[derive(Default, Clone, Debug, TypedBuilder, Args)] +#[derive(Default, Clone, Debug, Builder, Args)] pub struct LocalCommonArgs { /// The recipe file to build an image. #[arg()] @@ -45,7 +45,7 @@ pub struct LocalCommonArgs { drivers: DriverArgs, } -#[derive(Default, Clone, Debug, TypedBuilder, Args)] +#[derive(Default, Clone, Debug, Builder, Args)] pub struct UpgradeCommand { #[clap(flatten)] common: LocalCommonArgs, @@ -103,7 +103,7 @@ impl BlueBuildCommand for UpgradeCommand { } } -#[derive(Default, Clone, Debug, TypedBuilder, Args)] +#[derive(Default, Clone, Debug, Builder, Args)] pub struct RebaseCommand { #[clap(flatten)] common: LocalCommonArgs, diff --git a/src/commands/login.rs b/src/commands/login.rs index 2f163df0..e034b21a 100644 --- a/src/commands/login.rs +++ b/src/commands/login.rs @@ -5,11 +5,10 @@ use blue_build_utils::credentials::{Credentials, CredentialsArgs}; use clap::Args; use miette::{bail, IntoDiagnostic, Result}; use requestty::questions; -use typed_builder::TypedBuilder; use super::BlueBuildCommand; -#[derive(Debug, Clone, Args, TypedBuilder)] +#[derive(Debug, Clone, Args)] pub struct LoginCommand { /// The server to login to. server: String, @@ -31,7 +30,6 @@ pub struct LoginCommand { username: Option, #[clap(flatten)] - #[builder(default)] drivers: DriverArgs, } diff --git a/src/commands/switch.rs b/src/commands/switch.rs index 56b6f6be..0808ca90 100644 --- a/src/commands/switch.rs +++ b/src/commands/switch.rs @@ -12,19 +12,19 @@ use blue_build_utils::{ cmd, constants::{ARCHIVE_SUFFIX, LOCAL_BUILD, OCI_ARCHIVE, OSTREE_UNVERIFIED_IMAGE}, }; +use bon::Builder; use clap::Args; use colored::Colorize; use indicatif::ProgressBar; use log::{debug, trace, warn}; use miette::{bail, IntoDiagnostic, Result}; use tempdir::TempDir; -use typed_builder::TypedBuilder; use crate::{commands::build::BuildCommand, rpm_ostree_status::RpmOstreeStatus}; use super::BlueBuildCommand; -#[derive(Default, Clone, Debug, TypedBuilder, Args)] +#[derive(Default, Clone, Debug, Builder, Args)] pub struct SwitchCommand { /// The recipe file to build an image. #[arg()] diff --git a/template/Cargo.toml b/template/Cargo.toml index 9cd32f75..a7af1a4a 100644 --- a/template/Cargo.toml +++ b/template/Cargo.toml @@ -15,7 +15,7 @@ blue-build-utils = { version = "=0.8.17", path = "../utils" } log.workspace = true colored.workspace = true -typed-builder.workspace = true +bon.workspace = true uuid.workspace = true [lints] diff --git a/template/src/lib.rs b/template/src/lib.rs index 6f506e19..1ffc87e6 100644 --- a/template/src/lib.rs +++ b/template/src/lib.rs @@ -4,92 +4,57 @@ use blue_build_recipe::Recipe; use blue_build_utils::constants::{ CONFIG_PATH, CONTAINERFILES_PATH, CONTAINER_FILE, COSIGN_PUB_PATH, FILES_PATH, }; +use bon::Builder; use colored::control::ShouldColorize; use log::{debug, error, trace, warn}; -use typed_builder::TypedBuilder; use uuid::Uuid; pub use rinja::Template; -#[derive(Debug, Clone, Template, TypedBuilder)] +#[derive(Debug, Clone, Template, Builder)] #[template(path = "Containerfile.j2", escape = "none", whitespace = "minimize")] +#[builder(on(Cow<'_, str>, into))] pub struct ContainerFileTemplate<'a> { + #[builder(into)] recipe: &'a Recipe<'a>, - #[builder(setter(into))] - recipe_path: &'a Path, + #[builder(into)] + recipe_path: Cow<'a, Path>, - #[builder(setter(into))] + #[builder(into)] build_id: Uuid, - os_version: u64, - - #[builder(setter(into))] registry: Cow<'a, str>, - - #[builder(setter(into))] exports_tag: Cow<'a, str>, - - #[builder(setter(into))] repo: Cow<'a, str>, } -#[derive(Debug, Clone, Template, TypedBuilder)] +#[derive(Debug, Clone, Template, Builder)] #[template(path = "github_issue.j2", escape = "md")] +#[builder(on(Cow<'_, str>, into))] pub struct GithubIssueTemplate<'a> { - #[builder(setter(into))] bb_version: Cow<'a, str>, - - #[builder(setter(into))] build_rust_channel: Cow<'a, str>, - - #[builder(setter(into))] build_time: Cow<'a, str>, - - #[builder(setter(into))] git_commit_hash: Cow<'a, str>, - - #[builder(setter(into))] os_name: Cow<'a, str>, - - #[builder(setter(into))] os_version: Cow<'a, str>, - - #[builder(setter(into))] pkg_branch_tag: Cow<'a, str>, - - #[builder(setter(into))] recipe: Cow<'a, str>, - - #[builder(setter(into))] rust_channel: Cow<'a, str>, - - #[builder(setter(into))] rust_version: Cow<'a, str>, - - #[builder(setter(into))] shell_name: Cow<'a, str>, - - #[builder(setter(into))] shell_version: Cow<'a, str>, - - #[builder(setter(into))] terminal_name: Cow<'a, str>, - - #[builder(setter(into))] terminal_version: Cow<'a, str>, } -#[derive(Debug, Clone, Template, TypedBuilder)] +#[derive(Debug, Clone, Template, Builder)] #[template(path = "init/README.j2", escape = "md")] +#[builder(on(Cow<'_, str>, into))] pub struct InitReadmeTemplate<'a> { - #[builder(setter(into))] repo_name: Cow<'a, str>, - - #[builder(setter(into))] registry: Cow<'a, str>, - - #[builder(setter(into))] image_name: Cow<'a, str>, } diff --git a/utils/Cargo.toml b/utils/Cargo.toml index 7960e31f..7a638b2d 100644 --- a/utils/Cargo.toml +++ b/utils/Cargo.toml @@ -26,7 +26,7 @@ miette.workspace = true serde.workspace = true serde_json.workspace = true serde_yaml.workspace = true -typed-builder.workspace = true +bon.workspace = true [build-dependencies] syntect = "5" diff --git a/utils/src/credentials.rs b/utils/src/credentials.rs index b5ba9ed8..60ac5a2f 100644 --- a/utils/src/credentials.rs +++ b/utils/src/credentials.rs @@ -3,10 +3,10 @@ use std::{ sync::{LazyLock, Mutex}, }; +use bon::Builder; use clap::Args; use docker_credential::DockerCredential; use log::trace; -use typed_builder::TypedBuilder; use crate::{ constants::{ @@ -94,7 +94,7 @@ static ENV_CREDENTIALS: LazyLock> = LazyLock::new(|| { }); /// The credentials for logging into image registries. -#[derive(Debug, Default, Clone, TypedBuilder)] +#[derive(Debug, Default, Clone, Builder)] pub struct Credentials { pub registry: String, pub username: String, @@ -132,22 +132,20 @@ impl Credentials { } } -#[derive(Debug, Default, Clone, TypedBuilder, Args)] +#[derive(Debug, Default, Clone, Builder, Args)] +#[builder(on(String, into))] pub struct CredentialsArgs { /// The registry's domain name. #[arg(long, env = BB_REGISTRY)] - #[builder(default, setter(into, strip_option))] pub registry: Option, /// The username to login to the /// container registry. #[arg(short = 'U', long, env = BB_USERNAME, hide_env_values = true)] - #[builder(default, setter(into, strip_option))] pub username: Option, /// The password to login to the /// container registry. #[arg(short = 'P', long, env = BB_PASSWORD, hide_env_values = true)] - #[builder(default, setter(into, strip_option))] pub password: Option, } diff --git a/utils/src/lib.rs b/utils/src/lib.rs index 332b9506..8e52701c 100644 --- a/utils/src/lib.rs +++ b/utils/src/lib.rs @@ -5,6 +5,7 @@ mod macros; pub mod syntax_highlighting; #[cfg(feature = "test")] pub mod test_utils; +pub mod traits; use std::{ os::unix::ffi::OsStrExt, diff --git a/utils/src/macros.rs b/utils/src/macros.rs index 7f3e16f7..a9a4a716 100644 --- a/utils/src/macros.rs +++ b/utils/src/macros.rs @@ -27,23 +27,23 @@ macro_rules! cmd { (@ $command:ident $(,)?) => { }; (@ $command:ident, for $for_expr:expr $(, $($tail:tt)*)?) => { { - for arg in $for_expr.iter() { + for arg in $for_expr { $crate::cmd!($command, arg); } $($crate::cmd!(@ $command, $($tail)*);)* } }; - (@ $command:ident, for $iter:ident in $for_expr:expr => [ $($arg:expr),* $(,)? ] $(, $($tail:tt)*)?) => { + (@ $command:ident, for $iter:pat in $for_expr:expr => [ $($arg:expr),* $(,)? ] $(, $($tail:tt)*)?) => { { - for $iter in $for_expr.iter() { + for $iter in $for_expr { $($crate::cmd!(@ $command, $arg);)* } $($crate::cmd!(@ $command, $($tail)*);)* } }; - (@ $command:ident, for $iter:ident in $for_expr:expr => $arg:expr $(, $($tail:tt)*)?) => { + (@ $command:ident, for $iter:pat in $for_expr:expr => $arg:expr $(, $($tail:tt)*)?) => { { - for $iter in $for_expr.iter() { + for $iter in $for_expr { $crate::cmd!(@ $command, $arg); } $($crate::cmd!(@ $command, $($tail)*);)* diff --git a/utils/src/traits.rs b/utils/src/traits.rs new file mode 100644 index 00000000..fafa0b87 --- /dev/null +++ b/utils/src/traits.rs @@ -0,0 +1,62 @@ +use std::{ + borrow::Cow, + ffi::{OsStr, OsString}, + path::{Path, PathBuf}, +}; + +trait PrivateTrait {} + +macro_rules! impl_private_trait { + ($lt:lifetime, $type:ty) => { + impl<$lt, T> PrivateTrait<$type> for T where T: AsRef<[&$lt $type]> {} + }; + ($type:ty) => { + impl PrivateTrait<$type> for T where T: AsRef<[$type]> {} + }; +} + +impl_private_trait!(String); +impl_private_trait!('a, str); +impl_private_trait!(PathBuf); +impl_private_trait!('a, Path); +impl_private_trait!(OsString); +impl_private_trait!('a, OsStr); + +#[allow(private_bounds)] +pub trait CowCollecter<'a, IN, OUT>: PrivateTrait +where + IN: ToOwned + ?Sized, + OUT: ToOwned + ?Sized, +{ + fn to_cow_vec(&'a self) -> Vec>; +} + +macro_rules! impl_cow_collector { + ($type:ty) => { + impl<'a, T> CowCollecter<'a, $type, $type> for T + where + T: AsRef<[&'a $type]>, + { + fn to_cow_vec(&'a self) -> Vec> { + self.as_ref().iter().map(|v| Cow::Borrowed(*v)).collect() + } + } + }; + ($in:ty, $out:ty) => { + impl<'a, T> CowCollecter<'a, $in, $out> for T + where + T: AsRef<[$in]>, + { + fn to_cow_vec(&'a self) -> Vec> { + self.as_ref().iter().map(Cow::from).collect() + } + } + }; +} + +impl_cow_collector!(String, str); +impl_cow_collector!(str); +impl_cow_collector!(PathBuf, Path); +impl_cow_collector!(Path); +impl_cow_collector!(OsString, OsStr); +impl_cow_collector!(OsStr);