use anyhow::{Context as _, Result};
use crate::context::Context;
use crate::target::map_target;
pub const DEFAULT_NAME_TEMPLATE: &str = "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{% if Arm %}v{{ Arm }}{% endif %}{% if Mips %}_{{ Mips }}{% endif %}{% if Amd64 and Amd64 != \"v1\" %}{{ Amd64 }}{% endif %}";
pub const DEFAULT_NAME_TEMPLATE_MULTI_CRATE: &str = DEFAULT_NAME_TEMPLATE;
pub const DEFAULT_BINARY_NAME_TEMPLATE: &str = "{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{% if Arm %}v{{ Arm }}{% endif %}{% if Mips %}_{{ Mips }}{% endif %}{% if Amd64 and Amd64 != \"v1\" %}{{ Amd64 }}{% endif %}";
pub const MICRO_ARCH_VARIANT_SUFFIX: &str = "{% if Arm %}v{{ Arm }}{% endif %}{% if Mips %}_{{ Mips }}{% endif %}{% if Amd64 and Amd64 != \"v1\" %}{{ Amd64 }}{% endif %}";
pub const INSTALLER_AMD64_VARIANT_SUFFIX: &str =
"{% if Amd64 and Amd64 != \"v1\" %}{{ Amd64 }}{% endif %}";
pub fn seed_target_vars(ctx: &mut Context, target: &str) {
let (os, arch) = map_target(target);
let vars = ctx.template_vars_mut();
vars.set("Os", &os);
vars.set("Target", target);
reset_variant_vars(vars);
if let Some(version) = arch.strip_prefix("armv") {
vars.set("Arch", "arm");
vars.set("Arm", version);
} else {
if arch == "amd64" {
vars.set("Amd64", "v1");
}
vars.set("Arch", &arch);
}
}
pub fn reset_variant_vars(vars: &mut crate::template::TemplateVars) {
vars.set("Arm", "");
vars.set("Arm64", "");
vars.set("Amd64", "");
vars.set("Mips", "");
vars.set("I386", "");
}
pub fn seed_variant_vars(
vars: &mut crate::template::TemplateVars,
target: &str,
amd64_variant: Option<&str>,
) {
reset_variant_vars(vars);
match target.split('-').next().unwrap_or("") {
"aarch64" => vars.set("Arm64", "v8"),
"x86_64" => vars.set("Amd64", amd64_variant.unwrap_or("v1")),
"i686" | "i386" | "i586" => vars.set("I386", "sse2"),
_ => {}
}
}
pub fn seed_amd64_variant_var(
vars: &mut crate::template::TemplateVars,
arch: &str,
amd64_variant: Option<&str>,
) {
let value = match amd64_variant {
Some(v) => v,
None if arch == "amd64" => "v1",
None => "",
};
vars.set("Amd64", value);
}
pub fn render_archive_stem(ctx: &mut Context, name_template: &str, target: &str) -> Result<String> {
seed_target_vars(ctx, target);
ctx.render_template(name_template)
.with_context(|| format!("render archive name template for target '{target}'"))
}
pub fn render_archive_asset_name(
ctx: &mut Context,
name_template: &str,
target: &str,
format: &str,
) -> Result<String> {
render_archive_asset_name_with_variant(ctx, name_template, target, format, None)
}
pub fn render_archive_asset_name_with_variant(
ctx: &mut Context,
name_template: &str,
target: &str,
format: &str,
amd64_variant: Option<&str>,
) -> Result<String> {
let stem = if amd64_variant.is_some() {
seed_target_vars(ctx, target);
let (_, arch) = map_target(target);
seed_amd64_variant_var(ctx.template_vars_mut(), &arch, amd64_variant);
ctx.render_template(name_template)
.with_context(|| format!("render archive name template for target '{target}'"))?
} else {
render_archive_stem(ctx, name_template, target)?
};
Ok(format!("{stem}.{format}"))
}
pub fn binstall_pkg_fmt(format: &str) -> Option<&'static str> {
match format {
"tar.gz" | "tgz" => Some("tgz"),
"tar.xz" | "txz" => Some("txz"),
"tar.zst" | "tzst" => Some("tzstd"),
"tar.bz2" | "tbz2" => Some("tbz2"),
"tar" => Some("tar"),
"zip" => Some("zip"),
"bin" => Some("bin"),
_ => None,
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::config::Config;
use crate::context::{Context, ContextOptions};
fn ctx() -> Context {
let config = Config {
project_name: "anodizer".to_string(),
..Default::default()
};
let mut ctx = Context::new(config, ContextOptions::default());
ctx.template_vars_mut().set("ProjectName", "anodizer");
ctx.template_vars_mut().set("Version", "1.2.3");
ctx
}
#[test]
fn seeds_os_arch_target() {
let mut c = ctx();
seed_target_vars(&mut c, "x86_64-unknown-linux-gnu");
assert_eq!(c.template_vars().get("Os").unwrap(), "linux");
assert_eq!(c.template_vars().get("Arch").unwrap(), "amd64");
assert_eq!(
c.template_vars().get("Target").unwrap(),
"x86_64-unknown-linux-gnu"
);
assert_eq!(c.template_vars().get("Amd64").unwrap(), "v1");
assert_eq!(c.template_vars().get("Arm").unwrap(), "");
}
#[test]
fn armv7_splits_arch_and_arm() {
let mut c = ctx();
seed_target_vars(&mut c, "armv7-unknown-linux-gnueabihf");
assert_eq!(c.template_vars().get("Arch").unwrap(), "arm");
assert_eq!(c.template_vars().get("Arm").unwrap(), "7");
assert_eq!(c.template_vars().get("Amd64").unwrap(), "");
}
#[test]
fn mips_carries_no_variant_suffix() {
let mut c = ctx();
seed_target_vars(&mut c, "mips-unknown-linux-gnu");
assert_eq!(c.template_vars().get("Arch").unwrap(), "mips");
assert_eq!(c.template_vars().get("Mips").unwrap(), "");
}
#[test]
fn variant_vars_reset_between_targets() {
let mut c = ctx();
seed_target_vars(&mut c, "armv7-unknown-linux-gnueabihf");
assert_eq!(c.template_vars().get("Arm").unwrap(), "7");
seed_target_vars(&mut c, "x86_64-unknown-linux-gnu");
assert_eq!(c.template_vars().get("Arm").unwrap(), "");
assert_eq!(c.template_vars().get("Arch").unwrap(), "amd64");
}
#[test]
fn amd64_variant_var_is_arch_gated() {
let cases: [(&str, Option<&str>, &str); 4] = [
("arm64", None, ""),
("armv7", None, ""),
("amd64", None, "v1"),
("amd64", Some("v3"), "v3"),
];
let mut c = ctx();
for (arch, variant, expected) in cases {
seed_amd64_variant_var(c.template_vars_mut(), arch, variant);
assert_eq!(
c.template_vars().get("Amd64").unwrap(),
expected,
"Amd64 for arch={arch} variant={variant:?}"
);
}
}
#[test]
fn default_template_renders_goreleaser_stem() {
let mut c = ctx();
let stem =
render_archive_stem(&mut c, DEFAULT_NAME_TEMPLATE, "aarch64-apple-darwin").unwrap();
assert_eq!(stem, "anodizer_1.2.3_darwin_arm64");
}
#[test]
fn custom_template_renders_with_format_ext() {
let mut c = ctx();
let name = render_archive_asset_name(
&mut c,
"{{ ProjectName }}-{{ Version }}-{{ Os }}-{{ Arch }}",
"x86_64-pc-windows-msvc",
"zip",
)
.unwrap();
assert_eq!(name, "anodizer-1.2.3-windows-amd64.zip");
}
#[test]
fn default_template_byte_identical_to_head_for_every_arch() {
let cases: &[(&str, &str)] = &[
(
"armv7-unknown-linux-gnueabihf",
"anodizer_1.2.3_linux_armv7",
),
(
"armv6-unknown-linux-gnueabihf",
"anodizer_1.2.3_linux_armv6",
),
("mips-unknown-linux-gnu", "anodizer_1.2.3_linux_mips"),
("mipsel-unknown-linux-gnu", "anodizer_1.2.3_linux_mipsel"),
(
"mips64-unknown-linux-gnuabi64",
"anodizer_1.2.3_linux_mips64",
),
(
"mips64el-unknown-linux-gnuabi64",
"anodizer_1.2.3_linux_mips64el",
),
("i686-unknown-linux-gnu", "anodizer_1.2.3_linux_386"),
("x86_64-unknown-linux-gnu", "anodizer_1.2.3_linux_amd64"),
("aarch64-unknown-linux-gnu", "anodizer_1.2.3_linux_arm64"),
("x86_64-apple-darwin", "anodizer_1.2.3_darwin_amd64"),
("aarch64-apple-darwin", "anodizer_1.2.3_darwin_arm64"),
("x86_64-pc-windows-msvc", "anodizer_1.2.3_windows_amd64"),
("aarch64-pc-windows-msvc", "anodizer_1.2.3_windows_arm64"),
];
for (target, expected) in cases {
let mut c = ctx();
let stem = render_archive_stem(&mut c, DEFAULT_NAME_TEMPLATE, target).unwrap();
assert_eq!(
&stem, expected,
"default-template asset stem for {target} must match HEAD"
);
}
}
#[test]
fn new_seeding_equals_head_seeding_per_target() {
let targets = [
"armv7-unknown-linux-gnueabihf",
"armv6-unknown-linux-gnueabihf",
"mips-unknown-linux-gnu",
"mipsel-unknown-linux-gnu",
"mips64-unknown-linux-gnuabi64",
"i686-unknown-linux-gnu",
"x86_64-unknown-linux-gnu",
"aarch64-unknown-linux-gnu",
"x86_64-apple-darwin",
"aarch64-apple-darwin",
"x86_64-pc-windows-msvc",
"aarch64-pc-windows-msvc",
];
for target in targets {
let (os, arch) = crate::target::map_target(target);
let mut head = ctx();
{
let v = head.template_vars_mut();
v.set("Os", &os);
v.set("Arch", &arch);
v.set("Target", target);
v.set("Arm", "");
v.set("Arm64", "");
v.set("Amd64", "");
v.set("Mips", "");
v.set("I386", "");
}
let head_stem = head.render_template(DEFAULT_NAME_TEMPLATE).unwrap();
let mut new = ctx();
let new_stem = render_archive_stem(&mut new, DEFAULT_NAME_TEMPLATE, target).unwrap();
assert_eq!(
head_stem, new_stem,
"new seed_target_vars must be byte-identical to HEAD for {target}"
);
}
}
#[test]
fn archive_defaults_end_with_full_micro_arch_suffix() {
assert!(DEFAULT_NAME_TEMPLATE.ends_with(MICRO_ARCH_VARIANT_SUFFIX));
assert!(DEFAULT_BINARY_NAME_TEMPLATE.ends_with(MICRO_ARCH_VARIANT_SUFFIX));
}
#[test]
fn installer_amd64_suffix_is_the_tail_of_the_full_suffix() {
assert!(MICRO_ARCH_VARIANT_SUFFIX.ends_with(INSTALLER_AMD64_VARIANT_SUFFIX));
}
#[test]
fn variant_vars_mips_stays_empty_for_every_mips_goarch() {
use crate::template::TemplateVars;
for target in [
"mips-unknown-linux-gnu",
"mipsel-unknown-linux-gnu",
"mips64-unknown-linux-gnuabi64",
"mips64el-unknown-linux-gnuabi64",
] {
let mut v = TemplateVars::new();
seed_variant_vars(&mut v, target, None);
assert_eq!(
v.get("Mips").map(String::as_str),
Some(""),
"Mips must stay empty for {target}"
);
}
}
#[test]
fn variant_vars_untagged_x86_64_seeds_amd64_baseline() {
use crate::template::TemplateVars;
let mut v = TemplateVars::new();
seed_variant_vars(&mut v, "x86_64-unknown-linux-gnu", None);
assert_eq!(v.get("Amd64").map(String::as_str), Some("v1"));
seed_variant_vars(&mut v, "x86_64-unknown-linux-gnu", Some("v3"));
assert_eq!(v.get("Amd64").map(String::as_str), Some("v3"));
}
#[test]
fn variant_vars_family_levels_and_reset() {
use crate::template::TemplateVars;
let mut v = TemplateVars::new();
seed_variant_vars(&mut v, "aarch64-unknown-linux-gnu", None);
assert_eq!(v.get("Arm64").map(String::as_str), Some("v8"));
seed_variant_vars(&mut v, "i686-unknown-linux-gnu", None);
assert_eq!(v.get("I386").map(String::as_str), Some("sse2"));
assert_eq!(v.get("Arm64").map(String::as_str), Some(""));
}
#[test]
fn variant_vars_arm_stays_empty_for_every_arm_token() {
use crate::template::TemplateVars;
for target in [
"armv7-unknown-linux-gnueabihf",
"armv7l-unknown-linux-gnueabihf",
"armv6-unknown-linux-gnueabihf",
"arm-unknown-linux-gnueabi",
] {
let mut v = TemplateVars::new();
seed_variant_vars(&mut v, target, None);
assert_eq!(
v.get("Arm").map(String::as_str),
Some(""),
"Arm must stay empty for {target}"
);
}
}
#[test]
fn untagged_x86_64_renders_amd64_baseline_identically_across_policies() {
use crate::template::TemplateVars;
let target = "x86_64-unknown-linux-gnu";
let mut archive = ctx();
seed_target_vars(&mut archive, target);
let archive_val = archive.template_vars().get("Amd64").cloned().unwrap();
let mut build_vars = TemplateVars::new();
seed_variant_vars(&mut build_vars, target, None);
let build_val = build_vars.get("Amd64").cloned().unwrap();
let mut installer_vars = TemplateVars::new();
seed_amd64_variant_var(&mut installer_vars, "amd64", None);
let installer_val = installer_vars.get("Amd64").cloned().unwrap();
assert_eq!(archive_val, "v1");
assert_eq!(build_val, archive_val);
assert_eq!(installer_val, archive_val);
}
#[test]
fn untagged_x86_64_default_archive_name_stays_suffix_free() {
let mut c = ctx();
let stem =
render_archive_stem(&mut c, DEFAULT_NAME_TEMPLATE, "x86_64-unknown-linux-gnu").unwrap();
assert_eq!(stem, "anodizer_1.2.3_linux_amd64");
}
#[test]
fn pkg_fmt_maps_known_formats() {
assert_eq!(binstall_pkg_fmt("tar.gz"), Some("tgz"));
assert_eq!(binstall_pkg_fmt("zip"), Some("zip"));
assert_eq!(binstall_pkg_fmt("tar.xz"), Some("txz"));
assert_eq!(binstall_pkg_fmt("binary"), None);
assert_eq!(binstall_pkg_fmt("none"), None);
}
}