|
1 | | -use std::env; |
| 1 | +use color_eyre::eyre::Context; |
| 2 | +use tracing::{debug, warn}; |
2 | 3 |
|
3 | | -use color_eyre::eyre::{bail, Context}; |
4 | | -use tracing::{debug, info, warn}; |
5 | | - |
6 | | -use crate::commands; |
7 | 4 | use crate::commands::Command; |
8 | | -use crate::installable::Installable; |
9 | 5 | use crate::interface::{DarwinArgs, DarwinRebuildArgs, DarwinReplArgs, DarwinSubcommand}; |
10 | | -use crate::nixos::toplevel_for; |
11 | 6 | use crate::update::update; |
12 | | -use crate::util::get_hostname; |
| 7 | +use crate::util::platform; |
13 | 8 | use crate::Result; |
14 | 9 |
|
15 | 10 | const SYSTEM_PROFILE: &str = "/nix/var/nix/profiles/system"; |
@@ -40,85 +35,65 @@ impl DarwinRebuildArgs { |
40 | 35 | fn rebuild(self, variant: DarwinRebuildVariant) -> Result<()> { |
41 | 36 | use DarwinRebuildVariant::{Build, Switch}; |
42 | 37 |
|
43 | | - if nix::unistd::Uid::effective().is_root() { |
44 | | - bail!("Don't run nh os as root. I will call sudo internally as needed"); |
45 | | - } |
| 38 | + // Ensure we're not running as root |
| 39 | + platform::check_not_root(false)?; |
46 | 40 |
|
47 | 41 | if self.update_args.update { |
48 | 42 | update(&self.common.installable, self.update_args.update_input)?; |
49 | 43 | } |
50 | 44 |
|
51 | | - let hostname = self.hostname.ok_or(()).or_else(|()| get_hostname())?; |
52 | | - |
53 | | - let out_path: Box<dyn crate::util::MaybeTempPath> = match self.common.out_link { |
54 | | - Some(ref p) => Box::new(p.clone()), |
55 | | - None => Box::new({ |
56 | | - let dir = tempfile::Builder::new().prefix("nh-os").tempdir()?; |
57 | | - (dir.as_ref().join("result"), dir) |
58 | | - }), |
59 | | - }; |
| 45 | + let hostname = self |
| 46 | + .hostname |
| 47 | + .ok_or(()) |
| 48 | + .or_else(|()| crate::util::get_hostname())?; |
60 | 49 |
|
| 50 | + // Set up temporary directory for build results |
| 51 | + let out_path = platform::create_output_path(self.common.out_link, "nh-os")?; |
61 | 52 | debug!(?out_path); |
62 | 53 |
|
63 | | - // Use NH_DARWIN_FLAKE if available, otherwise use the provided installable |
64 | | - let installable = if let Ok(darwin_flake) = env::var("NH_DARWIN_FLAKE") { |
65 | | - debug!("Using NH_DARWIN_FLAKE: {}", darwin_flake); |
66 | | - |
67 | | - let mut elems = darwin_flake.splitn(2, '#'); |
68 | | - let reference = elems.next().unwrap().to_owned(); |
69 | | - let attribute = elems |
70 | | - .next() |
71 | | - .map(crate::installable::parse_attribute) |
72 | | - .unwrap_or_default(); |
73 | | - |
74 | | - Installable::Flake { |
75 | | - reference, |
76 | | - attribute, |
77 | | - } |
78 | | - } else { |
79 | | - self.common.installable.clone() |
80 | | - }; |
81 | | - |
82 | | - let mut processed_installable = installable; |
83 | | - if let Installable::Flake { |
84 | | - ref mut attribute, .. |
85 | | - } = processed_installable |
86 | | - { |
87 | | - // If user explicitly selects some other attribute, don't push darwinConfigurations |
88 | | - if attribute.is_empty() { |
89 | | - attribute.push(String::from("darwinConfigurations")); |
90 | | - attribute.push(hostname.clone()); |
91 | | - } |
92 | | - } |
93 | | - |
94 | | - let toplevel = toplevel_for(hostname, processed_installable, "toplevel"); |
95 | | - |
96 | | - commands::Build::new(toplevel) |
97 | | - .extra_arg("--out-link") |
98 | | - .extra_arg(out_path.get_path()) |
99 | | - .extra_args(&self.extra_args) |
100 | | - .message("Building Darwin configuration") |
101 | | - .nom(!self.common.no_nom) |
102 | | - .run()?; |
| 54 | + // Check for environment variable override for flake path |
| 55 | + let installable = |
| 56 | + platform::resolve_env_installable("NH_DARWIN_FLAKE", self.common.installable.clone()); |
| 57 | + |
| 58 | + // Configure the installable for Darwin |
| 59 | + let toplevel = platform::extend_installable_for_platform( |
| 60 | + installable, |
| 61 | + "darwinConfigurations", |
| 62 | + &["toplevel"], |
| 63 | + Some(hostname), |
| 64 | + true, |
| 65 | + &self |
| 66 | + .extra_args |
| 67 | + .iter() |
| 68 | + .map(std::convert::Into::into) |
| 69 | + .collect::<Vec<_>>(), |
| 70 | + )?; |
| 71 | + |
| 72 | + // Build the nix-darwin configuration |
| 73 | + platform::build_configuration( |
| 74 | + toplevel, |
| 75 | + out_path.as_ref(), |
| 76 | + &self.extra_args, |
| 77 | + None, |
| 78 | + "Building Darwin configuration", |
| 79 | + self.common.no_nom, |
| 80 | + )?; |
103 | 81 |
|
104 | 82 | let target_profile = out_path.get_path().to_owned(); |
105 | | - |
106 | 83 | target_profile.try_exists().context("Doesn't exist")?; |
107 | 84 |
|
108 | | - Command::new("nvd") |
109 | | - .arg("diff") |
110 | | - .arg(CURRENT_PROFILE) |
111 | | - .arg(&target_profile) |
112 | | - .message("Comparing changes") |
113 | | - .run()?; |
114 | | - |
115 | | - if self.common.ask && !self.common.dry && !matches!(variant, Build) { |
116 | | - info!("Apply the config?"); |
117 | | - let confirmation = dialoguer::Confirm::new().default(false).interact()?; |
| 85 | + // Show diff between current and new configuration |
| 86 | + platform::compare_configurations( |
| 87 | + CURRENT_PROFILE, |
| 88 | + &target_profile, |
| 89 | + false, |
| 90 | + "Comparing changes", |
| 91 | + )?; |
118 | 92 |
|
119 | | - if !confirmation { |
120 | | - bail!("User rejected the new config"); |
121 | | - } |
| 93 | + // Ask for confirmation if needed |
| 94 | + if !platform::confirm_action(self.common.ask, self.common.dry)? && !matches!(variant, Build) |
| 95 | + { |
| 96 | + return Ok(()); |
122 | 97 | } |
123 | 98 |
|
124 | 99 | if matches!(variant, Switch) { |
@@ -159,46 +134,16 @@ impl DarwinRebuildArgs { |
159 | 134 |
|
160 | 135 | impl DarwinReplArgs { |
161 | 136 | fn run(self) -> Result<()> { |
162 | | - // Use NH_DARWIN_FLAKE if available, otherwise use the provided installable |
163 | | - let mut target_installable = if let Ok(darwin_flake) = env::var("NH_DARWIN_FLAKE") { |
164 | | - debug!("Using NH_DARWIN_FLAKE: {}", darwin_flake); |
165 | | - |
166 | | - let mut elems = darwin_flake.splitn(2, '#'); |
167 | | - let reference = elems.next().unwrap().to_owned(); |
168 | | - let attribute = elems |
169 | | - .next() |
170 | | - .map(crate::installable::parse_attribute) |
171 | | - .unwrap_or_default(); |
172 | | - |
173 | | - Installable::Flake { |
174 | | - reference, |
175 | | - attribute, |
176 | | - } |
177 | | - } else { |
178 | | - self.installable |
179 | | - }; |
180 | | - |
181 | | - if matches!(target_installable, Installable::Store { .. }) { |
182 | | - bail!("Nix doesn't support nix store installables."); |
183 | | - } |
184 | | - |
185 | | - let hostname = self.hostname.ok_or(()).or_else(|()| get_hostname())?; |
186 | | - |
187 | | - if let Installable::Flake { |
188 | | - ref mut attribute, .. |
189 | | - } = target_installable |
190 | | - { |
191 | | - if attribute.is_empty() { |
192 | | - attribute.push(String::from("darwinConfigurations")); |
193 | | - attribute.push(hostname); |
194 | | - } |
195 | | - } |
196 | | - |
197 | | - Command::new("nix") |
198 | | - .arg("repl") |
199 | | - .args(target_installable.to_args()) |
200 | | - .run()?; |
201 | | - |
202 | | - Ok(()) |
| 137 | + // Check for environment variable override for flake path |
| 138 | + let installable = platform::resolve_env_installable("NH_DARWIN_FLAKE", self.installable); |
| 139 | + |
| 140 | + // Launch the nix REPL with the Darwin configuration |
| 141 | + platform::run_repl( |
| 142 | + installable, |
| 143 | + "darwinConfigurations", |
| 144 | + &["toplevel"], |
| 145 | + self.hostname, |
| 146 | + &[], |
| 147 | + ) |
203 | 148 | } |
204 | 149 | } |
0 commit comments