Skip to content

Commit 9bfb22f

Browse files
committed
unbreak darwin(?)
1 parent dc3be5c commit 9bfb22f

File tree

2 files changed

+97
-43
lines changed

2 files changed

+97
-43
lines changed

src/darwin.rs

Lines changed: 41 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
use color_eyre::eyre::bail;
2-
use color_eyre::Result;
3-
use tracing::{debug, info, warn};
1+
use color_eyre::eyre::{bail, Context};
2+
use tracing::{debug, warn};
43

54
use crate::commands::Command;
5+
use crate::installable::Installable;
66
use crate::interface::{DarwinArgs, DarwinRebuildArgs, DarwinReplArgs, DarwinSubcommand};
77
use crate::update::update;
8+
use crate::util::get_hostname;
89
use crate::util::platform;
10+
use crate::Result;
911

1012
const SYSTEM_PROFILE: &str = "/nix/var/nix/profiles/system";
1113
const CURRENT_PROFILE: &str = "/run/current-system";
@@ -35,69 +37,70 @@ impl DarwinRebuildArgs {
3537
fn rebuild(self, variant: DarwinRebuildVariant) -> Result<()> {
3638
use DarwinRebuildVariant::{Build, Switch};
3739

38-
// Check if we're running as root
40+
// Check if running as root
3941
platform::check_not_root(false)?;
4042

4143
if self.update_args.update {
4244
update(&self.common.installable, self.update_args.update_input)?;
4345
}
4446

45-
// Get the hostname
46-
let (hostname, _) = platform::get_target_hostname(self.hostname, false)?;
47+
let hostname = self.hostname.ok_or(()).or_else(|()| get_hostname())?;
4748

48-
// Create output path
49+
// Create temporary output path
4950
let out_path = platform::create_output_path(self.common.out_link, "nh-darwin")?;
5051
debug!(?out_path);
5152

52-
// Use NH_DARWIN_FLAKE if available, otherwise use the provided installable
53+
// Resolve the installable from env var or from the provided argument
5354
let installable =
5455
platform::resolve_env_installable("NH_DARWIN_FLAKE", self.common.installable.clone());
5556

56-
// Build the configuration
57-
let _target_profile = platform::handle_rebuild_workflow(
57+
// Build the darwin configuration with proper attribute path handling
58+
let target_profile = platform::handle_rebuild_workflow(
5859
installable,
5960
"darwinConfigurations",
6061
&["toplevel"],
6162
Some(hostname),
6263
out_path.as_ref(),
6364
&self.extra_args,
64-
None, // No builder
65+
None, // Darwin doesn't use remote builders
6566
"Building Darwin configuration",
6667
self.common.no_nom,
67-
"", // No specialisation path for Darwin
68-
false, // No specialisation
69-
None, // No specialisation
68+
"", // Darwin doesn't use specialisations like NixOS
69+
false,
70+
None,
7071
CURRENT_PROFILE,
71-
false, // Don't skip comparison
72+
false,
7273
)?;
7374

74-
if self.common.ask && !self.common.dry && !matches!(variant, Build) {
75-
info!("Apply the config?");
76-
let confirmation = dialoguer::Confirm::new().default(false).interact()?;
77-
78-
if !confirmation {
79-
bail!("User rejected the new config");
80-
}
75+
// Allow users to confirm before applying changes
76+
if !platform::confirm_action(
77+
self.common.ask && !matches!(variant, Build),
78+
self.common.dry,
79+
)? {
80+
return Ok(());
8181
}
8282

83-
if matches!(variant, Switch) && !self.common.dry {
83+
if matches!(variant, Switch) {
8484
Command::new("nix")
8585
.args(["build", "--no-link", "--profile", SYSTEM_PROFILE])
86-
.arg(out_path.get_path())
86+
.arg(&target_profile)
8787
.elevate(true)
8888
.dry(self.common.dry)
8989
.run()?;
9090

91-
let darwin_rebuild = out_path.get_path().join("sw/bin/darwin-rebuild");
92-
let activate_user = out_path.get_path().join("activate-user");
91+
let darwin_rebuild = target_profile.join("sw/bin/darwin-rebuild");
92+
let activate_user = target_profile.join("activate-user");
9393

94-
// Determine if we need to elevate privileges
95-
let needs_elevation = !activate_user.try_exists().unwrap_or(false)
94+
// Darwin activation may or may not need root privileges
95+
// This checks if we need elevation based on the activation-user script
96+
let needs_elevation = !activate_user
97+
.try_exists()
98+
.context("Failed to check if activate-user file exists")?
9699
|| std::fs::read_to_string(&activate_user)
97-
.unwrap_or_default()
100+
.context("Failed to read activate-user file")?
98101
.contains("# nix-darwin: deprecated");
99102

100-
// Create and run the activation command with or without elevation
103+
// Actually activate the configuration using darwin-rebuild
101104
Command::new(darwin_rebuild)
102105
.arg("activate")
103106
.message("Activating configuration")
@@ -108,30 +111,26 @@ impl DarwinRebuildArgs {
108111

109112
// Make sure out_path is not accidentally dropped
110113
// https://docs.rs/tempfile/3.12.0/tempfile/index.html#early-drop-pitfall
111-
drop(out_path);
112114

113115
Ok(())
114116
}
115117
}
116118

117119
impl DarwinReplArgs {
118120
fn run(self) -> Result<()> {
119-
// Use NH_DARWIN_FLAKE if available, otherwise use the provided installable
120-
let installable = platform::resolve_env_installable("NH_DARWIN_FLAKE", self.installable);
121+
if let Installable::Store { .. } = self.installable {
122+
bail!("Nix doesn't support nix store installables.");
123+
}
121124

122-
// Get hostname for the configuration
123-
let hostname = match self.hostname {
124-
Some(h) => h,
125-
None => crate::util::get_hostname()?,
126-
};
125+
let hostname = self.hostname.ok_or(()).or_else(|()| get_hostname())?;
127126

128-
// Start an interactive Nix REPL with the darwin configuration
127+
// Open an interactive REPL session for exploring darwin configurations
129128
platform::run_repl(
130-
installable,
129+
platform::resolve_env_installable("NH_DARWIN_FLAKE", self.installable),
131130
"darwinConfigurations",
132-
&[], // No extra path needed
131+
&[], // REPL doesn't need additional path elements
133132
Some(hostname),
134-
&[], // No extra arguments
133+
&[], // No extra REPL args
135134
)
136135
}
137136
}

src/util/platform.rs

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,61 @@ pub fn handle_rebuild_workflow(
354354
current_profile: &str,
355355
skip_compare: bool,
356356
) -> Result<PathBuf> {
357+
// Darwin configurations have a different structure that requires special handling
358+
if config_type == "darwinConfigurations" {
359+
// First construct the proper attribute path for darwin configs
360+
let mut processed_installable = installable;
361+
if let Installable::Flake {
362+
ref mut attribute, ..
363+
} = processed_installable
364+
{
365+
// Only set the attribute path if user hasn't already specified one
366+
if attribute.is_empty() {
367+
attribute.push(String::from(config_type));
368+
if let Some(name) = config_name {
369+
attribute.push(name);
370+
}
371+
}
372+
}
373+
374+
// Next, add config.system.build.<attr> to the path to access the derivation
375+
let mut toplevel_attr = processed_installable;
376+
if let Installable::Flake {
377+
ref mut attribute, ..
378+
} = toplevel_attr
379+
{
380+
// All darwin configurations expose their outputs under system.build
381+
let toplevel_path = ["config", "system", "build"];
382+
attribute.extend(toplevel_path.iter().map(|s| s.to_string()));
383+
384+
// Add the final component (usually "toplevel")
385+
if !extra_path.is_empty() {
386+
attribute.push(extra_path[0].to_string());
387+
}
388+
}
389+
390+
// Build the configuration
391+
build_configuration(
392+
toplevel_attr,
393+
out_path,
394+
extra_args,
395+
builder,
396+
message,
397+
no_nom,
398+
)?;
399+
400+
// Darwin doesn't use the specialisation mechanism like NixOS
401+
let target_profile = out_path.get_path().to_owned();
402+
403+
// Run the diff to show changes
404+
if !skip_compare {
405+
compare_configurations(current_profile, &target_profile, false, "Comparing changes")?;
406+
}
407+
408+
return Ok(target_profile);
409+
}
410+
411+
// NixOS and Home Manager follow a different pattern
357412
// Configure the installable with platform-specific attributes
358413
let configured_installable = extend_installable_for_platform(
359414
installable,
@@ -378,7 +433,7 @@ pub fn handle_rebuild_workflow(
378433
no_nom,
379434
)?;
380435

381-
// Process any specialisations
436+
// Process any specialisations (NixOS/Home-Manager specific feature)
382437
let target_specialisation =
383438
process_specialisation(no_specialisation, specialisation, specialisation_path)?;
384439

0 commit comments

Comments
 (0)