Skip to content

Commit

Permalink
Simplify health check trait & types (#64)
Browse files Browse the repository at this point in the history
Now, the check types represent the check configuration - rather than the check result. Consequently, we are also able to get rid of all the per-check leptos views (in future, check.info would use Markdown via #34).
  • Loading branch information
srid authored Sep 14, 2023
1 parent 817ba85 commit 913c505
Show file tree
Hide file tree
Showing 10 changed files with 246 additions and 362 deletions.
89 changes: 42 additions & 47 deletions crates/nix_health/src/check/caches.rs
Original file line number Diff line number Diff line change
@@ -1,60 +1,55 @@
use std::fmt::Display;

use nix_rs::{config::ConfigVal, env, info};
use nix_rs::{env, info};
use serde::{Deserialize, Serialize};
use url::Url;

use crate::{
report::{Report, WithDetails},
traits::Check,
};
use crate::traits::*;

/// Check that [nix_rs::config::NixConfig::substituters] is set to a good value.
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Caches(pub ConfigVal<Vec<Url>>);
pub struct Caches {
pub required_caches: Vec<Url>,
}

impl Check for Caches {
fn check(nix_info: &info::NixInfo, _nix_env: &env::NixEnv) -> Self {
Caches(nix_info.nix_config.substituters.clone())
}
fn name(&self) -> &'static str {
"Nix Caches in use"
}
fn report(&self) -> Report<WithDetails> {
let val = &self.0.value;
// TODO: Hardcoding this to test failed reports
// TODO: Make this customizable in a flake
let required_cache = Url::parse("https://nix-community.cachix.org").unwrap();
if val.contains(&Url::parse("https://cache.nixos.org").unwrap()) {
if val.contains(&required_cache) {
Report::Green
} else {
Report::Red(WithDetails {
msg: format!("You are missing a required cache: {}", required_cache),
// TODO: Suggestion should be smart. Use 'cachix use' if a cachix cache.
suggestion: "Add substituters in /etc/nix/nix.conf or use 'cachix use'".into(),
})
}
} else {
Report::Red(WithDetails {
msg: "You are missing the official cache".into(),
suggestion: "Try looking in /etc/nix/nix.conf".into(),
})
impl Default for Caches {
fn default() -> Self {
Caches {
required_caches: vec![
Url::parse("https://cache.nixos.org").unwrap(),
// TODO: Hardcoding this for now, so as to test failed reports
Url::parse("https://nix-community.cachix.org").unwrap(),
],
}
}
}

impl Display for Caches {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"substituters = {}",
self.0
.value
.iter()
.map(|url| url.to_string())
.collect::<Vec<String>>()
.join(" ")
)
impl Checkable for Caches {
fn check(&self, nix_info: &info::NixInfo, _nix_env: &env::NixEnv) -> Option<Check> {
let val = &nix_info.nix_config.substituters.value;
let result = if self.required_caches.iter().all(|c| val.contains(c)) {
CheckResult::Green
} else {
CheckResult::Red {
msg: format!(
"You are missing a required cache: {}",
self.required_caches
.iter()
.find(|required_cache| !val.contains(required_cache))
.unwrap()
),
suggestion: "Add in /etc/nix/nix.conf or use 'cachix use'".to_string(),
}
};
let check = Check {
title: "Nix Caches in use".to_string(),
info: format!(
"substituters = {}",
val.iter()
.map(|url| url.to_string())
.collect::<Vec<String>>()
.join(" ")
),
result,
};
Some(check)
}
}
54 changes: 22 additions & 32 deletions crates/nix_health/src/check/flake_enabled.rs
Original file line number Diff line number Diff line change
@@ -1,39 +1,29 @@
use std::fmt::Display;

use nix_rs::{config::ConfigVal, env, info};
use nix_rs::{env, info};
use serde::{Deserialize, Serialize};

use crate::{
report::{Report, WithDetails},
traits::Check,
};
use crate::traits::*;

/// Check that [nix_rs::config::NixConfig::experimental_features] is set to a good value.
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct FlakeEnabled(pub ConfigVal<Vec<String>>);

impl Check for FlakeEnabled {
fn check(nix_info: &info::NixInfo, _nix_env: &env::NixEnv) -> Self {
FlakeEnabled(nix_info.nix_config.experimental_features.clone())
}
fn name(&self) -> &'static str {
"Flakes Enabled"
}
fn report(&self) -> Report<WithDetails> {
let val = &self.0.value;
if val.contains(&"flakes".to_string()) && val.contains(&"nix-command".to_string()) {
Report::Green
} else {
Report::Red(WithDetails {
msg: "Nix flakes are not enabled".into(),
suggestion: "See https://nixos.wiki/wiki/Flakes#Enable_flakes".into(),
})
}
}
}
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct FlakeEnabled();

impl Display for FlakeEnabled {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "experimental-features = {}", self.0.value.join(" "))
impl Checkable for FlakeEnabled {
fn check(&self, nix_info: &info::NixInfo, _nix_env: &env::NixEnv) -> Option<Check> {
let val = &nix_info.nix_config.experimental_features.value;
let check = Check {
title: "Flakes Enabled".to_string(),
info: format!("experimental-features = {}", val.join(" ")),
result: if val.contains(&"flakes".to_string())
&& val.contains(&"nix-command".to_string())
{
CheckResult::Green
} else {
CheckResult::Red {
msg: "Nix flakes are not enabled".into(),
suggestion: "See https://nixos.wiki/wiki/Flakes#Enable_flakes".into(),
}
},
};
Some(check)
}
}
51 changes: 20 additions & 31 deletions crates/nix_health/src/check/max_jobs.rs
Original file line number Diff line number Diff line change
@@ -1,38 +1,27 @@
use std::fmt::Display;

use nix_rs::{config::ConfigVal, env, info};
use nix_rs::{env, info};
use serde::{Deserialize, Serialize};

use crate::{
report::{Report, WithDetails},
traits::Check,
};
use crate::traits::{Check, CheckResult, Checkable};

/// Check that [nix_rs::config::NixConfig::max_jobs] is set to a good value.
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct MaxJobs(pub ConfigVal<i32>);

impl Check for MaxJobs {
fn check(nix_info: &info::NixInfo, _nix_env: &env::NixEnv) -> Self {
MaxJobs(nix_info.nix_config.max_jobs.clone())
}
fn name(&self) -> &'static str {
"Max Jobs"
}
fn report(&self) -> Report<WithDetails> {
if self.0.value > 1 {
Report::Green
} else {
Report::Red(WithDetails {
msg: "You are using only 1 core for nix builds".into(),
suggestion: "Try editing /etc/nix/nix.conf".into(),
})
}
}
}
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct MaxJobs();

impl Display for MaxJobs {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "max-jobs = {}", self.0.value)
impl Checkable for MaxJobs {
fn check(&self, nix_info: &info::NixInfo, _nix_env: &env::NixEnv) -> Option<Check> {
let max_jobs = nix_info.nix_config.max_jobs.value;
let check = Check {
title: "Max Jobs".to_string(),
info: format!("max-jobs = {}", max_jobs),
result: if max_jobs > 1 {
CheckResult::Green
} else {
CheckResult::Red {
msg: "You are using only 1 core for nix builds".into(),
suggestion: "Try editing /etc/nix/nix.conf".into(),
}
},
};
Some(check)
}
}
58 changes: 28 additions & 30 deletions crates/nix_health/src/check/min_nix_version.rs
Original file line number Diff line number Diff line change
@@ -1,43 +1,41 @@
use std::fmt::Display;

use nix_rs::{env, info, version::NixVersion};
use serde::{Deserialize, Serialize};

use crate::{
report::{Report, WithDetails},
traits::Check,
};
use crate::traits::*;

/// Check that [nix_rs::version::NixVersion] is set to a good value.
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct MinNixVersion(pub NixVersion);
pub struct MinNixVersion {
pub min_required: NixVersion,
}

impl Check for MinNixVersion {
fn check(nix_info: &info::NixInfo, _nix_env: &env::NixEnv) -> Self {
MinNixVersion(nix_info.nix_version.clone())
}
fn name(&self) -> &'static str {
"Minimum Nix Version"
}
fn report(&self) -> Report<WithDetails> {
let min_required = NixVersion {
major: 2,
minor: 13,
patch: 0,
};
if self.0 >= min_required {
Report::Green
} else {
Report::Red(WithDetails {
msg: format!("Your Nix version ({}) is too old; we require at least {}", self.0, min_required),
suggestion: "See https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-upgrade-nix.html".into(),
})
impl Default for MinNixVersion {
fn default() -> Self {
MinNixVersion {
min_required: NixVersion {
major: 2,
minor: 13,
patch: 0,
},
}
}
}

impl Display for MinNixVersion {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "nix version = {}", self.0)
impl Checkable for MinNixVersion {
fn check(&self, nix_info: &info::NixInfo, _nix_env: &env::NixEnv) -> Option<Check> {
let val = &nix_info.nix_version;
let check = Check {
title: "Minimum Nix Version".to_string(),
info: format!("nix version = {}", val),
result: if val >= &self.min_required {
CheckResult::Green
} else {
CheckResult::Red {
msg: format!("Your Nix version ({}) is too old; we require at least {}", val, self.min_required),
suggestion: "See https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-upgrade-nix.html".into(),
}
},
};
Some(check)
}
}
56 changes: 20 additions & 36 deletions crates/nix_health/src/check/trusted_users.rs
Original file line number Diff line number Diff line change
@@ -1,54 +1,38 @@
use std::fmt::Display;

use nix_rs::{config::ConfigVal, env, info};
use nix_rs::{env, info};
use serde::{Deserialize, Serialize};

use crate::{
report::{Report, WithDetails},
traits::Check,
};
use crate::traits::*;

/// Check that [crate::nix::config::NixConfig::trusted_users] is set to a good value.
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct TrustedUsers {
pub trusted_users: ConfigVal<Vec<String>>,
nix_env: env::NixEnv,
}
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct TrustedUsers();

impl Check for TrustedUsers {
fn check(nix_info: &info::NixInfo, nix_env: &env::NixEnv) -> Self {
TrustedUsers {
trusted_users: nix_info.nix_config.trusted_users.clone(),
nix_env: nix_env.clone(),
}
}
fn name(&self) -> &'static str {
"Trusted users"
}
fn report(&self) -> Report<WithDetails> {
let current_user = &self.nix_env.current_user;
if self.trusted_users.value.contains(current_user) {
Report::Green
impl Checkable for TrustedUsers {
fn check(&self, nix_info: &info::NixInfo, nix_env: &env::NixEnv) -> Option<Check> {
let val = &nix_info.nix_config.trusted_users.value;
let current_user = &nix_env.current_user;
let result = if val.contains(current_user) {
CheckResult::Green
} else {
let msg = format!("User '{}' not present in trusted_users", current_user);
let suggestion = if self.nix_env.nix_system.has_configuration_nix() {
let suggestion = if nix_env.nix_system.has_configuration_nix() {
format!(
r#"Add `nix.trustedUsers = [ "root" "{}" ];` to your {} `configuration.nix`"#,
current_user, self.nix_env.nix_system,
current_user, nix_env.nix_system,
)
} else {
format!(
r#"Run 'echo "trusted-users = root {}" | sudo tee -a /etc/nix/nix.conf && sudo pkill nix-daemon'"#,
current_user
)
};
Report::Red(WithDetails { msg, suggestion })
}
}
}

impl Display for TrustedUsers {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "trusted_users = {}", self.trusted_users.value.join(" "))
CheckResult::Red { msg, suggestion }
};
let check = Check {
title: "Trusted Users".to_string(),
info: format!("trusted-users = {}", val.join(" ")),
result,
};
Some(check)
}
}
Loading

0 comments on commit 913c505

Please sign in to comment.