colmena/src/nix/info.rs
2022-08-17 11:56:30 -06:00

158 lines
4.3 KiB
Rust

use std::fmt;
use std::process::Stdio;
use log::Level;
use regex::Regex;
use tokio::process::Command;
use super::{ColmenaError, ColmenaResult};
pub struct NixVersion {
major: usize,
minor: usize,
string: String,
}
impl NixVersion {
fn parse(string: String) -> Self {
let re = Regex::new(r" (?P<major>\d+)\.(?P<minor>\d+)").unwrap();
if let Some(caps) = re.captures(&string) {
let major = caps.name("major").unwrap().as_str().parse().unwrap();
let minor = caps.name("minor").unwrap().as_str().parse().unwrap();
Self {
major,
minor,
string,
}
} else {
Self {
major: 0,
minor: 0,
string: String::from("unknown"),
}
}
}
fn has_flakes(&self) -> bool {
self.major > 2 || (self.major == 2 && self.minor >= 4)
}
pub fn at_least(&self, major: usize, minor: usize) -> bool {
self.major >= major && self.minor >= minor
}
}
impl fmt::Display for NixVersion {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.major != 0 {
write!(f, "{}.{}", self.major, self.minor)
} else {
write!(f, "{}???", self.string)
}
}
}
pub struct NixCheck {
version: Option<NixVersion>,
flakes_supported: bool,
flakes_enabled: bool,
}
impl NixCheck {
const NO_NIX: Self = Self {
version: None,
flakes_supported: false,
flakes_enabled: false,
};
pub async fn detect() -> Self {
let version_cmd = Command::new("nix-instantiate")
.arg("--version")
.output()
.await;
if version_cmd.is_err() {
return Self::NO_NIX;
}
let version =
NixVersion::parse(String::from_utf8_lossy(&version_cmd.unwrap().stdout).to_string());
let flakes_supported = version.has_flakes();
let flake_cmd = Command::new("nix-instantiate")
.args(&["--eval", "-E", "builtins.getFlake"])
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()
.await;
if flake_cmd.is_err() {
return Self::NO_NIX;
}
let flakes_enabled = flake_cmd.unwrap().success();
Self {
version: Some(version),
flakes_supported,
flakes_enabled,
}
}
pub async fn require_flake_support() -> ColmenaResult<()> {
let check = Self::detect().await;
if !check.flakes_supported() {
check.print_flakes_info(true);
Err(ColmenaError::NoFlakesSupport)
} else {
Ok(())
}
}
pub fn print_version_info(&self) {
if let Some(v) = &self.version {
log::info!("Nix Version: {}", v);
} else {
log::info!("Nix Version: Not found");
}
}
pub fn print_flakes_info(&self, required: bool) {
if self.version.is_none() {
log::error!("Nix doesn't appear to be installed.");
return;
}
if self.flakes_enabled {
log::info!("The Nix version you are using supports Flakes and it's enabled.");
} else if self.flakes_supported {
log::warn!("The Nix version you are using supports Flakes but it's disabled.");
log::warn!("Colmena will automatically enable Flakes for its operations, but you should enable it in your Nix configuration:");
log::warn!(" experimental-features = nix-command flakes");
} else {
let level = if required { Level::Error } else { Level::Warn };
log::log!(
level,
"The Nix version you are using does not support Flakes."
);
log::log!(level, "If you are using a Nixpkgs version before 21.11, please install nixUnstable for a version that includes Flakes support.");
if required {
log::log!(
level,
"Cannot continue since Flakes support is required for this operation."
);
}
}
}
pub fn flakes_supported(&self) -> bool {
self.flakes_supported
}
pub fn version(&self) -> Option<&NixVersion> {
self.version.as_ref()
}
}