refactor: Swtich to using bon for builder pattern
This commit is contained in:
parent
aed7e275f2
commit
0c52cf6a54
36 changed files with 326 additions and 314 deletions
53
Cargo.lock
generated
53
Cargo.lock
generated
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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<Mutex<HashMap<String, u64>>> = 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<BuildDriverType>,
|
||||
|
||||
/// Select which driver to use to inspect
|
||||
/// images.
|
||||
#[builder(default)]
|
||||
#[arg(short = 'I', long)]
|
||||
inspect_driver: Option<InspectDriverType>,
|
||||
|
||||
/// Select which driver to use to sign
|
||||
/// images.
|
||||
#[builder(default)]
|
||||
#[arg(short = 'S', long)]
|
||||
signing_driver: Option<SigningDriverType>,
|
||||
|
||||
/// Select which driver to use to run
|
||||
/// containers.
|
||||
#[builder(default)]
|
||||
#[arg(short = 'R', long)]
|
||||
run_driver: Option<RunDriverType>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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:?}");
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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<CompressionType>,
|
||||
}
|
||||
|
||||
/// 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<Cow<'a, str>>,
|
||||
#[builder(into)]
|
||||
pub image: Option<Cow<'scope, str>>,
|
||||
|
||||
/// 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<Cow<'a, str>>,
|
||||
#[builder(into)]
|
||||
pub archive_path: Option<Cow<'scope, str>>,
|
||||
|
||||
/// 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<Cow<'scope, str>>,
|
||||
|
||||
/// Enable pushing the image.
|
||||
#[builder(default)]
|
||||
|
|
|
|||
|
|
@ -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<Vec<Cow<'scope, str>>>,
|
||||
}
|
||||
|
||||
#[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<Cow<'scope, str>>,
|
||||
|
||||
#[builder(default, setter(into))]
|
||||
#[builder(into)]
|
||||
pub registry_namespace: Option<Cow<'scope, str>>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Cow<'a, str>>,
|
||||
#[builder(into)]
|
||||
pub tag: Option<Cow<'scope, str>>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Cow<'scope, str>>,
|
||||
|
||||
#[builder(default, setter(into))]
|
||||
#[builder(default, into)]
|
||||
pub env_vars: Vec<RunOptsEnv<'scope>>,
|
||||
|
||||
#[builder(default, setter(into))]
|
||||
#[builder(default, into)]
|
||||
pub volumes: Vec<RunOptsVolume<'scope>>,
|
||||
|
||||
#[builder(default, setter(strip_option))]
|
||||
pub uid: Option<u32>,
|
||||
|
||||
#[builder(default, setter(strip_option))]
|
||||
pub gid: Option<u32>,
|
||||
|
||||
#[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)
|
||||
|
|
|
|||
|
|
@ -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<T>
|
||||
where
|
||||
T: Zeroize,
|
||||
|
|
@ -40,39 +52,27 @@ impl PrivateKeyContents<String> 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<Cow<'scope, Path>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, TypedBuilder)]
|
||||
#[derive(Debug, Clone, Builder)]
|
||||
pub struct CheckKeyPairOpts<'scope> {
|
||||
#[builder(setter(into, strip_option))]
|
||||
#[builder(into)]
|
||||
pub dir: Option<Cow<'scope, Path>>,
|
||||
}
|
||||
|
||||
#[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<Cow<'scope, str>>,
|
||||
|
||||
#[builder(default, setter(into, strip_option))]
|
||||
#[builder(into)]
|
||||
pub dir: Option<Cow<'scope, Path>>,
|
||||
}
|
||||
|
||||
|
|
@ -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<Cow<'scope, str>>,
|
||||
|
||||
#[builder(default, setter(into, strip_option))]
|
||||
#[builder(into)]
|
||||
pub dir: Option<Cow<'scope, Path>>,
|
||||
|
||||
/// Enable retry logic for pushing.
|
||||
|
|
|
|||
|
|
@ -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:?}");
|
||||
|
||||
|
|
|
|||
|
|
@ -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}");
|
||||
|
||||
|
|
|
|||
|
|
@ -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)>,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 = []
|
||||
|
|
|
|||
|
|
@ -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<String>),
|
||||
|
||||
#[builder(into)]
|
||||
pub stage_name: String,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Cow<'a, str>>,
|
||||
|
||||
|
|
@ -26,7 +26,7 @@ pub struct ModuleRequiredFields<'a> {
|
|||
pub no_cache: bool,
|
||||
|
||||
#[serde(flatten)]
|
||||
#[builder(default, setter(into))]
|
||||
#[builder(default, into)]
|
||||
pub config: IndexMap<String, Value>,
|
||||
}
|
||||
|
||||
|
|
@ -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<ModuleRequiredFields<'a>>,
|
||||
|
||||
#[builder(default, setter(into, strip_option))]
|
||||
#[builder(into)]
|
||||
#[serde(rename = "from-file", skip_serializing_if = "Option::is_none")]
|
||||
pub from_file: Option<Cow<'a, str>>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Module<'a>>,
|
||||
}
|
||||
|
||||
impl ModuleExt<'_> {
|
||||
|
|
|
|||
|
|
@ -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<Cow<'a, str>>,
|
||||
|
||||
/// 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<Vec<Cow<'a, str>>>,
|
||||
#[builder(into)]
|
||||
pub alt_tags: Option<Vec<String>>,
|
||||
|
||||
/// 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<String, Value>,
|
||||
}
|
||||
|
||||
|
|
@ -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<Vec<Cow<'a, str>>> {
|
||||
self.alt_tags
|
||||
.as_ref()
|
||||
.map(|tags| tags.iter().map(|tag| cowstr!(&**tag)).collect())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Cow<'a, [Cow<'a, str>]>>,
|
||||
pub shell: Option<Vec<String>>,
|
||||
|
||||
/// 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<StageRequiredFields<'a>>,
|
||||
|
||||
|
|
@ -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<Cow<'a, str>>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Stage<'a>>,
|
||||
}
|
||||
|
||||
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)
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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<String>,
|
||||
recipe_path: Option<String>,
|
||||
}
|
||||
|
||||
#[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<String>,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<Vec<PathBuf>>,
|
||||
|
||||
/// The recipe file to build an image
|
||||
#[arg()]
|
||||
#[cfg(not(feature = "multi-recipe"))]
|
||||
#[builder(default, setter(into, strip_option))]
|
||||
#[builder(into)]
|
||||
recipe: Option<PathBuf>,
|
||||
|
||||
/// 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<PathBuf>,
|
||||
|
||||
/// 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<String>,
|
||||
|
||||
/// 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(),
|
||||
)?;
|
||||
|
||||
|
|
|
|||
|
|
@ -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<PathBuf>,
|
||||
|
||||
/// File to output to instead of STDOUT
|
||||
#[arg(short, long)]
|
||||
#[builder(default, setter(into, strip_option))]
|
||||
#[builder(into)]
|
||||
output: Option<PathBuf>,
|
||||
|
||||
/// 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<String>,
|
||||
|
||||
/// 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<String>,
|
||||
|
||||
/// 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<DefaultThemes>,
|
||||
|
||||
#[clap(flatten)]
|
||||
|
|
|
|||
|
|
@ -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<PathBuf>,
|
||||
|
||||
/// 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<String>,
|
||||
|
||||
#[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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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<String>,
|
||||
|
||||
#[clap(flatten)]
|
||||
#[builder(default)]
|
||||
drivers: DriverArgs,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()]
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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<Option<Credentials>> = 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<String>,
|
||||
|
||||
/// 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<String>,
|
||||
|
||||
/// 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<String>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)*);)*
|
||||
|
|
|
|||
62
utils/src/traits.rs
Normal file
62
utils/src/traits.rs
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
use std::{
|
||||
borrow::Cow,
|
||||
ffi::{OsStr, OsString},
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
trait PrivateTrait<T: ToOwned + ?Sized> {}
|
||||
|
||||
macro_rules! impl_private_trait {
|
||||
($lt:lifetime, $type:ty) => {
|
||||
impl<$lt, T> PrivateTrait<$type> for T where T: AsRef<[&$lt $type]> {}
|
||||
};
|
||||
($type:ty) => {
|
||||
impl<T> 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<IN>
|
||||
where
|
||||
IN: ToOwned + ?Sized,
|
||||
OUT: ToOwned + ?Sized,
|
||||
{
|
||||
fn to_cow_vec(&'a self) -> Vec<Cow<'a, OUT>>;
|
||||
}
|
||||
|
||||
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<Cow<'a, $type>> {
|
||||
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<Cow<'a, $out>> {
|
||||
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);
|
||||
Loading…
Add table
Add a link
Reference in a new issue