feat: add damp run type (#1217)
Co-authored-by: Stuart Reilly <sreilly@scottlogic.com>
This commit is contained in:
2
.github/ISSUE_TEMPLATE/feature_request.md
vendored
2
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -18,8 +18,10 @@ assignees: ''
|
|||||||
option to skip this step?
|
option to skip this step?
|
||||||
|
|
||||||
## I want to suggest some general feature
|
## I want to suggest some general feature
|
||||||
|
|
||||||
Topgrade should...
|
Topgrade should...
|
||||||
|
|
||||||
## More information
|
## More information
|
||||||
|
|
||||||
<!-- Assuming that someone else implements the feature,
|
<!-- Assuming that someone else implements the feature,
|
||||||
please state if you know how to test it from a side branch of Topgrade. -->
|
please state if you know how to test it from a side branch of Topgrade. -->
|
||||||
|
|||||||
1
.github/PULL_REQUEST_TEMPLATE.md
vendored
1
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,6 +1,5 @@
|
|||||||
## What does this PR do
|
## What does this PR do
|
||||||
|
|
||||||
|
|
||||||
## Standards checklist
|
## Standards checklist
|
||||||
|
|
||||||
- [ ] The PR title is descriptive
|
- [ ] The PR title is descriptive
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5.0.0
|
- uses: actions/checkout@v5.0.0
|
||||||
- run: |
|
- run: |
|
||||||
CONFIG_PATH=~/.config/topgrade.toml;
|
CONFIG_PATH=~/.config/topgrade.toml;
|
||||||
if [ -f "$CONFIG_PATH" ]; then rm $CONFIG_PATH; fi
|
if [ -f "$CONFIG_PATH" ]; then rm $CONFIG_PATH; fi
|
||||||
cargo build;
|
cargo build;
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
1. The `jet_brains_toolbox` step was renamed to `jetbrains_toolbox`. If you're
|
1. The `jet_brains_toolbox` step was renamed to `jetbrains_toolbox`. If you're
|
||||||
using the old name in your configuration file in the `disable` or `only`
|
using the old name in your configuration file in the `disable` or `only`
|
||||||
fields, simply change it to `jetbrains_toolbox`.
|
fields, simply change it to `jetbrains_toolbox`.
|
||||||
@@ -16,6 +16,22 @@ _version: 2
|
|||||||
zh_CN: "正在模拟 %{program_name} %{arguments} 的运行过程"
|
zh_CN: "正在模拟 %{program_name} %{arguments} 的运行过程"
|
||||||
zh_TW: "正在模擬 %{program_name} %{arguments} 的執行過程"
|
zh_TW: "正在模擬 %{program_name} %{arguments} 的執行過程"
|
||||||
de: "Testlauf: %{program_name} %{arguments}"
|
de: "Testlauf: %{program_name} %{arguments}"
|
||||||
|
"Executing: {program_name} {arguments}":
|
||||||
|
en: "Executing: %{program_name} %{arguments}"
|
||||||
|
lt: "Vykdymas: %{program_name} %{arguments}"
|
||||||
|
es: "Ejecutando: %{program_name} %{arguments}"
|
||||||
|
fr: "Exécution: %{program_name} %{arguments}"
|
||||||
|
zh_CN: "执行: %{program_name} %{arguments}"
|
||||||
|
zh_TW: "执行: %{program_name} %{arguments}"
|
||||||
|
de: "Ausführung: %{program_name} %{arguments}"
|
||||||
|
"with env: {env}":
|
||||||
|
en: "with env: %{env}"
|
||||||
|
lt: "su env: %{env}"
|
||||||
|
es: "con env: %{env}"
|
||||||
|
fr: "avec env: %{env}"
|
||||||
|
zh_CN: "与env: %{env}"
|
||||||
|
zh_TW: "与env: %{env}"
|
||||||
|
de: "mit env: %{env}"
|
||||||
"in {directory}":
|
"in {directory}":
|
||||||
en: "in %{directory}"
|
en: "in %{directory}"
|
||||||
lt: "kataloge %{directory}"
|
lt: "kataloge %{directory}"
|
||||||
@@ -1298,30 +1314,14 @@ _version: 2
|
|||||||
zh_CN: "Windows 更新"
|
zh_CN: "Windows 更新"
|
||||||
zh_TW: "Windows 更新"
|
zh_TW: "Windows 更新"
|
||||||
de: "Windows-Update"
|
de: "Windows-Update"
|
||||||
"Would check if OpenBSD is -current":
|
"Checking if /etc/motd contains -current or -beta":
|
||||||
en: "Would check if OpenBSD is -current"
|
en: "Checking if /etc/motd contains -current or -beta"
|
||||||
lt: "Patikrintų, ar OpenBSD yra -current"
|
lt: "Tikrinimas, jei /etc/motd yra -current arba -beta"
|
||||||
es: "Comprobaría si OpenBSD está en -current"
|
es: "Comprobación de si /etc/motd contiene -current o -beta"
|
||||||
fr: "Vérifierait si OpenBSD est à -curent"
|
fr: "Vérification si /etc/motd contient -current ou -beta"
|
||||||
zh_CN: "将检查 OpenBSD 是否为 -current"
|
zh_CN: "检查 /etc/motd 是否包含 -current 或 -beta"
|
||||||
zh_TW: "會檢查 OpenBSD 是否為 -current"
|
zh_TW: "检查 /etc/motd 是否包含 -current 或 -beta"
|
||||||
de: "Würde überprüfen, ob OpenBSD -current ist"
|
de: "Überprüfen, ob /etc/motd -current oder -beta enthält"
|
||||||
"Would upgrade the OpenBSD system":
|
|
||||||
en: "Would upgrade the OpenBSD system"
|
|
||||||
lt: "Atnaujintų OpenBSD sistemą"
|
|
||||||
es: "Actualizaría el sistema OpenBSD"
|
|
||||||
fr: "Mettrait à jour le système OpenBSD"
|
|
||||||
zh_CN: "将升级 OpenBSD 系统"
|
|
||||||
zh_TW: "會升級 OpenBSD 系統"
|
|
||||||
de: "Würde das OpenBSD-System aktualisieren"
|
|
||||||
"Would upgrade OpenBSD packages":
|
|
||||||
en: "Would upgrade OpenBSD packages"
|
|
||||||
lt: "Atnaujintų OpenBSD paketus"
|
|
||||||
es: "Actualizaría los paquetes de OpenBSD"
|
|
||||||
fr: "Mettrait à jour les paquets OpenBSD"
|
|
||||||
zh_CN: "将升级 OpenBSD 软件包"
|
|
||||||
zh_TW: "會升級 OpenBSD 套件"
|
|
||||||
de: "Würde OpenBSD-Pakete aktualisieren"
|
|
||||||
"Microsoft Store":
|
"Microsoft Store":
|
||||||
en: "Microsoft Store"
|
en: "Microsoft Store"
|
||||||
lt: "Microsoft parduotuvė"
|
lt: "Microsoft parduotuvė"
|
||||||
|
|||||||
@@ -18,14 +18,15 @@ use regex_split::RegexSplit;
|
|||||||
use rust_i18n::t;
|
use rust_i18n::t;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
|
use tracing::{debug, error};
|
||||||
use which_crate::which;
|
use which_crate::which;
|
||||||
|
|
||||||
use super::utils::editor;
|
use super::utils::editor;
|
||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
|
use crate::execution_context::RunType;
|
||||||
use crate::step::Step;
|
use crate::step::Step;
|
||||||
use crate::sudo::SudoKind;
|
use crate::sudo::SudoKind;
|
||||||
use crate::utils::string_prepend_str;
|
use crate::utils::string_prepend_str;
|
||||||
use tracing::{debug, error};
|
|
||||||
|
|
||||||
// TODO: Add i18n to this. Tracking issue: https://github.com/topgrade-rs/topgrade/issues/859
|
// TODO: Add i18n to this. Tracking issue: https://github.com/topgrade-rs/topgrade/issues/859
|
||||||
pub static EXAMPLE_CONFIG: &str = include_str!("../config.example.toml");
|
pub static EXAMPLE_CONFIG: &str = include_str!("../config.example.toml");
|
||||||
@@ -708,9 +709,15 @@ pub struct CommandLineArgs {
|
|||||||
cleanup: bool,
|
cleanup: bool,
|
||||||
|
|
||||||
/// Print what would be done
|
/// Print what would be done
|
||||||
|
///
|
||||||
|
/// Alias for --run-type dry
|
||||||
#[arg(short = 'n', long = "dry-run")]
|
#[arg(short = 'n', long = "dry-run")]
|
||||||
dry_run: bool,
|
dry_run: bool,
|
||||||
|
|
||||||
|
/// Pick between just running commands, running and logging commands, and just logging commands
|
||||||
|
#[arg(short = 'r', long = "run-type", value_enum, default_value_t)]
|
||||||
|
run_type: RunType,
|
||||||
|
|
||||||
/// Do not ask to retry failed steps
|
/// Do not ask to retry failed steps
|
||||||
#[arg(long = "no-retry")]
|
#[arg(long = "no-retry")]
|
||||||
no_retry: bool,
|
no_retry: bool,
|
||||||
@@ -1001,9 +1008,13 @@ impl Config {
|
|||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tell whether we are dry-running.
|
/// Get the [RunType] for the current execution
|
||||||
pub fn dry_run(&self) -> bool {
|
pub fn run_type(&self) -> RunType {
|
||||||
self.opt.dry_run
|
if self.opt.dry_run {
|
||||||
|
RunType::Dry
|
||||||
|
} else {
|
||||||
|
self.opt.run_type
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tell whether we should not attempt to retry anything.
|
/// Tell whether we should not attempt to retry anything.
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
use color_eyre::eyre::Result;
|
|
||||||
use rust_i18n::t;
|
|
||||||
use std::env::var;
|
use std::env::var;
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::sync::{LazyLock, Mutex};
|
use std::sync::{LazyLock, Mutex};
|
||||||
|
|
||||||
|
use clap::ValueEnum;
|
||||||
|
use color_eyre::eyre::Result;
|
||||||
|
use rust_i18n::t;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use strum::EnumString;
|
||||||
|
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::error::MissingSudo;
|
use crate::error::MissingSudo;
|
||||||
use crate::executor::{DryCommand, Executor};
|
use crate::executor::{DryCommand, Executor};
|
||||||
@@ -16,30 +20,26 @@ use crate::sudo::Sudo;
|
|||||||
use crate::utils::require_option;
|
use crate::utils::require_option;
|
||||||
|
|
||||||
/// An enum telling whether Topgrade should perform dry runs or actually perform the steps.
|
/// An enum telling whether Topgrade should perform dry runs or actually perform the steps.
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug, Deserialize, Default, EnumString, ValueEnum)]
|
||||||
pub enum RunType {
|
pub enum RunType {
|
||||||
/// Executing commands will just print the command with its argument.
|
/// Executing commands will just print the command with its argument.
|
||||||
Dry,
|
Dry,
|
||||||
|
|
||||||
/// Executing commands will perform actual execution.
|
/// Executing commands will perform actual execution.
|
||||||
|
#[default]
|
||||||
Wet,
|
Wet,
|
||||||
|
|
||||||
|
/// Executing commands will print the command and perform actual execution.
|
||||||
|
Damp,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RunType {
|
impl RunType {
|
||||||
/// Create a new instance from a boolean telling whether to dry run.
|
|
||||||
pub fn new(dry_run: bool) -> Self {
|
|
||||||
if dry_run {
|
|
||||||
RunType::Dry
|
|
||||||
} else {
|
|
||||||
RunType::Wet
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Tells whether we're performing a dry run.
|
/// Tells whether we're performing a dry run.
|
||||||
pub fn dry(self) -> bool {
|
pub fn dry(self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
RunType::Dry => true,
|
RunType::Dry => true,
|
||||||
RunType::Wet => false,
|
RunType::Wet => false,
|
||||||
|
RunType::Damp => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -84,6 +84,7 @@ impl<'a> ExecutionContext<'a> {
|
|||||||
match self.run_type {
|
match self.run_type {
|
||||||
RunType::Dry => Executor::Dry(DryCommand::new(program)),
|
RunType::Dry => Executor::Dry(DryCommand::new(program)),
|
||||||
RunType::Wet => Executor::Wet(Command::new(program)),
|
RunType::Wet => Executor::Wet(Command::new(program)),
|
||||||
|
RunType::Damp => Executor::Damp(Command::new(program)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
137
src/executor.rs
137
src/executor.rs
@@ -1,11 +1,13 @@
|
|||||||
//! Utilities for command execution
|
//! Utilities for command execution
|
||||||
use std::ffi::{OsStr, OsString};
|
use std::ffi::{OsStr, OsString};
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use std::iter;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::process::{Child, Command, ExitStatus, Output};
|
use std::process::{Child, Command, ExitStatus, Output};
|
||||||
|
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
use rust_i18n::t;
|
use rust_i18n::t;
|
||||||
use tracing::debug;
|
use tracing::{debug, enabled, Level};
|
||||||
|
|
||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
use crate::error::DryRun;
|
use crate::error::DryRun;
|
||||||
@@ -15,6 +17,7 @@ use crate::error::DryRun;
|
|||||||
/// If the enum is set to `Dry`, execution will just print the command with its arguments.
|
/// If the enum is set to `Dry`, execution will just print the command with its arguments.
|
||||||
pub enum Executor {
|
pub enum Executor {
|
||||||
Wet(Command),
|
Wet(Command),
|
||||||
|
Damp(Command),
|
||||||
Dry(DryCommand),
|
Dry(DryCommand),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,7 +27,7 @@ impl Executor {
|
|||||||
/// Will give weird results for non-UTF-8 programs; see `to_string_lossy()`.
|
/// Will give weird results for non-UTF-8 programs; see `to_string_lossy()`.
|
||||||
pub fn get_program(&self) -> String {
|
pub fn get_program(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
Executor::Wet(c) => c.get_program().to_string_lossy().into_owned(),
|
Executor::Wet(c) | Executor::Damp(c) => c.get_program().to_string_lossy().into_owned(),
|
||||||
Executor::Dry(c) => c.program.to_string_lossy().into_owned(),
|
Executor::Dry(c) => c.program.to_string_lossy().into_owned(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -32,7 +35,7 @@ impl Executor {
|
|||||||
/// See `std::process::Command::arg`
|
/// See `std::process::Command::arg`
|
||||||
pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Executor {
|
pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Executor {
|
||||||
match self {
|
match self {
|
||||||
Executor::Wet(c) => {
|
Executor::Wet(c) | Executor::Damp(c) => {
|
||||||
c.arg(arg);
|
c.arg(arg);
|
||||||
}
|
}
|
||||||
Executor::Dry(c) => {
|
Executor::Dry(c) => {
|
||||||
@@ -50,7 +53,7 @@ impl Executor {
|
|||||||
S: AsRef<OsStr>,
|
S: AsRef<OsStr>,
|
||||||
{
|
{
|
||||||
match self {
|
match self {
|
||||||
Executor::Wet(c) => {
|
Executor::Wet(c) | Executor::Damp(c) => {
|
||||||
c.args(args);
|
c.args(args);
|
||||||
}
|
}
|
||||||
Executor::Dry(c) => {
|
Executor::Dry(c) => {
|
||||||
@@ -65,7 +68,7 @@ impl Executor {
|
|||||||
/// See `std::process::Command::current_dir`
|
/// See `std::process::Command::current_dir`
|
||||||
pub fn current_dir<P: AsRef<Path>>(&mut self, dir: P) -> &mut Executor {
|
pub fn current_dir<P: AsRef<Path>>(&mut self, dir: P) -> &mut Executor {
|
||||||
match self {
|
match self {
|
||||||
Executor::Wet(c) => {
|
Executor::Wet(c) | Executor::Damp(c) => {
|
||||||
c.current_dir(dir);
|
c.current_dir(dir);
|
||||||
}
|
}
|
||||||
Executor::Dry(c) => c.directory = Some(dir.as_ref().into()),
|
Executor::Dry(c) => c.directory = Some(dir.as_ref().into()),
|
||||||
@@ -81,7 +84,7 @@ impl Executor {
|
|||||||
K: AsRef<OsStr>,
|
K: AsRef<OsStr>,
|
||||||
{
|
{
|
||||||
match self {
|
match self {
|
||||||
Executor::Wet(c) => {
|
Executor::Wet(c) | Executor::Damp(c) => {
|
||||||
c.env_remove(key);
|
c.env_remove(key);
|
||||||
}
|
}
|
||||||
Executor::Dry(_) => (),
|
Executor::Dry(_) => (),
|
||||||
@@ -98,7 +101,7 @@ impl Executor {
|
|||||||
V: AsRef<OsStr>,
|
V: AsRef<OsStr>,
|
||||||
{
|
{
|
||||||
match self {
|
match self {
|
||||||
Executor::Wet(c) => {
|
Executor::Wet(c) | Executor::Damp(c) => {
|
||||||
c.env(key, val);
|
c.env(key, val);
|
||||||
}
|
}
|
||||||
Executor::Dry(_) => (),
|
Executor::Dry(_) => (),
|
||||||
@@ -109,18 +112,16 @@ impl Executor {
|
|||||||
|
|
||||||
/// See `std::process::Command::spawn`
|
/// See `std::process::Command::spawn`
|
||||||
pub fn spawn(&mut self) -> Result<ExecutorChild> {
|
pub fn spawn(&mut self) -> Result<ExecutorChild> {
|
||||||
|
self.log_command();
|
||||||
let result = match self {
|
let result = match self {
|
||||||
Executor::Wet(c) => {
|
Executor::Wet(c) | Executor::Damp(c) => {
|
||||||
debug!("Running {:?}", c);
|
debug!("Running {:?}", c);
|
||||||
// We should use `spawn()` here rather than `spawn_checked()` since
|
// We should use `spawn()` here rather than `spawn_checked()` since
|
||||||
// their semantics and behaviors are different.
|
// their semantics and behaviors are different.
|
||||||
#[allow(clippy::disallowed_methods)]
|
#[allow(clippy::disallowed_methods)]
|
||||||
c.spawn().map(ExecutorChild::Wet)?
|
c.spawn().map(ExecutorChild::Wet)?
|
||||||
}
|
}
|
||||||
Executor::Dry(c) => {
|
Executor::Dry(_) => ExecutorChild::Dry,
|
||||||
c.dry_run();
|
|
||||||
ExecutorChild::Dry
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
@@ -128,17 +129,15 @@ impl Executor {
|
|||||||
|
|
||||||
/// See `std::process::Command::output`
|
/// See `std::process::Command::output`
|
||||||
pub fn output(&mut self) -> Result<ExecutorOutput> {
|
pub fn output(&mut self) -> Result<ExecutorOutput> {
|
||||||
|
self.log_command();
|
||||||
match self {
|
match self {
|
||||||
Executor::Wet(c) => {
|
Executor::Wet(c) | Executor::Damp(c) => {
|
||||||
// We should use `output()` here rather than `output_checked()` since
|
// We should use `output()` here rather than `output_checked()` since
|
||||||
// their semantics and behaviors are different.
|
// their semantics and behaviors are different.
|
||||||
#[allow(clippy::disallowed_methods)]
|
#[allow(clippy::disallowed_methods)]
|
||||||
Ok(ExecutorOutput::Wet(c.output()?))
|
Ok(ExecutorOutput::Wet(c.output()?))
|
||||||
}
|
}
|
||||||
Executor::Dry(c) => {
|
Executor::Dry(_) => Ok(ExecutorOutput::Dry),
|
||||||
c.dry_run();
|
|
||||||
Ok(ExecutorOutput::Dry)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,18 +145,38 @@ impl Executor {
|
|||||||
/// that can indicate success of a script
|
/// that can indicate success of a script
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn status_checked_with_codes(&mut self, codes: &[i32]) -> Result<()> {
|
pub fn status_checked_with_codes(&mut self, codes: &[i32]) -> Result<()> {
|
||||||
|
self.log_command();
|
||||||
match self {
|
match self {
|
||||||
Executor::Wet(c) => c.status_checked_with(|status| {
|
Executor::Wet(c) | Executor::Damp(c) => c.status_checked_with(|status| {
|
||||||
if status.success() || status.code().as_ref().is_some_and(|c| codes.contains(c)) {
|
if status.success() || status.code().as_ref().is_some_and(|c| codes.contains(c)) {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
Executor::Dry(c) => {
|
Executor::Dry(_) => Ok(()),
|
||||||
c.dry_run();
|
}
|
||||||
Ok(())
|
}
|
||||||
|
|
||||||
|
fn log_command(&self) {
|
||||||
|
match self {
|
||||||
|
Executor::Wet(_) => (),
|
||||||
|
Executor::Damp(c) => {
|
||||||
|
log_command(
|
||||||
|
"Executing: {program_name} {arguments}",
|
||||||
|
c.get_program(),
|
||||||
|
c.get_args(),
|
||||||
|
c.get_envs(),
|
||||||
|
c.get_current_dir(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
Executor::Dry(c) => log_command(
|
||||||
|
"Dry running: {program_name} {arguments}",
|
||||||
|
&c.program,
|
||||||
|
&c.args,
|
||||||
|
iter::empty(),
|
||||||
|
c.directory.as_ref(),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -182,30 +201,11 @@ impl DryCommand {
|
|||||||
directory: None,
|
directory: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dry_run(&self) {
|
|
||||||
print!(
|
|
||||||
"{}",
|
|
||||||
t!(
|
|
||||||
"Dry running: {program_name} {arguments}",
|
|
||||||
program_name = self.program.to_string_lossy(),
|
|
||||||
arguments = shell_words::join(
|
|
||||||
self.args
|
|
||||||
.iter()
|
|
||||||
.map(|a| String::from(a.to_string_lossy()))
|
|
||||||
.collect::<Vec<String>>()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
match &self.directory {
|
|
||||||
Some(dir) => println!(" {}", t!("in {directory}", directory = dir.to_string_lossy())),
|
|
||||||
None => println!(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The Result of spawn. Contains an actual `std::process::Child` if executed by a wet command.
|
/// The Result of spawn. Contains an actual `std::process::Child` if executed by a wet command.
|
||||||
pub enum ExecutorChild {
|
pub enum ExecutorChild {
|
||||||
|
// Both RunType::Wet and RunType::Damp use this variant
|
||||||
#[allow(unused)] // this type has not been used
|
#[allow(unused)] // this type has not been used
|
||||||
Wet(Child),
|
Wet(Child),
|
||||||
Dry,
|
Dry,
|
||||||
@@ -218,22 +218,18 @@ impl CommandExt for Executor {
|
|||||||
// variant for wet/dry runs.
|
// variant for wet/dry runs.
|
||||||
|
|
||||||
fn output_checked_with(&mut self, succeeded: impl Fn(&Output) -> Result<(), ()>) -> Result<Output> {
|
fn output_checked_with(&mut self, succeeded: impl Fn(&Output) -> Result<(), ()>) -> Result<Output> {
|
||||||
|
self.log_command();
|
||||||
match self {
|
match self {
|
||||||
Executor::Wet(c) => c.output_checked_with(succeeded),
|
Executor::Wet(c) | Executor::Damp(c) => c.output_checked_with(succeeded),
|
||||||
Executor::Dry(c) => {
|
Executor::Dry(_) => Err(DryRun().into()),
|
||||||
c.dry_run();
|
|
||||||
Err(DryRun().into())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn status_checked_with(&mut self, succeeded: impl Fn(ExitStatus) -> Result<(), ()>) -> Result<()> {
|
fn status_checked_with(&mut self, succeeded: impl Fn(ExitStatus) -> Result<(), ()>) -> Result<()> {
|
||||||
|
self.log_command();
|
||||||
match self {
|
match self {
|
||||||
Executor::Wet(c) => c.status_checked_with(succeeded),
|
Executor::Wet(c) | Executor::Damp(c) => c.status_checked_with(succeeded),
|
||||||
Executor::Dry(c) => {
|
Executor::Dry(_) => Ok(()),
|
||||||
c.dry_run();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,3 +237,42 @@ impl CommandExt for Executor {
|
|||||||
self.spawn()
|
self.spawn()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn log_command<
|
||||||
|
'a,
|
||||||
|
I: ExactSizeIterator<Item = (&'a (impl Debug + 'a + ?Sized), Option<&'a (impl Debug + 'a + ?Sized)>)>,
|
||||||
|
>(
|
||||||
|
prefix: &str,
|
||||||
|
exec: &OsStr,
|
||||||
|
args: impl IntoIterator<Item = &'a (impl AsRef<OsStr> + ?Sized + 'a)>,
|
||||||
|
env: impl IntoIterator<Item = (&'a OsStr, Option<&'a OsStr>), IntoIter = I>,
|
||||||
|
dir: Option<&'a (impl AsRef<Path> + ?Sized)>,
|
||||||
|
) {
|
||||||
|
println!(
|
||||||
|
"{}",
|
||||||
|
t!(
|
||||||
|
prefix,
|
||||||
|
program_name = exec.to_string_lossy(),
|
||||||
|
arguments = shell_words::join(args.into_iter().map(|s| s.as_ref().to_string_lossy()))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
let env_iter = env.into_iter();
|
||||||
|
if env_iter.len() != 0 && enabled!(Level::DEBUG) {
|
||||||
|
println!(
|
||||||
|
" {}",
|
||||||
|
t!(
|
||||||
|
"with env: {env}",
|
||||||
|
env = env_iter
|
||||||
|
.filter(|(_, val)| val.is_some())
|
||||||
|
.map(|(key, val)| format!("{:?}={:?}", key, val.unwrap()))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(" ")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(d) = dir {
|
||||||
|
println!(" {}", t!("in {directory}", directory = d.as_ref().display()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ fn run() -> Result<()> {
|
|||||||
debug!("Version: {}", crate_version!());
|
debug!("Version: {}", crate_version!());
|
||||||
debug!("OS: {}", env!("TARGET"));
|
debug!("OS: {}", env!("TARGET"));
|
||||||
debug!("{:?}", env::args());
|
debug!("{:?}", env::args());
|
||||||
debug!("Binary path: {:?}", std::env::current_exe());
|
debug!("Binary path: {:?}", env::current_exe());
|
||||||
debug!("self-update Feature Enabled: {:?}", cfg!(feature = "self-update"));
|
debug!("self-update Feature Enabled: {:?}", cfg!(feature = "self-update"));
|
||||||
debug!("Configuration: {:?}", config);
|
debug!("Configuration: {:?}", config);
|
||||||
|
|
||||||
@@ -163,7 +163,7 @@ fn run() -> Result<()> {
|
|||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
let distribution = linux::Distribution::detect();
|
let distribution = linux::Distribution::detect();
|
||||||
|
|
||||||
let run_type = execution_context::RunType::new(config.dry_run());
|
let run_type = config.run_type();
|
||||||
let ctx = execution_context::ExecutionContext::new(
|
let ctx = execution_context::ExecutionContext::new(
|
||||||
run_type,
|
run_type,
|
||||||
sudo,
|
sudo,
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ pub fn run_mas(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
pub fn upgrade_macos(ctx: &ExecutionContext) -> Result<()> {
|
pub fn upgrade_macos(ctx: &ExecutionContext) -> Result<()> {
|
||||||
print_separator(t!("macOS system update"));
|
print_separator(t!("macOS system update"));
|
||||||
|
|
||||||
let should_ask = !(ctx.config().yes(Step::System) || ctx.config().dry_run());
|
let should_ask = !(ctx.config().yes(Step::System) || ctx.run_type().dry());
|
||||||
if should_ask {
|
if should_ask {
|
||||||
println!("{}", t!("Finding available software"));
|
println!("{}", t!("Finding available software"));
|
||||||
if system_update_available()? {
|
if system_update_available()? {
|
||||||
@@ -95,7 +95,7 @@ pub fn update_xcodes(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
let xcodes = require("xcodes")?;
|
let xcodes = require("xcodes")?;
|
||||||
print_separator("Xcodes");
|
print_separator("Xcodes");
|
||||||
|
|
||||||
let should_ask = !(ctx.config().yes(Step::Xcodes) || ctx.config().dry_run());
|
let should_ask = !(ctx.config().yes(Step::Xcodes) || ctx.run_type().dry());
|
||||||
|
|
||||||
let releases = ctx.execute(&xcodes).args(["update"]).output_checked_utf8()?.stdout;
|
let releases = ctx.execute(&xcodes).args(["update"]).output_checked_utf8()?.stdout;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
|
use crate::executor::RunType;
|
||||||
use crate::terminal::print_separator;
|
use crate::terminal::print_separator;
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
use rust_i18n::t;
|
use rust_i18n::t;
|
||||||
@@ -8,12 +9,13 @@ use std::fs;
|
|||||||
fn is_openbsd_current(ctx: &ExecutionContext) -> Result<bool> {
|
fn is_openbsd_current(ctx: &ExecutionContext) -> Result<bool> {
|
||||||
let motd_content = fs::read_to_string("/etc/motd")?;
|
let motd_content = fs::read_to_string("/etc/motd")?;
|
||||||
let is_current = ["-current", "-beta"].iter().any(|&s| motd_content.contains(s));
|
let is_current = ["-current", "-beta"].iter().any(|&s| motd_content.contains(s));
|
||||||
if ctx.config().dry_run() {
|
match ctx.config.run_type() {
|
||||||
println!("{}", t!("Would check if OpenBSD is -current"));
|
RunType::Dry | RunType::Damp => {
|
||||||
Ok(is_current)
|
println!("{}", t!("Checking if /etc/motd contains -current or -beta"));
|
||||||
} else {
|
}
|
||||||
Ok(is_current)
|
RunType::Wet => {}
|
||||||
}
|
}
|
||||||
|
Ok(is_current)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn upgrade_openbsd(ctx: &ExecutionContext) -> Result<()> {
|
pub fn upgrade_openbsd(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -42,11 +44,6 @@ pub fn upgrade_packages(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
let is_current = is_openbsd_current(ctx)?;
|
let is_current = is_openbsd_current(ctx)?;
|
||||||
|
|
||||||
if ctx.config().dry_run() {
|
|
||||||
println!("{}", t!("Would upgrade OpenBSD packages"));
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
if ctx.config().cleanup() {
|
if ctx.config().cleanup() {
|
||||||
sudo.execute(ctx, "/usr/sbin/pkg_delete")?.arg("-ac").status_checked()?;
|
sudo.execute(ctx, "/usr/sbin/pkg_delete")?.arg("-ac").status_checked()?;
|
||||||
}
|
}
|
||||||
|
|||||||
10
translate.sh
Executable file
10
translate.sh
Executable file
@@ -0,0 +1,10 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
## Translate the given string into $langs using translate-shell, outputting to the yaml structure expected for locales/app.yml
|
||||||
|
|
||||||
|
langs="en lt es fr zh_CN zh_TW de"
|
||||||
|
|
||||||
|
printf "\"%s\":\n" "$@"
|
||||||
|
for lang in $langs; do
|
||||||
|
result=$(trans -brief -no-auto -s en -t "${lang/_/-/}" "$@")
|
||||||
|
printf " %s: \"%s\"\n" "$lang" "$result"
|
||||||
|
done
|
||||||
Reference in New Issue
Block a user