feat(sudo): print warning if steps were skipped due to missing sudo

This commit is contained in:
Andre Toerien
2025-09-26 15:41:38 +02:00
committed by Gideon
parent a886d20a7b
commit ad9f2c2ccb
6 changed files with 91 additions and 17 deletions

View File

@@ -1138,14 +1138,46 @@ _version: 2
zh_CN: "Topgrade 不应以 root 身份运行,它会在需要时使用 sudo 或等效工具执行命令。"
zh_TW: "Topgrade 不應以 root 身份執行,它會在需要時使用 sudo 或等效工具執行命令。"
de: "Topgrade sollte nicht als Root ausgeführt werden, es führt Befehle mit sudo oder einem Äquivalent aus, wenn erforderlich."
"Require sudo or counterpart but not found, skip":
en: "Require sudo or counterpart but not found, skip"
lt: "Reikalingas sudo arba atitikmuo, bet nerasta, praleidžiama"
es: "Se requiere sudo o su equivalente pero no ha sido encontrado, omitiendo"
fr: "Nécessite sudo ou un équivalent mais n'a pas été trouvé, passé"
zh_CN: "找不到权限管理程序sudo 等),跳过"
zh_TW: "找不到權限管理程式sudo 等),略過"
de: "Benötigt sudo oder Äquivalent, aber nicht gefunden, überspringe"
"Could not find sudo":
en: "Could not find sudo"
lt: "Nepavyko rasti sudo"
es: "No se pudo encontrar sudo"
fr: "Impossible de trouver sudo"
zh_CN: "未找到 sudo"
zh_TW: "找不到 sudo"
de: "Konnte sudo nicht finden"
"Skipping step, sudo is required":
en: "Skipping step, sudo is required"
lt: "Žingsnis praleidžiamas, reikalingas sudo"
es: "Omitiendo paso, se requiere sudo"
fr: "Étape ignorée, sudo est requis"
zh_CN: "跳过步骤,需要 sudo"
zh_TW: "跳過步驟,需要 sudo"
de: "Schritt wird übersprungen, sudo ist erforderlich"
"\nSome steps were skipped as sudo or equivalent could not be found.":
en: "\nSome steps were skipped as sudo or equivalent could not be found."
lt: "\nKai kurie veiksmai buvo praleisti, nes nepavyko rasti sudo ar atitikmens."
es: "\nAlgunos pasos se omitieron porque no se pudo encontrar sudo o equivalente."
fr: "\nCertaines étapes ont été ignorées car sudo ou équivalent est introuvable."
zh_CN: "\n由于未找到 sudo 或等效工具,某些步骤被跳过。"
zh_TW: "\n由於找不到 sudo 或等效工具,某些步驟已跳過。"
de: "\nEinige Schritte wurden übersprungen, da sudo oder ein Äquivalent nicht gefunden wurde."
"Install one of `sudo`, `doas`, `pkexec`, `run0` or `please` to run these steps.":
en: "Install one of `sudo`, `doas`, `pkexec`, `run0` or `please` to run these steps."
lt: "Įdiekite vieną iš `sudo`, `doas`, `pkexec`, `run0` arba `please`, kad vykdytumėte šiuos veiksmus."
es: "Instale uno de `sudo`, `doas`, `pkexec`, `run0` o `please` para ejecutar estos pasos."
fr: "Installez lun de `sudo`, `doas`, `pkexec`, `run0` ou `please` pour exécuter ces étapes."
zh_CN: "请安装 `sudo`、`doas`、`pkexec`、`run0` 或 `please` 之一来运行这些步骤。"
zh_TW: "請安裝 `sudo`、`doas`、`pkexec`、`run0` 或 `please` 之一來執行這些步驟。"
de: "Installieren Sie `sudo`, `doas`, `pkexec`, `run0` oder `please`, um diese Schritte auszuführen."
"Install gsudo or enable Windows Sudo to run these steps.":
en: "Install gsudo or enable Windows Sudo to run these steps."
lt: "Įdiekite gsudo arba įjunkite Windows Sudo, kad vykdytumėte šiuos veiksmus."
es: "Instale gsudo o habilite Windows Sudo para ejecutar estos pasos."
fr: "Installez gsudo ou activez Windows Sudo pour exécuter ces étapes."
zh_CN: "请安装 gsudo 或启用 Windows Sudo 来运行这些步骤。"
zh_TW: "請安裝 gsudo 或啟用 Windows Sudo 來執行這些步驟。"
de: "Installieren Sie gsudo oder aktivieren Sie Windows Sudo, um diese Schritte auszuführen."
"{sudo_kind} does not support the {option} option":
en: "%{sudo_kind} does not support the %{option} option"
lt: "%{sudo_kind} nepalaiko parinkties %{option}"

View File

@@ -90,6 +90,15 @@ impl Display for UnsupportedSudo<'_> {
}
}
#[derive(Error, Debug)]
pub struct MissingSudo();
impl Display for MissingSudo {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", t!("Could not find sudo"))
}
}
#[derive(Error, Debug)]
pub struct DryRun();

View File

@@ -6,13 +6,14 @@ use std::ffi::OsStr;
use std::process::Command;
use std::sync::{LazyLock, Mutex};
use crate::executor::DryCommand;
use crate::config::Config;
use crate::error::MissingSudo;
use crate::executor::{DryCommand, Executor};
use crate::powershell::Powershell;
#[cfg(target_os = "linux")]
use crate::steps::linux::Distribution;
use crate::sudo::Sudo;
use crate::utils::require_option;
use crate::{config::Config, executor::Executor};
/// An enum telling whether Topgrade should perform dry runs or actually perform the steps.
#[derive(Clone, Copy, Debug)]
@@ -95,10 +96,11 @@ impl<'a> ExecutionContext<'a> {
}
pub fn require_sudo(&self) -> Result<&Sudo> {
require_option(
self.sudo.as_ref(),
t!("Require sudo or counterpart but not found, skip").to_string(),
)
if let Some(value) = self.sudo() {
Ok(value)
} else {
Err(MissingSudo().into())
}
}
pub fn config(&self) -> &Config {

View File

@@ -25,6 +25,7 @@ use self::config::{CommandLineArgs, Config};
use self::error::StepFailed;
#[cfg(all(windows, feature = "self-update"))]
use self::error::Upgraded;
use self::runner::StepResult;
#[allow(clippy::wildcard_imports)]
use self::steps::{remote::*, *};
use self::sudo::{Sudo, SudoKind};
@@ -224,12 +225,30 @@ fn run() -> Result<()> {
if !report.is_empty() {
print_separator(t!("Summary"));
let mut skipped_missing_sudo = false;
for (key, result) in report {
if !failed && result.failed() {
failed = true;
}
if let StepResult::SkippedMissingSudo = result {
skipped_missing_sudo = true;
}
print_result(key, result);
}
if skipped_missing_sudo {
print_warning(t!(
"\nSome steps were skipped as sudo or equivalent could not be found."
));
#[cfg(unix)]
print_warning(t!(
"Install one of `sudo`, `doas`, `pkexec`, `run0` or `please` to run these steps."
));
#[cfg(windows)]
print_warning(t!("Install gsudo or enable Windows Sudo to run these steps."));
}
}
#[cfg(target_os = "linux")]

View File

@@ -1,18 +1,20 @@
use color_eyre::eyre::Result;
use rust_i18n::t;
use std::borrow::Cow;
use std::fmt::Debug;
use tracing::debug;
use crate::ctrlc;
use crate::error::{DryRun, SkipStep};
use crate::error::{DryRun, MissingSudo, SkipStep};
use crate::execution_context::ExecutionContext;
use crate::step::Step;
use crate::terminal::{print_error, should_retry};
use crate::terminal::{print_error, print_warning, should_retry};
pub enum StepResult {
Success,
Failure,
Ignored,
SkippedMissingSudo,
Skipped(String),
}
@@ -21,7 +23,7 @@ impl StepResult {
use StepResult::*;
match self {
Success | Ignored | Skipped(_) => false,
Success | Ignored | Skipped(_) | SkippedMissingSudo => false,
Failure => true,
}
}
@@ -74,6 +76,11 @@ impl<'a> Runner<'a> {
break;
}
Err(e) if e.downcast_ref::<DryRun>().is_some() => break,
Err(e) if e.downcast_ref::<MissingSudo>().is_some() => {
print_warning(t!("Skipping step, sudo is required"));
self.push_result(key, StepResult::SkippedMissingSudo);
break;
}
Err(e) if e.downcast_ref::<SkipStep>().is_some() => {
if self.ctx.config().verbose() || self.ctx.config().show_skipped() {
self.push_result(key, StepResult::Skipped(e.to_string()));

View File

@@ -173,6 +173,11 @@ impl Terminal {
StepResult::Success => format!("{}", style(t!("OK")).bold().green()),
StepResult::Failure => format!("{}", style(t!("FAILED")).bold().red()),
StepResult::Ignored => format!("{}", style(t!("IGNORED")).bold().yellow()),
StepResult::SkippedMissingSudo => format!(
"{}: {}",
style(t!("SKIPPED")).bold().yellow(),
t!("Could not find sudo")
),
StepResult::Skipped(reason) => format!("{}: {}", style(t!("SKIPPED")).bold().blue(), reason),
}
))