Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
462016e51e | ||
|
|
199b81183b | ||
|
|
342d7f7209 | ||
|
|
9c2d121fc9 | ||
|
|
7728819133 | ||
|
|
a5d5d987d2 | ||
|
|
fae5d80f0a | ||
|
|
2369e371be | ||
|
|
e3b71b647f | ||
|
|
e224ea38b3 | ||
|
|
8ec37bcd44 | ||
|
|
6b7f6f4cc7 | ||
|
|
d767ef31a5 | ||
|
|
fcf776fe07 | ||
|
|
58060dda09 | ||
|
|
8cfc8d66be | ||
|
|
9dcc8fdd0d | ||
|
|
828477b255 | ||
|
|
4eae1fedf7 | ||
|
|
1051e4cf47 | ||
|
|
80a95cb404 | ||
|
|
ab630cfbc6 | ||
|
|
c13e14080c | ||
|
|
4abbee99cc | ||
|
|
45d935eda3 | ||
|
|
b4c5efde50 | ||
|
|
cba9dc1c2c | ||
|
|
938647123c | ||
|
|
9f24f6474e |
4
.github/workflows/check-and-lint.yaml
vendored
4
.github/workflows/check-and-lint.yaml
vendored
@@ -7,8 +7,8 @@ on:
|
||||
name: CI
|
||||
|
||||
env:
|
||||
RUST_VER: '1.60.0'
|
||||
CROSS_VER: '0.2.4'
|
||||
RUST_VER: '1.68.0'
|
||||
CROSS_VER: '0.2.5'
|
||||
CARGO_NET_RETRY: 3
|
||||
|
||||
jobs:
|
||||
|
||||
563
Cargo.lock
generated
563
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@ keywords = ["upgrade", "update"]
|
||||
license = "GPL-3.0"
|
||||
# license-file = "LICENSE"
|
||||
repository = "https://github.com/topgrade-rs/topgrade"
|
||||
version = "10.2.4"
|
||||
version = "10.3.2"
|
||||
authors = ["Roey Darwish Dror <roey.ghost@gmail.com>", "Thomas Schönauer <t.schoenauer@hgs-wt.at>"]
|
||||
exclude = ["doc/screenshot.gif"]
|
||||
edition = "2021"
|
||||
@@ -39,7 +39,7 @@ strum = { version = "~0.24", features = ["derive"] }
|
||||
thiserror = "~1.0"
|
||||
tempfile = "~3.2"
|
||||
cfg-if = "~1.0"
|
||||
tokio = { version = "~1.8", features = ["process", "rt-multi-thread"] }
|
||||
tokio = { version = "~1.18", features = ["process", "rt-multi-thread"] }
|
||||
futures = "~0.3"
|
||||
regex = "~1.5"
|
||||
semver = "~1.0"
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
# Workaround for: https://github.com/cross-rs/cross/issues/1100
|
||||
# TODO: Remove this file altogether once a new version of cross (after v0.2.4) is released.
|
||||
[target.x86_64-unknown-freebsd.env]
|
||||
passthrough = ["AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd12-ar"]
|
||||
@@ -80,8 +80,6 @@ Just fork the repository and start coding.
|
||||
|
||||
- Check if your code passes `cargo fmt` and `cargo clippy`.
|
||||
- Check if your code is self explanatory, if not it should be documented by comments.
|
||||
- Make a pull request to the `dev` branch for new features or to the `bug-fixes` branch for bug fixes.
|
||||
|
||||
## Roadmap
|
||||
|
||||
- [ ] Add a proper testing framework to the code base.
|
||||
|
||||
@@ -44,6 +44,9 @@
|
||||
# Skip sending a notification at the end of a run
|
||||
#skip_notify = true
|
||||
|
||||
# Skip the preamble displayed when topgrade is run
|
||||
#display_preamble = false
|
||||
|
||||
[git]
|
||||
#max_concurrency = 5
|
||||
# Additional git repositories to pull
|
||||
@@ -74,12 +77,15 @@
|
||||
#autoremove = true
|
||||
|
||||
[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"
|
||||
# Arguments to pass yay (or paru) when updating packages
|
||||
#yay_arguments = "--nodevel"
|
||||
# Arguments to pass dnf when updating packages
|
||||
#dnf_arguments = "--refresh"
|
||||
#aura_aur_arguments = "-kx"
|
||||
#aura_pacman_arguments = ""
|
||||
#garuda_update_arguments = ""
|
||||
#show_arch_news = true
|
||||
#trizen_arguments = "--devel"
|
||||
#pikaur_arguments = ""
|
||||
@@ -89,11 +95,18 @@
|
||||
#emerge_update_flags = "-uDNa --with-bdeps=y world"
|
||||
#redhat_distro_sync = false
|
||||
#rpm_ostree = false
|
||||
#nix_arguments = "--flake"
|
||||
|
||||
[python]
|
||||
#enable_pip_review = true ###disabled by default
|
||||
#enable_pipupgrade = true ###disabled by default
|
||||
|
||||
[windows]
|
||||
# Manually select Windows updates
|
||||
#accept_all_updates = false
|
||||
#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
|
||||
# to upgrade it. Use this only if you installed Topgrade by using a package
|
||||
|
||||
@@ -71,6 +71,7 @@ type Commands = BTreeMap<String, String>;
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
pub enum Step {
|
||||
AM,
|
||||
Asdf,
|
||||
Atom,
|
||||
Bin,
|
||||
@@ -89,6 +90,7 @@ pub enum Step {
|
||||
DebGet,
|
||||
Deno,
|
||||
Distrobox,
|
||||
DkpPacman,
|
||||
Dotnet,
|
||||
Emacs,
|
||||
Firmware,
|
||||
@@ -123,6 +125,8 @@ pub enum Step {
|
||||
Pacstall,
|
||||
Pearl,
|
||||
Pip3,
|
||||
PipReview,
|
||||
Pipupgrade,
|
||||
Pipx,
|
||||
Pkg,
|
||||
Pkgin,
|
||||
@@ -154,6 +158,7 @@ pub enum Step {
|
||||
Vim,
|
||||
Winget,
|
||||
Wsl,
|
||||
WslUpdate,
|
||||
Yadm,
|
||||
Yarn,
|
||||
}
|
||||
@@ -182,6 +187,15 @@ pub struct Windows {
|
||||
self_rename: Option<bool>,
|
||||
open_remotes_in_new_terminal: 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)]
|
||||
@@ -230,15 +244,15 @@ pub struct Brew {
|
||||
#[derive(Debug, Deserialize, Clone, Copy)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum ArchPackageManager {
|
||||
GarudaUpdate,
|
||||
Autodetect,
|
||||
Trizen,
|
||||
Paru,
|
||||
Yay,
|
||||
Pacman,
|
||||
Pikaur,
|
||||
Pamac,
|
||||
Aura,
|
||||
GarudaUpdate,
|
||||
Pacman,
|
||||
Pamac,
|
||||
Paru,
|
||||
Pikaur,
|
||||
Trizen,
|
||||
Yay,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default, Debug)]
|
||||
@@ -249,10 +263,12 @@ pub struct Linux {
|
||||
aura_pacman_arguments: Option<String>,
|
||||
arch_package_manager: Option<ArchPackageManager>,
|
||||
show_arch_news: Option<bool>,
|
||||
garuda_update_arguments: Option<String>,
|
||||
trizen_arguments: Option<String>,
|
||||
pikaur_arguments: Option<String>,
|
||||
pamac_arguments: Option<String>,
|
||||
dnf_arguments: Option<String>,
|
||||
nix_arguments: Option<String>,
|
||||
apt_arguments: Option<String>,
|
||||
enable_tlmgr: Option<bool>,
|
||||
redhat_distro_sync: Option<bool>,
|
||||
@@ -292,10 +308,12 @@ pub struct ConfigFile {
|
||||
tmux_arguments: Option<String>,
|
||||
set_title: Option<bool>,
|
||||
display_time: Option<bool>,
|
||||
display_preamble: Option<bool>,
|
||||
assume_yes: Option<bool>,
|
||||
yay_arguments: Option<String>,
|
||||
aura_aur_arguments: Option<String>,
|
||||
aura_pacman_arguments: Option<String>,
|
||||
python: Option<Python>,
|
||||
no_retry: Option<bool>,
|
||||
run_in_tmux: Option<bool>,
|
||||
cleanup: Option<bool>,
|
||||
@@ -739,6 +757,24 @@ impl Config {
|
||||
.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
|
||||
pub fn brew_cask_greedy(&self) -> bool {
|
||||
self.config_file
|
||||
@@ -780,6 +816,15 @@ impl Config {
|
||||
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
|
||||
pub fn trizen_arguments(&self) -> &str {
|
||||
self.config_file
|
||||
@@ -867,6 +912,14 @@ impl Config {
|
||||
.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
|
||||
pub fn distrobox_root(&self) -> bool {
|
||||
self.config_file
|
||||
@@ -931,7 +984,7 @@ impl Config {
|
||||
.linux
|
||||
.as_ref()
|
||||
.and_then(|linux| linux.rpm_ostree)
|
||||
.unwrap_or(false)
|
||||
.unwrap_or(true)
|
||||
}
|
||||
|
||||
/// Should we ignore failures for this step
|
||||
@@ -1035,10 +1088,31 @@ impl Config {
|
||||
.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 {
|
||||
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 {
|
||||
if self.opt.custom_commands.is_empty() {
|
||||
return true;
|
||||
|
||||
35
src/main.rs
35
src/main.rs
@@ -3,6 +3,7 @@
|
||||
use std::env;
|
||||
use std::io;
|
||||
use std::process::exit;
|
||||
use std::time::Duration;
|
||||
|
||||
use clap::CommandFactory;
|
||||
use clap::{crate_version, Parser};
|
||||
@@ -85,6 +86,16 @@ fn run() -> Result<()> {
|
||||
debug!("Binary path: {:?}", std::env::current_exe());
|
||||
debug!("Self Update: {:?}", cfg!(feature = "self-update"));
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
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() {
|
||||
#[cfg(unix)]
|
||||
{
|
||||
@@ -115,7 +126,7 @@ fn run() -> Result<()> {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
print_warning(format!("Self update error: {}", e));
|
||||
print_warning(format!("Self update error: {e}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -145,9 +156,12 @@ fn run() -> Result<()> {
|
||||
#[cfg(windows)]
|
||||
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() {
|
||||
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)
|
||||
})?;
|
||||
}
|
||||
@@ -163,7 +177,7 @@ fn run() -> Result<()> {
|
||||
runner.execute(Step::System, "System update", || distribution.upgrade(&ctx))?;
|
||||
}
|
||||
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))?;
|
||||
@@ -305,6 +319,7 @@ fn run() -> Result<()> {
|
||||
{
|
||||
runner.execute(Step::Shell, "zr", || zsh::run_zr(&base_dirs, run_type))?;
|
||||
runner.execute(Step::Shell, "antibody", || zsh::run_antibody(run_type))?;
|
||||
runner.execute(Step::Shell, "antidote", || zsh::run_antidote(&ctx))?;
|
||||
runner.execute(Step::Shell, "antigen", || zsh::run_antigen(&base_dirs, run_type))?;
|
||||
runner.execute(Step::Shell, "zgenom", || zsh::run_zgenom(&base_dirs, run_type))?;
|
||||
runner.execute(Step::Shell, "zplug", || zsh::run_zplug(&base_dirs, run_type))?;
|
||||
@@ -352,6 +367,8 @@ fn run() -> Result<()> {
|
||||
runner.execute(Step::Pipx, "pipx", || generic::run_pipx_update(run_type))?;
|
||||
runner.execute(Step::Conda, "conda", || generic::run_conda_update(&ctx))?;
|
||||
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::Stack, "stack", || generic::run_stack_update(run_type))?;
|
||||
runner.execute(Step::Tlmgr, "tlmgr", || generic::run_tlmgr_update(&ctx))?;
|
||||
@@ -377,9 +394,7 @@ fn run() -> Result<()> {
|
||||
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::RubyGems, "rubygems", || {
|
||||
generic::run_rubygems(&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::Haxelib, "haxelib", || generic::run_haxelib_update(&ctx))?;
|
||||
runner.execute(Step::Sheldon, "sheldon", || generic::run_sheldon(&ctx))?;
|
||||
@@ -397,6 +412,7 @@ fn run() -> Result<()> {
|
||||
|
||||
#[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::Toolbx, "toolbx", || toolbx::run_toolbx(&ctx))?;
|
||||
runner.execute(Step::Flatpak, "Flatpak", || linux::flatpak_update(&ctx))?;
|
||||
@@ -405,6 +421,7 @@ fn run() -> Result<()> {
|
||||
runner.execute(Step::Pacdef, "pacdef", || linux::run_pacdef(&ctx))?;
|
||||
runner.execute(Step::Protonup, "protonup", || linux::run_protonup_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() {
|
||||
@@ -516,8 +533,8 @@ fn run() -> Result<()> {
|
||||
"Topgrade finished {}",
|
||||
if failed { "with errors" } else { "successfully" }
|
||||
),
|
||||
None,
|
||||
);
|
||||
Some(Duration::from_secs(10)),
|
||||
)
|
||||
}
|
||||
|
||||
if failed {
|
||||
@@ -550,7 +567,7 @@ fn main() {
|
||||
// The `Debug` implementation of `eyre::Result` prints a multi-line
|
||||
// error message that includes all the 'causes' added with
|
||||
// `.with_context(...)` calls.
|
||||
println!("Error: {:?}", error);
|
||||
println!("Error: {error:?}");
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ impl<'a> Report<'a> {
|
||||
if let Some((key, success)) = result {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ pub fn self_update() -> Result<()> {
|
||||
if let UpdateStatus::Updated(release) = &result {
|
||||
println!("\nTopgrade upgraded to {}:\n", release.version);
|
||||
if let Some(body) = &release.body {
|
||||
println!("{}", body);
|
||||
println!("{body}");
|
||||
}
|
||||
} else {
|
||||
println!("Topgrade is up-to-date");
|
||||
|
||||
@@ -10,15 +10,15 @@ use color_eyre::eyre::Context;
|
||||
use color_eyre::eyre::Result;
|
||||
use directories::BaseDirs;
|
||||
use tempfile::tempfile_in;
|
||||
use tracing::debug;
|
||||
use tracing::{debug, error};
|
||||
|
||||
use crate::command::{CommandExt, Utf8Output};
|
||||
use crate::execution_context::ExecutionContext;
|
||||
use crate::executor::{ExecutorOutput, RunType};
|
||||
use crate::terminal::{print_separator, shell};
|
||||
use crate::utils::{self, require_option, PathExt};
|
||||
use crate::utils::{self, require, require_option, which, PathExt};
|
||||
use crate::{
|
||||
error::{SkipStep, TopgradeError},
|
||||
error::{SkipStep, StepFailed, TopgradeError},
|
||||
terminal::print_warning,
|
||||
};
|
||||
|
||||
@@ -56,7 +56,24 @@ pub fn run_cargo_update(ctx: &ExecutionContext) -> Result<()> {
|
||||
ctx.run_type()
|
||||
.execute(cargo_update)
|
||||
.args(["install-update", "--git", "--all"])
|
||||
.status_checked()
|
||||
.status_checked()?;
|
||||
|
||||
if ctx.config().cleanup() {
|
||||
let cargo_cache = utils::require("cargo-cache")
|
||||
.ok()
|
||||
.or_else(|| cargo_dir.join("bin/cargo-cache").if_exists());
|
||||
match cargo_cache {
|
||||
Some(e) => {
|
||||
ctx.run_type().execute(e).args(["-a"]).status_checked()?;
|
||||
}
|
||||
None => {
|
||||
let message = String::from("cargo-cache isn't installed so Topgrade can't cleanup cargo packages.\nInstall cargo-cache by running `cargo install cargo-cache`");
|
||||
print_warning(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn run_flutter_upgrade(run_type: RunType) -> Result<()> {
|
||||
@@ -83,17 +100,30 @@ pub fn run_gem(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
||||
command.status_checked()
|
||||
}
|
||||
|
||||
pub fn run_rubygems(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
||||
let gem = utils::require("gem")?;
|
||||
base_dirs.home_dir().join(".gem").require()?;
|
||||
pub fn run_rubygems(ctx: &ExecutionContext) -> Result<()> {
|
||||
ctx.base_dirs().home_dir().join(".gem").require()?;
|
||||
let gem = require("gem")?;
|
||||
|
||||
print_separator("RubyGems");
|
||||
|
||||
if !std::path::Path::new("/usr/lib/ruby/vendor_ruby/rubygems/defaults/operating_system.rb").exists() {
|
||||
run_type.execute(gem).args(["update", "--system"]).status_checked()
|
||||
let gem_path_str = gem.as_os_str();
|
||||
if gem_path_str.to_str().unwrap().contains("asdf") {
|
||||
ctx.run_type()
|
||||
.execute(gem)
|
||||
.args(["update", "--system"])
|
||||
.status_checked()?;
|
||||
} else 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(gem)
|
||||
.args(["update", "--system"])
|
||||
.status_checked()?;
|
||||
}
|
||||
} else {
|
||||
Ok(())
|
||||
print_warning("No sudo detected. Skipping system upgrade");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn run_haxelib_update(ctx: &ExecutionContext) -> Result<()> {
|
||||
@@ -320,6 +350,21 @@ pub fn run_pip3_update(run_type: RunType) -> Result<()> {
|
||||
.output_checked_utf8()
|
||||
.map_err(|_| SkipStep("pip does not exists".to_string()))?;
|
||||
|
||||
let check_externally_managed = "import sysconfig; from os import path; print('Y') if path.isfile(path.join(sysconfig.get_path('stdlib'), 'EXTERNALLY-MANAGED')) else print('N')";
|
||||
Command::new(&python3)
|
||||
.args(["-c", check_externally_managed])
|
||||
.output_checked_utf8()
|
||||
.map_err(|_| SkipStep("pip may be externally managed".to_string()))
|
||||
.and_then(|output| match output.stdout.trim() {
|
||||
"N" => Ok(()),
|
||||
"Y" => Err(SkipStep("pip is externally managed".to_string())),
|
||||
_ => {
|
||||
print_warning("Unexpected output when checking EXTERNALLY-MANAGED");
|
||||
print_warning(output.stdout.trim());
|
||||
Err(SkipStep("pip may be externally managed".to_string()))
|
||||
}
|
||||
})?;
|
||||
|
||||
print_separator("pip3");
|
||||
if std::env::var("VIRTUAL_ENV").is_ok() {
|
||||
print_warning("This step is will be skipped when running inside a virtual environment");
|
||||
@@ -332,6 +377,39 @@ pub fn run_pip3_update(run_type: RunType) -> Result<()> {
|
||||
.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<()> {
|
||||
if utils::require("ghcup").is_ok() {
|
||||
// `ghcup` is present and probably(?) being used to install `stack`.
|
||||
@@ -427,7 +505,10 @@ pub fn run_myrepos_update(base_dirs: &BaseDirs, run_type: RunType) -> Result<()>
|
||||
|
||||
pub fn run_custom_command(name: &str, command: &str, ctx: &ExecutionContext) -> Result<()> {
|
||||
print_separator(name);
|
||||
ctx.run_type().execute(shell()).arg("-c").arg(command).status_checked()
|
||||
let mut exec = ctx.run_type().execute(shell());
|
||||
#[cfg(unix)]
|
||||
exec.arg("-i");
|
||||
exec.arg("-c").arg(command).status_checked()
|
||||
}
|
||||
|
||||
pub fn run_composer_update(ctx: &ExecutionContext) -> Result<()> {
|
||||
@@ -435,7 +516,7 @@ pub fn run_composer_update(ctx: &ExecutionContext) -> Result<()> {
|
||||
let composer_home = Command::new(&composer)
|
||||
.args(["global", "config", "--absolute", "--quiet", "home"])
|
||||
.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()))?
|
||||
.require()?;
|
||||
|
||||
@@ -488,34 +569,43 @@ pub fn run_composer_update(ctx: &ExecutionContext) -> Result<()> {
|
||||
pub fn run_dotnet_upgrade(ctx: &ExecutionContext) -> Result<()> {
|
||||
let dotnet = utils::require("dotnet")?;
|
||||
|
||||
let dotnet_help_output = ctx.run_type().execute(&dotnet).arg("-h").output_checked_utf8().unwrap();
|
||||
|
||||
if dotnet_help_output.to_string().contains("tool") {
|
||||
let output = Command::new(dotnet)
|
||||
.args(["tool", "list", "--global"])
|
||||
.output_checked_utf8()?;
|
||||
|
||||
if !output.stdout.starts_with("Package Id") {
|
||||
return Err(SkipStep(String::from("dotnet did not output packages")).into());
|
||||
//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"])
|
||||
.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())
|
||||
}
|
||||
};
|
||||
|
||||
let mut packages = output.stdout.lines().skip(2).filter(|line| !line.is_empty()).peekable();
|
||||
|
||||
if packages.peek().is_none() {
|
||||
return Err(SkipStep(String::from("No dotnet global tools installed")).into());
|
||||
}
|
||||
|
||||
print_separator(".NET");
|
||||
|
||||
for package in packages {
|
||||
let package_name = package.split_whitespace().next().unwrap();
|
||||
ctx.run_type()
|
||||
.execute("dotnet")
|
||||
.args(["tool", "update", package_name, "--global"])
|
||||
.status_checked()
|
||||
.with_context(|| format!("Failed to update .NET package {package_name}"))?;
|
||||
}
|
||||
if !output.stdout.starts_with("Package Id") {
|
||||
return Err(SkipStep(String::from("dotnet did not output packages")).into());
|
||||
}
|
||||
|
||||
let mut packages = output.stdout.lines().skip(2).filter(|line| !line.is_empty()).peekable();
|
||||
|
||||
if packages.peek().is_none() {
|
||||
return Err(SkipStep(String::from("No dotnet global tools installed")).into());
|
||||
}
|
||||
|
||||
print_separator(".NET");
|
||||
|
||||
for package in packages {
|
||||
let package_name = package.split_whitespace().next().unwrap();
|
||||
ctx.run_type()
|
||||
.execute(&dotnet)
|
||||
.args(["tool", "update", package_name, "--global"])
|
||||
.status_checked()
|
||||
.with_context(|| format!("Failed to update .NET package {package_name}"))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -591,5 +681,24 @@ pub fn run_helm_repo_update(run_type: RunType) -> Result<()> {
|
||||
let helm = utils::require("helm")?;
|
||||
|
||||
print_separator("Helm");
|
||||
run_type.execute(helm).arg("repo").arg("update").status_checked()
|
||||
|
||||
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 {
|
||||
println!("{} pulling {}", style("Failed").red().bold(), &repo);
|
||||
print!("{}", message);
|
||||
print!("{message}");
|
||||
} else {
|
||||
let after_revision = get_head_revision(git, &repo);
|
||||
|
||||
@@ -87,7 +87,7 @@ async fn pull_repository(repo: String, git: &Path, ctx: &ExecutionContext<'_>) -
|
||||
"log",
|
||||
"--no-decorate",
|
||||
"--oneline",
|
||||
&format!("{}..{}", before, after),
|
||||
&format!("{before}..{after}"),
|
||||
])
|
||||
.status_checked()?;
|
||||
println!();
|
||||
@@ -187,7 +187,7 @@ impl Git {
|
||||
repositories
|
||||
.bad_patterns
|
||||
.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)
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ pub fn upgrade_packages(ctx: &ExecutionContext) -> Result<()> {
|
||||
ctx.run_type().execute(&pkg).arg("clean").status_checked()?;
|
||||
|
||||
let apt = require("apt")?;
|
||||
let mut command = ctx.run_type().execute(&apt);
|
||||
let mut command = ctx.run_type().execute(apt);
|
||||
command.arg("autoremove");
|
||||
if ctx.config().yes(Step::System) {
|
||||
command.arg("-y");
|
||||
|
||||
@@ -80,8 +80,18 @@ pub struct GarudaUpdate {
|
||||
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());
|
||||
|
||||
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(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,9 @@ pub enum Distribution {
|
||||
Debian,
|
||||
Gentoo,
|
||||
OpenMandriva,
|
||||
PCLinuxOS,
|
||||
Suse,
|
||||
SuseMicro,
|
||||
Void,
|
||||
Solus,
|
||||
Exherbo,
|
||||
@@ -55,8 +57,10 @@ impl Distribution {
|
||||
Some("gentoo") => Distribution::Gentoo,
|
||||
Some("exherbo") => Distribution::Exherbo,
|
||||
Some("nixos") => Distribution::NixOS,
|
||||
Some("opensuse-microos") => Distribution::SuseMicro,
|
||||
Some("neon") => Distribution::KDENeon,
|
||||
Some("openmandriva") => Distribution::OpenMandriva,
|
||||
Some("pclinuxos") => Distribution::PCLinuxOS,
|
||||
_ => {
|
||||
if let Some(id_like) = id_like {
|
||||
if id_like.contains(&"debian") || id_like.contains(&"ubuntu") {
|
||||
@@ -103,6 +107,7 @@ impl Distribution {
|
||||
Distribution::Debian => upgrade_debian(ctx),
|
||||
Distribution::Gentoo => upgrade_gentoo(ctx),
|
||||
Distribution::Suse => upgrade_suse(ctx),
|
||||
Distribution::SuseMicro => upgrade_suse_micro(ctx),
|
||||
Distribution::Void => upgrade_void(ctx),
|
||||
Distribution::Solus => upgrade_solus(ctx),
|
||||
Distribution::Exherbo => upgrade_exherbo(ctx),
|
||||
@@ -110,6 +115,7 @@ impl Distribution {
|
||||
Distribution::KDENeon => upgrade_neon(ctx),
|
||||
Distribution::Bedrock => update_bedrock(ctx),
|
||||
Distribution::OpenMandriva => upgrade_openmandriva(ctx),
|
||||
Distribution::PCLinuxOS => upgrade_pclinuxos(ctx),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,7 +199,6 @@ fn upgrade_redhat(ctx: &ExecutionContext) -> Result<()> {
|
||||
} else {
|
||||
print_warning("No sudo detected. Skipping system upgrade");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -224,6 +229,18 @@ fn upgrade_suse(ctx: &ExecutionContext) -> Result<()> {
|
||||
|
||||
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<()> {
|
||||
if let Some(sudo) = &ctx.sudo() {
|
||||
@@ -246,6 +263,33 @@ fn upgrade_openmandriva(ctx: &ExecutionContext) -> Result<()> {
|
||||
|
||||
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<()> {
|
||||
if let Some(sudo) = ctx.sudo() {
|
||||
@@ -317,7 +361,20 @@ fn upgrade_gentoo(ctx: &ExecutionContext) -> Result<()> {
|
||||
fn upgrade_debian(ctx: &ExecutionContext) -> Result<()> {
|
||||
if let Some(sudo) = &ctx.sudo() {
|
||||
let apt = which("apt-fast")
|
||||
.or_else(|| which("nala"))
|
||||
.or_else(|| {
|
||||
if which("mist").is_some() {
|
||||
Some(PathBuf::from("mist"))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.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"));
|
||||
|
||||
let is_nala = apt.ends_with("nala");
|
||||
@@ -385,15 +442,44 @@ fn upgrade_solus(ctx: &ExecutionContext) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn update_am(ctx: &ExecutionContext) -> Result<()> {
|
||||
let am = require("am")?;
|
||||
if let Some(sudo) = ctx.sudo() {
|
||||
ctx.run_type().execute(sudo).arg(am).arg("-u").status_checked()?;
|
||||
} else {
|
||||
print_warning("No sudo detected. Skipping AM Step");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn run_pacdef(ctx: &ExecutionContext) -> Result<()> {
|
||||
let pacdef = require("pacdef")?;
|
||||
|
||||
print_separator("pacdef");
|
||||
|
||||
ctx.run_type().execute(&pacdef).arg("sync").status_checked()?;
|
||||
let output = ctx.run_type().execute(&pacdef).arg("version").output_checked()?;
|
||||
let string = String::from_utf8(output.stdout)?;
|
||||
let new_version = string.contains("version: 1");
|
||||
|
||||
println!();
|
||||
ctx.run_type().execute(&pacdef).arg("review").status_checked()
|
||||
if new_version {
|
||||
ctx.run_type()
|
||||
.execute(&pacdef)
|
||||
.args(["package", "sync"])
|
||||
.status_checked()?;
|
||||
|
||||
println!();
|
||||
ctx.run_type()
|
||||
.execute(&pacdef)
|
||||
.args(["package", "review"])
|
||||
.status_checked()?;
|
||||
} else {
|
||||
ctx.run_type().execute(&pacdef).arg("sync").status_checked()?;
|
||||
|
||||
println!();
|
||||
ctx.run_type().execute(&pacdef).arg("review").status_checked()?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn run_pacstall(ctx: &ExecutionContext) -> Result<()> {
|
||||
@@ -401,8 +487,16 @@ pub fn run_pacstall(ctx: &ExecutionContext) -> Result<()> {
|
||||
|
||||
print_separator("Pacstall");
|
||||
|
||||
ctx.run_type().execute(&pacstall).arg("-U").status_checked()?;
|
||||
ctx.run_type().execute(pacstall).arg("-Up").status_checked()
|
||||
let mut update_cmd = ctx.run_type().execute(&pacstall);
|
||||
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<()> {
|
||||
@@ -452,10 +546,13 @@ fn upgrade_exherbo(ctx: &ExecutionContext) -> Result<()> {
|
||||
|
||||
fn upgrade_nixos(ctx: &ExecutionContext) -> Result<()> {
|
||||
if let Some(sudo) = ctx.sudo() {
|
||||
ctx.run_type()
|
||||
.execute(sudo)
|
||||
.args(["/run/current-system/sw/bin/nixos-rebuild", "switch", "--upgrade"])
|
||||
.status_checked()?;
|
||||
let mut command = ctx.run_type().execute(sudo);
|
||||
command.args(["/run/current-system/sw/bin/nixos-rebuild", "switch", "--upgrade"]);
|
||||
|
||||
if let Some(args) = ctx.config().nix_arguments() {
|
||||
command.args(args.split_whitespace());
|
||||
}
|
||||
command.status_checked()?;
|
||||
|
||||
if ctx.config().cleanup() {
|
||||
ctx.run_type()
|
||||
@@ -660,6 +757,29 @@ pub fn run_distrobox_update(ctx: &ExecutionContext) -> Result<()> {
|
||||
.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<()> {
|
||||
let sudo = require_option(ctx.sudo().as_ref(), String::from("sudo is not installed"))?;
|
||||
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/"
|
||||
@@ -152,6 +152,8 @@ pub fn run_oh_my_fish(ctx: &ExecutionContext) -> Result<()> {
|
||||
pub fn run_pkgin(ctx: &ExecutionContext) -> Result<()> {
|
||||
let pkgin = require("pkgin")?;
|
||||
|
||||
print_separator("Pkgin");
|
||||
|
||||
let mut command = ctx.run_type().execute(ctx.sudo().as_ref().unwrap());
|
||||
command.arg(&pkgin).arg("update");
|
||||
if ctx.config().yes(Step::Pkgin) {
|
||||
|
||||
@@ -48,7 +48,7 @@ pub fn run_winget(ctx: &ExecutionContext) -> Result<()> {
|
||||
}
|
||||
|
||||
ctx.run_type()
|
||||
.execute(&winget)
|
||||
.execute(winget)
|
||||
.args(["upgrade", "--all"])
|
||||
.status_checked()
|
||||
}
|
||||
@@ -68,6 +68,25 @@ pub fn run_scoop(cleanup: bool, run_type: RunType) -> Result<()> {
|
||||
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>> {
|
||||
let output = Command::new(wsl).args(["--list", "-q"]).output_checked_utf8()?.stdout;
|
||||
Ok(output
|
||||
@@ -86,7 +105,7 @@ fn upgrade_wsl_distribution(wsl: &Path, dist: &str, ctx: &ExecutionContext) -> R
|
||||
let mut command = ctx.run_type().execute(wsl);
|
||||
command
|
||||
.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) {
|
||||
command.arg("-y");
|
||||
|
||||
@@ -50,7 +50,7 @@ impl Powershell {
|
||||
.args([
|
||||
"-NoProfile",
|
||||
"-Command",
|
||||
&format!("Get-Module -ListAvailable {}", command),
|
||||
&format!("Get-Module -ListAvailable {command}"),
|
||||
])
|
||||
.output_checked_utf8()
|
||||
.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());
|
||||
}
|
||||
|
||||
let env = format!("TOPGRADE_PREFIX={}", hostname);
|
||||
let env = format!("TOPGRADE_PREFIX={hostname}");
|
||||
args.extend(["env", &env, "$SHELL", "-lc", topgrade]);
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
let env = format!("TOPGRADE_PREFIX={}", hostname);
|
||||
let env = format!("TOPGRADE_PREFIX={hostname}");
|
||||
args.extend(["env", &env, "$SHELL", "-lc", topgrade]);
|
||||
|
||||
print_separator(format!("Remote ({})", hostname));
|
||||
println!("Connecting to {}...", hostname);
|
||||
print_separator(format!("Remote ({hostname})"));
|
||||
println!("Connecting to {hostname}...");
|
||||
|
||||
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;
|
||||
if !vagrant_box.initial_status.powered_on() {
|
||||
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 {
|
||||
print_separator(seperator);
|
||||
_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();
|
||||
|
||||
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![
|
||||
"run",
|
||||
"-c",
|
||||
|
||||
@@ -33,23 +33,20 @@ if exists(":PaqUpdate")
|
||||
PaqUpdate
|
||||
endif
|
||||
|
||||
if exists(":CocUpdateSync")
|
||||
echo "CocUpdateSync"
|
||||
CocUpdateSync
|
||||
if exists(":Lazy")
|
||||
echo "Lazy Update"
|
||||
Lazy! sync | qa
|
||||
endif
|
||||
|
||||
" TODO: Should this be after `PackerSync`?
|
||||
" Not sure how to sequence this after Packer without doing something weird
|
||||
" with that `PackerComplete` autocommand.
|
||||
if exists(":TSUpdate")
|
||||
echo "TreeSitter Update"
|
||||
TSUpdate
|
||||
if exists(":AstroUpdate")
|
||||
echo "AstroUpdate"
|
||||
AstroUpdate
|
||||
endif
|
||||
|
||||
if exists(':PackerSync')
|
||||
echo "Packer"
|
||||
autocmd User PackerComplete quitall
|
||||
PackerSync
|
||||
echo "Packer"
|
||||
autocmd User PackerComplete quitall
|
||||
PackerSync
|
||||
else
|
||||
quitall
|
||||
quitall
|
||||
endif
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use std::env;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
|
||||
use color_eyre::eyre::Result;
|
||||
@@ -25,10 +25,28 @@ pub fn run_zr(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
||||
run_type.execute(zsh).args(["-l", "-c", cmd.as_str()]).status_checked()
|
||||
}
|
||||
|
||||
pub fn zshrc(base_dirs: &BaseDirs) -> PathBuf {
|
||||
fn zdotdir(base_dirs: &BaseDirs) -> PathBuf {
|
||||
env::var("ZDOTDIR")
|
||||
.map(|p| Path::new(&p).join(".zshrc"))
|
||||
.unwrap_or_else(|_| base_dirs.home_dir().join(".zshrc"))
|
||||
.map(PathBuf::from)
|
||||
.unwrap_or_else(|_| base_dirs.home_dir().to_path_buf())
|
||||
}
|
||||
|
||||
pub fn zshrc(base_dirs: &BaseDirs) -> PathBuf {
|
||||
zdotdir(base_dirs).join(".zshrc")
|
||||
}
|
||||
|
||||
pub fn run_antidote(ctx: &ExecutionContext) -> Result<()> {
|
||||
let zsh = require("zsh")?;
|
||||
let mut antidote = zdotdir(ctx.base_dirs()).join(".antidote").require()?;
|
||||
antidote.push("antidote.zsh");
|
||||
|
||||
print_separator("antidote");
|
||||
|
||||
ctx.run_type()
|
||||
.execute(zsh)
|
||||
.arg("-c")
|
||||
.arg(format!("source {} && antidote update", antidote.display()))
|
||||
.status_checked()
|
||||
}
|
||||
|
||||
pub fn run_antibody(run_type: RunType) -> Result<()> {
|
||||
|
||||
@@ -24,6 +24,7 @@ impl Sudo {
|
||||
pub fn detect() -> Option<Self> {
|
||||
which("doas")
|
||||
.map(|p| (p, SudoKind::Doas))
|
||||
.or_else(|| which("please").map(|p| (p, SudoKind::Please)))
|
||||
.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)))
|
||||
@@ -47,6 +48,12 @@ impl Sudo {
|
||||
// See: https://man.openbsd.org/doas
|
||||
cmd.arg("echo");
|
||||
}
|
||||
SudoKind::Please => {
|
||||
// From `man please`
|
||||
// -w, --warm
|
||||
// Warm the access token and exit.
|
||||
cmd.arg("-w");
|
||||
}
|
||||
SudoKind::Sudo => {
|
||||
// From `man sudo` on macOS:
|
||||
// -v, --validate
|
||||
@@ -96,6 +103,7 @@ impl Sudo {
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
enum SudoKind {
|
||||
Doas,
|
||||
Please,
|
||||
Sudo,
|
||||
Gsudo,
|
||||
Pkexec,
|
||||
|
||||
@@ -60,7 +60,7 @@ impl Terminal {
|
||||
width: term.size_checked().map(|(_, w)| w),
|
||||
term,
|
||||
prefix: env::var("TOPGRADE_PREFIX")
|
||||
.map(|prefix| format!("({}) ", prefix))
|
||||
.map(|prefix| format!("({prefix}) "))
|
||||
.unwrap_or_else(|_| String::new()),
|
||||
set_title: true,
|
||||
display_time: true,
|
||||
@@ -106,7 +106,7 @@ impl Terminal {
|
||||
command.args(["-a", "Topgrade", "Topgrade"]);
|
||||
command.arg(message.as_ref());
|
||||
if let Err(err) = command.output_checked() {
|
||||
terminal::print_warning("Senfing notification failed with {err:?}");
|
||||
terminal::print_warning("Sending notification failed with {err:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -143,7 +143,7 @@ impl Terminal {
|
||||
.write_fmt(format_args!(
|
||||
"{}\n",
|
||||
style(format_args!(
|
||||
"\n―― {} {:―^border$}",
|
||||
"\n── {} {:─^border$}",
|
||||
message,
|
||||
"",
|
||||
border = max(
|
||||
@@ -159,7 +159,7 @@ impl Terminal {
|
||||
.ok();
|
||||
}
|
||||
None => {
|
||||
self.term.write_fmt(format_args!("―― {} ――\n", message)).ok();
|
||||
self.term.write_fmt(format_args!("―― {message} ――\n")).ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -171,7 +171,7 @@ impl Terminal {
|
||||
self.term
|
||||
.write_fmt(format_args!(
|
||||
"{} {}",
|
||||
style(format!("{} failed:", key)).red().bold(),
|
||||
style(format!("{key} failed:")).red().bold(),
|
||||
message
|
||||
))
|
||||
.ok();
|
||||
@@ -215,7 +215,7 @@ impl Terminal {
|
||||
self.term
|
||||
.write_fmt(format_args!(
|
||||
"{}",
|
||||
style(format!("{} (y)es/(N)o", question,)).yellow().bold()
|
||||
style(format!("{question} (y)es/(N)o",)).yellow().bold()
|
||||
))
|
||||
.ok();
|
||||
|
||||
@@ -237,13 +237,15 @@ impl Terminal {
|
||||
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))
|
||||
.yellow()
|
||||
.bold();
|
||||
|
||||
self.term.write_fmt(format_args!("\n{}", prompt_inner)).ok();
|
||||
self.term.write_fmt(format_args!("\n{prompt_inner}")).ok();
|
||||
|
||||
let answer = loop {
|
||||
match self.term.read_key() {
|
||||
@@ -251,7 +253,7 @@ impl Terminal {
|
||||
Ok(Key::Char('s')) | Ok(Key::Char('S')) => {
|
||||
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") {
|
||||
self.term.write_fmt(format_args!("{err:?}\n{}", prompt_inner)).ok();
|
||||
self.term.write_fmt(format_args!("{err:?}\n{prompt_inner}")).ok();
|
||||
} else {
|
||||
break Ok(true);
|
||||
}
|
||||
|
||||
@@ -149,6 +149,6 @@ pub fn hostname() -> Result<String> {
|
||||
|
||||
Command::new("hostname")
|
||||
.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())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user