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?
|
||||
|
||||
## I want to suggest some general feature
|
||||
|
||||
Topgrade should...
|
||||
|
||||
## More information
|
||||
|
||||
<!-- Assuming that someone else implements the feature,
|
||||
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
|
||||
|
||||
|
||||
## Standards checklist
|
||||
|
||||
- [ ] The PR title is descriptive
|
||||
|
||||
@@ -15,8 +15,8 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v5.0.0
|
||||
- run: |
|
||||
- uses: actions/checkout@v5.0.0
|
||||
- run: |
|
||||
CONFIG_PATH=~/.config/topgrade.toml;
|
||||
if [ -f "$CONFIG_PATH" ]; then rm $CONFIG_PATH; fi
|
||||
cargo build;
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
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`
|
||||
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_TW: "正在模擬 %{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}":
|
||||
en: "in %{directory}"
|
||||
lt: "kataloge %{directory}"
|
||||
@@ -1298,30 +1314,14 @@ _version: 2
|
||||
zh_CN: "Windows 更新"
|
||||
zh_TW: "Windows 更新"
|
||||
de: "Windows-Update"
|
||||
"Would check if OpenBSD is -current":
|
||||
en: "Would check if OpenBSD is -current"
|
||||
lt: "Patikrintų, ar OpenBSD yra -current"
|
||||
es: "Comprobaría si OpenBSD está en -current"
|
||||
fr: "Vérifierait si OpenBSD est à -curent"
|
||||
zh_CN: "将检查 OpenBSD 是否为 -current"
|
||||
zh_TW: "會檢查 OpenBSD 是否為 -current"
|
||||
de: "Würde überprüfen, ob OpenBSD -current ist"
|
||||
"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"
|
||||
"Checking if /etc/motd contains -current or -beta":
|
||||
en: "Checking if /etc/motd contains -current or -beta"
|
||||
lt: "Tikrinimas, jei /etc/motd yra -current arba -beta"
|
||||
es: "Comprobación de si /etc/motd contiene -current o -beta"
|
||||
fr: "Vérification si /etc/motd contient -current ou -beta"
|
||||
zh_CN: "检查 /etc/motd 是否包含 -current 或 -beta"
|
||||
zh_TW: "检查 /etc/motd 是否包含 -current 或 -beta"
|
||||
de: "Überprüfen, ob /etc/motd -current oder -beta enthält"
|
||||
"Microsoft Store":
|
||||
en: "Microsoft Store"
|
||||
lt: "Microsoft parduotuvė"
|
||||
|
||||
@@ -18,14 +18,15 @@ use regex_split::RegexSplit;
|
||||
use rust_i18n::t;
|
||||
use serde::Deserialize;
|
||||
use strum::IntoEnumIterator;
|
||||
use tracing::{debug, error};
|
||||
use which_crate::which;
|
||||
|
||||
use super::utils::editor;
|
||||
use crate::command::CommandExt;
|
||||
use crate::execution_context::RunType;
|
||||
use crate::step::Step;
|
||||
use crate::sudo::SudoKind;
|
||||
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
|
||||
pub static EXAMPLE_CONFIG: &str = include_str!("../config.example.toml");
|
||||
@@ -708,9 +709,15 @@ pub struct CommandLineArgs {
|
||||
cleanup: bool,
|
||||
|
||||
/// Print what would be done
|
||||
///
|
||||
/// Alias for --run-type dry
|
||||
#[arg(short = 'n', long = "dry-run")]
|
||||
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
|
||||
#[arg(long = "no-retry")]
|
||||
no_retry: bool,
|
||||
@@ -1001,9 +1008,13 @@ impl Config {
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
/// Tell whether we are dry-running.
|
||||
pub fn dry_run(&self) -> bool {
|
||||
self.opt.dry_run
|
||||
/// Get the [RunType] for the current execution
|
||||
pub fn run_type(&self) -> RunType {
|
||||
if self.opt.dry_run {
|
||||
RunType::Dry
|
||||
} else {
|
||||
self.opt.run_type
|
||||
}
|
||||
}
|
||||
|
||||
/// Tell whether we should not attempt to retry anything.
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
#![allow(dead_code)]
|
||||
use color_eyre::eyre::Result;
|
||||
use rust_i18n::t;
|
||||
use std::env::var;
|
||||
use std::ffi::OsStr;
|
||||
use std::process::Command;
|
||||
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::error::MissingSudo;
|
||||
use crate::executor::{DryCommand, Executor};
|
||||
@@ -16,30 +20,26 @@ use crate::sudo::Sudo;
|
||||
use crate::utils::require_option;
|
||||
|
||||
/// 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 {
|
||||
/// Executing commands will just print the command with its argument.
|
||||
Dry,
|
||||
|
||||
/// Executing commands will perform actual execution.
|
||||
#[default]
|
||||
Wet,
|
||||
|
||||
/// Executing commands will print the command and perform actual execution.
|
||||
Damp,
|
||||
}
|
||||
|
||||
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.
|
||||
pub fn dry(self) -> bool {
|
||||
match self {
|
||||
RunType::Dry => true,
|
||||
RunType::Wet => false,
|
||||
RunType::Damp => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -84,6 +84,7 @@ impl<'a> ExecutionContext<'a> {
|
||||
match self.run_type {
|
||||
RunType::Dry => Executor::Dry(DryCommand::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
|
||||
use std::ffi::{OsStr, OsString};
|
||||
use std::fmt::Debug;
|
||||
use std::iter;
|
||||
use std::path::Path;
|
||||
use std::process::{Child, Command, ExitStatus, Output};
|
||||
|
||||
use color_eyre::eyre::Result;
|
||||
use rust_i18n::t;
|
||||
use tracing::debug;
|
||||
use tracing::{debug, enabled, Level};
|
||||
|
||||
use crate::command::CommandExt;
|
||||
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.
|
||||
pub enum Executor {
|
||||
Wet(Command),
|
||||
Damp(Command),
|
||||
Dry(DryCommand),
|
||||
}
|
||||
|
||||
@@ -24,7 +27,7 @@ impl Executor {
|
||||
/// Will give weird results for non-UTF-8 programs; see `to_string_lossy()`.
|
||||
pub fn get_program(&self) -> String {
|
||||
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(),
|
||||
}
|
||||
}
|
||||
@@ -32,7 +35,7 @@ impl Executor {
|
||||
/// See `std::process::Command::arg`
|
||||
pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Executor {
|
||||
match self {
|
||||
Executor::Wet(c) => {
|
||||
Executor::Wet(c) | Executor::Damp(c) => {
|
||||
c.arg(arg);
|
||||
}
|
||||
Executor::Dry(c) => {
|
||||
@@ -50,7 +53,7 @@ impl Executor {
|
||||
S: AsRef<OsStr>,
|
||||
{
|
||||
match self {
|
||||
Executor::Wet(c) => {
|
||||
Executor::Wet(c) | Executor::Damp(c) => {
|
||||
c.args(args);
|
||||
}
|
||||
Executor::Dry(c) => {
|
||||
@@ -65,7 +68,7 @@ impl Executor {
|
||||
/// See `std::process::Command::current_dir`
|
||||
pub fn current_dir<P: AsRef<Path>>(&mut self, dir: P) -> &mut Executor {
|
||||
match self {
|
||||
Executor::Wet(c) => {
|
||||
Executor::Wet(c) | Executor::Damp(c) => {
|
||||
c.current_dir(dir);
|
||||
}
|
||||
Executor::Dry(c) => c.directory = Some(dir.as_ref().into()),
|
||||
@@ -81,7 +84,7 @@ impl Executor {
|
||||
K: AsRef<OsStr>,
|
||||
{
|
||||
match self {
|
||||
Executor::Wet(c) => {
|
||||
Executor::Wet(c) | Executor::Damp(c) => {
|
||||
c.env_remove(key);
|
||||
}
|
||||
Executor::Dry(_) => (),
|
||||
@@ -98,7 +101,7 @@ impl Executor {
|
||||
V: AsRef<OsStr>,
|
||||
{
|
||||
match self {
|
||||
Executor::Wet(c) => {
|
||||
Executor::Wet(c) | Executor::Damp(c) => {
|
||||
c.env(key, val);
|
||||
}
|
||||
Executor::Dry(_) => (),
|
||||
@@ -109,18 +112,16 @@ impl Executor {
|
||||
|
||||
/// See `std::process::Command::spawn`
|
||||
pub fn spawn(&mut self) -> Result<ExecutorChild> {
|
||||
self.log_command();
|
||||
let result = match self {
|
||||
Executor::Wet(c) => {
|
||||
Executor::Wet(c) | Executor::Damp(c) => {
|
||||
debug!("Running {:?}", c);
|
||||
// We should use `spawn()` here rather than `spawn_checked()` since
|
||||
// their semantics and behaviors are different.
|
||||
#[allow(clippy::disallowed_methods)]
|
||||
c.spawn().map(ExecutorChild::Wet)?
|
||||
}
|
||||
Executor::Dry(c) => {
|
||||
c.dry_run();
|
||||
ExecutorChild::Dry
|
||||
}
|
||||
Executor::Dry(_) => ExecutorChild::Dry,
|
||||
};
|
||||
|
||||
Ok(result)
|
||||
@@ -128,17 +129,15 @@ impl Executor {
|
||||
|
||||
/// See `std::process::Command::output`
|
||||
pub fn output(&mut self) -> Result<ExecutorOutput> {
|
||||
self.log_command();
|
||||
match self {
|
||||
Executor::Wet(c) => {
|
||||
Executor::Wet(c) | Executor::Damp(c) => {
|
||||
// We should use `output()` here rather than `output_checked()` since
|
||||
// their semantics and behaviors are different.
|
||||
#[allow(clippy::disallowed_methods)]
|
||||
Ok(ExecutorOutput::Wet(c.output()?))
|
||||
}
|
||||
Executor::Dry(c) => {
|
||||
c.dry_run();
|
||||
Ok(ExecutorOutput::Dry)
|
||||
}
|
||||
Executor::Dry(_) => Ok(ExecutorOutput::Dry),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,18 +145,38 @@ impl Executor {
|
||||
/// that can indicate success of a script
|
||||
#[allow(dead_code)]
|
||||
pub fn status_checked_with_codes(&mut self, codes: &[i32]) -> Result<()> {
|
||||
self.log_command();
|
||||
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)) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}),
|
||||
Executor::Dry(c) => {
|
||||
c.dry_run();
|
||||
Ok(())
|
||||
Executor::Dry(_) => 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,
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
pub enum ExecutorChild {
|
||||
// Both RunType::Wet and RunType::Damp use this variant
|
||||
#[allow(unused)] // this type has not been used
|
||||
Wet(Child),
|
||||
Dry,
|
||||
@@ -218,22 +218,18 @@ impl CommandExt for Executor {
|
||||
// variant for wet/dry runs.
|
||||
|
||||
fn output_checked_with(&mut self, succeeded: impl Fn(&Output) -> Result<(), ()>) -> Result<Output> {
|
||||
self.log_command();
|
||||
match self {
|
||||
Executor::Wet(c) => c.output_checked_with(succeeded),
|
||||
Executor::Dry(c) => {
|
||||
c.dry_run();
|
||||
Err(DryRun().into())
|
||||
}
|
||||
Executor::Wet(c) | Executor::Damp(c) => c.output_checked_with(succeeded),
|
||||
Executor::Dry(_) => Err(DryRun().into()),
|
||||
}
|
||||
}
|
||||
|
||||
fn status_checked_with(&mut self, succeeded: impl Fn(ExitStatus) -> Result<(), ()>) -> Result<()> {
|
||||
self.log_command();
|
||||
match self {
|
||||
Executor::Wet(c) => c.status_checked_with(succeeded),
|
||||
Executor::Dry(c) => {
|
||||
c.dry_run();
|
||||
Ok(())
|
||||
}
|
||||
Executor::Wet(c) | Executor::Damp(c) => c.status_checked_with(succeeded),
|
||||
Executor::Dry(_) => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,3 +237,42 @@ impl CommandExt for Executor {
|
||||
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!("OS: {}", env!("TARGET"));
|
||||
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!("Configuration: {:?}", config);
|
||||
|
||||
@@ -163,7 +163,7 @@ fn run() -> Result<()> {
|
||||
#[cfg(target_os = "linux")]
|
||||
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(
|
||||
run_type,
|
||||
sudo,
|
||||
|
||||
@@ -38,7 +38,7 @@ pub fn run_mas(ctx: &ExecutionContext) -> Result<()> {
|
||||
pub fn upgrade_macos(ctx: &ExecutionContext) -> Result<()> {
|
||||
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 {
|
||||
println!("{}", t!("Finding available software"));
|
||||
if system_update_available()? {
|
||||
@@ -95,7 +95,7 @@ pub fn update_xcodes(ctx: &ExecutionContext) -> Result<()> {
|
||||
let xcodes = require("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;
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::command::CommandExt;
|
||||
use crate::execution_context::ExecutionContext;
|
||||
use crate::executor::RunType;
|
||||
use crate::terminal::print_separator;
|
||||
use color_eyre::eyre::Result;
|
||||
use rust_i18n::t;
|
||||
@@ -8,12 +9,13 @@ use std::fs;
|
||||
fn is_openbsd_current(ctx: &ExecutionContext) -> Result<bool> {
|
||||
let motd_content = fs::read_to_string("/etc/motd")?;
|
||||
let is_current = ["-current", "-beta"].iter().any(|&s| motd_content.contains(s));
|
||||
if ctx.config().dry_run() {
|
||||
println!("{}", t!("Would check if OpenBSD is -current"));
|
||||
Ok(is_current)
|
||||
} else {
|
||||
Ok(is_current)
|
||||
match ctx.config.run_type() {
|
||||
RunType::Dry | RunType::Damp => {
|
||||
println!("{}", t!("Checking if /etc/motd contains -current or -beta"));
|
||||
}
|
||||
RunType::Wet => {}
|
||||
}
|
||||
Ok(is_current)
|
||||
}
|
||||
|
||||
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)?;
|
||||
|
||||
if ctx.config().dry_run() {
|
||||
println!("{}", t!("Would upgrade OpenBSD packages"));
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if ctx.config().cleanup() {
|
||||
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