Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80a95cb404 | ||
|
|
ab630cfbc6 | ||
|
|
c13e14080c | ||
|
|
4abbee99cc | ||
|
|
45d935eda3 | ||
|
|
b4c5efde50 | ||
|
|
cba9dc1c2c | ||
|
|
938647123c | ||
|
|
9f24f6474e | ||
|
|
814e39644c | ||
|
|
eb51be0732 | ||
|
|
56a717dcc6 | ||
|
|
ee353ccb66 | ||
|
|
33cea0e5b6 | ||
|
|
78a491a976 | ||
|
|
9553be04e4 | ||
|
|
81928f55a2 | ||
|
|
4e56bf07f3 | ||
|
|
9f424f03c3 | ||
|
|
1e14b3bf28 | ||
|
|
51e7a31f48 | ||
|
|
9847fd9d4d | ||
|
|
24ef44291f | ||
|
|
ebb0c5a6d8 | ||
|
|
1dee462175 | ||
|
|
dc82b8b766 | ||
|
|
73888e7669 | ||
|
|
46a010cc8f | ||
|
|
96e4de4594 | ||
|
|
70616b2ec5 | ||
|
|
22ab07d88e | ||
|
|
70045fca29 | ||
|
|
f6ec6c76db | ||
|
|
37b900c56a | ||
|
|
e26ec4d9e0 | ||
|
|
b31778bdd8 | ||
|
|
526c4c9a58 | ||
|
|
3c1dda0c39 | ||
|
|
25c5057171 | ||
|
|
e456155562 | ||
|
|
f2c7e4848e |
8
.github/workflows/check-and-lint.yaml
vendored
8
.github/workflows/check-and-lint.yaml
vendored
@@ -23,10 +23,11 @@ jobs:
|
|||||||
uses: dtolnay/rust-toolchain@master
|
uses: dtolnay/rust-toolchain@master
|
||||||
with:
|
with:
|
||||||
toolchain: '${{ env.RUST_VER }}'
|
toolchain: '${{ env.RUST_VER }}'
|
||||||
targets: ${{ matrix.target }}
|
components: rustfmt
|
||||||
components: clippy, rustfmt
|
|
||||||
|
|
||||||
- name: Run cargo fmt
|
- name: Run cargo fmt
|
||||||
|
env:
|
||||||
|
TERM: xterm-256color
|
||||||
run: |
|
run: |
|
||||||
cargo fmt --all -- --check
|
cargo fmt --all -- --check
|
||||||
|
|
||||||
@@ -72,8 +73,7 @@ jobs:
|
|||||||
uses: dtolnay/rust-toolchain@master
|
uses: dtolnay/rust-toolchain@master
|
||||||
with:
|
with:
|
||||||
toolchain: '${{ env.RUST_VER }}'
|
toolchain: '${{ env.RUST_VER }}'
|
||||||
targets: ${{ matrix.target }}
|
components: clippy
|
||||||
components: clippy, rustfmt
|
|
||||||
|
|
||||||
- name: Setup Rust Cache
|
- name: Setup Rust Cache
|
||||||
uses: Swatinem/rust-cache@v2
|
uses: Swatinem/rust-cache@v2
|
||||||
|
|||||||
433
Cargo.lock
generated
433
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
12
Cargo.toml
12
Cargo.toml
@@ -6,7 +6,7 @@ keywords = ["upgrade", "update"]
|
|||||||
license = "GPL-3.0"
|
license = "GPL-3.0"
|
||||||
# license-file = "LICENSE"
|
# license-file = "LICENSE"
|
||||||
repository = "https://github.com/topgrade-rs/topgrade"
|
repository = "https://github.com/topgrade-rs/topgrade"
|
||||||
version = "10.2.0"
|
version = "10.2.5"
|
||||||
authors = ["Roey Darwish Dror <roey.ghost@gmail.com>", "Thomas Schönauer <t.schoenauer@hgs-wt.at>"]
|
authors = ["Roey Darwish Dror <roey.ghost@gmail.com>", "Thomas Schönauer <t.schoenauer@hgs-wt.at>"]
|
||||||
exclude = ["doc/screenshot.gif"]
|
exclude = ["doc/screenshot.gif"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
@@ -28,6 +28,8 @@ toml = "0.5"
|
|||||||
which_crate = { version = "~4.1", package = "which" }
|
which_crate = { version = "~4.1", package = "which" }
|
||||||
shellexpand = "~2.1"
|
shellexpand = "~2.1"
|
||||||
clap = { version = "~3.1", features = ["cargo", "derive"] }
|
clap = { version = "~3.1", features = ["cargo", "derive"] }
|
||||||
|
clap_complete = "~3.1"
|
||||||
|
clap_mangen = "~0.1"
|
||||||
walkdir = "~2.3"
|
walkdir = "~2.3"
|
||||||
console = "~0.15"
|
console = "~0.15"
|
||||||
lazy_static = "~1.4"
|
lazy_static = "~1.4"
|
||||||
@@ -37,14 +39,14 @@ strum = { version = "~0.24", features = ["derive"] }
|
|||||||
thiserror = "~1.0"
|
thiserror = "~1.0"
|
||||||
tempfile = "~3.2"
|
tempfile = "~3.2"
|
||||||
cfg-if = "~1.0"
|
cfg-if = "~1.0"
|
||||||
tokio = { version = "~1.5", features = ["process", "rt-multi-thread"] }
|
tokio = { version = "~1.18", features = ["process", "rt-multi-thread"] }
|
||||||
futures = "~0.3"
|
futures = "~0.3"
|
||||||
regex = "~1.5"
|
regex = "~1.5"
|
||||||
semver = "~1.0"
|
semver = "~1.0"
|
||||||
shell-words = "~1.1"
|
shell-words = "~1.1"
|
||||||
color-eyre = "0.6.2"
|
color-eyre = "~0.6"
|
||||||
tracing = { version = "0.1.37", features = ["attributes", "log"] }
|
tracing = { version = "~0.1", features = ["attributes", "log"] }
|
||||||
tracing-subscriber = { version = "0.3.16", features = ["env-filter", "time"] }
|
tracing-subscriber = { version = "~0.3", features = ["env-filter", "time"] }
|
||||||
|
|
||||||
[target.'cfg(target_os = "macos")'.dependencies]
|
[target.'cfg(target_os = "macos")'.dependencies]
|
||||||
notify-rust = "~4.5"
|
notify-rust = "~4.5"
|
||||||
|
|||||||
@@ -13,6 +13,10 @@
|
|||||||
# Do not ask to retry failed steps (default: false)
|
# Do not ask to retry failed steps (default: false)
|
||||||
#no_retry = true
|
#no_retry = true
|
||||||
|
|
||||||
|
# Run `sudo -v` to cache credentials at the start of the run; this avoids a
|
||||||
|
# blocking password prompt in the middle of a possibly-unattended run.
|
||||||
|
#pre_sudo = false
|
||||||
|
|
||||||
# Run inside tmux
|
# Run inside tmux
|
||||||
#run_in_tmux = true
|
#run_in_tmux = true
|
||||||
|
|
||||||
@@ -40,6 +44,9 @@
|
|||||||
# Skip sending a notification at the end of a run
|
# Skip sending a notification at the end of a run
|
||||||
#skip_notify = true
|
#skip_notify = true
|
||||||
|
|
||||||
|
# Skip the preamble displayed when topgrade is run
|
||||||
|
#display_preamble = false
|
||||||
|
|
||||||
[git]
|
[git]
|
||||||
#max_concurrency = 5
|
#max_concurrency = 5
|
||||||
# Additional git repositories to pull
|
# Additional git repositories to pull
|
||||||
@@ -70,12 +77,15 @@
|
|||||||
#autoremove = true
|
#autoremove = true
|
||||||
|
|
||||||
[linux]
|
[linux]
|
||||||
# Arch Package Manager to use. Allowed values: autodetect, trizen, aura, paru, yay, pikaur, pacman, pamac.
|
# Arch Package Manager to use. Allowed values: autodetect, aura, garuda_update, pacman, pamac, paru, pikaur, trizen, yay.
|
||||||
#arch_package_manager = "pacman"
|
#arch_package_manager = "pacman"
|
||||||
# Arguments to pass yay (or paru) when updating packages
|
# Arguments to pass yay (or paru) when updating packages
|
||||||
#yay_arguments = "--nodevel"
|
#yay_arguments = "--nodevel"
|
||||||
|
# Arguments to pass dnf when updating packages
|
||||||
|
#dnf_arguments = "--refresh"
|
||||||
#aura_aur_arguments = "-kx"
|
#aura_aur_arguments = "-kx"
|
||||||
#aura_pacman_arguments = ""
|
#aura_pacman_arguments = ""
|
||||||
|
#garuda_update_arguments = ""
|
||||||
#show_arch_news = true
|
#show_arch_news = true
|
||||||
#trizen_arguments = "--devel"
|
#trizen_arguments = "--devel"
|
||||||
#pikaur_arguments = ""
|
#pikaur_arguments = ""
|
||||||
@@ -85,11 +95,18 @@
|
|||||||
#emerge_update_flags = "-uDNa --with-bdeps=y world"
|
#emerge_update_flags = "-uDNa --with-bdeps=y world"
|
||||||
#redhat_distro_sync = false
|
#redhat_distro_sync = false
|
||||||
#rpm_ostree = false
|
#rpm_ostree = false
|
||||||
|
#nix_arguments = "--flake"
|
||||||
|
|
||||||
|
[python]
|
||||||
|
#enable_pip_review = true ###disabled by default
|
||||||
|
#enable_pipupgrade = true ###disabled by default
|
||||||
|
|
||||||
[windows]
|
[windows]
|
||||||
# Manually select Windows updates
|
# Manually select Windows updates
|
||||||
#accept_all_updates = false
|
#accept_all_updates = false
|
||||||
#open_remotes_in_new_terminal = true
|
#open_remotes_in_new_terminal = true
|
||||||
|
#wsl_update_pre_release = true
|
||||||
|
#wsl_update_use_web_download = true
|
||||||
|
|
||||||
# Causes Topgrade to rename itself during the run to allow package managers
|
# Causes Topgrade to rename itself during the run to allow package managers
|
||||||
# to upgrade it. Use this only if you installed Topgrade by using a package
|
# to upgrade it. Use this only if you installed Topgrade by using a package
|
||||||
|
|||||||
119
src/config.rs
119
src/config.rs
@@ -6,6 +6,7 @@ use std::process::Command;
|
|||||||
use std::{env, fs};
|
use std::{env, fs};
|
||||||
|
|
||||||
use clap::{ArgEnum, Parser};
|
use clap::{ArgEnum, Parser};
|
||||||
|
use clap_complete::Shell;
|
||||||
use color_eyre::eyre;
|
use color_eyre::eyre;
|
||||||
use color_eyre::eyre::Context;
|
use color_eyre::eyre::Context;
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
@@ -70,12 +71,13 @@ type Commands = BTreeMap<String, String>;
|
|||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
#[strum(serialize_all = "snake_case")]
|
#[strum(serialize_all = "snake_case")]
|
||||||
pub enum Step {
|
pub enum Step {
|
||||||
|
AM,
|
||||||
Asdf,
|
Asdf,
|
||||||
Atom,
|
Atom,
|
||||||
|
Bin,
|
||||||
BrewCask,
|
BrewCask,
|
||||||
BrewFormula,
|
BrewFormula,
|
||||||
Bun,
|
Bun,
|
||||||
Bin,
|
|
||||||
Cargo,
|
Cargo,
|
||||||
Chezmoi,
|
Chezmoi,
|
||||||
Chocolatey,
|
Chocolatey,
|
||||||
@@ -86,8 +88,9 @@ pub enum Step {
|
|||||||
Containers,
|
Containers,
|
||||||
CustomCommands,
|
CustomCommands,
|
||||||
DebGet,
|
DebGet,
|
||||||
Distrobox,
|
|
||||||
Deno,
|
Deno,
|
||||||
|
Distrobox,
|
||||||
|
DkpPacman,
|
||||||
Dotnet,
|
Dotnet,
|
||||||
Emacs,
|
Emacs,
|
||||||
Firmware,
|
Firmware,
|
||||||
@@ -99,14 +102,17 @@ pub enum Step {
|
|||||||
Ghcup,
|
Ghcup,
|
||||||
GithubCliExtensions,
|
GithubCliExtensions,
|
||||||
GitRepos,
|
GitRepos,
|
||||||
|
GnomeShellExtensions,
|
||||||
Go,
|
Go,
|
||||||
Guix,
|
Guix,
|
||||||
Haxelib,
|
Haxelib,
|
||||||
GnomeShellExtensions,
|
Helm,
|
||||||
HomeManager,
|
HomeManager,
|
||||||
Jetpack,
|
Jetpack,
|
||||||
Julia,
|
Julia,
|
||||||
|
Juliaup,
|
||||||
Kakoune,
|
Kakoune,
|
||||||
|
Helix,
|
||||||
Krew,
|
Krew,
|
||||||
Macports,
|
Macports,
|
||||||
Mas,
|
Mas,
|
||||||
@@ -118,10 +124,13 @@ pub enum Step {
|
|||||||
Pacdef,
|
Pacdef,
|
||||||
Pacstall,
|
Pacstall,
|
||||||
Pearl,
|
Pearl,
|
||||||
Pipx,
|
|
||||||
Pip3,
|
Pip3,
|
||||||
|
PipReview,
|
||||||
|
Pipupgrade,
|
||||||
|
Pipx,
|
||||||
Pkg,
|
Pkg,
|
||||||
Pkgin,
|
Pkgin,
|
||||||
|
Pnpm,
|
||||||
Powershell,
|
Powershell,
|
||||||
Protonup,
|
Protonup,
|
||||||
Raco,
|
Raco,
|
||||||
@@ -129,6 +138,7 @@ pub enum Step {
|
|||||||
Remotes,
|
Remotes,
|
||||||
Restarts,
|
Restarts,
|
||||||
Rtcl,
|
Rtcl,
|
||||||
|
RubyGems,
|
||||||
Rustup,
|
Rustup,
|
||||||
Scoop,
|
Scoop,
|
||||||
Sdkman,
|
Sdkman,
|
||||||
@@ -148,7 +158,9 @@ pub enum Step {
|
|||||||
Vim,
|
Vim,
|
||||||
Winget,
|
Winget,
|
||||||
Wsl,
|
Wsl,
|
||||||
|
WslUpdate,
|
||||||
Yadm,
|
Yadm,
|
||||||
|
Yarn,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Default, Debug)]
|
#[derive(Deserialize, Default, Debug)]
|
||||||
@@ -175,6 +187,15 @@ pub struct Windows {
|
|||||||
self_rename: Option<bool>,
|
self_rename: Option<bool>,
|
||||||
open_remotes_in_new_terminal: Option<bool>,
|
open_remotes_in_new_terminal: Option<bool>,
|
||||||
enable_winget: Option<bool>,
|
enable_winget: Option<bool>,
|
||||||
|
wsl_update_pre_release: Option<bool>,
|
||||||
|
wsl_update_use_web_download: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Default, Debug)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub struct Python {
|
||||||
|
enable_pip_review: Option<bool>,
|
||||||
|
enable_pipupgrade: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Default, Debug)]
|
#[derive(Deserialize, Default, Debug)]
|
||||||
@@ -224,13 +245,14 @@ pub struct Brew {
|
|||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum ArchPackageManager {
|
pub enum ArchPackageManager {
|
||||||
Autodetect,
|
Autodetect,
|
||||||
Trizen,
|
|
||||||
Paru,
|
|
||||||
Yay,
|
|
||||||
Pacman,
|
|
||||||
Pikaur,
|
|
||||||
Pamac,
|
|
||||||
Aura,
|
Aura,
|
||||||
|
GarudaUpdate,
|
||||||
|
Pacman,
|
||||||
|
Pamac,
|
||||||
|
Paru,
|
||||||
|
Pikaur,
|
||||||
|
Trizen,
|
||||||
|
Yay,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Default, Debug)]
|
#[derive(Deserialize, Default, Debug)]
|
||||||
@@ -241,10 +263,12 @@ pub struct Linux {
|
|||||||
aura_pacman_arguments: Option<String>,
|
aura_pacman_arguments: Option<String>,
|
||||||
arch_package_manager: Option<ArchPackageManager>,
|
arch_package_manager: Option<ArchPackageManager>,
|
||||||
show_arch_news: Option<bool>,
|
show_arch_news: Option<bool>,
|
||||||
|
garuda_update_arguments: Option<String>,
|
||||||
trizen_arguments: Option<String>,
|
trizen_arguments: Option<String>,
|
||||||
pikaur_arguments: Option<String>,
|
pikaur_arguments: Option<String>,
|
||||||
pamac_arguments: Option<String>,
|
pamac_arguments: Option<String>,
|
||||||
dnf_arguments: Option<String>,
|
dnf_arguments: Option<String>,
|
||||||
|
nix_arguments: Option<String>,
|
||||||
apt_arguments: Option<String>,
|
apt_arguments: Option<String>,
|
||||||
enable_tlmgr: Option<bool>,
|
enable_tlmgr: Option<bool>,
|
||||||
redhat_distro_sync: Option<bool>,
|
redhat_distro_sync: Option<bool>,
|
||||||
@@ -269,6 +293,7 @@ pub struct Vim {
|
|||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
/// Configuration file
|
/// Configuration file
|
||||||
pub struct ConfigFile {
|
pub struct ConfigFile {
|
||||||
|
pre_sudo: Option<bool>,
|
||||||
pre_commands: Option<Commands>,
|
pre_commands: Option<Commands>,
|
||||||
post_commands: Option<Commands>,
|
post_commands: Option<Commands>,
|
||||||
commands: Option<Commands>,
|
commands: Option<Commands>,
|
||||||
@@ -283,10 +308,12 @@ pub struct ConfigFile {
|
|||||||
tmux_arguments: Option<String>,
|
tmux_arguments: Option<String>,
|
||||||
set_title: Option<bool>,
|
set_title: Option<bool>,
|
||||||
display_time: Option<bool>,
|
display_time: Option<bool>,
|
||||||
|
display_preamble: Option<bool>,
|
||||||
assume_yes: Option<bool>,
|
assume_yes: Option<bool>,
|
||||||
yay_arguments: Option<String>,
|
yay_arguments: Option<String>,
|
||||||
aura_aur_arguments: Option<String>,
|
aura_aur_arguments: Option<String>,
|
||||||
aura_pacman_arguments: Option<String>,
|
aura_pacman_arguments: Option<String>,
|
||||||
|
python: Option<Python>,
|
||||||
no_retry: Option<bool>,
|
no_retry: Option<bool>,
|
||||||
run_in_tmux: Option<bool>,
|
run_in_tmux: Option<bool>,
|
||||||
cleanup: Option<bool>,
|
cleanup: Option<bool>,
|
||||||
@@ -485,6 +512,14 @@ pub struct CommandLineArgs {
|
|||||||
/// See: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/struct.EnvFilter.html
|
/// See: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/struct.EnvFilter.html
|
||||||
#[clap(long, default_value = "info")]
|
#[clap(long, default_value = "info")]
|
||||||
pub log_filter: String,
|
pub log_filter: String,
|
||||||
|
|
||||||
|
/// Print completion script for the given shell and exit
|
||||||
|
#[clap(long, arg_enum, hide = true)]
|
||||||
|
pub gen_completion: Option<Shell>,
|
||||||
|
|
||||||
|
/// Print roff manpage and exit
|
||||||
|
#[clap(long, hide = true)]
|
||||||
|
pub gen_manpage: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CommandLineArgs {
|
impl CommandLineArgs {
|
||||||
@@ -722,6 +757,24 @@ impl Config {
|
|||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Should wsl --update should use the --pre-release flag
|
||||||
|
pub fn wsl_update_pre_release(&self) -> bool {
|
||||||
|
self.config_file
|
||||||
|
.windows
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|w| w.wsl_update_pre_release)
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should wsl --update use the --web-download flag
|
||||||
|
pub fn wsl_update_use_web_download(&self) -> bool {
|
||||||
|
self.config_file
|
||||||
|
.windows
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|w| w.wsl_update_use_web_download)
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
/// Whether Brew cask should be greedy
|
/// Whether Brew cask should be greedy
|
||||||
pub fn brew_cask_greedy(&self) -> bool {
|
pub fn brew_cask_greedy(&self) -> bool {
|
||||||
self.config_file
|
self.config_file
|
||||||
@@ -763,6 +816,15 @@ impl Config {
|
|||||||
self.config_file.notify_each_step.unwrap_or(false)
|
self.config_file.notify_each_step.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Extra garuda-update arguments
|
||||||
|
pub fn garuda_update_arguments(&self) -> &str {
|
||||||
|
self.config_file
|
||||||
|
.linux
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|s| s.garuda_update_arguments.as_deref())
|
||||||
|
.unwrap_or("")
|
||||||
|
}
|
||||||
|
|
||||||
/// Extra trizen arguments
|
/// Extra trizen arguments
|
||||||
pub fn trizen_arguments(&self) -> &str {
|
pub fn trizen_arguments(&self) -> &str {
|
||||||
self.config_file
|
self.config_file
|
||||||
@@ -850,6 +912,14 @@ impl Config {
|
|||||||
.and_then(|linux| linux.dnf_arguments.as_deref())
|
.and_then(|linux| linux.dnf_arguments.as_deref())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Extra nix arguments
|
||||||
|
pub fn nix_arguments(&self) -> Option<&str> {
|
||||||
|
self.config_file
|
||||||
|
.linux
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|linux| linux.nix_arguments.as_deref())
|
||||||
|
}
|
||||||
|
|
||||||
/// Distrobox use root
|
/// Distrobox use root
|
||||||
pub fn distrobox_root(&self) -> bool {
|
pub fn distrobox_root(&self) -> bool {
|
||||||
self.config_file
|
self.config_file
|
||||||
@@ -914,7 +984,7 @@ impl Config {
|
|||||||
.linux
|
.linux
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|linux| linux.rpm_ostree)
|
.and_then(|linux| linux.rpm_ostree)
|
||||||
.unwrap_or(false)
|
.unwrap_or(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Should we ignore failures for this step
|
/// Should we ignore failures for this step
|
||||||
@@ -947,6 +1017,12 @@ impl Config {
|
|||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If `true`, `sudo` should be called after `pre_commands` in order to elevate at the
|
||||||
|
/// start of the session (and not in the middle).
|
||||||
|
pub fn pre_sudo(&self) -> bool {
|
||||||
|
self.config_file.pre_sudo.unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
pub fn npm_use_sudo(&self) -> bool {
|
pub fn npm_use_sudo(&self) -> bool {
|
||||||
self.config_file
|
self.config_file
|
||||||
@@ -1012,10 +1088,31 @@ impl Config {
|
|||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn enable_pipupgrade(&self) -> bool {
|
||||||
|
return self
|
||||||
|
.config_file
|
||||||
|
.python
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|python| python.enable_pipupgrade)
|
||||||
|
.unwrap_or(false);
|
||||||
|
}
|
||||||
|
pub fn enable_pip_review(&self) -> bool {
|
||||||
|
return self
|
||||||
|
.config_file
|
||||||
|
.python
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|python| python.enable_pip_review)
|
||||||
|
.unwrap_or(false);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn display_time(&self) -> bool {
|
pub fn display_time(&self) -> bool {
|
||||||
self.config_file.display_time.unwrap_or(true)
|
self.config_file.display_time.unwrap_or(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn display_preamble(&self) -> bool {
|
||||||
|
self.config_file.display_preamble.unwrap_or(true)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn should_run_custom_command(&self, name: &str) -> bool {
|
pub fn should_run_custom_command(&self, name: &str) -> bool {
|
||||||
if self.opt.custom_commands.is_empty() {
|
if self.opt.custom_commands.is_empty() {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
use crate::executor::RunType;
|
use crate::executor::RunType;
|
||||||
use crate::git::Git;
|
use crate::git::Git;
|
||||||
|
use crate::sudo::Sudo;
|
||||||
use crate::utils::require_option;
|
use crate::utils::require_option;
|
||||||
use crate::{config::Config, executor::Executor};
|
use crate::{config::Config, executor::Executor};
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
use directories::BaseDirs;
|
use directories::BaseDirs;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::Path;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
pub struct ExecutionContext<'a> {
|
pub struct ExecutionContext<'a> {
|
||||||
run_type: RunType,
|
run_type: RunType,
|
||||||
sudo: &'a Option<PathBuf>,
|
sudo: Option<Sudo>,
|
||||||
git: &'a Git,
|
git: &'a Git,
|
||||||
config: &'a Config,
|
config: &'a Config,
|
||||||
base_dirs: &'a BaseDirs,
|
base_dirs: &'a BaseDirs,
|
||||||
@@ -23,7 +24,7 @@ pub struct ExecutionContext<'a> {
|
|||||||
impl<'a> ExecutionContext<'a> {
|
impl<'a> ExecutionContext<'a> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
run_type: RunType,
|
run_type: RunType,
|
||||||
sudo: &'a Option<PathBuf>,
|
sudo: Option<Sudo>,
|
||||||
git: &'a Git,
|
git: &'a Git,
|
||||||
config: &'a Config,
|
config: &'a Config,
|
||||||
base_dirs: &'a BaseDirs,
|
base_dirs: &'a BaseDirs,
|
||||||
@@ -40,18 +41,7 @@ impl<'a> ExecutionContext<'a> {
|
|||||||
|
|
||||||
pub fn execute_elevated(&self, command: &Path, interactive: bool) -> Result<Executor> {
|
pub fn execute_elevated(&self, command: &Path, interactive: bool) -> Result<Executor> {
|
||||||
let sudo = require_option(self.sudo.clone(), "Sudo is required for this operation".into())?;
|
let sudo = require_option(self.sudo.clone(), "Sudo is required for this operation".into())?;
|
||||||
let mut cmd = self.run_type.execute(&sudo);
|
Ok(sudo.execute_elevated(self, command, interactive))
|
||||||
|
|
||||||
if sudo.ends_with("sudo") {
|
|
||||||
cmd.arg("--preserve-env=DIFFPROG");
|
|
||||||
}
|
|
||||||
|
|
||||||
if interactive {
|
|
||||||
cmd.arg("-i");
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd.arg(command);
|
|
||||||
Ok(cmd)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_type(&self) -> RunType {
|
pub fn run_type(&self) -> RunType {
|
||||||
@@ -62,8 +52,8 @@ impl<'a> ExecutionContext<'a> {
|
|||||||
self.git
|
self.git
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sudo(&self) -> &Option<PathBuf> {
|
pub fn sudo(&self) -> &Option<Sudo> {
|
||||||
self.sudo
|
&self.sudo
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn config(&self) -> &Config {
|
pub fn config(&self) -> &Config {
|
||||||
|
|||||||
@@ -176,7 +176,7 @@ impl Executor {
|
|||||||
|
|
||||||
/// An extension of `status_checked` that allows you to set a sequence of codes
|
/// An extension of `status_checked` that allows you to set a sequence of codes
|
||||||
/// that can indicate success of a script
|
/// that can indicate success of a script
|
||||||
#[cfg_attr(windows, 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<()> {
|
||||||
match self {
|
match self {
|
||||||
Executor::Wet(c) => c.status_checked_with(|status| {
|
Executor::Wet(c) => c.status_checked_with(|status| {
|
||||||
|
|||||||
81
src/main.rs
81
src/main.rs
@@ -3,7 +3,9 @@
|
|||||||
use std::env;
|
use std::env;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use clap::CommandFactory;
|
||||||
use clap::{crate_version, Parser};
|
use clap::{crate_version, Parser};
|
||||||
use color_eyre::eyre::Context;
|
use color_eyre::eyre::Context;
|
||||||
use color_eyre::eyre::{eyre, Result};
|
use color_eyre::eyre::{eyre, Result};
|
||||||
@@ -30,6 +32,7 @@ mod self_renamer;
|
|||||||
#[cfg(feature = "self-update")]
|
#[cfg(feature = "self-update")]
|
||||||
mod self_update;
|
mod self_update;
|
||||||
mod steps;
|
mod steps;
|
||||||
|
mod sudo;
|
||||||
mod terminal;
|
mod terminal;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
@@ -41,6 +44,18 @@ fn run() -> Result<()> {
|
|||||||
|
|
||||||
let opt = CommandLineArgs::parse();
|
let opt = CommandLineArgs::parse();
|
||||||
|
|
||||||
|
if let Some(shell) = opt.gen_completion {
|
||||||
|
let cmd = &mut CommandLineArgs::command();
|
||||||
|
clap_complete::generate(shell, cmd, clap::crate_name!(), &mut std::io::stdout());
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
if opt.gen_manpage {
|
||||||
|
let man = clap_mangen::Man::new(CommandLineArgs::command());
|
||||||
|
man.render(&mut std::io::stdout())?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
install_tracing(&opt.tracing_filter_directives())?;
|
install_tracing(&opt.tracing_filter_directives())?;
|
||||||
|
|
||||||
for env in opt.env_variables() {
|
for env in opt.env_variables() {
|
||||||
@@ -71,6 +86,13 @@ fn run() -> Result<()> {
|
|||||||
debug!("Binary path: {:?}", std::env::current_exe());
|
debug!("Binary path: {:?}", std::env::current_exe());
|
||||||
debug!("Self Update: {:?}", cfg!(feature = "self-update"));
|
debug!("Self Update: {:?}", cfg!(feature = "self-update"));
|
||||||
|
|
||||||
|
if config.display_preamble() || !config.skip_notify() {
|
||||||
|
print_warning("Due to a design issue with notify-send it could be that topgrade hangs when it's finished.
|
||||||
|
If this is the case on your system add the --skip-notify flag to the topgrade command or set skip_notify = true in the config file.
|
||||||
|
If you don't want this message to appear any longer set display_preamble = false in the config file.
|
||||||
|
For more information about this issue see https://askubuntu.com/questions/110969/notify-send-ignores-timeout and https://github.com/topgrade-rs/topgrade/issues/288.");
|
||||||
|
}
|
||||||
|
|
||||||
if config.run_in_tmux() && env::var("TOPGRADE_INSIDE_TMUX").is_err() {
|
if config.run_in_tmux() && env::var("TOPGRADE_INSIDE_TMUX").is_err() {
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
{
|
{
|
||||||
@@ -82,10 +104,10 @@ fn run() -> Result<()> {
|
|||||||
let git = git::Git::new();
|
let git = git::Git::new();
|
||||||
let mut git_repos = git::Repositories::new(&git);
|
let mut git_repos = git::Repositories::new(&git);
|
||||||
|
|
||||||
let sudo = utils::sudo();
|
let sudo = sudo::Sudo::detect();
|
||||||
let run_type = executor::RunType::new(config.dry_run());
|
let run_type = executor::RunType::new(config.dry_run());
|
||||||
|
|
||||||
let ctx = execution_context::ExecutionContext::new(run_type, &sudo, &git, &config, &base_dirs);
|
let ctx = execution_context::ExecutionContext::new(run_type, sudo, &git, &config, &base_dirs);
|
||||||
|
|
||||||
let mut runner = runner::Runner::new(&ctx);
|
let mut runner = runner::Runner::new(&ctx);
|
||||||
|
|
||||||
@@ -101,7 +123,7 @@ fn run() -> Result<()> {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
print_warning(format!("Self update error: {}", e));
|
print_warning(format!("Self update error: {e}"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -119,15 +141,24 @@ fn run() -> Result<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if config.pre_sudo() {
|
||||||
|
if let Some(sudo) = ctx.sudo() {
|
||||||
|
sudo.elevate(&ctx)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let powershell = powershell::Powershell::new();
|
let powershell = powershell::Powershell::new();
|
||||||
let should_run_powershell = powershell.profile().is_some() && config.should_run(Step::Powershell);
|
let should_run_powershell = powershell.profile().is_some() && config.should_run(Step::Powershell);
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
runner.execute(Step::Wsl, "WSL", || windows::run_wsl_topgrade(&ctx))?;
|
runner.execute(Step::Wsl, "WSL", || windows::run_wsl_topgrade(&ctx))?;
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
runner.execute(Step::WslUpdate, "WSL", || windows::update_wsl(&ctx))?;
|
||||||
|
|
||||||
if let Some(topgrades) = config.remote_topgrades() {
|
if let Some(topgrades) = config.remote_topgrades() {
|
||||||
for remote_topgrade in topgrades.iter().filter(|t| config.should_execute_remote(t)) {
|
for remote_topgrade in topgrades.iter().filter(|t| config.should_execute_remote(t)) {
|
||||||
runner.execute(Step::Remotes, format!("Remote ({})", remote_topgrade), || {
|
runner.execute(Step::Remotes, format!("Remote ({remote_topgrade})"), || {
|
||||||
remote::ssh::ssh_step(&ctx, remote_topgrade)
|
remote::ssh::ssh_step(&ctx, remote_topgrade)
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
@@ -143,7 +174,7 @@ fn run() -> Result<()> {
|
|||||||
runner.execute(Step::System, "System update", || distribution.upgrade(&ctx))?;
|
runner.execute(Step::System, "System update", || distribution.upgrade(&ctx))?;
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("Error detecting current distribution: {}", e);
|
println!("Error detecting current distribution: {e}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
runner.execute(Step::ConfigUpdate, "config-update", || linux::run_config_update(&ctx))?;
|
runner.execute(Step::ConfigUpdate, "config-update", || linux::run_config_update(&ctx))?;
|
||||||
@@ -197,17 +228,17 @@ fn run() -> Result<()> {
|
|||||||
|
|
||||||
#[cfg(target_os = "dragonfly")]
|
#[cfg(target_os = "dragonfly")]
|
||||||
runner.execute(Step::Pkg, "DragonFly BSD Packages", || {
|
runner.execute(Step::Pkg, "DragonFly BSD Packages", || {
|
||||||
dragonfly::upgrade_packages(sudo.as_ref(), run_type)
|
dragonfly::upgrade_packages(ctx.sudo().as_ref(), run_type)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
#[cfg(target_os = "freebsd")]
|
#[cfg(target_os = "freebsd")]
|
||||||
runner.execute(Step::Pkg, "FreeBSD Packages", || {
|
runner.execute(Step::Pkg, "FreeBSD Packages", || {
|
||||||
freebsd::upgrade_packages(&ctx, sudo.as_ref(), run_type)
|
freebsd::upgrade_packages(&ctx, ctx.sudo().as_ref(), run_type)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
#[cfg(target_os = "openbsd")]
|
#[cfg(target_os = "openbsd")]
|
||||||
runner.execute(Step::Pkg, "OpenBSD Packages", || {
|
runner.execute(Step::Pkg, "OpenBSD Packages", || {
|
||||||
openbsd::upgrade_packages(sudo.as_ref(), run_type)
|
openbsd::upgrade_packages(ctx.sudo().as_ref(), run_type)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
@@ -319,6 +350,7 @@ fn run() -> Result<()> {
|
|||||||
runner.execute(Step::Atom, "apm", || generic::run_apm(run_type))?;
|
runner.execute(Step::Atom, "apm", || generic::run_apm(run_type))?;
|
||||||
runner.execute(Step::Fossil, "fossil", || generic::run_fossil(run_type))?;
|
runner.execute(Step::Fossil, "fossil", || generic::run_fossil(run_type))?;
|
||||||
runner.execute(Step::Rustup, "rustup", || generic::run_rustup(&base_dirs, run_type))?;
|
runner.execute(Step::Rustup, "rustup", || generic::run_rustup(&base_dirs, run_type))?;
|
||||||
|
runner.execute(Step::Juliaup, "juliaup", || generic::run_juliaup(&base_dirs, run_type))?;
|
||||||
runner.execute(Step::Dotnet, ".NET", || generic::run_dotnet_upgrade(&ctx))?;
|
runner.execute(Step::Dotnet, ".NET", || generic::run_dotnet_upgrade(&ctx))?;
|
||||||
runner.execute(Step::Choosenim, "choosenim", || generic::run_choosenim(&ctx))?;
|
runner.execute(Step::Choosenim, "choosenim", || generic::run_choosenim(&ctx))?;
|
||||||
runner.execute(Step::Cargo, "cargo", || generic::run_cargo_update(&ctx))?;
|
runner.execute(Step::Cargo, "cargo", || generic::run_cargo_update(&ctx))?;
|
||||||
@@ -327,10 +359,12 @@ fn run() -> Result<()> {
|
|||||||
runner.execute(Step::Go, "gup", || go::run_go_gup(run_type))?;
|
runner.execute(Step::Go, "gup", || go::run_go_gup(run_type))?;
|
||||||
runner.execute(Step::Emacs, "Emacs", || emacs.upgrade(&ctx))?;
|
runner.execute(Step::Emacs, "Emacs", || emacs.upgrade(&ctx))?;
|
||||||
runner.execute(Step::Opam, "opam", || generic::run_opam_update(&ctx))?;
|
runner.execute(Step::Opam, "opam", || generic::run_opam_update(&ctx))?;
|
||||||
runner.execute(Step::Vcpkg, "vcpkg", || generic::run_vcpkg_update(run_type))?;
|
runner.execute(Step::Vcpkg, "vcpkg", || generic::run_vcpkg_update(&ctx))?;
|
||||||
runner.execute(Step::Pipx, "pipx", || generic::run_pipx_update(run_type))?;
|
runner.execute(Step::Pipx, "pipx", || generic::run_pipx_update(run_type))?;
|
||||||
runner.execute(Step::Conda, "conda", || generic::run_conda_update(&ctx))?;
|
runner.execute(Step::Conda, "conda", || generic::run_conda_update(&ctx))?;
|
||||||
runner.execute(Step::Pip3, "pip3", || generic::run_pip3_update(run_type))?;
|
runner.execute(Step::Pip3, "pip3", || generic::run_pip3_update(run_type))?;
|
||||||
|
runner.execute(Step::PipReview, "pip-review", || generic::run_pip_review_update(&ctx))?;
|
||||||
|
runner.execute(Step::Pipupgrade, "pipupgrade", || generic::run_pipupgrade_update(&ctx))?;
|
||||||
runner.execute(Step::Ghcup, "ghcup", || generic::run_ghcup_update(run_type))?;
|
runner.execute(Step::Ghcup, "ghcup", || generic::run_ghcup_update(run_type))?;
|
||||||
runner.execute(Step::Stack, "stack", || generic::run_stack_update(run_type))?;
|
runner.execute(Step::Stack, "stack", || generic::run_stack_update(run_type))?;
|
||||||
runner.execute(Step::Tlmgr, "tlmgr", || generic::run_tlmgr_update(&ctx))?;
|
runner.execute(Step::Tlmgr, "tlmgr", || generic::run_tlmgr_update(&ctx))?;
|
||||||
@@ -346,14 +380,17 @@ fn run() -> Result<()> {
|
|||||||
runner.execute(Step::Vim, "The Ultimate vimrc", || vim::upgrade_ultimate_vimrc(&ctx))?;
|
runner.execute(Step::Vim, "The Ultimate vimrc", || vim::upgrade_ultimate_vimrc(&ctx))?;
|
||||||
runner.execute(Step::Vim, "voom", || vim::run_voom(&base_dirs, run_type))?;
|
runner.execute(Step::Vim, "voom", || vim::run_voom(&base_dirs, run_type))?;
|
||||||
runner.execute(Step::Kakoune, "Kakoune", || kakoune::upgrade_kak_plug(&ctx))?;
|
runner.execute(Step::Kakoune, "Kakoune", || kakoune::upgrade_kak_plug(&ctx))?;
|
||||||
|
runner.execute(Step::Helix, "helix", || generic::run_helix_grammars(&ctx))?;
|
||||||
runner.execute(Step::Node, "npm", || node::run_npm_upgrade(&ctx))?;
|
runner.execute(Step::Node, "npm", || node::run_npm_upgrade(&ctx))?;
|
||||||
runner.execute(Step::Node, "yarn", || node::run_yarn_upgrade(&ctx))?;
|
runner.execute(Step::Yarn, "yarn", || node::run_yarn_upgrade(&ctx))?;
|
||||||
runner.execute(Step::Node, "pnpm", || node::run_pnpm_upgrade(&ctx))?;
|
runner.execute(Step::Pnpm, "pnpm", || node::run_pnpm_upgrade(&ctx))?;
|
||||||
runner.execute(Step::Containers, "Containers", || containers::run_containers(&ctx))?;
|
runner.execute(Step::Containers, "Containers", || containers::run_containers(&ctx))?;
|
||||||
runner.execute(Step::Deno, "deno", || node::deno_upgrade(&ctx))?;
|
runner.execute(Step::Deno, "deno", || node::deno_upgrade(&ctx))?;
|
||||||
runner.execute(Step::Composer, "composer", || generic::run_composer_update(&ctx))?;
|
runner.execute(Step::Composer, "composer", || generic::run_composer_update(&ctx))?;
|
||||||
runner.execute(Step::Krew, "krew", || generic::run_krew_upgrade(run_type))?;
|
runner.execute(Step::Krew, "krew", || generic::run_krew_upgrade(run_type))?;
|
||||||
|
runner.execute(Step::Helm, "helm", || generic::run_helm_repo_update(run_type))?;
|
||||||
runner.execute(Step::Gem, "gem", || generic::run_gem(&base_dirs, run_type))?;
|
runner.execute(Step::Gem, "gem", || generic::run_gem(&base_dirs, run_type))?;
|
||||||
|
runner.execute(Step::RubyGems, "rubygems", || generic::run_rubygems(&ctx))?;
|
||||||
runner.execute(Step::Julia, "julia", || generic::update_julia_packages(&ctx))?;
|
runner.execute(Step::Julia, "julia", || generic::update_julia_packages(&ctx))?;
|
||||||
runner.execute(Step::Haxelib, "haxelib", || generic::run_haxelib_update(&ctx))?;
|
runner.execute(Step::Haxelib, "haxelib", || generic::run_haxelib_update(&ctx))?;
|
||||||
runner.execute(Step::Sheldon, "sheldon", || generic::run_sheldon(&ctx))?;
|
runner.execute(Step::Sheldon, "sheldon", || generic::run_sheldon(&ctx))?;
|
||||||
@@ -371,14 +408,16 @@ fn run() -> Result<()> {
|
|||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
{
|
{
|
||||||
|
runner.execute(Step::AM, "am", || linux::update_am(&ctx))?;
|
||||||
runner.execute(Step::DebGet, "deb-get", || linux::run_deb_get(&ctx))?;
|
runner.execute(Step::DebGet, "deb-get", || linux::run_deb_get(&ctx))?;
|
||||||
runner.execute(Step::Toolbx, "toolbx", || toolbx::run_toolbx(&ctx))?;
|
runner.execute(Step::Toolbx, "toolbx", || toolbx::run_toolbx(&ctx))?;
|
||||||
runner.execute(Step::Flatpak, "Flatpak", || linux::flatpak_update(&ctx))?;
|
runner.execute(Step::Flatpak, "Flatpak", || linux::flatpak_update(&ctx))?;
|
||||||
runner.execute(Step::Snap, "snap", || linux::run_snap(sudo.as_ref(), run_type))?;
|
runner.execute(Step::Snap, "snap", || linux::run_snap(ctx.sudo().as_ref(), run_type))?;
|
||||||
runner.execute(Step::Pacstall, "pacstall", || linux::run_pacstall(&ctx))?;
|
runner.execute(Step::Pacstall, "pacstall", || linux::run_pacstall(&ctx))?;
|
||||||
runner.execute(Step::Pacdef, "pacdef", || linux::run_pacdef(&ctx))?;
|
runner.execute(Step::Pacdef, "pacdef", || linux::run_pacdef(&ctx))?;
|
||||||
runner.execute(Step::Protonup, "protonup", || linux::run_protonup_update(&ctx))?;
|
runner.execute(Step::Protonup, "protonup", || linux::run_protonup_update(&ctx))?;
|
||||||
runner.execute(Step::Distrobox, "distrobox", || linux::run_distrobox_update(&ctx))?;
|
runner.execute(Step::Distrobox, "distrobox", || linux::run_distrobox_update(&ctx))?;
|
||||||
|
runner.execute(Step::DkpPacman, "dkp-pacman", || linux::run_dkp_pacman_update(&ctx))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(commands) = config.commands() {
|
if let Some(commands) = config.commands() {
|
||||||
@@ -394,11 +433,11 @@ fn run() -> Result<()> {
|
|||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
{
|
{
|
||||||
runner.execute(Step::System, "pihole", || {
|
runner.execute(Step::System, "pihole", || {
|
||||||
linux::run_pihole_update(sudo.as_ref(), run_type)
|
linux::run_pihole_update(ctx.sudo().as_ref(), run_type)
|
||||||
})?;
|
})?;
|
||||||
runner.execute(Step::Firmware, "Firmware upgrades", || linux::run_fwupdmgr(&ctx))?;
|
runner.execute(Step::Firmware, "Firmware upgrades", || linux::run_fwupdmgr(&ctx))?;
|
||||||
runner.execute(Step::Restarts, "Restarts", || {
|
runner.execute(Step::Restarts, "Restarts", || {
|
||||||
linux::run_needrestart(sudo.as_ref(), run_type)
|
linux::run_needrestart(ctx.sudo().as_ref(), run_type)
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -411,12 +450,12 @@ fn run() -> Result<()> {
|
|||||||
|
|
||||||
#[cfg(target_os = "freebsd")]
|
#[cfg(target_os = "freebsd")]
|
||||||
runner.execute(Step::System, "FreeBSD Upgrade", || {
|
runner.execute(Step::System, "FreeBSD Upgrade", || {
|
||||||
freebsd::upgrade_freebsd(sudo.as_ref(), run_type)
|
freebsd::upgrade_freebsd(ctx.sudo().as_ref(), run_type)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
#[cfg(target_os = "openbsd")]
|
#[cfg(target_os = "openbsd")]
|
||||||
runner.execute(Step::System, "OpenBSD Upgrade", || {
|
runner.execute(Step::System, "OpenBSD Upgrade", || {
|
||||||
openbsd::upgrade_openbsd(sudo.as_ref(), run_type)
|
openbsd::upgrade_openbsd(ctx.sudo().as_ref(), run_type)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@@ -448,10 +487,10 @@ fn run() -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "freebsd")]
|
#[cfg(target_os = "freebsd")]
|
||||||
freebsd::audit_packages(&sudo).ok();
|
freebsd::audit_packages(ctx.sudo().as_ref()).ok();
|
||||||
|
|
||||||
#[cfg(target_os = "dragonfly")]
|
#[cfg(target_os = "dragonfly")]
|
||||||
dragonfly::audit_packages(&sudo).ok();
|
dragonfly::audit_packages(ctx.sudo().as_ref()).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut post_command_failed = false;
|
let mut post_command_failed = false;
|
||||||
@@ -490,8 +529,8 @@ fn run() -> Result<()> {
|
|||||||
"Topgrade finished {}",
|
"Topgrade finished {}",
|
||||||
if failed { "with errors" } else { "successfully" }
|
if failed { "with errors" } else { "successfully" }
|
||||||
),
|
),
|
||||||
None,
|
Some(Duration::from_secs(10)),
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if failed {
|
if failed {
|
||||||
@@ -524,7 +563,7 @@ fn main() {
|
|||||||
// The `Debug` implementation of `eyre::Result` prints a multi-line
|
// The `Debug` implementation of `eyre::Result` prints a multi-line
|
||||||
// error message that includes all the 'causes' added with
|
// error message that includes all the 'causes' added with
|
||||||
// `.with_context(...)` calls.
|
// `.with_context(...)` calls.
|
||||||
println!("Error: {:?}", error);
|
println!("Error: {error:?}");
|
||||||
}
|
}
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ impl<'a> Report<'a> {
|
|||||||
if let Some((key, success)) = result {
|
if let Some((key, success)) = result {
|
||||||
let key = key.into();
|
let key = key.into();
|
||||||
|
|
||||||
debug_assert!(!self.data.iter().any(|(k, _)| k == &key), "{} already reported", key);
|
debug_assert!(!self.data.iter().any(|(k, _)| k == &key), "{key} already reported");
|
||||||
self.data.push((key, success));
|
self.data.push((key, success));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ pub fn self_update() -> Result<()> {
|
|||||||
if let UpdateStatus::Updated(release) = &result {
|
if let UpdateStatus::Updated(release) = &result {
|
||||||
println!("\nTopgrade upgraded to {}:\n", release.version);
|
println!("\nTopgrade upgraded to {}:\n", release.version);
|
||||||
if let Some(body) = &release.body {
|
if let Some(body) = &release.body {
|
||||||
println!("{}", body);
|
println!("{body}");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
println!("Topgrade is up-to-date");
|
println!("Topgrade is up-to-date");
|
||||||
|
|||||||
@@ -10,15 +10,15 @@ use color_eyre::eyre::Context;
|
|||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
use directories::BaseDirs;
|
use directories::BaseDirs;
|
||||||
use tempfile::tempfile_in;
|
use tempfile::tempfile_in;
|
||||||
use tracing::debug;
|
use tracing::{debug, error};
|
||||||
|
|
||||||
use crate::command::{CommandExt, Utf8Output};
|
use crate::command::{CommandExt, Utf8Output};
|
||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
use crate::executor::{ExecutorOutput, RunType};
|
use crate::executor::{ExecutorOutput, RunType};
|
||||||
use crate::terminal::{print_separator, shell};
|
use crate::terminal::{print_separator, shell};
|
||||||
use crate::utils::{self, require_option, PathExt};
|
use crate::utils::{self, require, require_option, which, PathExt};
|
||||||
use crate::{
|
use crate::{
|
||||||
error::{SkipStep, TopgradeError},
|
error::{SkipStep, StepFailed, TopgradeError},
|
||||||
terminal::print_warning,
|
terminal::print_warning,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -70,7 +70,7 @@ pub fn run_gem(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
|||||||
let gem = utils::require("gem")?;
|
let gem = utils::require("gem")?;
|
||||||
base_dirs.home_dir().join(".gem").require()?;
|
base_dirs.home_dir().join(".gem").require()?;
|
||||||
|
|
||||||
print_separator("RubyGems");
|
print_separator("Gems");
|
||||||
|
|
||||||
let mut command = run_type.execute(gem);
|
let mut command = run_type.execute(gem);
|
||||||
command.arg("update");
|
command.arg("update");
|
||||||
@@ -83,6 +83,26 @@ pub fn run_gem(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
|||||||
command.status_checked()
|
command.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn run_rubygems(ctx: &ExecutionContext) -> Result<()> {
|
||||||
|
ctx.base_dirs().home_dir().join(".gem").require()?;
|
||||||
|
|
||||||
|
print_separator("RubyGems");
|
||||||
|
if let Some(sudo) = &ctx.sudo() {
|
||||||
|
if !std::path::Path::new("/usr/lib/ruby/vendor_ruby/rubygems/defaults/operating_system.rb").exists() {
|
||||||
|
ctx.run_type()
|
||||||
|
.execute(sudo)
|
||||||
|
.arg("-EH")
|
||||||
|
.arg(require("gem")?)
|
||||||
|
.args(["update", "--system"])
|
||||||
|
.status_checked()?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
print_warning("No sudo detected. Skipping system upgrade");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn run_haxelib_update(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_haxelib_update(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let haxelib = utils::require("haxelib")?;
|
let haxelib = utils::require("haxelib")?;
|
||||||
|
|
||||||
@@ -175,6 +195,18 @@ pub fn run_rustup(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
|||||||
run_type.execute(&rustup).arg("update").status_checked()
|
run_type.execute(&rustup).arg("update").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn run_juliaup(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
||||||
|
let juliaup = utils::require("juliaup")?;
|
||||||
|
|
||||||
|
print_separator("juliaup");
|
||||||
|
|
||||||
|
if juliaup.canonicalize()?.is_descendant_of(base_dirs.home_dir()) {
|
||||||
|
run_type.execute(&juliaup).args(["self", "update"]).status_checked()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
run_type.execute(&juliaup).arg("update").status_checked()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn run_choosenim(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_choosenim(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let choosenim = utils::require("choosenim")?;
|
let choosenim = utils::require("choosenim")?;
|
||||||
|
|
||||||
@@ -239,14 +271,27 @@ pub fn run_opam_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_vcpkg_update(run_type: RunType) -> Result<()> {
|
pub fn run_vcpkg_update(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let vcpkg = utils::require("vcpkg")?;
|
let vcpkg = utils::require("vcpkg")?;
|
||||||
print_separator("vcpkg");
|
print_separator("vcpkg");
|
||||||
|
|
||||||
run_type
|
#[cfg(unix)]
|
||||||
.execute(vcpkg)
|
let is_root_install = !&vcpkg.starts_with("/home");
|
||||||
.args(["upgrade", "--no-dry-run"])
|
|
||||||
.status_checked()
|
#[cfg(not(unix))]
|
||||||
|
let is_root_install = false;
|
||||||
|
|
||||||
|
let mut command = if is_root_install {
|
||||||
|
ctx.run_type().execute(&vcpkg)
|
||||||
|
} else {
|
||||||
|
let mut c = ctx
|
||||||
|
.run_type()
|
||||||
|
.execute(ctx.sudo().as_ref().ok_or(TopgradeError::SudoRequired)?);
|
||||||
|
c.arg(&vcpkg);
|
||||||
|
c
|
||||||
|
};
|
||||||
|
|
||||||
|
command.args(["upgrade", "--no-dry-run"]).status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_pipx_update(run_type: RunType) -> Result<()> {
|
pub fn run_pipx_update(run_type: RunType) -> Result<()> {
|
||||||
@@ -294,6 +339,39 @@ pub fn run_pip3_update(run_type: RunType) -> Result<()> {
|
|||||||
.status_checked()
|
.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn run_pip_review_update(ctx: &ExecutionContext) -> Result<()> {
|
||||||
|
let pip_review = require("pip-review")?;
|
||||||
|
|
||||||
|
print_separator("pip-review");
|
||||||
|
|
||||||
|
if !ctx.config().enable_pip_review() {
|
||||||
|
print_warning(
|
||||||
|
"Pip-review is disabled by default. Enable it by setting enable_pip_review=true in the configuration.",
|
||||||
|
);
|
||||||
|
return Err(SkipStep(String::from("Pip-review is disabled by default")).into());
|
||||||
|
}
|
||||||
|
ctx.run_type()
|
||||||
|
.execute(pip_review)
|
||||||
|
.arg("--auto")
|
||||||
|
.status_checked_with_codes(&[1])?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn run_pipupgrade_update(ctx: &ExecutionContext) -> Result<()> {
|
||||||
|
let pipupgrade = require("pipupgrade")?;
|
||||||
|
|
||||||
|
print_separator("Pipupgrade");
|
||||||
|
if !ctx.config().enable_pip_review() {
|
||||||
|
print_warning(
|
||||||
|
"Pipupgrade is disabled by default. Enable it by setting enable_pipupgrade=true in the configuration.",
|
||||||
|
);
|
||||||
|
return Err(SkipStep(String::from("Pipupgrade is disabled by default")).into());
|
||||||
|
}
|
||||||
|
ctx.run_type().execute(pipupgrade).status_checked()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn run_stack_update(run_type: RunType) -> Result<()> {
|
pub fn run_stack_update(run_type: RunType) -> Result<()> {
|
||||||
if utils::require("ghcup").is_ok() {
|
if utils::require("ghcup").is_ok() {
|
||||||
// `ghcup` is present and probably(?) being used to install `stack`.
|
// `ghcup` is present and probably(?) being used to install `stack`.
|
||||||
@@ -397,7 +475,7 @@ pub fn run_composer_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
let composer_home = Command::new(&composer)
|
let composer_home = Command::new(&composer)
|
||||||
.args(["global", "config", "--absolute", "--quiet", "home"])
|
.args(["global", "config", "--absolute", "--quiet", "home"])
|
||||||
.output_checked_utf8()
|
.output_checked_utf8()
|
||||||
.map_err(|e| (SkipStep(format!("Error getting the composer directory: {}", e))))
|
.map_err(|e| (SkipStep(format!("Error getting the composer directory: {e}"))))
|
||||||
.map(|s| PathBuf::from(s.stdout.trim()))?
|
.map(|s| PathBuf::from(s.stdout.trim()))?
|
||||||
.require()?;
|
.require()?;
|
||||||
|
|
||||||
@@ -450,9 +528,21 @@ pub fn run_composer_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
pub fn run_dotnet_upgrade(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_dotnet_upgrade(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let dotnet = utils::require("dotnet")?;
|
let dotnet = utils::require("dotnet")?;
|
||||||
|
|
||||||
let output = Command::new(dotnet)
|
//Skip when the `dotnet tool list` subcommand fails. (This is expected when a dotnet runtime is installed but no SDK.)
|
||||||
|
let output = match ctx
|
||||||
|
.run_type()
|
||||||
|
.execute(&dotnet)
|
||||||
.args(["tool", "list", "--global"])
|
.args(["tool", "list", "--global"])
|
||||||
.output_checked_utf8()?;
|
.output_checked_utf8()
|
||||||
|
{
|
||||||
|
Ok(output) => output,
|
||||||
|
Err(_) => {
|
||||||
|
return Err(SkipStep(String::from(
|
||||||
|
"Error running `dotnet tool list`. This is expected when a dotnet runtime is installed but no SDK.",
|
||||||
|
))
|
||||||
|
.into())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if !output.stdout.starts_with("Package Id") {
|
if !output.stdout.starts_with("Package Id") {
|
||||||
return Err(SkipStep(String::from("dotnet did not output packages")).into());
|
return Err(SkipStep(String::from("dotnet did not output packages")).into());
|
||||||
@@ -469,7 +559,7 @@ pub fn run_dotnet_upgrade(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
for package in packages {
|
for package in packages {
|
||||||
let package_name = package.split_whitespace().next().unwrap();
|
let package_name = package.split_whitespace().next().unwrap();
|
||||||
ctx.run_type()
|
ctx.run_type()
|
||||||
.execute("dotnet")
|
.execute(&dotnet)
|
||||||
.args(["tool", "update", package_name, "--global"])
|
.args(["tool", "update", package_name, "--global"])
|
||||||
.status_checked()
|
.status_checked()
|
||||||
.with_context(|| format!("Failed to update .NET package {package_name}"))?;
|
.with_context(|| format!("Failed to update .NET package {package_name}"))?;
|
||||||
@@ -478,6 +568,26 @@ pub fn run_dotnet_upgrade(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn run_helix_grammars(ctx: &ExecutionContext) -> Result<()> {
|
||||||
|
utils::require("helix")?;
|
||||||
|
|
||||||
|
print_separator("Helix");
|
||||||
|
|
||||||
|
ctx.run_type()
|
||||||
|
.execute(ctx.sudo().as_ref().ok_or(TopgradeError::SudoRequired)?)
|
||||||
|
.args(["helix", "--grammar", "fetch"])
|
||||||
|
.status_checked()
|
||||||
|
.with_context(|| "Failed to download helix grammars!")?;
|
||||||
|
|
||||||
|
ctx.run_type()
|
||||||
|
.execute(ctx.sudo().as_ref().ok_or(TopgradeError::SudoRequired)?)
|
||||||
|
.args(["helix", "--grammar", "build"])
|
||||||
|
.status_checked()
|
||||||
|
.with_context(|| "Failed to build helix grammars!")?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn run_raco_update(run_type: RunType) -> Result<()> {
|
pub fn run_raco_update(run_type: RunType) -> Result<()> {
|
||||||
let raco = utils::require("raco")?;
|
let raco = utils::require("raco")?;
|
||||||
|
|
||||||
@@ -525,3 +635,29 @@ pub fn update_julia_packages(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
.args(["-e", "using Pkg; Pkg.update()"])
|
.args(["-e", "using Pkg; Pkg.update()"])
|
||||||
.status_checked()
|
.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn run_helm_repo_update(run_type: RunType) -> Result<()> {
|
||||||
|
let helm = utils::require("helm")?;
|
||||||
|
|
||||||
|
print_separator("Helm");
|
||||||
|
|
||||||
|
let no_repo = "no repositories found";
|
||||||
|
let mut success = true;
|
||||||
|
let mut exec = run_type.execute(helm);
|
||||||
|
if let Err(e) = exec.arg("repo").arg("update").status_checked() {
|
||||||
|
error!("Updating repositories failed: {}", e);
|
||||||
|
success = match exec.output_checked_utf8() {
|
||||||
|
Ok(s) => s.stdout.contains(no_repo) || s.stderr.contains(no_repo),
|
||||||
|
Err(e) => match e.downcast_ref::<TopgradeError>() {
|
||||||
|
Some(TopgradeError::ProcessFailedWithOutput(_, _, stderr)) => stderr.contains(no_repo),
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if success {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(eyre!(StepFailed))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ async fn pull_repository(repo: String, git: &Path, ctx: &ExecutionContext<'_>) -
|
|||||||
|
|
||||||
if let Err(message) = &result {
|
if let Err(message) = &result {
|
||||||
println!("{} pulling {}", style("Failed").red().bold(), &repo);
|
println!("{} pulling {}", style("Failed").red().bold(), &repo);
|
||||||
print!("{}", message);
|
print!("{message}");
|
||||||
} else {
|
} else {
|
||||||
let after_revision = get_head_revision(git, &repo);
|
let after_revision = get_head_revision(git, &repo);
|
||||||
|
|
||||||
@@ -87,7 +87,7 @@ async fn pull_repository(repo: String, git: &Path, ctx: &ExecutionContext<'_>) -
|
|||||||
"log",
|
"log",
|
||||||
"--no-decorate",
|
"--no-decorate",
|
||||||
"--oneline",
|
"--oneline",
|
||||||
&format!("{}..{}", before, after),
|
&format!("{before}..{after}"),
|
||||||
])
|
])
|
||||||
.status_checked()?;
|
.status_checked()?;
|
||||||
println!();
|
println!();
|
||||||
@@ -187,7 +187,7 @@ impl Git {
|
|||||||
repositories
|
repositories
|
||||||
.bad_patterns
|
.bad_patterns
|
||||||
.iter()
|
.iter()
|
||||||
.for_each(|pattern| print_warning(format!("Path {} did not contain any git repositories", pattern)));
|
.for_each(|pattern| print_warning(format!("Path {pattern} did not contain any git repositories")));
|
||||||
self.multi_pull(repositories, ctx)
|
self.multi_pull(repositories, ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,9 +12,7 @@ use semver::Version;
|
|||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
use crate::executor::RunType;
|
|
||||||
use crate::terminal::print_separator;
|
use crate::terminal::print_separator;
|
||||||
use crate::utils::sudo;
|
|
||||||
use crate::utils::{require, PathExt};
|
use crate::utils::{require, PathExt};
|
||||||
use crate::{error::SkipStep, execution_context::ExecutionContext};
|
use crate::{error::SkipStep, execution_context::ExecutionContext};
|
||||||
|
|
||||||
@@ -90,14 +88,17 @@ impl NPM {
|
|||||||
Version::parse(&version_str?).map_err(|err| err.into())
|
Version::parse(&version_str?).map_err(|err| err.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn upgrade(&self, run_type: RunType, use_sudo: bool) -> Result<()> {
|
fn upgrade(&self, ctx: &ExecutionContext, use_sudo: bool) -> Result<()> {
|
||||||
let args = ["update", self.global_location_arg()];
|
let args = ["update", self.global_location_arg()];
|
||||||
if use_sudo {
|
if use_sudo {
|
||||||
let sudo_option = sudo();
|
let sudo = require_option(ctx.sudo().clone(), String::from("sudo is not installed"))?;
|
||||||
let sudo = require_option(sudo_option, String::from("sudo is not installed"))?;
|
ctx.run_type()
|
||||||
run_type.execute(sudo).arg(&self.command).args(args).status_checked()?;
|
.execute(sudo)
|
||||||
|
.arg(&self.command)
|
||||||
|
.args(args)
|
||||||
|
.status_checked()?;
|
||||||
} else {
|
} else {
|
||||||
run_type.execute(&self.command).args(args).status_checked()?;
|
ctx.run_type().execute(&self.command).args(args).status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -150,17 +151,18 @@ impl Yarn {
|
|||||||
.map(|s| PathBuf::from(s.stdout.trim()))
|
.map(|s| PathBuf::from(s.stdout.trim()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn upgrade(&self, run_type: RunType, use_sudo: bool) -> Result<()> {
|
fn upgrade(&self, ctx: &ExecutionContext, use_sudo: bool) -> Result<()> {
|
||||||
let args = ["global", "upgrade"];
|
let args = ["global", "upgrade"];
|
||||||
|
|
||||||
if use_sudo {
|
if use_sudo {
|
||||||
run_type
|
let sudo = require_option(ctx.sudo().clone(), String::from("sudo is not installed"))?;
|
||||||
.execute("sudo")
|
ctx.run_type()
|
||||||
|
.execute(sudo)
|
||||||
.arg(self.yarn.as_ref().unwrap_or(&self.command))
|
.arg(self.yarn.as_ref().unwrap_or(&self.command))
|
||||||
.args(args)
|
.args(args)
|
||||||
.status_checked()?;
|
.status_checked()?;
|
||||||
} else {
|
} else {
|
||||||
run_type.execute(&self.command).args(args).status_checked()?;
|
ctx.run_type().execute(&self.command).args(args).status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -215,12 +217,12 @@ pub fn run_npm_upgrade(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
{
|
{
|
||||||
npm.upgrade(ctx.run_type(), should_use_sudo(&npm, ctx)?)
|
npm.upgrade(ctx, should_use_sudo(&npm, ctx)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_os = "linux"))]
|
#[cfg(not(target_os = "linux"))]
|
||||||
{
|
{
|
||||||
npm.upgrade(ctx.run_type(), false)
|
npm.upgrade(ctx, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,12 +233,12 @@ pub fn run_pnpm_upgrade(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
{
|
{
|
||||||
pnpm.upgrade(ctx.run_type(), should_use_sudo(&pnpm, ctx)?)
|
pnpm.upgrade(ctx, should_use_sudo(&pnpm, ctx)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_os = "linux"))]
|
#[cfg(not(target_os = "linux"))]
|
||||||
{
|
{
|
||||||
pnpm.upgrade(ctx.run_type(), false)
|
pnpm.upgrade(ctx, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,12 +254,12 @@ pub fn run_yarn_upgrade(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
{
|
{
|
||||||
yarn.upgrade(ctx.run_type(), should_use_sudo_yarn(&yarn, ctx)?)
|
yarn.upgrade(ctx, should_use_sudo_yarn(&yarn, ctx)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_os = "linux"))]
|
#[cfg(not(target_os = "linux"))]
|
||||||
{
|
{
|
||||||
yarn.upgrade(ctx.run_type(), false)
|
yarn.upgrade(ctx, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
use std::env::var_os;
|
use std::env::var_os;
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::Command;
|
|
||||||
|
|
||||||
use color_eyre::eyre;
|
use color_eyre::eyre;
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
@@ -10,6 +9,7 @@ use walkdir::WalkDir;
|
|||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
use crate::error::TopgradeError;
|
use crate::error::TopgradeError;
|
||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
|
use crate::sudo::Sudo;
|
||||||
use crate::utils::which;
|
use crate::utils::which;
|
||||||
use crate::{config, Step};
|
use crate::{config, Step};
|
||||||
|
|
||||||
@@ -31,7 +31,10 @@ pub struct YayParu {
|
|||||||
impl ArchPackageManager for YayParu {
|
impl ArchPackageManager for YayParu {
|
||||||
fn upgrade(&self, ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade(&self, ctx: &ExecutionContext) -> Result<()> {
|
||||||
if ctx.config().show_arch_news() {
|
if ctx.config().show_arch_news() {
|
||||||
Command::new(&self.executable).arg("-Pw").status_checked()?;
|
ctx.run_type()
|
||||||
|
.execute(&self.executable)
|
||||||
|
.arg("-Pw")
|
||||||
|
.status_checked_with_codes(&[1, 0])?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut command = ctx.run_type().execute(&self.executable);
|
let mut command = ctx.run_type().execute(&self.executable);
|
||||||
@@ -70,6 +73,37 @@ impl YayParu {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct GarudaUpdate {
|
||||||
|
executable: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ArchPackageManager for GarudaUpdate {
|
||||||
|
fn upgrade(&self, ctx: &ExecutionContext) -> Result<()> {
|
||||||
|
let mut command = ctx.run_type().execute(&self.executable);
|
||||||
|
|
||||||
|
command
|
||||||
|
.env("PATH", get_execution_path())
|
||||||
|
.env("UPDATE_AUR", "1")
|
||||||
|
.env("SKIP_MIRRORLIST", "1");
|
||||||
|
|
||||||
|
if ctx.config().yes(Step::System) {
|
||||||
|
command.env("PACMAN_NOCONFIRM", "1");
|
||||||
|
}
|
||||||
|
command.args(ctx.config().garuda_update_arguments().split_whitespace());
|
||||||
|
command.status_checked()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GarudaUpdate {
|
||||||
|
fn get() -> Option<Self> {
|
||||||
|
Some(Self {
|
||||||
|
executable: which("garuda-update")?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Trizen {
|
pub struct Trizen {
|
||||||
executable: PathBuf,
|
executable: PathBuf,
|
||||||
}
|
}
|
||||||
@@ -110,7 +144,7 @@ impl Trizen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct Pacman {
|
pub struct Pacman {
|
||||||
sudo: PathBuf,
|
sudo: Sudo,
|
||||||
executable: PathBuf,
|
executable: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,7 +263,7 @@ impl ArchPackageManager for Pamac {
|
|||||||
|
|
||||||
pub struct Aura {
|
pub struct Aura {
|
||||||
executable: PathBuf,
|
executable: PathBuf,
|
||||||
sudo: PathBuf,
|
sudo: Sudo,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Aura {
|
impl Aura {
|
||||||
@@ -282,14 +316,16 @@ pub fn get_arch_package_manager(ctx: &ExecutionContext) -> Option<Box<dyn ArchPa
|
|||||||
let pacman = which("powerpill").unwrap_or_else(|| PathBuf::from("pacman"));
|
let pacman = which("powerpill").unwrap_or_else(|| PathBuf::from("pacman"));
|
||||||
|
|
||||||
match ctx.config().arch_package_manager() {
|
match ctx.config().arch_package_manager() {
|
||||||
config::ArchPackageManager::Autodetect => YayParu::get("paru", &pacman)
|
config::ArchPackageManager::Autodetect => GarudaUpdate::get()
|
||||||
.map(box_package_manager)
|
.map(box_package_manager)
|
||||||
|
.or_else(|| YayParu::get("paru", &pacman).map(box_package_manager))
|
||||||
.or_else(|| YayParu::get("yay", &pacman).map(box_package_manager))
|
.or_else(|| YayParu::get("yay", &pacman).map(box_package_manager))
|
||||||
.or_else(|| Trizen::get().map(box_package_manager))
|
.or_else(|| Trizen::get().map(box_package_manager))
|
||||||
.or_else(|| Pikaur::get().map(box_package_manager))
|
.or_else(|| Pikaur::get().map(box_package_manager))
|
||||||
.or_else(|| Pamac::get().map(box_package_manager))
|
.or_else(|| Pamac::get().map(box_package_manager))
|
||||||
.or_else(|| Pacman::get(ctx).map(box_package_manager))
|
.or_else(|| Pacman::get(ctx).map(box_package_manager))
|
||||||
.or_else(|| Aura::get(ctx).map(box_package_manager)),
|
.or_else(|| Aura::get(ctx).map(box_package_manager)),
|
||||||
|
config::ArchPackageManager::GarudaUpdate => GarudaUpdate::get().map(box_package_manager),
|
||||||
config::ArchPackageManager::Trizen => Trizen::get().map(box_package_manager),
|
config::ArchPackageManager::Trizen => Trizen::get().map(box_package_manager),
|
||||||
config::ArchPackageManager::Paru => YayParu::get("paru", &pacman).map(box_package_manager),
|
config::ArchPackageManager::Paru => YayParu::get("paru", &pacman).map(box_package_manager),
|
||||||
config::ArchPackageManager::Yay => YayParu::get("yay", &pacman).map(box_package_manager),
|
config::ArchPackageManager::Yay => YayParu::get("yay", &pacman).map(box_package_manager),
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
use crate::executor::RunType;
|
use crate::executor::RunType;
|
||||||
|
use crate::sudo::Sudo;
|
||||||
use crate::terminal::print_separator;
|
use crate::terminal::print_separator;
|
||||||
use crate::utils::require_option;
|
use crate::utils::require_option;
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
use std::path::PathBuf;
|
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
pub fn upgrade_packages(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> {
|
pub fn upgrade_packages(sudo: Option<&Sudo>, run_type: RunType) -> Result<()> {
|
||||||
let sudo = require_option(sudo, String::from("No sudo detected"))?;
|
let sudo = require_option(sudo, String::from("No sudo detected"))?;
|
||||||
print_separator("DragonFly BSD Packages");
|
print_separator("DragonFly BSD Packages");
|
||||||
run_type
|
run_type
|
||||||
@@ -15,7 +15,7 @@ pub fn upgrade_packages(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()>
|
|||||||
.status_checked()
|
.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn audit_packages(sudo: &Option<PathBuf>) -> Result<()> {
|
pub fn audit_packages(sudo: Option<&Sudo>) -> Result<()> {
|
||||||
if let Some(sudo) = sudo {
|
if let Some(sudo) = sudo {
|
||||||
println!();
|
println!();
|
||||||
Command::new(sudo)
|
Command::new(sudo)
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
use crate::executor::RunType;
|
use crate::executor::RunType;
|
||||||
|
use crate::sudo::Sudo;
|
||||||
use crate::terminal::print_separator;
|
use crate::terminal::print_separator;
|
||||||
use crate::utils::require_option;
|
use crate::utils::require_option;
|
||||||
use crate::Step;
|
use crate::Step;
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
use std::path::PathBuf;
|
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
pub fn upgrade_freebsd(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> {
|
pub fn upgrade_freebsd(sudo: Option<&Sudo>, run_type: RunType) -> Result<()> {
|
||||||
let sudo = require_option(sudo, String::from("No sudo detected"))?;
|
let sudo = require_option(sudo, String::from("No sudo detected"))?;
|
||||||
print_separator("FreeBSD Update");
|
print_separator("FreeBSD Update");
|
||||||
run_type
|
run_type
|
||||||
@@ -17,7 +17,7 @@ pub fn upgrade_freebsd(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()>
|
|||||||
.status_checked()
|
.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn upgrade_packages(ctx: &ExecutionContext, sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> {
|
pub fn upgrade_packages(ctx: &ExecutionContext, sudo: Option<&Sudo>, run_type: RunType) -> Result<()> {
|
||||||
let sudo = require_option(sudo, String::from("No sudo detected"))?;
|
let sudo = require_option(sudo, String::from("No sudo detected"))?;
|
||||||
print_separator("FreeBSD Packages");
|
print_separator("FreeBSD Packages");
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ pub fn upgrade_packages(ctx: &ExecutionContext, sudo: Option<&PathBuf>, run_type
|
|||||||
command.status_checked()
|
command.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn audit_packages(sudo: &Option<PathBuf>) -> Result<()> {
|
pub fn audit_packages(sudo: Option<&Sudo>) -> Result<()> {
|
||||||
if let Some(sudo) = sudo {
|
if let Some(sudo) = sudo {
|
||||||
println!();
|
println!();
|
||||||
Command::new(sudo)
|
Command::new(sudo)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ use crate::error::{SkipStep, TopgradeError};
|
|||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
use crate::executor::RunType;
|
use crate::executor::RunType;
|
||||||
use crate::steps::os::archlinux;
|
use crate::steps::os::archlinux;
|
||||||
|
use crate::sudo::Sudo;
|
||||||
use crate::terminal::{print_separator, print_warning};
|
use crate::terminal::{print_separator, print_warning};
|
||||||
use crate::utils::{require, require_option, which, PathExt};
|
use crate::utils::{require, require_option, which, PathExt};
|
||||||
use crate::Step;
|
use crate::Step;
|
||||||
@@ -28,7 +29,9 @@ pub enum Distribution {
|
|||||||
Debian,
|
Debian,
|
||||||
Gentoo,
|
Gentoo,
|
||||||
OpenMandriva,
|
OpenMandriva,
|
||||||
|
PCLinuxOS,
|
||||||
Suse,
|
Suse,
|
||||||
|
SuseMicro,
|
||||||
Void,
|
Void,
|
||||||
Solus,
|
Solus,
|
||||||
Exherbo,
|
Exherbo,
|
||||||
@@ -54,8 +57,10 @@ impl Distribution {
|
|||||||
Some("gentoo") => Distribution::Gentoo,
|
Some("gentoo") => Distribution::Gentoo,
|
||||||
Some("exherbo") => Distribution::Exherbo,
|
Some("exherbo") => Distribution::Exherbo,
|
||||||
Some("nixos") => Distribution::NixOS,
|
Some("nixos") => Distribution::NixOS,
|
||||||
|
Some("opensuse-microos") => Distribution::SuseMicro,
|
||||||
Some("neon") => Distribution::KDENeon,
|
Some("neon") => Distribution::KDENeon,
|
||||||
Some("openmandriva") => Distribution::OpenMandriva,
|
Some("openmandriva") => Distribution::OpenMandriva,
|
||||||
|
Some("pclinuxos") => Distribution::PCLinuxOS,
|
||||||
_ => {
|
_ => {
|
||||||
if let Some(id_like) = id_like {
|
if let Some(id_like) = id_like {
|
||||||
if id_like.contains(&"debian") || id_like.contains(&"ubuntu") {
|
if id_like.contains(&"debian") || id_like.contains(&"ubuntu") {
|
||||||
@@ -102,6 +107,7 @@ impl Distribution {
|
|||||||
Distribution::Debian => upgrade_debian(ctx),
|
Distribution::Debian => upgrade_debian(ctx),
|
||||||
Distribution::Gentoo => upgrade_gentoo(ctx),
|
Distribution::Gentoo => upgrade_gentoo(ctx),
|
||||||
Distribution::Suse => upgrade_suse(ctx),
|
Distribution::Suse => upgrade_suse(ctx),
|
||||||
|
Distribution::SuseMicro => upgrade_suse_micro(ctx),
|
||||||
Distribution::Void => upgrade_void(ctx),
|
Distribution::Void => upgrade_void(ctx),
|
||||||
Distribution::Solus => upgrade_solus(ctx),
|
Distribution::Solus => upgrade_solus(ctx),
|
||||||
Distribution::Exherbo => upgrade_exherbo(ctx),
|
Distribution::Exherbo => upgrade_exherbo(ctx),
|
||||||
@@ -109,6 +115,7 @@ impl Distribution {
|
|||||||
Distribution::KDENeon => upgrade_neon(ctx),
|
Distribution::KDENeon => upgrade_neon(ctx),
|
||||||
Distribution::Bedrock => update_bedrock(ctx),
|
Distribution::Bedrock => update_bedrock(ctx),
|
||||||
Distribution::OpenMandriva => upgrade_openmandriva(ctx),
|
Distribution::OpenMandriva => upgrade_openmandriva(ctx),
|
||||||
|
Distribution::PCLinuxOS => upgrade_pclinuxos(ctx),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,7 +199,6 @@ fn upgrade_redhat(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
} else {
|
} else {
|
||||||
print_warning("No sudo detected. Skipping system upgrade");
|
print_warning("No sudo detected. Skipping system upgrade");
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,6 +229,18 @@ fn upgrade_suse(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
fn upgrade_suse_micro(ctx: &ExecutionContext) -> Result<()> {
|
||||||
|
if let Some(sudo) = ctx.sudo() {
|
||||||
|
ctx.run_type()
|
||||||
|
.execute(sudo)
|
||||||
|
.args(["transactional-update", "dup"])
|
||||||
|
.status_checked()?;
|
||||||
|
} else {
|
||||||
|
print_warning("No sudo detected. Skipping system upgrade");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn upgrade_openmandriva(ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade_openmandriva(ctx: &ExecutionContext) -> Result<()> {
|
||||||
if let Some(sudo) = &ctx.sudo() {
|
if let Some(sudo) = &ctx.sudo() {
|
||||||
@@ -245,6 +263,33 @@ fn upgrade_openmandriva(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
fn upgrade_pclinuxos(ctx: &ExecutionContext) -> Result<()> {
|
||||||
|
if let Some(sudo) = &ctx.sudo() {
|
||||||
|
let mut command_update = ctx.run_type().execute(sudo);
|
||||||
|
|
||||||
|
command_update.arg(&which("apt-get").unwrap()).arg("update");
|
||||||
|
|
||||||
|
if let Some(args) = ctx.config().dnf_arguments() {
|
||||||
|
command_update.args(args.split_whitespace());
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctx.config().yes(Step::System) {
|
||||||
|
command_update.arg("-y");
|
||||||
|
}
|
||||||
|
|
||||||
|
command_update.status_checked()?;
|
||||||
|
|
||||||
|
ctx.run_type()
|
||||||
|
.execute(sudo)
|
||||||
|
.arg(&which("apt-get").unwrap())
|
||||||
|
.arg("dist-upgrade")
|
||||||
|
.status_checked()?;
|
||||||
|
} else {
|
||||||
|
print_warning("No sudo detected. Skipping system upgrade");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn upgrade_void(ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade_void(ctx: &ExecutionContext) -> Result<()> {
|
||||||
if let Some(sudo) = ctx.sudo() {
|
if let Some(sudo) = ctx.sudo() {
|
||||||
@@ -316,7 +361,13 @@ fn upgrade_gentoo(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
fn upgrade_debian(ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade_debian(ctx: &ExecutionContext) -> Result<()> {
|
||||||
if let Some(sudo) = &ctx.sudo() {
|
if let Some(sudo) = &ctx.sudo() {
|
||||||
let apt = which("apt-fast")
|
let apt = which("apt-fast")
|
||||||
.or_else(|| which("nala"))
|
.or_else(|| {
|
||||||
|
if Path::new("/usr/bin/nala").exists() {
|
||||||
|
Some(Path::new("/usr/bin/nala").to_path_buf())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
.unwrap_or_else(|| PathBuf::from("apt-get"));
|
.unwrap_or_else(|| PathBuf::from("apt-get"));
|
||||||
|
|
||||||
let is_nala = apt.ends_with("nala");
|
let is_nala = apt.ends_with("nala");
|
||||||
@@ -384,6 +435,16 @@ fn upgrade_solus(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn update_am(ctx: &ExecutionContext) -> Result<()> {
|
||||||
|
if let Some(sudo) = ctx.sudo() {
|
||||||
|
ctx.run_type().execute(sudo).args(["am", "-u"]).status_checked()?;
|
||||||
|
} else {
|
||||||
|
print_warning("No sudo detected. Skipping AM Step");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn run_pacdef(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_pacdef(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let pacdef = require("pacdef")?;
|
let pacdef = require("pacdef")?;
|
||||||
|
|
||||||
@@ -400,8 +461,16 @@ pub fn run_pacstall(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("Pacstall");
|
print_separator("Pacstall");
|
||||||
|
|
||||||
ctx.run_type().execute(&pacstall).arg("-U").status_checked()?;
|
let mut update_cmd = ctx.run_type().execute(&pacstall);
|
||||||
ctx.run_type().execute(pacstall).arg("-Up").status_checked()
|
let mut upgrade_cmd = ctx.run_type().execute(pacstall);
|
||||||
|
|
||||||
|
if ctx.config().yes(Step::Pacstall) {
|
||||||
|
update_cmd.arg("-P");
|
||||||
|
upgrade_cmd.arg("-P");
|
||||||
|
}
|
||||||
|
|
||||||
|
update_cmd.arg("-U").status_checked()?;
|
||||||
|
upgrade_cmd.arg("-Up").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn upgrade_clearlinux(ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade_clearlinux(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -451,10 +520,13 @@ fn upgrade_exherbo(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
fn upgrade_nixos(ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade_nixos(ctx: &ExecutionContext) -> Result<()> {
|
||||||
if let Some(sudo) = ctx.sudo() {
|
if let Some(sudo) = ctx.sudo() {
|
||||||
ctx.run_type()
|
let mut command = ctx.run_type().execute(sudo);
|
||||||
.execute(sudo)
|
command.args(["/run/current-system/sw/bin/nixos-rebuild", "switch", "--upgrade"]);
|
||||||
.args(["/run/current-system/sw/bin/nixos-rebuild", "switch", "--upgrade"])
|
|
||||||
.status_checked()?;
|
if let Some(args) = ctx.config().nix_arguments() {
|
||||||
|
command.args(args.split_whitespace());
|
||||||
|
}
|
||||||
|
command.status_checked()?;
|
||||||
|
|
||||||
if ctx.config().cleanup() {
|
if ctx.config().cleanup() {
|
||||||
ctx.run_type()
|
ctx.run_type()
|
||||||
@@ -498,7 +570,7 @@ fn upgrade_neon(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_needrestart(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> {
|
pub fn run_needrestart(sudo: Option<&Sudo>, run_type: RunType) -> Result<()> {
|
||||||
let sudo = require_option(sudo, String::from("sudo is not installed"))?;
|
let sudo = require_option(sudo, String::from("sudo is not installed"))?;
|
||||||
let needrestart = require("needrestart")?;
|
let needrestart = require("needrestart")?;
|
||||||
let distribution = Distribution::detect()?;
|
let distribution = Distribution::detect()?;
|
||||||
@@ -603,7 +675,7 @@ pub fn flatpak_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_snap(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> {
|
pub fn run_snap(sudo: Option<&Sudo>, run_type: RunType) -> Result<()> {
|
||||||
let sudo = require_option(sudo, String::from("sudo is not installed"))?;
|
let sudo = require_option(sudo, String::from("sudo is not installed"))?;
|
||||||
let snap = require("snap")?;
|
let snap = require("snap")?;
|
||||||
|
|
||||||
@@ -615,7 +687,7 @@ pub fn run_snap(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> {
|
|||||||
run_type.execute(sudo).arg(snap).arg("refresh").status_checked()
|
run_type.execute(sudo).arg(snap).arg("refresh").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_pihole_update(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> {
|
pub fn run_pihole_update(sudo: Option<&Sudo>, run_type: RunType) -> Result<()> {
|
||||||
let sudo = require_option(sudo, String::from("sudo is not installed"))?;
|
let sudo = require_option(sudo, String::from("sudo is not installed"))?;
|
||||||
let pihole = require("pihole")?;
|
let pihole = require("pihole")?;
|
||||||
Path::new("/opt/pihole/update.sh").require()?;
|
Path::new("/opt/pihole/update.sh").require()?;
|
||||||
@@ -659,6 +731,29 @@ pub fn run_distrobox_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
.status_checked()
|
.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn run_dkp_pacman_update(ctx: &ExecutionContext) -> Result<()> {
|
||||||
|
let sudo = require_option(ctx.sudo().as_ref(), String::from("sudo is not installed"))?;
|
||||||
|
let dkp_pacman = require("dkp-pacman")?;
|
||||||
|
|
||||||
|
print_separator("Devkitpro pacman");
|
||||||
|
|
||||||
|
ctx.run_type()
|
||||||
|
.execute(sudo)
|
||||||
|
.arg(&dkp_pacman)
|
||||||
|
.arg("-Syu")
|
||||||
|
.status_checked()?;
|
||||||
|
|
||||||
|
if ctx.config().cleanup() {
|
||||||
|
ctx.run_type()
|
||||||
|
.execute(sudo)
|
||||||
|
.arg(&dkp_pacman)
|
||||||
|
.arg("-Scc")
|
||||||
|
.status_checked()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn run_config_update(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_config_update(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), String::from("sudo is not installed"))?;
|
let sudo = require_option(ctx.sudo().as_ref(), String::from("sudo is not installed"))?;
|
||||||
if ctx.config().yes(Step::ConfigUpdate) {
|
if ctx.config().yes(Step::ConfigUpdate) {
|
||||||
|
|||||||
9
src/steps/os/os_release/pclinuxos
Normal file
9
src/steps/os/os_release/pclinuxos
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
NAME="PCLinuxOS"
|
||||||
|
VERSION="2022"
|
||||||
|
ID=pclinuxos
|
||||||
|
VERSION_ID=2022
|
||||||
|
ID_LIKE="mandriva"
|
||||||
|
PRETTY_NAME="PCLinuxOS 2022"
|
||||||
|
ANSI_COLOR="1;37"
|
||||||
|
HOME_URL="http://www.pclinuxos.com/"
|
||||||
|
SUPPORT_URL="http://www.pclinuxos.com/"
|
||||||
@@ -102,6 +102,12 @@ pub fn run_fisher(run_type: RunType) -> Result<()> {
|
|||||||
.and_then(|output| Path::new(&output.stdout.trim()).require().map(|_| ()))
|
.and_then(|output| Path::new(&output.stdout.trim()).require().map(|_| ()))
|
||||||
.map_err(|err| SkipStep(format!("`fish_plugins` path doesn't exist: {err}")))?;
|
.map_err(|err| SkipStep(format!("`fish_plugins` path doesn't exist: {err}")))?;
|
||||||
|
|
||||||
|
Command::new(&fish)
|
||||||
|
.args(["-c", "fish_update_completions"])
|
||||||
|
.output_checked_utf8()
|
||||||
|
.map(|_| ())
|
||||||
|
.map_err(|_| SkipStep("`fish_update_completions` is not available".to_owned()))?;
|
||||||
|
|
||||||
print_separator("Fisher");
|
print_separator("Fisher");
|
||||||
|
|
||||||
let version_str = run_type
|
let version_str = run_type
|
||||||
@@ -146,6 +152,8 @@ pub fn run_oh_my_fish(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
pub fn run_pkgin(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_pkgin(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let pkgin = require("pkgin")?;
|
let pkgin = require("pkgin")?;
|
||||||
|
|
||||||
|
print_separator("Pkgin");
|
||||||
|
|
||||||
let mut command = ctx.run_type().execute(ctx.sudo().as_ref().unwrap());
|
let mut command = ctx.run_type().execute(ctx.sudo().as_ref().unwrap());
|
||||||
command.arg(&pkgin).arg("update");
|
command.arg(&pkgin).arg("update");
|
||||||
if ctx.config().yes(Step::Pkgin) {
|
if ctx.config().yes(Step::Pkgin) {
|
||||||
|
|||||||
@@ -19,17 +19,16 @@ pub fn run_chocolatey(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("Chocolatey");
|
print_separator("Chocolatey");
|
||||||
|
|
||||||
let mut cmd = &choco;
|
let mut command = match ctx.sudo() {
|
||||||
let mut args = vec!["upgrade", "all"];
|
Some(sudo) => {
|
||||||
|
let mut command = ctx.run_type().execute(sudo);
|
||||||
|
command.arg(choco);
|
||||||
|
command
|
||||||
|
}
|
||||||
|
None => ctx.run_type().execute(choco),
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(sudo) = ctx.sudo() {
|
command.args(["upgrade", "all"]);
|
||||||
cmd = sudo;
|
|
||||||
args.insert(0, "choco");
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut command = ctx.run_type().execute(cmd);
|
|
||||||
|
|
||||||
command.args(&args);
|
|
||||||
|
|
||||||
if yes {
|
if yes {
|
||||||
command.arg("--yes");
|
command.arg("--yes");
|
||||||
@@ -49,7 +48,7 @@ pub fn run_winget(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctx.run_type()
|
ctx.run_type()
|
||||||
.execute(&winget)
|
.execute(winget)
|
||||||
.args(["upgrade", "--all"])
|
.args(["upgrade", "--all"])
|
||||||
.status_checked()
|
.status_checked()
|
||||||
}
|
}
|
||||||
@@ -69,6 +68,25 @@ pub fn run_scoop(cleanup: bool, run_type: RunType) -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn update_wsl(ctx: &ExecutionContext) -> Result<()> {
|
||||||
|
let wsl = require("wsl")?;
|
||||||
|
|
||||||
|
print_separator("Update WSL");
|
||||||
|
|
||||||
|
let mut wsl_command = ctx.run_type().execute(wsl);
|
||||||
|
wsl_command.args(["--update"]);
|
||||||
|
|
||||||
|
if ctx.config().wsl_update_pre_release() {
|
||||||
|
wsl_command.args(["--pre-release"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctx.config().wsl_update_use_web_download() {
|
||||||
|
wsl_command.args(["--web-download"]);
|
||||||
|
}
|
||||||
|
wsl_command.status_checked()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn get_wsl_distributions(wsl: &Path) -> Result<Vec<String>> {
|
fn get_wsl_distributions(wsl: &Path) -> Result<Vec<String>> {
|
||||||
let output = Command::new(wsl).args(["--list", "-q"]).output_checked_utf8()?.stdout;
|
let output = Command::new(wsl).args(["--list", "-q"]).output_checked_utf8()?.stdout;
|
||||||
Ok(output
|
Ok(output
|
||||||
@@ -87,7 +105,7 @@ fn upgrade_wsl_distribution(wsl: &Path, dist: &str, ctx: &ExecutionContext) -> R
|
|||||||
let mut command = ctx.run_type().execute(wsl);
|
let mut command = ctx.run_type().execute(wsl);
|
||||||
command
|
command
|
||||||
.args(["-d", dist, "bash", "-c"])
|
.args(["-d", dist, "bash", "-c"])
|
||||||
.arg(format!("TOPGRADE_PREFIX={} exec {}", dist, topgrade));
|
.arg(format!("TOPGRADE_PREFIX={dist} exec {topgrade}"));
|
||||||
|
|
||||||
if ctx.config().yes(Step::Wsl) {
|
if ctx.config().yes(Step::Wsl) {
|
||||||
command.arg("-y");
|
command.arg("-y");
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ impl Powershell {
|
|||||||
.args([
|
.args([
|
||||||
"-NoProfile",
|
"-NoProfile",
|
||||||
"-Command",
|
"-Command",
|
||||||
&format!("Get-Module -ListAvailable {}", command),
|
&format!("Get-Module -ListAvailable {command}"),
|
||||||
])
|
])
|
||||||
.output_checked_utf8()
|
.output_checked_utf8()
|
||||||
.map(|result| !result.stdout.is_empty())
|
.map(|result| !result.stdout.is_empty())
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ pub fn ssh_step(ctx: &ExecutionContext, hostname: &str) -> Result<()> {
|
|||||||
args.extend(ssh_arguments.split_whitespace());
|
args.extend(ssh_arguments.split_whitespace());
|
||||||
}
|
}
|
||||||
|
|
||||||
let env = format!("TOPGRADE_PREFIX={}", hostname);
|
let env = format!("TOPGRADE_PREFIX={hostname}");
|
||||||
args.extend(["env", &env, "$SHELL", "-lc", topgrade]);
|
args.extend(["env", &env, "$SHELL", "-lc", topgrade]);
|
||||||
|
|
||||||
if ctx.config().run_in_tmux() && !ctx.run_type().dry() {
|
if ctx.config().run_in_tmux() && !ctx.run_type().dry() {
|
||||||
@@ -43,11 +43,11 @@ pub fn ssh_step(ctx: &ExecutionContext, hostname: &str) -> Result<()> {
|
|||||||
args.extend(ssh_arguments.split_whitespace());
|
args.extend(ssh_arguments.split_whitespace());
|
||||||
}
|
}
|
||||||
|
|
||||||
let env = format!("TOPGRADE_PREFIX={}", hostname);
|
let env = format!("TOPGRADE_PREFIX={hostname}");
|
||||||
args.extend(["env", &env, "$SHELL", "-lc", topgrade]);
|
args.extend(["env", &env, "$SHELL", "-lc", topgrade]);
|
||||||
|
|
||||||
print_separator(format!("Remote ({})", hostname));
|
print_separator(format!("Remote ({hostname})"));
|
||||||
println!("Connecting to {}...", hostname);
|
println!("Connecting to {hostname}...");
|
||||||
|
|
||||||
ctx.run_type().execute(ssh).args(&args).status_checked()
|
ctx.run_type().execute(ssh).args(&args).status_checked()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ pub fn topgrade_vagrant_box(ctx: &ExecutionContext, vagrant_box: &VagrantBox) ->
|
|||||||
let mut _poweron = None;
|
let mut _poweron = None;
|
||||||
if !vagrant_box.initial_status.powered_on() {
|
if !vagrant_box.initial_status.powered_on() {
|
||||||
if !(ctx.config().vagrant_power_on().unwrap_or(true)) {
|
if !(ctx.config().vagrant_power_on().unwrap_or(true)) {
|
||||||
return Err(SkipStep(format!("Skipping powered off box {}", vagrant_box)).into());
|
return Err(SkipStep(format!("Skipping powered off box {vagrant_box}")).into());
|
||||||
} else {
|
} else {
|
||||||
print_separator(seperator);
|
print_separator(seperator);
|
||||||
_poweron = Some(vagrant.temporary_power_on(vagrant_box, ctx)?);
|
_poweron = Some(vagrant.temporary_power_on(vagrant_box, ctx)?);
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ pub fn run_toolbx(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
let topgrade_path = topgrade_path.to_str().unwrap();
|
let topgrade_path = topgrade_path.to_str().unwrap();
|
||||||
|
|
||||||
for tb in toolboxes.iter() {
|
for tb in toolboxes.iter() {
|
||||||
let topgrade_prefix = format!("TOPGRADE_PREFIX='Toolbx {}'", tb);
|
let topgrade_prefix = format!("TOPGRADE_PREFIX='Toolbx {tb}'");
|
||||||
let mut args = vec![
|
let mut args = vec![
|
||||||
"run",
|
"run",
|
||||||
"-c",
|
"-c",
|
||||||
|
|||||||
@@ -33,23 +33,29 @@ if exists(":PaqUpdate")
|
|||||||
PaqUpdate
|
PaqUpdate
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if exists(":CocUpdateSync")
|
if exists(":Lazy")
|
||||||
echo "CocUpdateSync"
|
echo "Lazy Update"
|
||||||
CocUpdateSync
|
+Lazy! sync
|
||||||
endif
|
endif
|
||||||
|
|
||||||
" TODO: Should this be after `PackerSync`?
|
function! UpdateCoCAndTS()
|
||||||
" Not sure how to sequence this after Packer without doing something weird
|
if exists(":CocUpdateSync")
|
||||||
" with that `PackerComplete` autocommand.
|
echo "CocUpdateSync"
|
||||||
if exists(":TSUpdate")
|
CocUpdateSync
|
||||||
echo "TreeSitter Update"
|
endif
|
||||||
TSUpdate
|
|
||||||
endif
|
if exists(":TSUpdateSync")
|
||||||
|
echo "TreeSitter Update"
|
||||||
|
TSUpdate
|
||||||
|
endif
|
||||||
|
|
||||||
|
quitall
|
||||||
|
endfunction
|
||||||
|
|
||||||
if exists(':PackerSync')
|
if exists(':PackerSync')
|
||||||
echo "Packer"
|
echo "Packer"
|
||||||
autocmd User PackerComplete quitall
|
autocmd User PackerComplete * call UpdateCoCAndTS()
|
||||||
PackerSync
|
PackerSync
|
||||||
else
|
else
|
||||||
quitall
|
call UpdateCoCAndTS()
|
||||||
endif
|
endif
|
||||||
|
|||||||
108
src/sudo.rs
Normal file
108
src/sudo.rs
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
use std::ffi::OsStr;
|
||||||
|
use std::path::Path;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use color_eyre::eyre::Context;
|
||||||
|
use color_eyre::eyre::Result;
|
||||||
|
|
||||||
|
use crate::command::CommandExt;
|
||||||
|
use crate::execution_context::ExecutionContext;
|
||||||
|
use crate::executor::Executor;
|
||||||
|
use crate::terminal::print_separator;
|
||||||
|
use crate::utils::which;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Sudo {
|
||||||
|
/// The path to the `sudo` binary.
|
||||||
|
path: PathBuf,
|
||||||
|
/// The type of program being used as `sudo`.
|
||||||
|
kind: SudoKind,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sudo {
|
||||||
|
/// Get the `sudo` binary for this platform.
|
||||||
|
pub fn detect() -> Option<Self> {
|
||||||
|
which("doas")
|
||||||
|
.map(|p| (p, SudoKind::Doas))
|
||||||
|
.or_else(|| which("sudo").map(|p| (p, SudoKind::Sudo)))
|
||||||
|
.or_else(|| which("gsudo").map(|p| (p, SudoKind::Gsudo)))
|
||||||
|
.or_else(|| which("pkexec").map(|p| (p, SudoKind::Pkexec)))
|
||||||
|
.map(|(path, kind)| Self { path, kind })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Elevate permissions with `sudo`.
|
||||||
|
///
|
||||||
|
/// This helps prevent blocking `sudo` prompts from stopping the run in the middle of a
|
||||||
|
/// step.
|
||||||
|
///
|
||||||
|
/// See: https://github.com/topgrade-rs/topgrade/issues/205
|
||||||
|
pub fn elevate(&self, ctx: &ExecutionContext) -> Result<()> {
|
||||||
|
print_separator("Sudo");
|
||||||
|
let mut cmd = ctx.run_type().execute(self);
|
||||||
|
match self.kind {
|
||||||
|
SudoKind::Doas => {
|
||||||
|
// `doas` doesn't have anything like `sudo -v` to cache credentials,
|
||||||
|
// so we just execute a dummy `echo` command so we have something
|
||||||
|
// unobtrusive to run.
|
||||||
|
// See: https://man.openbsd.org/doas
|
||||||
|
cmd.arg("echo");
|
||||||
|
}
|
||||||
|
SudoKind::Sudo => {
|
||||||
|
// From `man sudo` on macOS:
|
||||||
|
// -v, --validate
|
||||||
|
// Update the user's cached credentials, authenticating the user
|
||||||
|
// if necessary. For the sudoers plugin, this extends the sudo
|
||||||
|
// timeout for another 5 minutes by default, but does not run a
|
||||||
|
// command. Not all security policies support cached credentials.
|
||||||
|
cmd.arg("-v");
|
||||||
|
}
|
||||||
|
SudoKind::Gsudo => {
|
||||||
|
// Shows current user, cache and console status.
|
||||||
|
// See: https://gerardog.github.io/gsudo/docs/usage
|
||||||
|
cmd.arg("status");
|
||||||
|
}
|
||||||
|
SudoKind::Pkexec => {
|
||||||
|
// I don't think this does anything; `pkexec` usually asks for
|
||||||
|
// authentication every time, although it can be configured
|
||||||
|
// differently.
|
||||||
|
//
|
||||||
|
// See the note for `doas` above.
|
||||||
|
//
|
||||||
|
// See: https://linux.die.net/man/1/pkexec
|
||||||
|
cmd.arg("echo");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmd.status_checked().wrap_err("Failed to elevate permissions")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Execute a command with `sudo`.
|
||||||
|
pub fn execute_elevated(&self, ctx: &ExecutionContext, command: &Path, interactive: bool) -> Executor {
|
||||||
|
let mut cmd = ctx.run_type().execute(self);
|
||||||
|
|
||||||
|
if let SudoKind::Sudo = self.kind {
|
||||||
|
cmd.arg("--preserve-env=DIFFPROG");
|
||||||
|
}
|
||||||
|
|
||||||
|
if interactive {
|
||||||
|
cmd.arg("-i");
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.arg(command);
|
||||||
|
|
||||||
|
cmd
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
enum SudoKind {
|
||||||
|
Doas,
|
||||||
|
Sudo,
|
||||||
|
Gsudo,
|
||||||
|
Pkexec,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<OsStr> for Sudo {
|
||||||
|
fn as_ref(&self) -> &OsStr {
|
||||||
|
self.path.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,8 +21,9 @@ use which_crate::which;
|
|||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
use crate::report::StepResult;
|
use crate::report::StepResult;
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
|
use crate::terminal;
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
use crate::utils::which;
|
use crate::utils::which;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref TERMINAL: Mutex<Terminal> = Mutex::new(Terminal::new());
|
static ref TERMINAL: Mutex<Terminal> = Mutex::new(Terminal::new());
|
||||||
}
|
}
|
||||||
@@ -59,7 +60,7 @@ impl Terminal {
|
|||||||
width: term.size_checked().map(|(_, w)| w),
|
width: term.size_checked().map(|(_, w)| w),
|
||||||
term,
|
term,
|
||||||
prefix: env::var("TOPGRADE_PREFIX")
|
prefix: env::var("TOPGRADE_PREFIX")
|
||||||
.map(|prefix| format!("({}) ", prefix))
|
.map(|prefix| format!("({prefix}) "))
|
||||||
.unwrap_or_else(|_| String::new()),
|
.unwrap_or_else(|_| String::new()),
|
||||||
set_title: true,
|
set_title: true,
|
||||||
display_time: true,
|
display_time: true,
|
||||||
@@ -105,7 +106,7 @@ impl Terminal {
|
|||||||
command.args(["-a", "Topgrade", "Topgrade"]);
|
command.args(["-a", "Topgrade", "Topgrade"]);
|
||||||
command.arg(message.as_ref());
|
command.arg(message.as_ref());
|
||||||
if let Err(err) = command.output_checked() {
|
if let Err(err) = command.output_checked() {
|
||||||
tracing::error!("{err:?}");
|
terminal::print_warning("Sending notification failed with {err:?}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -142,7 +143,7 @@ impl Terminal {
|
|||||||
.write_fmt(format_args!(
|
.write_fmt(format_args!(
|
||||||
"{}\n",
|
"{}\n",
|
||||||
style(format_args!(
|
style(format_args!(
|
||||||
"\n―― {} {:―^border$}",
|
"\n── {} {:─^border$}",
|
||||||
message,
|
message,
|
||||||
"",
|
"",
|
||||||
border = max(
|
border = max(
|
||||||
@@ -158,7 +159,7 @@ impl Terminal {
|
|||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
self.term.write_fmt(format_args!("―― {} ――\n", message)).ok();
|
self.term.write_fmt(format_args!("―― {message} ――\n")).ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -170,7 +171,7 @@ impl Terminal {
|
|||||||
self.term
|
self.term
|
||||||
.write_fmt(format_args!(
|
.write_fmt(format_args!(
|
||||||
"{} {}",
|
"{} {}",
|
||||||
style(format!("{} failed:", key)).red().bold(),
|
style(format!("{key} failed:")).red().bold(),
|
||||||
message
|
message
|
||||||
))
|
))
|
||||||
.ok();
|
.ok();
|
||||||
@@ -214,7 +215,7 @@ impl Terminal {
|
|||||||
self.term
|
self.term
|
||||||
.write_fmt(format_args!(
|
.write_fmt(format_args!(
|
||||||
"{}",
|
"{}",
|
||||||
style(format!("{} (y)es/(N)o", question,)).yellow().bold()
|
style(format!("{question} (y)es/(N)o",)).yellow().bold()
|
||||||
))
|
))
|
||||||
.ok();
|
.ok();
|
||||||
|
|
||||||
@@ -236,13 +237,15 @@ impl Terminal {
|
|||||||
self.term.set_title("Topgrade - Awaiting user");
|
self.term.set_title("Topgrade - Awaiting user");
|
||||||
}
|
}
|
||||||
|
|
||||||
self.notify_desktop(format!("{} failed", step_name), None);
|
if self.desktop_notification {
|
||||||
|
self.notify_desktop(format!("{step_name} failed"), None);
|
||||||
|
}
|
||||||
|
|
||||||
let prompt_inner = style(format!("{}Retry? (y)es/(N)o/(s)hell/(q)uit", self.prefix))
|
let prompt_inner = style(format!("{}Retry? (y)es/(N)o/(s)hell/(q)uit", self.prefix))
|
||||||
.yellow()
|
.yellow()
|
||||||
.bold();
|
.bold();
|
||||||
|
|
||||||
self.term.write_fmt(format_args!("\n{}", prompt_inner)).ok();
|
self.term.write_fmt(format_args!("\n{prompt_inner}")).ok();
|
||||||
|
|
||||||
let answer = loop {
|
let answer = loop {
|
||||||
match self.term.read_key() {
|
match self.term.read_key() {
|
||||||
@@ -250,7 +253,7 @@ impl Terminal {
|
|||||||
Ok(Key::Char('s')) | Ok(Key::Char('S')) => {
|
Ok(Key::Char('s')) | Ok(Key::Char('S')) => {
|
||||||
println!("\n\nDropping you to shell. Fix what you need and then exit the shell.\n");
|
println!("\n\nDropping you to shell. Fix what you need and then exit the shell.\n");
|
||||||
if let Err(err) = run_shell().context("Failed to run shell") {
|
if let Err(err) = run_shell().context("Failed to run shell") {
|
||||||
self.term.write_fmt(format_args!("{err:?}\n{}", prompt_inner)).ok();
|
self.term.write_fmt(format_args!("{err:?}\n{prompt_inner}")).ok();
|
||||||
} else {
|
} else {
|
||||||
break Ok(true);
|
break Ok(true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,13 +67,6 @@ pub fn which<T: AsRef<OsStr> + Debug>(binary_name: T) -> Option<PathBuf> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sudo() -> Option<PathBuf> {
|
|
||||||
which("doas")
|
|
||||||
.or_else(|| which("sudo"))
|
|
||||||
.or_else(|| which("gsudo"))
|
|
||||||
.or_else(|| which("pkexec"))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn editor() -> Vec<String> {
|
pub fn editor() -> Vec<String> {
|
||||||
env::var("EDITOR")
|
env::var("EDITOR")
|
||||||
.unwrap_or_else(|_| String::from(if cfg!(windows) { "notepad" } else { "vi" }))
|
.unwrap_or_else(|_| String::from(if cfg!(windows) { "notepad" } else { "vi" }))
|
||||||
@@ -156,6 +149,6 @@ pub fn hostname() -> Result<String> {
|
|||||||
|
|
||||||
Command::new("hostname")
|
Command::new("hostname")
|
||||||
.output_checked_utf8()
|
.output_checked_utf8()
|
||||||
.map_err(|err| SkipStep(format!("Failed to get hostname: {}", err)).into())
|
.map_err(|err| SkipStep(format!("Failed to get hostname: {err}")).into())
|
||||||
.map(|output| output.stdout.trim().to_owned())
|
.map(|output| output.stdout.trim().to_owned())
|
||||||
}
|
}
|
||||||
|
|||||||
80
topgrade.8
80
topgrade.8
@@ -1,80 +0,0 @@
|
|||||||
.hy
|
|
||||||
.TH "topgrade" "8"
|
|
||||||
.SH NAME
|
|
||||||
.PP
|
|
||||||
Topgrade \- Upgrade everything
|
|
||||||
.SH SYNOPSIS
|
|
||||||
.PP
|
|
||||||
topgrade [\fIoptions\f[]]
|
|
||||||
.SH DESCRIPTION
|
|
||||||
.PP
|
|
||||||
Keeping your system up to date usually involves invoking multiple package managers.
|
|
||||||
This results in big, non-portable shell one-liners saved in your shell.
|
|
||||||
To remedy this, \fBTopgrade\fR detects which tools you use and runs the appropriate commands to update them.
|
|
||||||
.SH OPTIONS
|
|
||||||
.TP
|
|
||||||
.B \-\-only <only>
|
|
||||||
Run only specific steps
|
|
||||||
.RS
|
|
||||||
.RE
|
|
||||||
.TP
|
|
||||||
.B \-\-disable <disable>
|
|
||||||
Disable specific steps
|
|
||||||
.RS
|
|
||||||
.RE
|
|
||||||
.TP
|
|
||||||
.B \-c, \-\-cleanup
|
|
||||||
Cleanup temporary or old files
|
|
||||||
.RS
|
|
||||||
.RE
|
|
||||||
.TP
|
|
||||||
.B \-n, \-\-dry\-run
|
|
||||||
List the commands that would be run
|
|
||||||
.RS
|
|
||||||
.RE
|
|
||||||
.TP
|
|
||||||
.B \-\-edit\-config
|
|
||||||
Edit the configuration file
|
|
||||||
.RS
|
|
||||||
.RE
|
|
||||||
.TP
|
|
||||||
.B \-h, \-\-help
|
|
||||||
Print help information
|
|
||||||
.RS
|
|
||||||
.RE
|
|
||||||
.TP
|
|
||||||
.B \-k, \-\-keep
|
|
||||||
Prompt for a key before exiting
|
|
||||||
.RS
|
|
||||||
.RE
|
|
||||||
.TP
|
|
||||||
.B \-\-no\-retry
|
|
||||||
Do not ask to retry failed steps
|
|
||||||
.RS
|
|
||||||
.RE
|
|
||||||
.TP
|
|
||||||
.B \-t, \-\-tmux
|
|
||||||
Run inside tmux
|
|
||||||
.RS
|
|
||||||
.RE
|
|
||||||
.TP
|
|
||||||
.B \-V, \-\-version
|
|
||||||
Print version information
|
|
||||||
.RS
|
|
||||||
.RE
|
|
||||||
.TP
|
|
||||||
.B \-v, \-\-verbose
|
|
||||||
Output logs
|
|
||||||
.RS
|
|
||||||
.RE
|
|
||||||
.B \-y, \-\-yes
|
|
||||||
Skip package manager's prompts (experimental)
|
|
||||||
.SH ARGUMENT FORMAT
|
|
||||||
Options can be given in any order.
|
|
||||||
A list of steps must be provided as a list of separate arguments, i.e. 'topgrade --only system shell'.
|
|
||||||
.SH BUGS
|
|
||||||
For a list of bugs see <\fIhttps://github.com/r-darwish/topgrade/issues\fR>.
|
|
||||||
.SH AUTHOR
|
|
||||||
\fBTopgrade\fR is maintained by Roey Dror (\[aq]r\-darwish\[aq]) and many other contributors.
|
|
||||||
You can view the full list at
|
|
||||||
<\fIhttps://github.com/r-darwish/topgrade/graphs/contributors\fR>
|
|
||||||
Reference in New Issue
Block a user