diff --git a/nix/image/haze.nix b/nix/image/haze.nix index ffdeb73..7c740af 100644 --- a/nix/image/haze.nix +++ b/nix/image/haze.nix @@ -38,6 +38,8 @@ inherit (builtins) toString; inherit (lib) readFile getExe concatStringsSep splitString take; + version = (fromTOML (readFile ../../Cargo.toml)).package.version; + phpVersion = concatStringsSep "." (take 2 (splitString "." php.version)); phpEnv = callPackage ./php.nix {inherit debug php;}; @@ -187,7 +189,14 @@ in ''; config = { Cmd = [(getExe bootstrap)]; - Env = ["EDITOR=hx" "WEBROOT=/var/www/html"]; + Env = [ + "EDITOR=hx" + "WEBROOT=/var/www/html" + "HAZE_IMAGE_VERSION=${toString version}" + ]; WorkingDir = "/var/www/html"; + Labels = { + "nl.icewind.haze.version" = toString version; + }; }; } diff --git a/src/image.rs b/src/image.rs index 94da352..e24abfd 100644 --- a/src/image.rs +++ b/src/image.rs @@ -5,11 +5,48 @@ use futures_util::StreamExt; use indicatif::{MultiProgress, ProgressBar, ProgressStyle}; use miette::{IntoDiagnostic, Result, WrapErr}; use std::collections::HashMap; +use std::fmt::{Display, Formatter}; +use std::str::FromStr; + +#[derive(Debug, Copy, Clone, PartialOrd, PartialEq)] +pub struct ImageVersion { + pub major: u8, + pub minor: u8, + pub patch: u8, +} + +impl FromStr for ImageVersion { + type Err = (); + + fn from_str(s: &str) -> std::result::Result { + let mut parts = s.split('.'); + let major = parts.next().ok_or(())?.parse().map_err(|_| ())?; + let minor = parts.next().ok_or(())?.parse().map_err(|_| ())?; + let patch = parts.next().ok_or(())?.parse().map_err(|_| ())?; + Ok(ImageVersion { + major, + minor, + patch, + }) + } +} + +impl Display for ImageVersion { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}.{}.{}", self.major, self.minor, self.patch) + } +} pub async fn image_exists(docker: &Docker, image: &str) -> bool { docker.inspect_image(image).await.is_ok() } +pub async fn image_version(docker: &Docker, image: &str) -> Option { + let labels = docker.inspect_image(image).await.ok()?.config?.labels?; + let label = labels.get("nl.icewind.haze.version")?; + ImageVersion::from_str(label).ok() +} + pub async fn update_image(docker: &Docker, image: &str) -> Result<()> { if image_exists(docker, image).await { force_pull_image(docker, image).await?; diff --git a/src/php.rs b/src/php.rs index 1451108..ab01f79 100644 --- a/src/php.rs +++ b/src/php.rs @@ -1,6 +1,7 @@ +use owo_colors::OwoColorize; use crate::config::ProxyConfig; use crate::database::Database; -use crate::image::pull_image; +use crate::image::{image_version, pull_image, ImageVersion}; use crate::network::ensure_network_exists; use crate::service::Service; use crate::service::ServiceTrait; @@ -123,6 +124,17 @@ impl PhpVersion { ) -> Result { ensure_network_exists(docker, "haze").await?; pull_image(docker, self.image()).await?; + + let image_version = image_version(&docker, self.image()).await; + let haze_version = ImageVersion::from_str(env!("CARGO_PKG_VERSION")); + if let (Some(image_version), Ok(haze_version)) = (image_version, haze_version) { + if image_version < haze_version { + eprintln!("{}: image version is out of date, run {} to update.", "Warning".red(), "haze update".blue()); + eprintln!(" Haze version: {}", haze_version.bright_yellow()); + eprintln!(" Image version: {}", image_version.bright_yellow()); + } + } + let options = Some(CreateContainerOptions { name: Some(id.to_string()), ..CreateContainerOptions::default()