diff --git a/Cargo.lock b/Cargo.lock index 7e892af48..2bec7af8d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -96,8 +96,8 @@ dependencies = [ "git2", "glob", "oci-spec", + "regex", "rstest", - "semver", "serde", "serde_json", "snafu", @@ -1142,10 +1142,6 @@ name = "semver" version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" -dependencies = [ - "serde", - "serde_core", -] [[package]] name = "serde" diff --git a/Cargo.toml b/Cargo.toml index 8d5d2c086..16cccf679 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ git2 = "0.20.1" glob = "0.3.2" oci-spec = "0.9.0" rstest = "0.26.1" -semver = { version = "1.0.26", features = ["serde"] } +regex = "1.12.3" serde = { version = "1.0.217", features = ["derive"] } serde_json = "1.0.140" snafu = "0.9.0" diff --git a/rust/boil/Cargo.toml b/rust/boil/Cargo.toml index 1f0465e49..3f6e750c1 100644 --- a/rust/boil/Cargo.toml +++ b/rust/boil/Cargo.toml @@ -15,7 +15,7 @@ clap_complete_nushell.workspace = true git2.workspace = true glob.workspace = true oci-spec.workspace = true -semver.workspace = true +regex.workspace = true serde.workspace = true serde_json.workspace = true snafu.workspace = true diff --git a/rust/boil/src/cli/build.rs b/rust/boil/src/cli/build.rs index 539440a09..2c7854485 100644 --- a/rust/boil/src/cli/build.rs +++ b/rust/boil/src/cli/build.rs @@ -2,10 +2,11 @@ use std::{ fmt::{Debug, Display}, path::PathBuf, str::FromStr, + sync::LazyLock, }; use clap::{Args, ValueHint, value_parser}; -use semver::Version; +use regex::Regex; use snafu::{ResultExt, Snafu, ensure}; use strum::EnumDiscriminants; use url::Host; @@ -30,7 +31,7 @@ pub struct BuildArguments { default_value_t = Self::default_image_version(), help_heading = "Image Options" )] - pub image_version: Version, + pub image_version: String, /// Target platform of the image. #[arg( @@ -129,16 +130,24 @@ pub struct BuildArguments { pub rest: Vec, } +// This is derived from the general rule where the length of the tag can be up to 128 chars +// See: https://github.com/opencontainers/distribution-spec/blob/main/spec.md +// But that checking needs to be at a higher layer. +static VALID_IMAGE_TAG: LazyLock = + LazyLock::new(|| Regex::new(r"^[a-zA-Z0-9_][a-zA-Z0-9_.-]+$").expect("regex is valid")); + impl BuildArguments { - fn parse_image_version(input: &str) -> Result { - let version = Version::from_str(input).context(ParseVersionSnafu)?; - ensure!(version.build.is_empty(), ContainsBuildMetadataSnafu); + /// Ensure that the given version will be valid for use in the image tag + fn parse_image_version(version: &str) -> Result { + if !VALID_IMAGE_TAG.is_match(version) { + return ParseVersionSnafu { version }.fail(); + } - Ok(version) + Ok(version.to_owned()) } - fn default_image_version() -> Version { - "0.0.0-dev".parse().expect("must be a valid SemVer") + fn default_image_version() -> String { + "0.0.0-dev".to_owned() } fn default_registry() -> HostPort { @@ -160,11 +169,8 @@ impl BuildArguments { #[derive(Debug, Snafu)] pub enum ParseImageVersionError { - #[snafu(display("failed to parse semantic version"))] - ParseVersion { source: semver::Error }, - - #[snafu(display("semantic version must not contain build metadata"))] - ContainsBuildMetadata, + #[snafu(display("invalid image tag characters for {version:?}"))] + ParseVersion { version: String }, } #[derive(Debug, PartialEq, Snafu, EnumDiscriminants)] diff --git a/rust/boil/src/cmd/build.rs b/rust/boil/src/cmd/build.rs index adc1f970f..116ac40a1 100644 --- a/rust/boil/src/cmd/build.rs +++ b/rust/boil/src/cmd/build.rs @@ -45,12 +45,6 @@ pub enum Error { /// This is the `boil build` command handler function. pub fn run_command(args: Box, config: Config) -> Result<(), Error> { // TODO (@Techassi): Parse Dockerfile instead to build the target graph - // Validation - ensure!( - args.image_version.build.is_empty(), - InvalidImageVersionSnafu - ); - // Create bakefile let bakefile = Bakefile::from_cli_args(&args, config).context(CreateBakefileSnafu)?; let image_manifest_uris = bakefile.image_manifest_uris(); diff --git a/rust/boil/src/core/bakefile.rs b/rust/boil/src/core/bakefile.rs index fa9b74c33..417fcef0c 100644 --- a/rust/boil/src/core/bakefile.rs +++ b/rust/boil/src/core/bakefile.rs @@ -11,13 +11,11 @@ use oci_spec::image::{ ANNOTATION_AUTHORS, ANNOTATION_CREATED, ANNOTATION_DOCUMENTATION, ANNOTATION_LICENSES, ANNOTATION_REVISION, ANNOTATION_SOURCE, ANNOTATION_VENDOR, ANNOTATION_VERSION, }; -use semver::Version; use serde::Serialize; use snafu::{OptionExt, ResultExt, Snafu, ensure}; use time::format_description::well_known::Rfc3339; use crate::{ - VersionExt, cli::{self, HostPort}, config::{self, Config, Metadata}, constants::DOCKER_LABEL_BUILD_DATE, @@ -294,7 +292,7 @@ impl Bakefile { let target = BakefileTarget::common( date_time, revision, - cli_args.image_version.base_prerelease(), + cli_args.image_version.clone(), container_build_args, user_container_build_args, metadata, @@ -642,7 +640,7 @@ impl BakefileTarget { fn image_version_annotation( image_version: &str, vendor_tag_prefix: &str, - vendor_image_version: &Version, + vendor_image_version: &str, ) -> Vec { let image_index_manifest_tag = utils::format_image_index_manifest_tag( image_version, diff --git a/rust/boil/src/main.rs b/rust/boil/src/main.rs index 20f5d53c4..fa767fd93 100644 --- a/rust/boil/src/main.rs +++ b/rust/boil/src/main.rs @@ -1,5 +1,4 @@ use clap::Parser; -use semver::Version; use snafu::{ResultExt, Snafu}; use crate::{ @@ -46,39 +45,6 @@ impl IfContext for T { } } -pub trait VersionExt { - /// Returns the base of a [`Version`] as a string, eg. `1.2.3`. - fn base(&self) -> String; - - /// Returns the base and prerelease of a [`Version`] as a string, eg. `1.2.3-rc.1`. - fn base_prerelease(&self) -> String; -} - -impl VersionExt for Version { - fn base(&self) -> String { - let Self { - major, - minor, - patch, - .. - } = self; - - format!("{major}.{minor}.{patch}") - } - - fn base_prerelease(&self) -> String { - let mut base = self.base(); - - // Well, that was a big doozy, ruined the whole release... - if !self.pre.is_empty() { - base.push('-'); - base.push_str(&self.pre); - } - - base - } -} - #[derive(Debug, Snafu)] enum Error { #[snafu(display("failed to run build command"))] diff --git a/rust/boil/src/utils.rs b/rust/boil/src/utils.rs index 6a81ec954..6f214a9ca 100644 --- a/rust/boil/src/utils.rs +++ b/rust/boil/src/utils.rs @@ -1,7 +1,5 @@ use std::process::Command; -use semver::Version; - use crate::{cli::HostPort, core::platform::Architecture}; /// Formats and returns the image repository URI, eg. `oci.stackable.tech/sdp/opa`. @@ -22,7 +20,7 @@ pub fn format_image_manifest_uri(image_repository_uri: &str, image_manifest_tag: pub fn format_image_index_manifest_tag( image_version: &str, vendor_tag_prefix: &str, - vendor_image_version: &Version, + vendor_image_version: &str, ) -> String { format!("{image_version}-{vendor_tag_prefix}{vendor_image_version}") } diff --git a/shell.nix b/shell.nix index f467c334e..b8058d582 100644 --- a/shell.nix +++ b/shell.nix @@ -6,8 +6,7 @@ pkgs.mkShell { packages = with pkgs; [ - cargo - rustc + rustup nodejs zizmor ];