2021-06-29 01:02:43 -07:00
|
|
|
use std::fmt;
|
|
|
|
use std::process::Stdio;
|
|
|
|
|
|
|
|
use log::Level;
|
|
|
|
use regex::Regex;
|
|
|
|
use tokio::process::Command;
|
|
|
|
|
2022-01-08 01:20:36 -08:00
|
|
|
use super::{ColmenaError, ColmenaResult};
|
2021-10-25 23:38:10 -07:00
|
|
|
|
2022-08-17 11:56:30 -06:00
|
|
|
pub struct NixVersion {
|
2021-06-29 01:02:43 -07:00
|
|
|
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();
|
|
|
|
|
2022-07-29 22:13:09 -07:00
|
|
|
Self {
|
|
|
|
major,
|
|
|
|
minor,
|
|
|
|
string,
|
|
|
|
}
|
2021-06-29 01:02:43 -07:00
|
|
|
} else {
|
|
|
|
Self {
|
|
|
|
major: 0,
|
|
|
|
minor: 0,
|
|
|
|
string: String::from("unknown"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn has_flakes(&self) -> bool {
|
|
|
|
self.major > 2 || (self.major == 2 && self.minor >= 4)
|
|
|
|
}
|
2022-08-17 11:56:30 -06:00
|
|
|
|
|
|
|
pub fn at_least(&self, major: usize, minor: usize) -> bool {
|
|
|
|
self.major >= major && self.minor >= minor
|
|
|
|
}
|
2021-06-29 01:02:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
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")
|
2022-07-29 22:13:09 -07:00
|
|
|
.output()
|
|
|
|
.await;
|
2021-06-29 01:02:43 -07:00
|
|
|
|
|
|
|
if version_cmd.is_err() {
|
|
|
|
return Self::NO_NIX;
|
|
|
|
}
|
|
|
|
|
2022-07-29 22:13:09 -07:00
|
|
|
let version =
|
|
|
|
NixVersion::parse(String::from_utf8_lossy(&version_cmd.unwrap().stdout).to_string());
|
2021-06-29 01:02:43 -07:00
|
|
|
let flakes_supported = version.has_flakes();
|
|
|
|
|
|
|
|
let flake_cmd = Command::new("nix-instantiate")
|
|
|
|
.args(&["--eval", "-E", "builtins.getFlake"])
|
|
|
|
.stdout(Stdio::null())
|
|
|
|
.stderr(Stdio::null())
|
2022-07-29 22:13:09 -07:00
|
|
|
.status()
|
|
|
|
.await;
|
2021-06-29 01:02:43 -07:00
|
|
|
|
|
|
|
if flake_cmd.is_err() {
|
|
|
|
return Self::NO_NIX;
|
|
|
|
}
|
|
|
|
|
|
|
|
let flakes_enabled = flake_cmd.unwrap().success();
|
|
|
|
|
|
|
|
Self {
|
|
|
|
version: Some(version),
|
|
|
|
flakes_supported,
|
|
|
|
flakes_enabled,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-08 01:20:36 -08:00
|
|
|
pub async fn require_flake_support() -> ColmenaResult<()> {
|
2021-10-25 23:38:10 -07:00
|
|
|
let check = Self::detect().await;
|
|
|
|
|
|
|
|
if !check.flakes_supported() {
|
|
|
|
check.print_flakes_info(true);
|
2022-01-08 01:20:36 -08:00
|
|
|
Err(ColmenaError::NoFlakesSupport)
|
2021-10-25 23:38:10 -07:00
|
|
|
} else {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-29 01:02:43 -07:00
|
|
|
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 {
|
2022-07-29 22:13:09 -07:00
|
|
|
let level = if required { Level::Error } else { Level::Warn };
|
|
|
|
log::log!(
|
|
|
|
level,
|
|
|
|
"The Nix version you are using does not support Flakes."
|
|
|
|
);
|
2021-11-18 15:41:02 -08:00
|
|
|
log::log!(level, "If you are using a Nixpkgs version before 21.11, please install nixUnstable for a version that includes Flakes support.");
|
2021-06-29 01:02:43 -07:00
|
|
|
|
|
|
|
if required {
|
2022-07-29 22:13:09 -07:00
|
|
|
log::log!(
|
|
|
|
level,
|
|
|
|
"Cannot continue since Flakes support is required for this operation."
|
|
|
|
);
|
2021-06-29 01:02:43 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn flakes_supported(&self) -> bool {
|
|
|
|
self.flakes_supported
|
|
|
|
}
|
2022-08-17 11:56:30 -06:00
|
|
|
|
|
|
|
pub fn version(&self) -> Option<&NixVersion> {
|
|
|
|
self.version.as_ref()
|
|
|
|
}
|
2021-06-29 01:02:43 -07:00
|
|
|
}
|