Skip to content

Commit d53458b

Browse files
authored
om health: Add homebrew check
The homebrew check is disabled by default, but can be enabled through om configuration (YAML or nix).
1 parent 2d7ce4d commit d53458b

File tree

7 files changed

+115
-4
lines changed

7 files changed

+115
-4
lines changed

crates/omnix-common/src/check.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,22 @@
11
//! Prerequisite checks for the Omnix project.
22
3-
use which::which;
3+
use std::path::PathBuf;
4+
use which::{which, Error};
45

56
/// Check if Nix is installed.
67
pub fn nix_installed() -> bool {
7-
let out = which("nix");
8-
out.is_ok()
8+
which_strict("nix").is_some()
9+
}
10+
11+
/// Check if a binary is available in the system's PATH and return its path.
12+
/// Returns None if the binary is not found, panics on unexpected errors.
13+
pub fn which_strict(binary: &str) -> Option<PathBuf> {
14+
match which(binary) {
15+
Ok(path) => Some(path),
16+
Err(Error::CannotFindBinaryPath) => None,
17+
Err(e) => panic!(
18+
"Unexpected error while searching for binary '{}': {:?}",
19+
binary, e
20+
),
21+
}
922
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
use nix_rs::{flake::url::FlakeUrl, info::NixInfo};
2+
use omnix_common::check::which_strict;
3+
use serde::{Deserialize, Serialize};
4+
5+
use crate::traits::{Check, CheckResult, Checkable};
6+
7+
/// Check if Homebrew is installed
8+
#[derive(Default, Debug, Serialize, Deserialize, Clone)]
9+
#[serde(default, rename_all = "kebab-case")]
10+
pub struct Homebrew {
11+
pub(crate) enable: bool,
12+
pub(crate) required: bool,
13+
}
14+
15+
impl Checkable for Homebrew {
16+
fn check(
17+
&self,
18+
nix_info: &NixInfo,
19+
_flake_url: Option<&FlakeUrl>,
20+
) -> Vec<(&'static str, Check)> {
21+
let mut checks = vec![];
22+
23+
if self.enable && matches!(nix_info.nix_env.os, nix_rs::env::OS::MacOS { .. }) {
24+
checks.push((
25+
"homebrew-check",
26+
installation_check(&HomebrewInstall::detect(), self.required),
27+
));
28+
}
29+
30+
checks
31+
}
32+
}
33+
34+
/// Information about user's homebrew installation.
35+
#[derive(Debug)]
36+
pub struct HomebrewInstall {
37+
/// The path to the Homebrew binary.
38+
pub bin_path: std::path::PathBuf,
39+
}
40+
41+
impl HomebrewInstall {
42+
/// Detect homebrew installation.
43+
pub fn detect() -> Option<Self> {
44+
which_strict("brew").map(|bin_path| HomebrewInstall { bin_path })
45+
}
46+
}
47+
48+
/// Create a [Check] for Homebrew installation
49+
fn installation_check(homebrew_result: &Option<HomebrewInstall>, required: bool) -> Check {
50+
let nix_setup_url = "https://github.com/juspay/nixos-unified-template";
51+
52+
Check {
53+
title: "Homebrew installation".to_string(),
54+
info: format!(
55+
"Homebrew binary: {}",
56+
homebrew_result
57+
.as_ref()
58+
.map(|h| format!("Found at {:?}", h.bin_path))
59+
.unwrap_or_else(|| "Not found".to_string())
60+
),
61+
result: match homebrew_result {
62+
Some(homebrew) => CheckResult::Red {
63+
msg: format!(
64+
"Homebrew is installed at {:?}. Consider using Nix for better reproducibility",
65+
homebrew.bin_path
66+
),
67+
suggestion: format!(
68+
"Managing packages with Nix, rather than Homebrew, provides better reproducibility and integration. See <{}>\n\n{}",
69+
nix_setup_url,
70+
HOMEBREW_REMOVAL_INSTRUCTIONS
71+
),
72+
},
73+
None => CheckResult::Green,
74+
},
75+
required,
76+
}
77+
}
78+
79+
/// A string containing step-by-step removal commands and migration advice.
80+
const HOMEBREW_REMOVAL_INSTRUCTIONS: &str = r#"To completely remove Homebrew from your system:
81+
82+
- **Uninstall Homebrew and all packages:**
83+
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/uninstall.sh)"
84+
85+
For a safer migration, consider using 'brew list' to inventory your packages before removal, then install equivalents via Nix."#;

crates/omnix-health/src/check/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
pub mod caches;
33
pub mod direnv;
44
pub mod flake_enabled;
5+
pub mod homebrew;
56
pub mod max_jobs;
67
pub mod nix_version;
78
pub mod rosetta;

crates/omnix-health/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use check::shell::ShellCheck;
1010
use colored::Colorize;
1111

1212
use check::direnv::Direnv;
13+
use check::homebrew::Homebrew;
1314
use json::HealthOutput;
1415
use nix_rs::command::NixCmd;
1516
use nix_rs::env::OS;
@@ -39,6 +40,7 @@ pub struct NixHealth {
3940
pub trusted_users: TrustedUsers,
4041
pub caches: Caches,
4142
pub direnv: Direnv,
43+
pub homebrew: Homebrew,
4244
pub shell: ShellCheck,
4345
}
4446

@@ -57,6 +59,7 @@ impl<'a> IntoIterator for &'a NixHealth {
5759
&self.trusted_users,
5860
&self.caches,
5961
&self.direnv,
62+
&self.homebrew,
6063
&self.shell,
6164
];
6265
items.into_iter()

doc/src/history.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
## 1.0.4 (UNRELEASED)
44

55
- `om ci`: Allow impure builds through `impure = true;` setting in `om.yaml` (#445)
6-
- `om health`: Fix DetSys installer hijacking its own version into `nix --version` causing false Nix version detection. (#458)
6+
- `om health`
7+
- Fix DetSys installer hijacking its own version into `nix --version` causing false Nix version detection. (#458)
8+
- Add homebrew check (disabled by default) (#459)
79

810
## 1.0.3 (2025-03-17) {#1.0.3}
911

doc/src/om/health.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@ The `om health` command checks the health of your Nix install. Furthermore, indi
2020
| Direnv: installed and activated | Yes |
2121
| Dotfiles are managed by Nix | Yes |
2222
| Min RAM / Disk space | Yes |
23+
| Homebrew install detection (disabled by default)[^macos] | Yes |
2324

2425
[^ros]: This check is only performed on macOS with Apple Silicon.
26+
[^macos]: This check is only performed on macOS.
2527

2628
Note that some checks are considered non-essential. For eg., the disk space check looks for 1TB+ disk space, but if the user is on a laptop with 256GB SSD, the check will report a warning instead of failing. This can also be configured in per-project basis from `flake.nix` (see below).
2729

@@ -74,6 +76,9 @@ caches:
7476
direnv:
7577
enable: true
7678
required: false
79+
homebrew:
80+
enable: false
81+
required: false
7782
shell:
7883
enable: true
7984
required: false

om.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ health:
6565
- https://om.cachix.org
6666
direnv:
6767
required: true
68+
homebrew:
69+
enable: true
6870
develop:
6971
default:
7072
readme: |

0 commit comments

Comments
 (0)