chore: Add version checks for upstream tools (#121)
This commit is contained in:
parent
0e3d6eba9e
commit
5fc4096f0f
9 changed files with 238 additions and 84 deletions
8
Cargo.lock
generated
8
Cargo.lock
generated
|
|
@ -300,6 +300,7 @@ dependencies = [
|
|||
"podman-api",
|
||||
"requestty",
|
||||
"rusty-hook",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml 0.9.32",
|
||||
|
|
@ -2936,9 +2937,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.21"
|
||||
version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0"
|
||||
checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
|
|
|
|||
|
|
@ -57,9 +57,11 @@ clap_complete_nushell = "4"
|
|||
colorized = "1"
|
||||
env_logger = "0.11"
|
||||
fuzzy-matcher = "0.3"
|
||||
once_cell = "1.19.0"
|
||||
open = "5"
|
||||
os_info = "3.7" # update os module config and tests when upgrading os_info
|
||||
requestty = { version = "0.5", features = ["macros", "termion"] }
|
||||
semver = { version = "1.0.22", features = ["serde"] }
|
||||
shadow-rs = { version = "0.26" }
|
||||
urlencoding = "2.1.3"
|
||||
users = "0.11.0"
|
||||
|
|
@ -82,7 +84,6 @@ serde_json.workspace = true
|
|||
serde_yaml.workspace = true
|
||||
typed-builder.workspace = true
|
||||
uuid.workspace = true
|
||||
once_cell = "1.19.0"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
|
|
|||
|
|
@ -8,6 +8,14 @@
|
|||
|
||||
BlueBuild's command line program that builds Containerfiles and custom images based on your recipe.yml.
|
||||
|
||||
## Requirements
|
||||
|
||||
The `bluebuild` tool takes advantage of newer build features. Specifically bind, cache, and tmpfs mounts on the `RUN` instructions. We support using the following tools and their versions:
|
||||
|
||||
- Docker - v23 and above
|
||||
- Podman - v4 and above
|
||||
- Buildah - v1.24 and above
|
||||
|
||||
## Installation
|
||||
|
||||
### Distrobox
|
||||
|
|
|
|||
|
|
@ -1,3 +1,16 @@
|
|||
#!/bin/sh
|
||||
|
||||
echo 'Running buildah'
|
||||
print_version_json() {
|
||||
local version="1.24.0"
|
||||
printf '{"version": "%s"}\n' "$version"
|
||||
}
|
||||
|
||||
main() {
|
||||
if [[ "$1" == "version" && "$2" == "--json" ]]; then
|
||||
print_version_json
|
||||
else
|
||||
echo 'Running buildah'
|
||||
fi
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
|
|
|||
|
|
@ -1,3 +1,16 @@
|
|||
#!/bin/sh
|
||||
|
||||
echo 'Running podman'
|
||||
print_version_json() {
|
||||
local version="4.0.0"
|
||||
printf '{"Client":{"Version": "%s"}}\n' "$version"
|
||||
}
|
||||
|
||||
main() {
|
||||
if [[ "$1" == "version" && "$2" == "-f" && "$3" == "json" ]]; then
|
||||
print_version_json
|
||||
else
|
||||
echo 'Running podman'
|
||||
fi
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
|
|
|||
179
src/drivers.rs
179
src/drivers.rs
|
|
@ -20,6 +20,7 @@ use blue_build_utils::constants::{
|
|||
};
|
||||
use log::{debug, error, info, trace};
|
||||
use once_cell::sync::Lazy;
|
||||
use semver::{Version, VersionReq};
|
||||
use typed_builder::TypedBuilder;
|
||||
use uuid::Uuid;
|
||||
|
||||
|
|
@ -92,6 +93,26 @@ static BUILD_ID: Lazy<Uuid> = Lazy::new(Uuid::new_v4);
|
|||
/// The cached os versions
|
||||
static OS_VERSION: Lazy<Mutex<HashMap<String, String>>> = Lazy::new(|| Mutex::new(HashMap::new()));
|
||||
|
||||
/// Trait for retrieving version of a driver.
|
||||
pub trait DriverVersion {
|
||||
/// The version req string slice that follows
|
||||
/// the semver standard <https://semver.org/>.
|
||||
const VERSION_REQ: &'static str;
|
||||
|
||||
/// Returns the version of the driver.
|
||||
///
|
||||
/// # Errors
|
||||
/// Will error if it can't retrieve the version.
|
||||
fn version() -> Result<Version>;
|
||||
|
||||
#[must_use]
|
||||
fn is_supported_version() -> bool {
|
||||
Self::version().is_ok_and(|version| {
|
||||
VersionReq::parse(Self::VERSION_REQ).is_ok_and(|req| req.matches(&version))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Allows agnostic building, tagging
|
||||
/// pushing, and login.
|
||||
pub trait BuildDriver: Sync + Send {
|
||||
|
|
@ -221,86 +242,92 @@ impl Driver<'_> {
|
|||
fn determine_inspect_driver() -> Result<Arc<dyn InspectDriver>> {
|
||||
trace!("Strategy::determine_inspect_strategy()");
|
||||
|
||||
Ok(
|
||||
match (
|
||||
blue_build_utils::check_command_exists("skopeo"),
|
||||
blue_build_utils::check_command_exists("docker"),
|
||||
blue_build_utils::check_command_exists("podman"),
|
||||
) {
|
||||
(Ok(_skopeo), _, _) => Arc::new(SkopeoDriver),
|
||||
(_, Ok(_docker), _) => Arc::new(DockerDriver),
|
||||
(_, _, Ok(_podman)) => Arc::new(PodmanDriver),
|
||||
_ => bail!("Could not determine inspection strategy. You need either skopeo, docker, or podman"),
|
||||
}
|
||||
)
|
||||
let driver: Arc<dyn InspectDriver> = match (
|
||||
blue_build_utils::check_command_exists("skopeo"),
|
||||
blue_build_utils::check_command_exists("docker"),
|
||||
blue_build_utils::check_command_exists("podman"),
|
||||
) {
|
||||
(Ok(_skopeo), _, _) => Arc::new(SkopeoDriver),
|
||||
(_, Ok(_docker), _) => Arc::new(DockerDriver),
|
||||
(_, _, Ok(_podman)) => Arc::new(PodmanDriver),
|
||||
_ => bail!("Could not determine inspection strategy. You need either skopeo, docker, or podman"),
|
||||
};
|
||||
|
||||
Ok(driver)
|
||||
}
|
||||
|
||||
fn determine_build_driver() -> Result<Arc<dyn BuildDriver>> {
|
||||
trace!("Strategy::determine_build_strategy()");
|
||||
|
||||
Ok(
|
||||
match (
|
||||
env::var(XDG_RUNTIME_DIR),
|
||||
PathBuf::from(RUN_PODMAN_SOCK),
|
||||
PathBuf::from(VAR_RUN_PODMAN_PODMAN_SOCK),
|
||||
PathBuf::from(VAR_RUN_PODMAN_SOCK),
|
||||
blue_build_utils::check_command_exists("docker"),
|
||||
blue_build_utils::check_command_exists("podman"),
|
||||
blue_build_utils::check_command_exists("buildah"),
|
||||
) {
|
||||
#[cfg(feature = "builtin-podman")]
|
||||
(Ok(xdg_runtime), _, _, _, _, _, _)
|
||||
if PathBuf::from(format!("{xdg_runtime}/podman/podman.sock")).exists() =>
|
||||
{
|
||||
Arc::new(
|
||||
PodmanApiDriver::builder()
|
||||
.client(
|
||||
Podman::unix(PathBuf::from(format!(
|
||||
"{xdg_runtime}/podman/podman.sock"
|
||||
)))
|
||||
.into(),
|
||||
)
|
||||
.rt(Runtime::new()?)
|
||||
.build(),
|
||||
)
|
||||
}
|
||||
#[cfg(feature = "builtin-podman")]
|
||||
(_, run_podman_podman_sock, _, _, _, _, _) if run_podman_podman_sock.exists() => {
|
||||
Arc::new(
|
||||
PodmanApiDriver::builder()
|
||||
.client(Podman::unix(run_podman_podman_sock).into())
|
||||
.rt(Runtime::new()?)
|
||||
.build(),
|
||||
)
|
||||
}
|
||||
#[cfg(feature = "builtin-podman")]
|
||||
(_, _, var_run_podman_podman_sock, _, _, _, _)
|
||||
if var_run_podman_podman_sock.exists() =>
|
||||
{
|
||||
Arc::new(
|
||||
PodmanApiDriver::builder()
|
||||
.client(Podman::unix(var_run_podman_podman_sock).into())
|
||||
.rt(Runtime::new()?)
|
||||
.build(),
|
||||
)
|
||||
}
|
||||
#[cfg(feature = "builtin-podman")]
|
||||
(_, _, _, var_run_podman_sock, _, _, _) if var_run_podman_sock.exists() => {
|
||||
Arc::new(
|
||||
PodmanApiDriver::builder()
|
||||
.client(Podman::unix(var_run_podman_sock).into())
|
||||
.rt(Runtime::new()?)
|
||||
.build(),
|
||||
)
|
||||
}
|
||||
// (_, _, _, _, Ok(_docker), _, _) if !oci_required => {
|
||||
(_, _, _, _, Ok(_docker), _, _) => Arc::new(DockerDriver),
|
||||
(_, _, _, _, _, Ok(_podman), _) => Arc::new(PodmanDriver),
|
||||
(_, _, _, _, _, _, Ok(_buildah)) => Arc::new(BuildahDriver),
|
||||
_ => bail!(
|
||||
"Could not determine strategy, need either docker, podman, or buildah to continue"
|
||||
),
|
||||
},
|
||||
)
|
||||
let driver: Arc<dyn BuildDriver> = match (
|
||||
env::var(XDG_RUNTIME_DIR),
|
||||
PathBuf::from(RUN_PODMAN_SOCK),
|
||||
PathBuf::from(VAR_RUN_PODMAN_PODMAN_SOCK),
|
||||
PathBuf::from(VAR_RUN_PODMAN_SOCK),
|
||||
blue_build_utils::check_command_exists("docker"),
|
||||
blue_build_utils::check_command_exists("podman"),
|
||||
blue_build_utils::check_command_exists("buildah"),
|
||||
) {
|
||||
#[cfg(feature = "builtin-podman")]
|
||||
(Ok(xdg_runtime), _, _, _, _, _, _)
|
||||
if PathBuf::from(format!("{xdg_runtime}/podman/podman.sock")).exists() =>
|
||||
{
|
||||
Arc::new(
|
||||
PodmanApiDriver::builder()
|
||||
.client(
|
||||
Podman::unix(PathBuf::from(format!(
|
||||
"{xdg_runtime}/podman/podman.sock"
|
||||
)))
|
||||
.into(),
|
||||
)
|
||||
.rt(Runtime::new()?)
|
||||
.build(),
|
||||
)
|
||||
}
|
||||
#[cfg(feature = "builtin-podman")]
|
||||
(_, run_podman_podman_sock, _, _, _, _, _) if run_podman_podman_sock.exists() => {
|
||||
Arc::new(
|
||||
PodmanApiDriver::builder()
|
||||
.client(Podman::unix(run_podman_podman_sock).into())
|
||||
.rt(Runtime::new()?)
|
||||
.build(),
|
||||
)
|
||||
}
|
||||
#[cfg(feature = "builtin-podman")]
|
||||
(_, _, var_run_podman_podman_sock, _, _, _, _)
|
||||
if var_run_podman_podman_sock.exists() =>
|
||||
{
|
||||
Arc::new(
|
||||
PodmanApiDriver::builder()
|
||||
.client(Podman::unix(var_run_podman_podman_sock).into())
|
||||
.rt(Runtime::new()?)
|
||||
.build(),
|
||||
)
|
||||
}
|
||||
#[cfg(feature = "builtin-podman")]
|
||||
(_, _, _, var_run_podman_sock, _, _, _) if var_run_podman_sock.exists() => Arc::new(
|
||||
PodmanApiDriver::builder()
|
||||
.client(Podman::unix(var_run_podman_sock).into())
|
||||
.rt(Runtime::new()?)
|
||||
.build(),
|
||||
),
|
||||
(_, _, _, _, Ok(_docker), _, _) if DockerDriver::is_supported_version() => {
|
||||
Arc::new(DockerDriver)
|
||||
}
|
||||
(_, _, _, _, _, Ok(_podman), _) if PodmanDriver::is_supported_version() => {
|
||||
Arc::new(PodmanDriver)
|
||||
}
|
||||
(_, _, _, _, _, _, Ok(_buildah)) if BuildahDriver::is_supported_version() => {
|
||||
Arc::new(BuildahDriver)
|
||||
}
|
||||
_ => bail!(
|
||||
"Could not determine strategy, need either docker version {}, podman version {}, or buildah version {} to continue",
|
||||
DockerDriver::VERSION_REQ,
|
||||
PodmanDriver::VERSION_REQ,
|
||||
BuildahDriver::VERSION_REQ,
|
||||
),
|
||||
};
|
||||
|
||||
Ok(driver)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,14 +2,38 @@ use std::process::Command;
|
|||
|
||||
use anyhow::{bail, Result};
|
||||
use log::{info, trace};
|
||||
use semver::Version;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::credentials;
|
||||
|
||||
use super::BuildDriver;
|
||||
use super::{BuildDriver, DriverVersion};
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct BuildahVersionJson {
|
||||
pub version: Version,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BuildahDriver;
|
||||
|
||||
impl DriverVersion for BuildahDriver {
|
||||
// RUN mounts for bind, cache, and tmpfs first supported in 1.24.0
|
||||
// https://buildah.io/releases/#changes-for-v1240
|
||||
const VERSION_REQ: &'static str = ">=1.24";
|
||||
|
||||
fn version() -> Result<Version> {
|
||||
let output = Command::new("buildah")
|
||||
.arg("version")
|
||||
.arg("--json")
|
||||
.output()?;
|
||||
|
||||
let version_json: BuildahVersionJson = serde_json::from_slice(&output.stdout)?;
|
||||
|
||||
Ok(version_json.version)
|
||||
}
|
||||
}
|
||||
|
||||
impl BuildDriver for BuildahDriver {
|
||||
fn build(&self, image: &str) -> Result<()> {
|
||||
trace!("buildah build -t {image}");
|
||||
|
|
|
|||
|
|
@ -6,14 +6,46 @@ use std::{
|
|||
use anyhow::{bail, Result};
|
||||
use blue_build_utils::constants::{BB_BUILDKIT_CACHE_GHA, SKOPEO_IMAGE};
|
||||
use log::{info, trace};
|
||||
use semver::Version;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::image_inspection::ImageInspection;
|
||||
|
||||
use super::{credentials, BuildDriver, InspectDriver};
|
||||
use super::{credentials, BuildDriver, DriverVersion, InspectDriver};
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct DockerVerisonJsonClient {
|
||||
#[serde(alias = "Version")]
|
||||
pub version: Version,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct DockerVersionJson {
|
||||
#[serde(alias = "Client")]
|
||||
pub client: DockerVerisonJsonClient,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DockerDriver;
|
||||
|
||||
impl DriverVersion for DockerDriver {
|
||||
// First docker verison to use buildkit
|
||||
// https://docs.docker.com/build/buildkit/
|
||||
const VERSION_REQ: &'static str = ">=23";
|
||||
|
||||
fn version() -> Result<Version> {
|
||||
let output = Command::new("docker")
|
||||
.arg("version")
|
||||
.arg("-f")
|
||||
.arg("json")
|
||||
.output()?;
|
||||
|
||||
let version_json: DockerVersionJson = serde_json::from_slice(&output.stdout)?;
|
||||
|
||||
Ok(version_json.client.version)
|
||||
}
|
||||
}
|
||||
|
||||
impl BuildDriver for DockerDriver {
|
||||
fn build(&self, image: &str) -> Result<()> {
|
||||
trace!("docker");
|
||||
|
|
|
|||
|
|
@ -3,14 +3,46 @@ use std::process::{Command, Stdio};
|
|||
use anyhow::{bail, Result};
|
||||
use blue_build_utils::constants::SKOPEO_IMAGE;
|
||||
use log::{debug, info, trace};
|
||||
use semver::Version;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::image_inspection::ImageInspection;
|
||||
|
||||
use super::{credentials, BuildDriver, InspectDriver};
|
||||
use super::{credentials, BuildDriver, DriverVersion, InspectDriver};
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct PodmanVersionJsonClient {
|
||||
#[serde(alias = "Version")]
|
||||
pub version: Version,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct PodmanVersionJson {
|
||||
#[serde(alias = "Client")]
|
||||
pub client: PodmanVersionJsonClient,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PodmanDriver;
|
||||
|
||||
impl DriverVersion for PodmanDriver {
|
||||
// First podman version to use buildah v1.24
|
||||
// https://github.com/containers/podman/blob/main/RELEASE_NOTES.md#400
|
||||
const VERSION_REQ: &'static str = ">=4";
|
||||
|
||||
fn version() -> Result<Version> {
|
||||
let output = Command::new("podman")
|
||||
.arg("version")
|
||||
.arg("-f")
|
||||
.arg("json")
|
||||
.output()?;
|
||||
|
||||
let version_json: PodmanVersionJson = serde_json::from_slice(&output.stdout)?;
|
||||
|
||||
Ok(version_json.client.version)
|
||||
}
|
||||
}
|
||||
|
||||
impl BuildDriver for PodmanDriver {
|
||||
fn build(&self, image: &str) -> Result<()> {
|
||||
trace!("podman build . -t {image}");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue