Skip to content

Commit

Permalink
feat(lib): Expose print_returning_exit_code (#25)
Browse files Browse the repository at this point in the history
  • Loading branch information
shivaraj-bh authored Jul 10, 2024
1 parent 4773c9f commit b9c70a9
Show file tree
Hide file tree
Showing 11 changed files with 100 additions and 91 deletions.
2 changes: 1 addition & 1 deletion src/check/caches.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ impl Checkable for Caches {
fn check(
&self,
nix_info: &info::NixInfo,
_: Option<nix_rs::flake::url::FlakeUrl>,
_: Option<&nix_rs::flake::url::FlakeUrl>,
) -> Vec<Check> {
let val = &nix_info.nix_config.substituters.value;
let missing_caches = self
Expand Down
2 changes: 1 addition & 1 deletion src/check/direnv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ impl Default for Direnv {
}

impl Checkable for Direnv {
fn check(&self, _nix_info: &info::NixInfo, flake_url: Option<FlakeUrl>) -> Vec<Check> {
fn check(&self, _nix_info: &info::NixInfo, flake_url: Option<&FlakeUrl>) -> Vec<Check> {
let mut checks = vec![];
if !self.enable {
return checks;
Expand Down
2 changes: 1 addition & 1 deletion src/check/flake_enabled.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ impl Checkable for FlakeEnabled {
fn check(
&self,
nix_info: &info::NixInfo,
_: Option<nix_rs::flake::url::FlakeUrl>,
_: Option<&nix_rs::flake::url::FlakeUrl>,
) -> Vec<Check> {
let val = &nix_info.nix_config.experimental_features.value;
let check = Check {
Expand Down
2 changes: 1 addition & 1 deletion src/check/max_jobs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ impl Checkable for MaxJobs {
fn check(
&self,
nix_info: &info::NixInfo,
_: Option<nix_rs::flake::url::FlakeUrl>,
_: Option<&nix_rs::flake::url::FlakeUrl>,
) -> Vec<Check> {
let max_jobs = nix_info.nix_config.max_jobs.value;
let check = Check {
Expand Down
2 changes: 1 addition & 1 deletion src/check/min_nix_version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ impl Checkable for MinNixVersion {
fn check(
&self,
nix_info: &info::NixInfo,
_: Option<nix_rs::flake::url::FlakeUrl>,
_: Option<&nix_rs::flake::url::FlakeUrl>,
) -> Vec<Check> {
let val = &nix_info.nix_version;
let check = Check {
Expand Down
2 changes: 1 addition & 1 deletion src/check/rosetta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ impl Checkable for Rosetta {
fn check(
&self,
nix_info: &info::NixInfo,
_: Option<nix_rs::flake::url::FlakeUrl>,
_: Option<&nix_rs::flake::url::FlakeUrl>,
) -> Vec<Check> {
let mut checks = vec![];
if let (true, Some(emulation)) = (self.enable, get_apple_emulation(&nix_info.nix_env.os)) {
Expand Down
2 changes: 1 addition & 1 deletion src/check/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ impl Checkable for System {
fn check(
&self,
nix_info: &nix_rs::info::NixInfo,
_: Option<nix_rs::flake::url::FlakeUrl>,
_: Option<&nix_rs::flake::url::FlakeUrl>,
) -> Vec<Check> {
let mut checks = vec![];
let nix_env = &nix_info.nix_env;
Expand Down
2 changes: 1 addition & 1 deletion src/check/trusted_users.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ impl Checkable for TrustedUsers {
fn check(
&self,
nix_info: &nix_rs::info::NixInfo,
_: Option<nix_rs::flake::url::FlakeUrl>,
_: Option<&nix_rs::flake::url::FlakeUrl>,
) -> Vec<Check> {
let result = if is_current_user_trusted(nix_info) {
CheckResult::Green
Expand Down
87 changes: 80 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@ pub mod check;
pub mod report;
pub mod traits;

use colored::Colorize;

use check::direnv::Direnv;
use nix_rs::command::NixCmd;
use nix_rs::flake::eval::nix_eval_attr_json;
use nix_rs::flake::url::FlakeUrl;
use serde::{Deserialize, Serialize};
use tracing::instrument;
Expand Down Expand Up @@ -56,12 +59,13 @@ impl NixHealth {
///
/// Fallback to using the default health check config if the flake doesn't
/// override it.
pub async fn from_flake(
url: nix_rs::flake::url::FlakeUrl,
) -> Result<Self, nix_rs::command::NixCmdError> {
let nix = NixCmd::default();
use nix_rs::flake::eval::nix_eval_attr_json;
nix_eval_attr_json(&nix, &url, true).await
pub async fn from_flake(url: &FlakeUrl) -> Result<Self, nix_rs::command::NixCmdError> {
nix_eval_attr_json(
&NixCmd::default(),
&url.with_fully_qualified_root_attr("nix-health"),
true,
)
.await
}

/// Run all checks and collect the results
Expand All @@ -73,15 +77,84 @@ impl NixHealth {
) -> Vec<traits::Check> {
tracing::info!("🩺 Running health checks");
self.into_iter()
.flat_map(|c| c.check(nix_info, flake_url.clone()))
.flat_map(|c| c.check(nix_info, flake_url.as_ref()))
.collect()
}

pub fn print_report_returning_exit_code(checks: &[traits::Check], quiet: bool) -> i32 {
let mut res = AllChecksResult::new();
for check in checks {
match &check.result {
traits::CheckResult::Green => {
if !quiet {
println!("{}", format!("✅ {}", check.title).green().bold());
println!(" {}", check.info.blue());
}
}
traits::CheckResult::Red { msg, suggestion } => {
res.register_failure(check.required);
if check.required {
println!("{}", format!("❌ {}", check.title).red().bold());
} else {
println!("{}", format!("🟧 {}", check.title).yellow().bold());
}
println!(" {}", check.info.blue());
println!(" {}", msg.yellow());
println!(" {}", suggestion);
}
}
}
res.report()
}

pub fn schema() -> Result<String, serde_json::Error> {
serde_json::to_string_pretty(&NixHealth::default())
}
}

/// A convenient type to aggregate check failures, and summary report at end.
enum AllChecksResult {
Pass,
PassSomeFail,
Fail,
}

impl AllChecksResult {
fn new() -> Self {
AllChecksResult::Pass
}

fn register_failure(&mut self, required: bool) {
if required {
*self = AllChecksResult::Fail;
} else if matches!(self, AllChecksResult::Pass) {
*self = AllChecksResult::PassSomeFail;
}
}

/// Print a summary report of the checks and return the exit code
fn report(self) -> i32 {
match self {
AllChecksResult::Pass => {
println!("{}", "✅ All checks passed".green().bold());
0
}
AllChecksResult::PassSomeFail => {
println!(
"{}, {}",
"✅ Required checks passed".green().bold(),
"but some non-required checks failed".yellow().bold()
);
0
}
AllChecksResult::Fail => {
println!("{}", "❌ Some required checks failed".red().bold());
1
}
}
}
}

#[cfg(test)]
mod tests {
use crate::check::{caches::Caches, min_nix_version::MinNixVersion};
Expand Down
82 changes: 7 additions & 75 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
use anyhow::Context;
use clap::{command, Parser};
use colored::Colorize;
use nix_health::{
traits::{Check, CheckResult},
NixHealth,
};
use nix_health::{traits::Check, NixHealth};
use nix_rs::{command::NixCmd, env::NixEnv, flake::url::FlakeUrl, info::NixInfo};

#[derive(Parser)]
Expand Down Expand Up @@ -32,33 +28,11 @@ async fn main() -> anyhow::Result<()> {
return Ok(());
}

let flake_url = args
.flake_url
.map(|url| url.with_fully_qualified_root_attr("nix-health"));
let checks = run_checks(flake_url).await?;
let mut res = AllChecksResult::new();
for check in &checks {
match &check.result {
CheckResult::Green => {
if !args.quiet {
println!("{}", format!("✅ {}", check.title).green().bold());
println!(" {}", check.info.blue());
}
}
CheckResult::Red { msg, suggestion } => {
res.register_failure(check.required);
if check.required {
println!("{}", format!("❌ {}", check.title).red().bold());
} else {
println!("{}", format!("🟧 {}", check.title).yellow().bold());
}
println!(" {}", check.info.blue());
println!(" {}", msg.yellow());
println!(" {}", suggestion);
}
}
}
std::process::exit(res.report())
let checks = run_checks(args.flake_url).await?;

let exit_code = NixHealth::print_report_returning_exit_code(&checks, args.quiet);

std::process::exit(exit_code)
}

/// Run health checks, taking current directory flake into account if there is
Expand All @@ -77,7 +51,7 @@ async fn run_checks(flake_url: Option<FlakeUrl>) -> anyhow::Result<Vec<Check>> {
let health: NixHealth = match flake_url.as_ref() {
Some(flake_url) => {
println!("{}, using config from flake '{}':", action_msg, flake_url);
NixHealth::from_flake(flake_url.clone()).await
NixHealth::from_flake(flake_url).await
}
None => {
println!("{}:", action_msg);
Expand All @@ -87,45 +61,3 @@ async fn run_checks(flake_url: Option<FlakeUrl>) -> anyhow::Result<Vec<Check>> {
let checks = health.run_checks(&nix_info, flake_url.clone());
Ok(checks)
}

/// A convenient type to aggregate check failures, and summary report at end.
enum AllChecksResult {
Pass,
PassSomeFail,
Fail,
}

impl AllChecksResult {
fn new() -> Self {
AllChecksResult::Pass
}

fn register_failure(&mut self, required: bool) {
if required {
*self = AllChecksResult::Fail;
} else if matches!(self, AllChecksResult::Pass) {
*self = AllChecksResult::PassSomeFail;
}
}

fn report(self) -> i32 {
match self {
AllChecksResult::Pass => {
println!("{}", "✅ All checks passed".green().bold());
0
}
AllChecksResult::PassSomeFail => {
println!(
"{}, {}",
"✅ Required checks passed".green().bold(),
"but some non-required checks failed".yellow().bold()
);
0
}
AllChecksResult::Fail => {
println!("{}", "❌ Some required checks failed".red().bold());
1
}
}
}
}
6 changes: 5 additions & 1 deletion src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ pub trait Checkable {
fn check(
&self,
nix_info: &nix_rs::info::NixInfo,
flake: Option<nix_rs::flake::url::FlakeUrl>,
// The flake against which the check is being run
//
// If None, the check is run against the current environment, with no
// specific configuration from a flake.
flake: Option<&nix_rs::flake::url::FlakeUrl>,
) -> Vec<Check>;
}

Expand Down

0 comments on commit b9c70a9

Please sign in to comment.