Add check for Flakes support
This commit is contained in:
parent
e50ba82bf2
commit
67db0e73d1
6 changed files with 169 additions and 1 deletions
|
@ -73,6 +73,7 @@ For a sample configuration, see <https://github.com/zhaofengli/colmena>.
|
|||
register_command!(introspect, app);
|
||||
register_command!(upload_keys, app);
|
||||
register_command!(exec, app);
|
||||
register_command!(nix_info, app);
|
||||
|
||||
app
|
||||
}
|
||||
|
@ -87,6 +88,7 @@ pub async fn run() {
|
|||
handle_command!(introspect, matches);
|
||||
handle_command!("upload-keys", upload_keys, matches);
|
||||
handle_command!(exec, matches);
|
||||
handle_command!("nix-info", nix_info, matches);
|
||||
|
||||
if let Some(args) = matches.subcommand_matches("gen-completions") {
|
||||
return gen_completions(args);
|
||||
|
|
|
@ -4,3 +4,4 @@ pub mod introspect;
|
|||
pub mod apply_local;
|
||||
pub mod upload_keys;
|
||||
pub mod exec;
|
||||
pub mod nix_info;
|
||||
|
|
14
src/command/nix_info.rs
Normal file
14
src/command/nix_info.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
use clap::{App, SubCommand, ArgMatches};
|
||||
|
||||
use crate::nix::NixCheck;
|
||||
|
||||
pub fn subcommand() -> App<'static, 'static> {
|
||||
SubCommand::with_name("nix-info")
|
||||
.about("Show information about the current Nix installation")
|
||||
}
|
||||
|
||||
pub async fn run(_global_args: &ArgMatches<'_>, _local_args: &ArgMatches<'_>) {
|
||||
let check = NixCheck::detect().await;
|
||||
check.print_version_info();
|
||||
check.print_flakes_info(false);
|
||||
}
|
|
@ -11,10 +11,11 @@ use validator::Validate;
|
|||
use super::{
|
||||
StoreDerivation,
|
||||
NixResult,
|
||||
NixError,
|
||||
NodeConfig,
|
||||
ProfileMap,
|
||||
};
|
||||
use super::NixCommand;
|
||||
use super::{NixCommand, NixCheck};
|
||||
use crate::util::CommandExecution;
|
||||
use crate::progress::TaskProgress;
|
||||
|
||||
|
@ -58,6 +59,14 @@ impl HivePath {
|
|||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_flake(&self) -> bool {
|
||||
if let Self::Flake(_) = self {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -120,6 +129,13 @@ impl Hive {
|
|||
|
||||
/// Retrieve deployment info for all nodes.
|
||||
pub async fn deployment_info(&self) -> NixResult<HashMap<String, NodeConfig>> {
|
||||
let nix_check = NixCheck::detect().await;
|
||||
|
||||
if self.path.is_flake() && !nix_check.flakes_supported() {
|
||||
nix_check.print_flakes_info(true);
|
||||
return Err(NixError::NoFlakesSupport);
|
||||
}
|
||||
|
||||
// FIXME: Really ugly :(
|
||||
let s: String = self.nix_instantiate("hive.deploymentConfigJson").eval()
|
||||
.capture_json().await?;
|
||||
|
|
129
src/nix/info.rs
Normal file
129
src/nix/info.rs
Normal file
|
@ -0,0 +1,129 @@
|
|||
use std::fmt;
|
||||
use std::process::Stdio;
|
||||
|
||||
use log::Level;
|
||||
use regex::Regex;
|
||||
|
||||
use tokio::process::Command;
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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 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, "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
|
||||
}
|
||||
}
|
|
@ -32,6 +32,9 @@ pub use profile::{Profile, ProfileMap};
|
|||
pub mod deployment;
|
||||
pub use deployment::{Goal, Target, Deployment};
|
||||
|
||||
pub mod info;
|
||||
pub use info::NixCheck;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
|
@ -72,6 +75,9 @@ pub enum NixError {
|
|||
#[snafu(display("Unknown active profile: {}", store_path))]
|
||||
ActiveProfileUnknown { store_path: String },
|
||||
|
||||
#[snafu(display("Current Nix version does not support Flakes"))]
|
||||
NoFlakesSupport,
|
||||
|
||||
#[snafu(display("Nix Error: {}", message))]
|
||||
Unknown { message: String },
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue