Skip to content

Commit 1444215

Browse files
committed
feat: add notification support to --ask flags
Change-Id: I6a6a69642ac3443525df583fd200827414801d41
1 parent 19179ac commit 1444215

File tree

9 files changed

+168
-56
lines changed

9 files changed

+168
-56
lines changed

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,8 @@ hostname = "0.4.1"
3838
humantime = "2.3.0"
3939
inquire = { default-features = false, version = "0.9.1", features = [ "crossterm" ] }
4040
nix = { default-features = false, features = [ "fs", "user" ], version = "0.30.1" }
41-
yansi = "1.0.1"
42-
regex = "1.11.3"
4341
notify-rust = "4.11.7"
42+
regex = "1.11.3"
4443
reqwest = { default-features = false, features = [
4544
"rustls-tls-native-roots",
4645
"blocking",
@@ -58,6 +57,7 @@ thiserror = "2.0.17"
5857
tracing = "0.1.41"
5958
tracing-subscriber = { features = [ "env-filter", "registry", "std" ], version = "0.3.20" }
6059
which = "8.0.0"
60+
yansi = "1.0.1"
6161

6262
[target.'cfg(target_os="macos")'.dependencies]
6363
system-configuration = "0.6.1"

src/clean.rs

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ use yansi::{Color, Paint};
2020
use crate::{
2121
Result,
2222
commands::{Command, ElevationStrategy},
23-
interface,
23+
interface::{self, NotifyAskMode},
2424
nh_info,
25+
notify::NotificationSender,
2526
};
2627

2728
// Nix impl:
@@ -334,12 +335,26 @@ impl interface::CleanMode {
334335
}
335336

336337
// Clean the paths
337-
if args.ask
338-
&& !Confirm::new("Confirm the cleanup plan?")
339-
.with_default(false)
340-
.prompt()?
341-
{
342-
bail!("User rejected the cleanup plan");
338+
if let Some(ask) = &args.ask {
339+
let confirmation = match ask {
340+
NotifyAskMode::Prompt => {
341+
Confirm::new("Confirm the cleanup plan?")
342+
.with_default(false)
343+
.prompt()?
344+
},
345+
NotifyAskMode::Notify => {
346+
NotificationSender::new(
347+
"nh clean",
348+
"Do you want to confirm the cleanup plan?",
349+
)
350+
.ask()
351+
},
352+
NotifyAskMode::Both => unimplemented!(),
353+
};
354+
355+
if !confirmation {
356+
bail!("User rejected the cleanup plan");
357+
}
343358
}
344359

345360
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: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,16 @@ use crate::{
1010
commands,
1111
commands::Command,
1212
installable::Installable,
13-
interface::{self, DiffType, HomeRebuildArgs, HomeReplArgs, HomeSubcommand},
13+
interface::{
14+
self,
15+
DiffType,
16+
HomeRebuildArgs,
17+
HomeReplArgs,
18+
HomeSubcommand,
19+
NotifyAskMode,
20+
},
1421
nh_info,
22+
notify::NotificationSender,
1523
update::update,
1624
util::{get_hostname, print_dix_diff},
1725
};
@@ -27,7 +35,7 @@ impl interface::HomeArgs {
2735
match self.subcommand {
2836
HomeSubcommand::Switch(args) => args.rebuild(&Switch),
2937
HomeSubcommand::Build(args) => {
30-
if args.common.ask || args.common.dry {
38+
if args.common.ask.is_some() || args.common.dry {
3139
warn!("`--ask` and `--dry` have no effect for `nh home build`");
3240
}
3341
args.rebuild(&Build)
@@ -151,16 +159,28 @@ impl HomeRebuildArgs {
151159
}
152160

153161
if self.common.dry || matches!(variant, Build) {
154-
if self.common.ask {
162+
if self.common.ask.is_some() {
155163
warn!("--ask has no effect as dry run was requested");
156164
}
157165
return Ok(());
158166
}
159167

160-
if self.common.ask {
161-
let confirmation = inquire::Confirm::new("Apply the config?")
162-
.with_default(false)
163-
.prompt()?;
168+
if let Some(ask) = &self.common.ask {
169+
let confirmation = match ask {
170+
NotifyAskMode::Prompt => {
171+
inquire::Confirm::new("Apply the config?")
172+
.with_default(false)
173+
.prompt()?
174+
},
175+
NotifyAskMode::Notify => {
176+
NotificationSender::new(
177+
"nh home switch",
178+
"Do you want to apply the Home Manager configuration?",
179+
)
180+
.ask()
181+
},
182+
NotifyAskMode::Both => unimplemented!(),
183+
};
164184

165185
if !confirmation {
166186
bail!("User rejected the new config");

src/interface.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -264,15 +264,25 @@ pub enum DiffType {
264264
Never,
265265
}
266266

267+
#[derive(Debug, Clone, ValueEnum, PartialEq)]
268+
pub enum NotifyAskMode {
269+
/// Ask in the terminal (stdin prompt)
270+
Prompt,
271+
/// Ask via a desktop notification action
272+
Notify,
273+
/// Show both notification and terminal prompt (fallback-safe)
274+
Both,
275+
}
276+
267277
#[derive(Debug, Args)]
268278
pub struct OsRollbackArgs {
269279
/// Only print actions, without performing them
270280
#[arg(long, short = 'n')]
271281
pub dry: bool,
272282

273283
/// Ask for confirmation
274-
#[arg(long, short)]
275-
pub ask: bool,
284+
#[arg(long, short, value_enum, default_missing_value = "prompt", num_args = 0..=1)]
285+
pub ask: Option<NotifyAskMode>,
276286

277287
/// Explicitly select some specialisation
278288
#[arg(long, short)]
@@ -303,8 +313,8 @@ pub struct CommonRebuildArgs {
303313
pub dry: bool,
304314

305315
/// Ask for confirmation
306-
#[arg(long, short)]
307-
pub ask: bool,
316+
#[arg(long, short, default_missing_value = "prompt", num_args = 0..=1)]
317+
pub ask: Option<NotifyAskMode>,
308318

309319
#[command(flatten)]
310320
pub installable: Installable,
@@ -435,8 +445,8 @@ pub struct CleanArgs {
435445
pub dry: bool,
436446

437447
/// Ask for confirmation
438-
#[arg(long, short)]
439-
pub ask: bool,
448+
#[arg(long, short, default_missing_value = "prompt", num_args = 0..=1)]
449+
pub ask: Option<NotifyAskMode>,
440450

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

src/logging.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,15 @@ where
3131

3232
match *level {
3333
Level::ERROR => {
34-
write!(writer, "{} ", Paint::new("ERROR").fg(Color::Red))?
34+
write!(writer, "{} ", Paint::new("ERROR").fg(Color::Red))?;
3535
},
3636
Level::WARN => write!(writer, "{} ", Paint::new("!").fg(Color::Yellow))?,
3737
Level::INFO => write!(writer, "{} ", Paint::new(">").fg(Color::Green))?,
3838
Level::DEBUG => {
39-
write!(writer, "{} ", Paint::new("DEBUG").fg(Color::Blue))?
39+
write!(writer, "{} ", Paint::new("DEBUG").fg(Color::Blue))?;
4040
},
4141
Level::TRACE => {
42-
write!(writer, "{} ", Paint::new("TRACE").fg(Color::Cyan))?
42+
write!(writer, "{} ", Paint::new("TRACE").fg(Color::Cyan))?;
4343
},
4444
}
4545

@@ -99,7 +99,7 @@ pub fn setup_logging(
9999
macro_rules! nh_info {
100100
($($arg:tt)*) => {{
101101
use notify_rust::Urgency;
102-
use crate::notify::NotificationSender;
102+
use $crate::notify::NotificationSender;
103103
let message = format!($($arg)*);
104104
tracing::info!($($arg)*);
105105
NotificationSender::new("nh info", &message).urgency(Urgency::Normal).send().unwrap();
@@ -110,7 +110,7 @@ macro_rules! nh_info {
110110
macro_rules! nh_warn {
111111
($($arg:tt)*) => {{
112112
use notify_rust::Urgency;
113-
use crate::notify::NotificationSender;
113+
use $crate::notify::NotificationSender;
114114
let message = format!($($arg)*);
115115
tracing::warn!($($arg)*);
116116
NotificationSender::new("nh warn", &message).urgency(Urgency::Normal).send().unwrap();

0 commit comments

Comments
 (0)