diff --git a/CHANGELOG.md b/CHANGELOG.md index cdddffcd..465101ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] - ReleaseDate +- add file-level `laze_required_version` + ## [0.1.17] - 2023-10-06 ### Fixed diff --git a/Cargo.lock b/Cargo.lock index 583b366a..aab87d86 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -479,6 +479,7 @@ dependencies = [ "pathdiff", "rayon", "rust-embed", + "semver", "serde", "serde_derive", "serde_yaml", @@ -691,6 +692,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "semver" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" +dependencies = [ + "serde", +] + [[package]] name = "serde" version = "1.0.193" diff --git a/Cargo.toml b/Cargo.toml index 99bf6d97..0f3ff0e7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,6 +41,7 @@ clap_complete = "4.4.4" clap_mangen = "0.2.15" camino = { version = "1.1.6", features = ["serde1"] } evalexpr = "11.3.0" +semver = { version = "1.0.20", features = ["serde"] } [profile.release] lto = "fat" diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index 79cf6030..0df4b1e1 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -18,6 +18,7 @@ # Reference - [laze file format](./reference/laze_yaml.md) + - [laze_required_version](./reference/laze_required_version.md) - [apps](./reference/apps.md) - [builders](./reference/builders.md) - [contexts](./reference/contexts.md) diff --git a/book/src/reference/laze_required_version.md b/book/src/reference/laze_required_version.md new file mode 100644 index 00000000..a80f1fe0 --- /dev/null +++ b/book/src/reference/laze_required_version.md @@ -0,0 +1,10 @@ +# laze_required_version + +Expects a semver version string (`a.b.c`). Laze will refuse to read the file if +its own version is smaller. + +Example: + +```yaml +laze_required_version: 1.0.0 +``` diff --git a/src/data.rs b/src/data.rs index 00999e49..ca08a24f 100644 --- a/src/data.rs +++ b/src/data.rs @@ -15,6 +15,7 @@ use std::time::Instant; use anyhow::{Context as _, Error, Result}; use camino::{Utf8Path, Utf8PathBuf}; +use semver::Version; use serde::{Deserialize, Deserializer}; use treestate::{FileState, TreeState}; @@ -40,6 +41,33 @@ where Deserialize::deserialize(deserializer).map(Some) } +fn deserialize_version_checked<'de, D>(deserializer: D) -> Result, D::Error> +where + // T: Deserialize<'de>, + D: Deserializer<'de>, +{ + use serde::de; + + let version: Option = Deserialize::deserialize(deserializer)?; + if let Some(version) = &version { + if let Ok(version) = Version::parse(version) { + let my_version = Version::parse(env!("CARGO_PKG_VERSION")).unwrap(); + if version > my_version { + return Err(de::Error::custom(format!( + "laze_required_version: got \"{version}\", expected any version <={my_version}" + ))); + } + Ok(Some(version)) + } else { + return Err(de::Error::custom(format!( + "error parsing \"{version}\" as semver version string" + ))); + } + } else { + Ok(None) + } +} + #[derive(Debug, Serialize, Deserialize)] struct YamlFile { contexts: Option>, @@ -51,6 +79,8 @@ struct YamlFile { imports: Option>, subdirs: Option>, defaults: Option>, + #[serde(default, deserialize_with = "deserialize_version_checked")] + laze_required_version: Option, #[serde(skip)] filename: Option, #[serde(skip)]