use crate::build::{Build, Emit};
use crate::error::{Error, Result};
use crate::features::Features;
const FEATURES: &str = "DEP_MF2_V2_FEATURES";
const VERSION: &str = "DEP_MF2_V2_VERSION";
pub fn run() {
if let Err(e) = build() {
for line in e.to_string().lines() {
println!("cargo::error={line}");
}
std::process::exit(1);
}
}
fn build() -> Result<()> {
let features = mf2_features(
std::env::var(FEATURES).ok().as_deref(),
std::env::var(VERSION).ok().as_deref(),
cfg!(feature = "icu-blob"),
)?;
let emit = emit_for(&features);
Build::new()?
.features(features)
.emit(emit)
.emit_cargo(true)
.run()?
.into_result()
.map(drop)
}
fn mf2_features(features: Option<&str>, version: Option<&str>, icu_blob: bool) -> Result<Features> {
let features = Features::parse(features.ok_or(Error::NoMf2)?);
let ours = env!("CARGO_PKG_VERSION");
if version != Some(ours) {
return Err(Error::Mf2Version {
mf2: version.unwrap_or("unknown").to_owned(),
build: ours.to_owned(),
});
}
if features.datetime_icu() && !icu_blob {
return Err(Error::IcuBlob);
}
Ok(features)
}
fn emit_for(features: &Features) -> Emit {
let leptos_mode = ["ssr", "hydrate", "csr"].iter().any(|m| features.has(m));
if features.has("ssr") || (features.has("axum") && !leptos_mode) {
Emit::Both
} else if features.has("native") {
Emit::Native
} else {
Emit::Module
}
}
#[cfg(test)]
mod tests {
use super::{emit_for, mf2_features};
use crate::build::Emit;
use crate::error::Error;
use crate::features::Features;
const OURS: Option<&str> = Some(env!("CARGO_PKG_VERSION"));
#[test]
fn each_mode_emits_what_it_serves() {
let emit = |list: &str| emit_for(&Features::parse(list));
assert_eq!(emit("fn-number,native"), Emit::Native);
assert_eq!(emit("native,ratatui"), Emit::Native);
assert_eq!(emit("leptos,ssr"), Emit::Both);
assert_eq!(emit("leptos,native,ssr"), Emit::Both);
assert_eq!(emit("axum"), Emit::Both);
assert_eq!(emit("axum,hydrate,leptos"), Emit::Module);
assert_eq!(emit("hydrate,leptos"), Emit::Module);
assert_eq!(emit("csr,leptos"), Emit::Module);
assert_eq!(emit(""), Emit::Module);
assert_eq!(emit("host-std"), Emit::Module);
}
#[test]
fn the_features_come_from_mf2_and_its_version_must_match() {
let features = mf2_features(Some("fn-number,native"), OURS, false).expect("read");
assert!(features.fn_number() && features.has("native"));
assert_eq!(
mf2_features(Some(""), OURS, false).expect("no features"),
Features::default()
);
assert!(matches!(mf2_features(None, None, false), Err(Error::NoMf2)));
let Err(Error::Mf2Version { mf2, .. }) = mf2_features(Some(""), Some("1.0.0"), false)
else {
panic!("a version mismatch is refused");
};
assert_eq!(mf2, "1.0.0");
}
#[test]
fn datetime_icu_needs_icu_blob_here() {
let list = Some("datetime-icu,fn-datetime");
let e = mf2_features(list, OURS, false).expect_err("refused without icu-blob");
assert!(e.to_string().contains(
"add `features = [\"icu-blob\"]` to this crate's `mf2-build` build-dependency"
));
assert!(mf2_features(list, OURS, true).is_ok());
}
}