use crate::app::Either;
use crate::{ResolvedZigVersion, ZigVersion};
use crate::{
Result, ZvError,
app::{App, CacheStrategy},
};
use color_eyre::eyre::{Context, eyre};
use yansi::Paint;
pub(crate) async fn use_version(
zig_version: ZigVersion,
app: &mut App,
force_ziglang: bool,
) -> Result<()> {
let resolved_version = resolve_zig_version(app, &zig_version).await
.map_err(|e| {
match e {
ZvError::ZigVersionResolveError(err) => {
ZvError::ZigVersionResolveError(eyre!(
"Failed to resolve version '{}': {}. Try running 'zv sync' to update the index or 'zv list' to see available versions.",
zig_version, err
))
}
_ => e,
}
})?;
if let Some(p) = app.check_installed(&resolved_version) {
app.set_active_version(&resolved_version, Some(p)).await?
} else {
if let Some(Either::Version(_)) = app.to_install {
app.install_direct(force_ziglang).await.wrap_err_with(|| {
format!(
"Failed to download and install Zig version {}",
resolved_version
)
})?;
} else {
app.install_release(force_ziglang).await.wrap_err_with(|| {
format!(
"Failed to download and install Zig version {}",
resolved_version
)
})?;
}
app.set_active_version(&resolved_version, None).await?
}
println!(
"✅ Active zig version set: {}",
Paint::blue(&resolved_version.version().to_string())
);
Ok(())
}
pub async fn resolve_zig_version(
app: &mut App,
version: &ZigVersion,
) -> Result<ResolvedZigVersion, ZvError> {
const TARGET: &str = "zv::resolve_zig_version";
match version {
ZigVersion::Semver(v) => {
if !v.pre.is_empty() {
tracing::trace!(target: TARGET, "Pre-release semver version, skipping index resolution: {v}");
app.to_install = Some(Either::Version(ResolvedZigVersion::Semver(v.to_owned())));
return Ok(ResolvedZigVersion::Semver(v.clone()));
}
tracing::trace!(target: TARGET, "Resolving semver version: {}", v);
let zig_release = app.validate_semver(v).await?;
app.to_install = Some(Either::Release(zig_release));
Ok(ResolvedZigVersion::Semver(v.clone()))
}
ZigVersion::Master(Some(v)) => {
tracing::trace!(target: TARGET, "Resolving master version: {}", v);
let master_release = app.fetch_master_version().await?;
let master_version = master_release.resolved_version();
let index_master_version = match master_version {
ResolvedZigVersion::Semver(semver) => semver,
ResolvedZigVersion::Master(semver) => semver,
};
if index_master_version == v {
app.to_install = Some(master_release.into());
Ok(ResolvedZigVersion::Master(v.clone()))
} else {
tracing::warn!(
"Master version mismatch: requested {}, but master is at {}",
v,
index_master_version
);
Ok(ResolvedZigVersion::Master(v.clone()))
}
}
ZigVersion::Master(None) => {
tracing::trace!(target: TARGET, "Resolving latest master(none) version");
let master_release = app.fetch_master_version().await?;
let master_version = master_release.resolved_version().clone();
match master_version {
ResolvedZigVersion::Master(v) => {
app.to_install = Some(master_release.into());
Ok(ResolvedZigVersion::Master(v))
}
ResolvedZigVersion::Semver(v) => {
app.to_install = Some(master_release.into());
Ok(ResolvedZigVersion::Master(v))
}
}
}
ZigVersion::Stable(Some(v)) => {
tracing::trace!(target: TARGET, "Resolving stable version: {}", v);
if !v.pre.is_empty() || !v.build.is_empty() {
return Err(ZvError::ZigVersionResolveError(eyre!(
"Version {} is not stable (contains pre-release or build metadata)",
v
)));
}
let zig_release = app.validate_semver(v).await?;
app.to_install = Some(zig_release.into());
Ok(ResolvedZigVersion::Semver(v.clone()))
}
ZigVersion::Stable(None) => {
tracing::trace!(target: TARGET, "Resolving latest stable(none) version");
let stable_release = app.fetch_latest_version(CacheStrategy::RespectTtl).await?;
let stable_version = stable_release.resolved_version().clone();
match stable_version {
ResolvedZigVersion::Semver(semver) => {
app.to_install = Some(stable_release.into());
Ok(ResolvedZigVersion::Semver(semver.clone()))
}
_ => Err(ZvError::ZigVersionResolveError(eyre!(
"Latest stable version is not a semver release"
))),
}
}
ZigVersion::Latest(Some(v)) => {
tracing::trace!(target: TARGET, "Resolving latest version: {}", v);
let zig_release = app.validate_semver(v).await?;
app.to_install = Some(zig_release.into());
Ok(ResolvedZigVersion::Semver(v.clone()))
}
ZigVersion::Latest(None) => {
tracing::trace!(target: TARGET, "Resolving latest(none) version");
let latest_release = app
.fetch_latest_version(CacheStrategy::AlwaysRefresh)
.await?;
let latest_version = latest_release.resolved_version().clone();
match latest_version {
ResolvedZigVersion::Semver(semver) => {
app.to_install = Some(latest_release.into());
Ok(ResolvedZigVersion::Semver(semver.clone()))
}
_ => Err(ZvError::ZigVersionResolveError(eyre!(
"Latest version is not a semver release"
))),
}
}
}
}