Skip to content

Commit a27af9b

Browse files
committed
feat: add notification support to --ask flags
Change-Id: I6a6a69642ac3443525df583fd200827414801d41
1 parent 461c6d8 commit a27af9b

File tree

6 files changed

+178
-50
lines changed

6 files changed

+178
-50
lines changed

src/clean.rs

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ use tracing::{Level, debug, info, instrument, span, warn};
1919
use crate::{
2020
Result,
2121
commands::{Command, ElevationStrategy},
22-
interface,
22+
interface::{self, NotifyAskMode},
23+
notify::NotificationSender,
2324
};
2425

2526
// Nix impl:
@@ -306,12 +307,33 @@ impl interface::CleanMode {
306307
}
307308

308309
// Clean the paths
309-
if args.ask
310-
&& !Confirm::new("Confirm the cleanup plan?")
311-
.with_default(false)
312-
.prompt()?
313-
{
314-
bail!("User rejected the cleanup plan");
310+
if let Some(ask) = args.ask.as_ref() {
311+
let confirmation = match ask {
312+
NotifyAskMode::Prompt => {
313+
Confirm::new("Confirm the cleanup plan?")
314+
.with_default(false)
315+
.prompt()?
316+
},
317+
NotifyAskMode::Notify => {
318+
let clean_mode = match self {
319+
Self::Profile(_) => "profile",
320+
Self::All(_) => "all",
321+
Self::User(_) => "user",
322+
};
323+
324+
NotificationSender::new(
325+
&format!("nh clean {clean_mode}"),
326+
"Confirm the cleanup plan?",
327+
)
328+
.ask()
329+
.unwrap()
330+
},
331+
NotifyAskMode::Both => unimplemented!(),
332+
};
333+
334+
if !confirmation {
335+
bail!("User rejected the cleanup plan");
336+
}
315337
}
316338

317339
if !args.dry {

src/darwin.rs

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
1-
use std::{env, path::PathBuf};
1+
use std::{env, fmt, path::PathBuf};
22

33
use color_eyre::eyre::{Context, bail, eyre};
44
use tracing::{debug, warn};
55

66
use crate::{
77
Result,
8-
commands,
9-
commands::{Command, ElevationStrategy},
8+
commands::{self, Command, ElevationStrategy},
109
installable::Installable,
1110
interface::{
1211
DarwinArgs,
1312
DarwinRebuildArgs,
1413
DarwinReplArgs,
1514
DarwinSubcommand,
1615
DiffType,
16+
NotifyAskMode,
1717
},
1818
nixos::toplevel_for,
19+
notify::NotificationSender,
1920
update::update,
2021
util::{get_hostname, print_dix_diff},
2122
};
@@ -34,7 +35,7 @@ impl DarwinArgs {
3435
match self.subcommand {
3536
DarwinSubcommand::Switch(args) => args.rebuild(&Switch, elevation),
3637
DarwinSubcommand::Build(args) => {
37-
if args.common.ask || args.common.dry {
38+
if args.common.ask.is_some() || args.common.dry {
3839
warn!("`--ask` and `--dry` have no effect for `nh darwin build`");
3940
}
4041
args.rebuild(&Build, elevation)
@@ -49,6 +50,16 @@ enum DarwinRebuildVariant {
4950
Build,
5051
}
5152

53+
impl fmt::Display for DarwinRebuildVariant {
54+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
55+
let s = match self {
56+
DarwinRebuildVariant::Build => "build",
57+
DarwinRebuildVariant::Switch => "switch",
58+
};
59+
write!(f, "{s}")
60+
}
61+
}
62+
5263
impl DarwinRebuildArgs {
5364
fn rebuild(
5465
self,
@@ -144,13 +155,29 @@ impl DarwinRebuildArgs {
144155
let _ = print_dix_diff(&PathBuf::from(CURRENT_PROFILE), &target_profile);
145156
}
146157

147-
if self.common.ask && !self.common.dry && !matches!(variant, Build) {
148-
let confirmation = inquire::Confirm::new("Apply the config?")
149-
.with_default(false)
150-
.prompt()?;
158+
if !self.common.dry && !matches!(variant, Build) {
159+
if let Some(ask) = self.common.ask {
160+
let confirmation = match ask {
161+
NotifyAskMode::Prompt => {
162+
inquire::Confirm::new("Apply the config?")
163+
.with_default(false)
164+
.prompt()?
165+
},
166+
// MacOS doesn't support notification actions
167+
NotifyAskMode::Notify | NotifyAskMode::Both => {
168+
NotificationSender::new(&format!("nh darwin {variant}"), "testing")
169+
.send()
170+
.unwrap();
171+
172+
inquire::Confirm::new("Apply the config?")
173+
.with_default(false)
174+
.prompt()?
175+
},
176+
};
151177

152-
if !confirmation {
153-
bail!("User rejected the new config");
178+
if !confirmation {
179+
bail!("User rejected the new config");
180+
}
154181
}
155182
}
156183

src/home.rs

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{env, ffi::OsString, path::PathBuf};
1+
use std::{env, ffi::OsString, fmt, path::PathBuf};
22

33
use color_eyre::{
44
Result,
@@ -7,10 +7,17 @@ use color_eyre::{
77
use tracing::{debug, info, warn};
88

99
use crate::{
10-
commands,
11-
commands::Command,
10+
commands::{self, Command},
1211
installable::Installable,
13-
interface::{self, DiffType, HomeRebuildArgs, HomeReplArgs, HomeSubcommand},
12+
interface::{
13+
self,
14+
DiffType,
15+
HomeRebuildArgs,
16+
HomeReplArgs,
17+
HomeSubcommand,
18+
NotifyAskMode,
19+
},
20+
notify::NotificationSender,
1421
update::update,
1522
util::{get_hostname, print_dix_diff},
1623
};
@@ -26,7 +33,7 @@ impl interface::HomeArgs {
2633
match self.subcommand {
2734
HomeSubcommand::Switch(args) => args.rebuild(&Switch),
2835
HomeSubcommand::Build(args) => {
29-
if args.common.ask || args.common.dry {
36+
if args.common.ask.is_some() || args.common.dry {
3037
warn!("`--ask` and `--dry` have no effect for `nh home build`");
3138
}
3239
args.rebuild(&Build)
@@ -42,6 +49,16 @@ enum HomeRebuildVariant {
4249
Switch,
4350
}
4451

52+
impl fmt::Display for HomeRebuildVariant {
53+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
54+
let s = match self {
55+
HomeRebuildVariant::Build => "build",
56+
HomeRebuildVariant::Switch => "switch",
57+
};
58+
write!(f, "{s}")
59+
}
60+
}
61+
4562
impl HomeRebuildArgs {
4663
fn rebuild(self, variant: &HomeRebuildVariant) -> Result<()> {
4764
use HomeRebuildVariant::Build;
@@ -150,16 +167,26 @@ impl HomeRebuildArgs {
150167
}
151168

152169
if self.common.dry || matches!(variant, Build) {
153-
if self.common.ask {
170+
if self.common.ask.is_some() {
154171
warn!("--ask has no effect as dry run was requested");
155172
}
156173
return Ok(());
157174
}
158175

159-
if self.common.ask {
160-
let confirmation = inquire::Confirm::new("Apply the config?")
161-
.with_default(false)
162-
.prompt()?;
176+
if let Some(ask) = self.common.ask {
177+
let confirmation = match ask {
178+
NotifyAskMode::Prompt => {
179+
inquire::Confirm::new("Apply the config?")
180+
.with_default(false)
181+
.prompt()?
182+
},
183+
NotifyAskMode::Notify => {
184+
NotificationSender::new("nh os rollback", "testing")
185+
.ask()
186+
.unwrap()
187+
},
188+
NotifyAskMode::Both => unimplemented!(),
189+
};
163190

164191
if !confirmation {
165192
bail!("User rejected the new config");

src/interface.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -256,15 +256,25 @@ pub enum DiffType {
256256
Never,
257257
}
258258

259+
#[derive(Debug, Clone, ValueEnum, PartialEq)]
260+
pub enum NotifyAskMode {
261+
/// Ask in the terminal (stdin prompt)
262+
Prompt,
263+
/// Ask via a desktop notification action
264+
Notify,
265+
/// Show both notification and terminal prompt (fallback-safe)
266+
Both,
267+
}
268+
259269
#[derive(Debug, Args)]
260270
pub struct OsRollbackArgs {
261271
/// Only print actions, without performing them
262272
#[arg(long, short = 'n')]
263273
pub dry: bool,
264274

265275
/// Ask for confirmation
266-
#[arg(long, short)]
267-
pub ask: bool,
276+
#[arg(long, short, value_enum, default_missing_value = "prompt", num_args = 0..=1)]
277+
pub ask: Option<NotifyAskMode>,
268278

269279
/// Explicitly select some specialisation
270280
#[arg(long, short)]
@@ -295,8 +305,8 @@ pub struct CommonRebuildArgs {
295305
pub dry: bool,
296306

297307
/// Ask for confirmation
298-
#[arg(long, short)]
299-
pub ask: bool,
308+
#[arg(long, short, default_missing_value = "prompt", num_args = 0..=1)]
309+
pub ask: Option<NotifyAskMode>,
300310

301311
#[command(flatten)]
302312
pub installable: Installable,
@@ -427,8 +437,8 @@ pub struct CleanArgs {
427437
pub dry: bool,
428438

429439
/// Ask for confirmation
430-
#[arg(long, short)]
431-
pub ask: bool,
440+
#[arg(long, short, default_missing_value = "prompt", num_args = 0..=1)]
441+
pub ask: Option<NotifyAskMode>,
432442

433443
/// Don't run nix store --gc
434444
#[arg(long = "no-gc", alias = "nogc")]

0 commit comments

Comments
 (0)