From 4d8dc69e7f04817b148c0dfcd32f91b1a320ab95 Mon Sep 17 00:00:00 2001 From: Roey Darwish Dror Date: Mon, 15 Jun 2020 15:43:59 +0300 Subject: [PATCH] Ask before installing macOS upgrades (#433) --- src/main.rs | 5 +++-- src/steps/os/macos.rs | 52 ++++++++++++++++++++++++++++++++++++------- src/terminal.rs | 22 ++++++++++++++++++ 3 files changed, 69 insertions(+), 10 deletions(-) diff --git a/src/main.rs b/src/main.rs index 31810136..2e821db9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -141,6 +141,8 @@ fn run() -> Result<()> { #[cfg(unix)] { if config.should_run(Step::PackageManagers) { + #[cfg(target_os = "macos")] + runner.execute("Microsoft AutoUpdate", || macos::run_msupdate(&ctx))?; runner.execute("brew", || unix::run_homebrew(&ctx))?; #[cfg(target_os = "macos")] runner.execute("MacPorts", || macos::run_macports(&ctx))?; @@ -361,9 +363,8 @@ fn run() -> Result<()> { #[cfg(target_os = "macos")] { if config.should_run(Step::System) { - runner.execute("Microsoft AutoUpdate", || macos::run_msupdate(&ctx))?; runner.execute("App Store", || macos::run_mas(run_type))?; - runner.execute("System upgrade", || macos::upgrade_macos(run_type))?; + runner.execute("System upgrade", || macos::upgrade_macos(&ctx))?; } } diff --git a/src/steps/os/macos.rs b/src/steps/os/macos.rs index 62ff21ef..dc240c9f 100644 --- a/src/steps/os/macos.rs +++ b/src/steps/os/macos.rs @@ -1,9 +1,13 @@ use crate::execution_context::ExecutionContext; use crate::executor::RunType; -use crate::terminal::print_separator; -use crate::utils::{require, PathExt}; +use crate::terminal::{print_separator, prompt_yesno}; +use crate::{ + error::{SkipStep, TopgradeError}, + utils::{require, PathExt}, +}; use anyhow::Result; -use std::path::Path; +use log::debug; +use std::{path::Path, process::Command}; pub fn run_msupdate(ctx: &ExecutionContext) -> Result<()> { let msupdate = @@ -41,11 +45,43 @@ pub fn run_mas(run_type: RunType) -> Result<()> { run_type.execute(mas).arg("upgrade").check_run() } -pub fn upgrade_macos(run_type: RunType) -> Result<()> { +pub fn upgrade_macos(ctx: &ExecutionContext) -> Result<()> { print_separator("macOS system update"); - run_type - .execute("softwareupdate") - .args(&["--install", "--all"]) - .check_run() + let should_ask = !(ctx.config().yes()) || (ctx.config().dry_run()); + if should_ask { + println!("Finding available software"); + if system_update_available()? { + let answer = prompt_yesno("A system update is available. Do you wish to install it?")?; + if !answer { + return Err(SkipStep.into()); + } + println!(); + } else { + println!("No new software available."); + return Err(SkipStep.into()); + } + } + + let mut command = ctx.run_type().execute("softwareupdate"); + command.args(&["--install", "--all"]); + + if should_ask { + command.arg("--no-scan"); + } + + command.check_run() +} + +fn system_update_available() -> Result { + let output = Command::new("softwareupdate").arg("--list").output()?; + debug!("{:?}", output); + + let status = output.status; + if !status.success() { + return Err(TopgradeError::ProcessFailed(status).into()); + } + let string_output = String::from_utf8(output.stderr)?; + debug!("{:?}", string_output); + Ok(!string_output.contains("No new software available")) } diff --git a/src/terminal.rs b/src/terminal.rs index 09404927..e78660ed 100644 --- a/src/terminal.rs +++ b/src/terminal.rs @@ -176,6 +176,23 @@ impl Terminal { .ok(); } + #[allow(dead_code)] + fn prompt_yesno(&mut self, question: &str) -> Result { + self.term + .write_fmt(format_args!( + "{}", + style(format!("{} (y)es/(N)o", question,)).yellow().bold() + )) + .ok(); + + loop { + match self.term.read_char()? { + 'y' | 'Y' => break Ok(true), + 'n' | 'N' | '\r' | '\n' => break Ok(false), + _ => (), + } + } + } #[allow(unused_variables)] fn should_retry(&mut self, interrupted: bool, step_name: &str) -> Result { if self.width.is_none() { @@ -275,3 +292,8 @@ pub fn set_desktop_notifications(desktop_notifications: bool) { .unwrap() .set_desktop_notifications(desktop_notifications); } + +#[allow(dead_code)] +pub fn prompt_yesno(question: &str) -> Result { + TERMINAL.lock().unwrap().prompt_yesno(question) +}