From 101af1776a39d2bc831eacc47d2f7efb9d04fe34 Mon Sep 17 00:00:00 2001 From: Ed Morley <501702+edmorley@users.noreply.github.com> Date: Tue, 30 Apr 2024 14:56:31 +0100 Subject: [PATCH] Improve usability of `Target` (#821) * Makes the distro name/version fields non-optional (`String` instead of `Option`), since (a) they will never be `None` in practice (see #820), and (b) it otherwise causes a lot of unnecessary friction for languages that have distro-version-specific binaries and need to use the metadata in multiple places in the buildpack. * Implements `Clone` and `Debug` on `Target`, which unblocks a number of use-cases, such as including the target as part of a buildpack Error enum variant. Fixes #820. GUS-W-15639138. --- CHANGELOG.md | 10 ++++++++++ libcnb/src/error.rs | 6 ++++++ libcnb/src/layer/tests.rs | 4 ++-- libcnb/src/runtime.rs | 6 ++++-- libcnb/src/target.rs | 19 ++++++++++++------- 5 files changed, 34 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7aa9faeb..9eb5e8de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- `libcnb`: + - `Target` now implements `Clone` and `Debug`. ([#821](https://github.com/heroku/libcnb.rs/pull/821)) + +### Changed + +- `libcnb`: + - Changed the type of `Target`'s `distro_name` and `distro_version` fields from `Option` to `String`. ([#821](https://github.com/heroku/libcnb.rs/pull/821)) + - The libcnb runtime now enforces that the `CNB_TARGET_DISTRO_NAME` and `CNB_TARGET_DISTRO_VERSION` env vars have been set by `lifecycle`. ([#821](https://github.com/heroku/libcnb.rs/pull/821)) ## [0.20.0] - 2024-04-12 diff --git a/libcnb/src/error.rs b/libcnb/src/error.rs index 7b75c414..bc0ffd37 100644 --- a/libcnb/src/error.rs +++ b/libcnb/src/error.rs @@ -29,6 +29,12 @@ pub enum Error { #[error("Couldn't determine target arch: {0}")] CannotDetermineTargetArch(std::env::VarError), + #[error("Couldn't determine target distro name: {0}. Ensure the `io.buildpacks.base.distro.*` Docker labels are set on the base image.")] + CannotDetermineTargetDistroName(std::env::VarError), + + #[error("Couldn't determine target distro version: {0}. Ensure the `io.buildpacks.base.distro.*` Docker labels are set on the base image.")] + CannotDetermineTargetDistroVersion(std::env::VarError), + #[error("Couldn't create platform from platform path: {0}")] CannotCreatePlatformFromPath(std::io::Error), diff --git a/libcnb/src/layer/tests.rs b/libcnb/src/layer/tests.rs index 854bac49..9b99d39e 100644 --- a/libcnb/src/layer/tests.rs +++ b/libcnb/src/layer/tests.rs @@ -904,8 +904,8 @@ fn build_context(temp_dir: &TempDir) -> BuildContext { os: String::from("linux"), arch: String::from("amd64"), arch_variant: None, - distro_name: Some(String::from("ubuntu")), - distro_version: Some(String::from("22.04")), + distro_name: String::from("ubuntu"), + distro_version: String::from("22.04"), }, platform: GenericPlatform::new(Env::new()), buildpack_plan: BuildpackPlan { diff --git a/libcnb/src/runtime.rs b/libcnb/src/runtime.rs index 594f65c1..be9f5a9f 100644 --- a/libcnb/src/runtime.rs +++ b/libcnb/src/runtime.rs @@ -364,8 +364,10 @@ where let os = env::var("CNB_TARGET_OS").map_err(Error::CannotDetermineTargetOs)?; let arch = env::var("CNB_TARGET_ARCH").map_err(Error::CannotDetermineTargetArch)?; let arch_variant = env::var("CNB_TARGET_ARCH_VARIANT").ok(); - let distro_name = env::var("CNB_TARGET_DISTRO_NAME").ok(); - let distro_version = env::var("CNB_TARGET_DISTRO_VERSION").ok(); + let distro_name = + env::var("CNB_TARGET_DISTRO_NAME").map_err(Error::CannotDetermineTargetDistroName)?; + let distro_version = + env::var("CNB_TARGET_DISTRO_VERSION").map_err(Error::CannotDetermineTargetDistroVersion)?; Ok(Target { os, diff --git a/libcnb/src/target.rs b/libcnb/src/target.rs index 0d102aa6..aca0c0ca 100644 --- a/libcnb/src/target.rs +++ b/libcnb/src/target.rs @@ -1,35 +1,40 @@ +#[derive(Clone, Debug)] pub struct Target { /// The name of the target operating system. /// /// The value should conform to [Go's `$GOOS`](https://golang.org/doc/install/source#environment), for example /// `linux` or `windows`. /// - /// CNB `lifecycle` sources this value from the build OCI image's [`os` property](https://github.com/opencontainers/image-spec/blob/main/config.md#properties). + /// CNB `lifecycle` sources this value from the run OCI image's [`os` property](https://github.com/opencontainers/image-spec/blob/main/config.md#properties). pub os: String, /// The name of the target CPU architecture. /// /// The value should conform to [Go's $GOARCH](https://golang.org/doc/install/source#environment), for example /// `amd64` or `arm64`. /// - /// CNB `lifecycle` sources this value from the build OCI image's [`architecture` property](https://github.com/opencontainers/image-spec/blob/main/config.md#properties). + /// CNB `lifecycle` sources this value from the run OCI image's [`architecture` property](https://github.com/opencontainers/image-spec/blob/main/config.md#properties). pub arch: String, /// The variant of the specified CPU architecture. /// /// The value should conform to [OCI image spec platform variants](https://github.com/opencontainers/image-spec/blob/main/image-index.md#platform-variants), for example /// `v7` or `v8`. /// - /// CNB `lifecycle` sources this value from the build OCI image's [`variant` property](https://github.com/opencontainers/image-spec/blob/main/config.md#properties). + /// CNB `lifecycle` sources this value from the run OCI image's [`variant` property](https://github.com/opencontainers/image-spec/blob/main/config.md#properties). pub arch_variant: Option, /// The name of the operating system distribution. Should be empty for Windows. /// /// For example: `ubuntu` or `alpine`. /// - /// CNB `lifecycle` sources this value from the build OCI image's `io.buildpacks.base.distro.name` label. - pub distro_name: Option, + /// CNB `lifecycle` sources this value from either: + /// 1. The `io.buildpacks.base.distro.name` OCI image label, if set on the run image. + /// 2. Or else, the `ID` field of the `/etc/os-release` file in the build image. + pub distro_name: String, /// The version of the operating system distribution. /// /// For example: `22.04` or `3.19`. /// - /// CNB `lifecycle` sources this value from the build OCI image's `io.buildpacks.base.distro.version` label. - pub distro_version: Option, + /// CNB `lifecycle` sources this value from either: + /// 1. The `io.buildpacks.base.distro.version` OCI image label, if set on the run image. + /// 2. Or else, the `VERSION_ID` field of the `/etc/os-release` file in the build image. + pub distro_version: String, }