9.1.0 Release (#27)

This commit is contained in:
Thomas Schönauer
2022-10-17 20:39:20 +00:00
committed by GitHub
14 changed files with 387 additions and 93 deletions

24
.github/workflows/build-and-test.yml vendored Normal file
View File

@@ -0,0 +1,24 @@
name: Cargo Build & Test
on:
push:
pull_request:
env:
CARGO_TERM_COLOR: always
jobs:
build_and_test:
name: Rust project - latest
runs-on: ubuntu-latest
strategy:
matrix:
toolchain:
- stable
- beta
- nightly
steps:
- uses: actions/checkout@v3
- run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }}
- run: cargo build --verbose
- run: cargo test --verbose

24
.github/workflows/rust-ubuntu.yml vendored Normal file
View File

@@ -0,0 +1,24 @@
name: Rust
on:
push:
branches: [ "master", "dev" ]
pull_request:
branches: [ "master", "dev" ]
env:
CARGO_TERM_COLOR: always
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build
run: cargo build --verbose
- name: Fmt
run: cargo fmt --check --all
- name: Run tests
run: cargo test --verbose

View File

@@ -1,54 +1,54 @@
[package] [package]
name = "topgrade-rs" name = "topgrade-rs"
description = "Upgrade all the things" description = "Upgrade all the things, successor of topgrade"
categories = ["os"] categories = ["os"]
keywords = ["upgrade", "update"] keywords = ["upgrade", "update"]
license-file = "LICENSE" license-file = "LICENSE"
repository = "https://github.com/topgrade-rs/topgrade" repository = "https://github.com/topgrade-rs/topgrade"
version = "9.0.1" version = "9.1.0"
authors = ["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 = "2018" edition = "2018"
readme = "README.md" readme = "README.md"
[dependencies] [dependencies]
directories = "4.0.1" directories = "4.0"
serde = { version = "1.0.125", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
toml = "0.5.8" toml = "0.5"
which_crate = { version = "4.1.0", package = "which" } which_crate = { version = "4.1", package = "which" }
shellexpand = "2.1.0" shellexpand = "2.1"
clap = { version = "3.1", features = ["cargo", "derive"] } clap = { version = "3.1", features = ["cargo", "derive"] }
log = "0.4.14" log = "0.4"
walkdir = "2.3.2" walkdir = "2.3"
console = "0.15.0" console = "0.15"
lazy_static = "1.4.0" lazy_static = "1.4"
chrono = "0.4.19" chrono = "0.4"
pretty_env_logger = "0.4.0" pretty_env_logger = "0.4"
glob = "0.3.0" glob = "0.3"
strum = { version = "0.24.0", features = ["derive"] } strum = { version = "0.24", features = ["derive"] }
thiserror = "1.0.24" thiserror = "1.0"
anyhow = "1.0.40" anyhow = "1.0"
tempfile = "3.2.0" tempfile = "3.2"
cfg-if = "1.0.0" cfg-if = "1.0"
tokio = { version = "1.5.0", features = ["process", "rt-multi-thread"] } tokio = { version = "1.5", features = ["process", "rt-multi-thread"] }
futures = "0.3.14" futures = "0.3"
regex = "1.5.3" regex = "1.5"
sys-info = "0.9" sys-info = "0.9"
semver = "1.0" semver = "1.0"
[target.'cfg(target_os = "macos")'.dependencies] [target.'cfg(target_os = "macos")'.dependencies]
notify-rust = "4.5.0" notify-rust = "4.5"
[target.'cfg(unix)'.dependencies] [target.'cfg(unix)'.dependencies]
nix = "0.24.1" nix = "0.24"
rust-ini = "0.18.0" rust-ini = "0.18"
self_update_crate = { version = "0.30.0", default-features = false, optional = true, package = "self_update", features = ["archive-tar", "compression-flate2", "rustls"] } self_update_crate = { version = "0.30", default-features = false, optional = true, package = "self_update", features = ["archive-tar", "compression-flate2", "rustls"] }
[target.'cfg(windows)'.dependencies] [target.'cfg(windows)'.dependencies]
self_update_crate = { version = "0.30.0", default-features = false, optional = true, package = "self_update", features = ["archive-zip", "compression-zip-deflate", "rustls"] } self_update_crate = { version = "0.30", default-features = false, optional = true, package = "self_update", features = ["archive-zip", "compression-zip-deflate", "rustls"] }
winapi = "0.3.9" winapi = "0.3"
parselnk = "0.1.0" parselnk = "0.1"
[profile.release] [profile.release]
lto = true lto = true

View File

@@ -1,14 +1,17 @@
![Topgrade](doc/topgrade.png) ![Topgrade](doc/topgrade.png)
<!---
[![Travis](https://api.travis-ci.org/r-darwish/topgrade.svg?branch=master)](https://travis-ci.org/r-darwish/topgrade)
[![AppVeyor](https://ci.appveyor.com/api/projects/status/github/r-darwish/topgrade?svg=true)](https://ci.appveyor.com/project/r-darwish/topgrade)
![GitHub release](https://img.shields.io/github/release/r-darwish/topgrade.svg) ![GitHub release](https://img.shields.io/github/release/r-darwish/topgrade.svg)
[![Crates.io](https://img.shields.io/crates/v/topgrade.svg)](https://crates.io/crates/topgrade) [![Crates.io](https://img.shields.io/crates/v/topgrade.svg)](https://crates.io/crates/topgrade)
[![AUR](https://img.shields.io/aur/version/topgrade.svg)](https://aur.archlinux.org/packages/topgrade/) [![AUR](https://img.shields.io/aur/version/topgrade.svg)](https://aur.archlinux.org/packages/topgrade/)
![homebrew](https://img.shields.io/homebrew/v/topgrade.svg) ![homebrew](https://img.shields.io/homebrew/v/topgrade.svg) -->
--->
![Demo](doc/screenshot.gif) ![Demo](doc/screenshot.gif)
## Fork
This is a fork of [topgrade by r-darwish](https://github.com/r-darwish/topgrade) to keep it maintained.
Keeping your system up to date usually involves invoking multiple package managers. 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. This results in big, non-portable shell one-liners saved in your shell.
To remedy this, _topgrade_ detects which tools you use and runs the appropriate commands to update them. To remedy this, _topgrade_ detects which tools you use and runs the appropriate commands to update them.
@@ -23,6 +26,9 @@ The compiled binaries contain a self-upgrading feature.
Topgrade requires Rust 1.51 or above. Topgrade requires Rust 1.51 or above.
## Documentation[WIP]
You can visit the documentation at [topgrade-rs.github.io](https://topgrade-rs.github.io/) .
## Usage ## Usage
Just run `topgrade`. Just run `topgrade`.
See [the wiki](https://github.com/r-darwish/topgrade/wiki/Step-list) for the list of things Topgrade supports. See [the wiki](https://github.com/r-darwish/topgrade/wiki/Step-list) for the list of things Topgrade supports.

View File

@@ -37,6 +37,9 @@
# Cleanup temporary or old files # Cleanup temporary or old files
#cleanup = true #cleanup = true
# Skip sending a notification at the end of a run
#skip_notify = true
[git] [git]
#max_concurrency = 5 #max_concurrency = 5
# Additional git repositories to pull # Additional git repositories to pull
@@ -64,6 +67,7 @@
[brew] [brew]
#greedy_cask = true #greedy_cask = true
#autoremove = true
[linux] [linux]
# Arch Package Manager to use. Allowed values: autodetect, trizen, paru, yay, pikaur, pacman, pamac. # Arch Package Manager to use. Allowed values: autodetect, trizen, paru, yay, pikaur, pacman, pamac.
@@ -87,7 +91,7 @@
# 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
# manager such as Scoop to Cargo # manager such as Scoop or Cargo
#self_rename = true #self_rename = true
[npm] [npm]

View File

@@ -62,7 +62,7 @@ macro_rules! get_deprecated {
type Commands = BTreeMap<String, String>; type Commands = BTreeMap<String, String>;
#[derive(ArgEnum, EnumString, EnumVariantNames, Debug, Clone, PartialEq, Deserialize, EnumIter, Copy)] #[derive(ArgEnum, EnumString, EnumVariantNames, Debug, Clone, PartialEq, Eq, Deserialize, EnumIter, Copy)]
#[clap(rename_all = "snake_case")] #[clap(rename_all = "snake_case")]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")] #[strum(serialize_all = "snake_case")]
@@ -71,6 +71,7 @@ pub enum Step {
Atom, Atom,
BrewCask, BrewCask,
BrewFormula, BrewFormula,
Bun,
Bin, Bin,
Cargo, Cargo,
Chezmoi, Chezmoi,
@@ -94,10 +95,12 @@ pub enum Step {
GithubCliExtensions, GithubCliExtensions,
GitRepos, GitRepos,
Go, Go,
Guix,
Haxelib, Haxelib,
GnomeShellExtensions, GnomeShellExtensions,
HomeManager, HomeManager,
Jetpack, Jetpack,
Julia,
Kakoune, Kakoune,
Krew, Krew,
Macports, Macports,
@@ -107,6 +110,7 @@ pub enum Step {
Nix, Nix,
Node, Node,
Opam, Opam,
Pacdef,
Pacstall, Pacstall,
Pearl, Pearl,
Pipx, Pipx,
@@ -114,6 +118,7 @@ pub enum Step {
Pkg, Pkg,
Pkgin, Pkgin,
Powershell, Powershell,
Protonup,
Raco, Raco,
Remotes, Remotes,
Restarts, Restarts,
@@ -166,6 +171,13 @@ pub struct Windows {
enable_winget: Option<bool>, enable_winget: Option<bool>,
} }
#[derive(Deserialize, Default, Debug)]
#[serde(deny_unknown_fields)]
#[allow(clippy::upper_case_acronyms)]
pub struct Yarn {
use_sudo: Option<bool>,
}
#[derive(Deserialize, Default, Debug)] #[derive(Deserialize, Default, Debug)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
#[allow(clippy::upper_case_acronyms)] #[allow(clippy::upper_case_acronyms)]
@@ -191,6 +203,7 @@ pub struct Flatpak {
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
pub struct Brew { pub struct Brew {
greedy_cask: Option<bool>, greedy_cask: Option<bool>,
autoremove: Option<bool>,
} }
#[derive(Debug, Deserialize, Clone, Copy)] #[derive(Debug, Deserialize, Clone, Copy)]
@@ -260,6 +273,7 @@ pub struct ConfigFile {
cleanup: Option<bool>, cleanup: Option<bool>,
notify_each_step: Option<bool>, notify_each_step: Option<bool>,
accept_all_windows_updates: Option<bool>, accept_all_windows_updates: Option<bool>,
skip_notify: Option<bool>,
bashit_branch: Option<String>, bashit_branch: Option<String>,
only: Option<Vec<Step>>, only: Option<Vec<Step>>,
composer: Option<Composer>, composer: Option<Composer>,
@@ -268,6 +282,7 @@ pub struct ConfigFile {
git: Option<Git>, git: Option<Git>,
windows: Option<Windows>, windows: Option<Windows>,
npm: Option<NPM>, npm: Option<NPM>,
yarn: Option<Yarn>,
vim: Option<Vim>, vim: Option<Vim>,
firmware: Option<Firmware>, firmware: Option<Firmware>,
vagrant: Option<Vagrant>, vagrant: Option<Vagrant>,
@@ -415,6 +430,10 @@ pub struct CommandLineArgs {
#[clap(short = 'k', long = "keep")] #[clap(short = 'k', long = "keep")]
keep_at_end: bool, keep_at_end: bool,
/// Skip sending a notification at the end of a run
#[clap(long = "skip-notify")]
skip_notify: bool,
/// Say yes to package manager's prompt /// Say yes to package manager's prompt
#[clap(short = 'y', long = "yes", arg_enum, multiple_values = true, min_values = 0)] #[clap(short = 'y', long = "yes", arg_enum, multiple_values = true, min_values = 0)]
yes: Option<Vec<Step>>, yes: Option<Vec<Step>>,
@@ -600,6 +619,15 @@ impl Config {
self.opt.keep_at_end || env::var("TOPGRADE_KEEP_END").is_ok() self.opt.keep_at_end || env::var("TOPGRADE_KEEP_END").is_ok()
} }
/// Skip sending a notification at the end of a run
pub fn skip_notify(&self) -> bool {
if let Some(yes) = self.config_file.skip_notify {
return yes;
}
self.opt.skip_notify
}
/// Whether to set the terminal title /// Whether to set the terminal title
pub fn set_title(&self) -> bool { pub fn set_title(&self) -> bool {
self.config_file.set_title.unwrap_or(true) self.config_file.set_title.unwrap_or(true)
@@ -656,6 +684,15 @@ impl Config {
.unwrap_or(false) .unwrap_or(false)
} }
/// Whether Brew should autoremove
pub fn brew_autoremove(&self) -> bool {
self.config_file
.brew
.as_ref()
.and_then(|c| c.autoremove)
.unwrap_or(false)
}
/// Whether Composer should update itself /// Whether Composer should update itself
pub fn composer_self_update(&self) -> bool { pub fn composer_self_update(&self) -> bool {
self.config_file self.config_file
@@ -839,6 +876,14 @@ impl Config {
.and_then(|npm| npm.use_sudo) .and_then(|npm| npm.use_sudo)
.unwrap_or(false) .unwrap_or(false)
} }
#[cfg(target_os = "linux")]
pub fn yarn_use_sudo(&self) -> bool {
self.config_file
.yarn
.as_ref()
.and_then(|yarn| yarn.use_sudo)
.unwrap_or(false)
}
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
pub fn firmware_upgrade(&self) -> bool { pub fn firmware_upgrade(&self) -> bool {

View File

@@ -2,7 +2,7 @@ use std::process::ExitStatus;
use thiserror::Error; use thiserror::Error;
#[derive(Error, Debug, PartialEq)] #[derive(Error, Debug, PartialEq, Eq)]
pub enum TopgradeError { pub enum TopgradeError {
#[error("{0}")] #[error("{0}")]
ProcessFailed(ExitStatus), ProcessFailed(ExitStatus),

View File

@@ -191,9 +191,12 @@ fn run() -> Result<()> {
{ {
runner.execute(Step::Yadm, "yadm", || unix::run_yadm(&ctx))?; runner.execute(Step::Yadm, "yadm", || unix::run_yadm(&ctx))?;
runner.execute(Step::Nix, "nix", || unix::run_nix(&ctx))?; runner.execute(Step::Nix, "nix", || unix::run_nix(&ctx))?;
runner.execute(Step::Guix, "guix", || unix::run_guix(&ctx))?;
runner.execute(Step::HomeManager, "home-manager", || unix::run_home_manager(run_type))?; runner.execute(Step::HomeManager, "home-manager", || unix::run_home_manager(run_type))?;
runner.execute(Step::Asdf, "asdf", || unix::run_asdf(run_type))?; runner.execute(Step::Asdf, "asdf", || unix::run_asdf(run_type))?;
runner.execute(Step::Pkgin, "pkgin", || unix::run_pkgin(&ctx))?; runner.execute(Step::Pkgin, "pkgin", || unix::run_pkgin(&ctx))?;
runner.execute(Step::Bun, "bun", || unix::run_bun(&ctx))?;
} }
#[cfg(target_os = "dragonfly")] #[cfg(target_os = "dragonfly")]
@@ -315,7 +318,7 @@ fn run() -> Result<()> {
runner.execute(Step::Flutter, "Flutter", || generic::run_flutter_upgrade(run_type))?; runner.execute(Step::Flutter, "Flutter", || generic::run_flutter_upgrade(run_type))?;
runner.execute(Step::Go, "Go", || generic::run_go(run_type))?; runner.execute(Step::Go, "Go", || generic::run_go(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(run_type))?; 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(run_type))?;
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))?;
@@ -335,11 +338,13 @@ fn run() -> Result<()> {
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::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::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::Gem, "gem", || generic::run_gem(&base_dirs, run_type))?; runner.execute(Step::Gem, "gem", || generic::run_gem(&base_dirs, run_type))?;
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))?;
runner.execute(Step::Rtcl, "rtcl", || generic::run_rtcl(&ctx))?; runner.execute(Step::Rtcl, "rtcl", || generic::run_rtcl(&ctx))?;
@@ -361,6 +366,8 @@ fn run() -> Result<()> {
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(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::Protonup, "protonup", || linux::run_protonup_update(&ctx))?;
} }
if let Some(commands) = config.commands() { if let Some(commands) = config.commands() {
@@ -460,6 +467,8 @@ fn run() -> Result<()> {
} }
let failed = post_command_failed || runner.report().data().iter().any(|(_, result)| result.failed()); let failed = post_command_failed || runner.report().data().iter().any(|(_, result)| result.failed());
if !config.skip_notify() {
terminal::notify_desktop( terminal::notify_desktop(
format!( format!(
"Topgrade finished {}", "Topgrade finished {}",
@@ -467,6 +476,8 @@ fn run() -> Result<()> {
), ),
None, None,
); );
}
if failed { if failed {
Err(StepFailed.into()) Err(StepFailed.into())
} else { } else {

0
src/steps/bun.rs Normal file
View File

View File

@@ -67,25 +67,24 @@ impl Emacs {
print_separator("Doom Emacs"); print_separator("Doom Emacs");
let mut command = ctx.run_type().execute(doom); let mut command = ctx.run_type().execute(doom);
command.args(&["-y", "upgrade"]);
if ctx.config().yes(Step::Emacs) { if ctx.config().yes(Step::Emacs) {
command.arg("--force"); command.arg("--force");
} }
command.args(&["upgrade"]);
command.check_run() command.check_run()
} }
pub fn upgrade(&self, ctx: &ExecutionContext) -> Result<()> { pub fn upgrade(&self, ctx: &ExecutionContext) -> Result<()> {
let emacs = require("emacs")?; let emacs = require("emacs")?;
if let Some(doom) = &self.doom {
Emacs::update_doom(doom, ctx)?;
}
let init_file = require_option(self.directory.as_ref(), String::from("Emacs directory does not exist"))? let init_file = require_option(self.directory.as_ref(), String::from("Emacs directory does not exist"))?
.join("init.el") .join("init.el")
.require()?; .require()?;
if let Some(doom) = &self.doom {
return Emacs::update_doom(doom, ctx);
}
print_separator("Emacs"); print_separator("Emacs");
let mut command = ctx.run_type().execute(&emacs); let mut command = ctx.run_type().execute(&emacs);

View File

@@ -220,13 +220,19 @@ pub fn run_rtcl(ctx: &ExecutionContext) -> Result<()> {
ctx.run_type().execute(&rupdate).check_run() ctx.run_type().execute(&rupdate).check_run()
} }
pub fn run_opam_update(run_type: RunType) -> Result<()> { pub fn run_opam_update(ctx: &ExecutionContext) -> Result<()> {
let opam = utils::require("opam")?; let opam = utils::require("opam")?;
print_separator("OCaml Package Manager"); print_separator("OCaml Package Manager");
run_type.execute(&opam).arg("update").check_run()?; ctx.run_type().execute(&opam).arg("update").check_run()?;
run_type.execute(&opam).arg("upgrade").check_run() ctx.run_type().execute(&opam).arg("upgrade").check_run()?;
if ctx.config().cleanup() {
ctx.run_type().execute(&opam).arg("clean").check_run()?;
}
Ok(())
} }
pub fn run_vcpkg_update(run_type: RunType) -> Result<()> { pub fn run_vcpkg_update(run_type: RunType) -> Result<()> {
@@ -496,3 +502,14 @@ pub fn run_ghcli_extensions_upgrade(ctx: &ExecutionContext) -> Result<()> {
.args(&["extension", "upgrade", "--all"]) .args(&["extension", "upgrade", "--all"])
.check_run() .check_run()
} }
pub fn update_julia_packages(ctx: &ExecutionContext) -> Result<()> {
let julia = utils::require("julia")?;
print_separator("Julia Packages");
ctx.run_type()
.execute(&julia)
.args(&["-e", "using Pkg; Pkg.update()"])
.check_run()
}

View File

@@ -20,15 +20,11 @@ use crate::{error::SkipStep, execution_context::ExecutionContext};
#[allow(clippy::upper_case_acronyms)] #[allow(clippy::upper_case_acronyms)]
struct NPM { struct NPM {
command: PathBuf, command: PathBuf,
pnpm: Option<PathBuf>,
} }
impl NPM { impl NPM {
fn new(command: PathBuf) -> Self { fn new(command: PathBuf) -> Self {
Self { Self { command }
command,
pnpm: require("pnpm").ok(),
}
} }
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
@@ -56,17 +52,13 @@ impl NPM {
fn upgrade(&self, run_type: RunType, use_sudo: bool) -> Result<()> { fn upgrade(&self, run_type: RunType, use_sudo: bool) -> Result<()> {
print_separator("Node Package Manager"); print_separator("Node Package Manager");
let version = self.version()?; let version = self.version()?;
let args = if version < Version::new(8, 11, 0) || self.pnpm.is_some() { let args = if version < Version::new(8, 11, 0) {
["update", "-g"] ["update", "-g"]
} else { } else {
["update", "--location=global"] ["update", "--location=global"]
}; };
if use_sudo { if use_sudo {
run_type run_type.execute("sudo").args(args).check_run()?;
.execute("sudo")
.arg(self.pnpm.as_ref().unwrap_or(&self.command))
.args(args)
.check_run()?;
} else { } else {
run_type.execute(&self.command).args(args).check_run()?; run_type.execute(&self.command).args(args).check_run()?;
} }
@@ -88,6 +80,59 @@ impl NPM {
} }
} }
struct Yarn {
command: PathBuf,
yarn: Option<PathBuf>,
}
impl Yarn {
fn new(command: PathBuf) -> Self {
Self {
command,
yarn: require("yarn").ok(),
}
}
#[cfg(target_os = "linux")]
fn root(&self) -> Result<PathBuf> {
let args = ["global", "dir"];
Command::new(&self.command)
.args(args)
.check_output()
.map(|s| PathBuf::from(s.trim()))
}
fn upgrade(&self, run_type: RunType, use_sudo: bool) -> Result<()> {
print_separator("Yarn Package Manager");
let args = ["global", "upgrade"];
if use_sudo {
run_type
.execute("sudo")
.arg(self.yarn.as_ref().unwrap_or(&self.command))
.args(args)
.check_run()?;
} else {
run_type.execute(&self.command).args(args).check_run()?;
}
Ok(())
}
#[cfg(target_os = "linux")]
pub fn should_use_sudo(&self) -> Result<bool> {
let yarn_root = self.root()?;
if !yarn_root.exists() {
return Err(SkipStep(format!("NPM root at {} doesn't exist", yarn_root.display(),)).into());
}
let metadata = std::fs::metadata(&yarn_root)?;
let uid = Uid::effective();
Ok(metadata.uid() != uid.as_raw() && metadata.uid() == 0)
}
}
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
fn should_use_sudo(npm: &NPM, ctx: &ExecutionContext) -> Result<bool> { fn should_use_sudo(npm: &NPM, ctx: &ExecutionContext) -> Result<bool> {
if npm.should_use_sudo()? { if npm.should_use_sudo()? {
@@ -102,8 +147,22 @@ fn should_use_sudo(npm: &NPM, ctx: &ExecutionContext) -> Result<bool> {
} }
} }
#[cfg(target_os = "linux")]
fn should_use_sudo_yarn(yarn: &Yarn, ctx: &ExecutionContext) -> Result<bool> {
if yarn.should_use_sudo()? {
if ctx.config().yarn_use_sudo() {
Ok(true)
} else {
Err(SkipStep("NPM root is owned by another user which is not the current user. Set use_sudo = true under the NPM section in your configuration to run NPM as sudo".to_string())
.into())
}
} else {
Ok(false)
}
}
pub fn run_npm_upgrade(ctx: &ExecutionContext) -> Result<()> { pub fn run_npm_upgrade(ctx: &ExecutionContext) -> Result<()> {
let npm = require("npm").map(NPM::new)?; let npm = require("pnpm").or_else(|_| require("npm")).map(NPM::new)?;
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
{ {
@@ -116,6 +175,20 @@ pub fn run_npm_upgrade(ctx: &ExecutionContext) -> Result<()> {
} }
} }
pub fn run_yarn_upgrade(ctx: &ExecutionContext) -> Result<()> {
let yarn = require("yarn").map(Yarn::new)?;
#[cfg(target_os = "linux")]
{
yarn.upgrade(ctx.run_type(), should_use_sudo_yarn(&yarn, ctx)?)
}
#[cfg(not(target_os = "linux"))]
{
yarn.upgrade(ctx.run_type(), false)
}
}
pub fn deno_upgrade(ctx: &ExecutionContext) -> Result<()> { pub fn deno_upgrade(ctx: &ExecutionContext) -> Result<()> {
let deno = require("deno")?; let deno = require("deno")?;
let deno_dir = ctx.base_dirs().home_dir().join(".deno"); let deno_dir = ctx.base_dirs().home_dir().join(".deno");

View File

@@ -26,6 +26,7 @@ pub enum Distribution {
Fedora, Fedora,
Debian, Debian,
Gentoo, Gentoo,
OpenMandriva,
Suse, Suse,
Void, Void,
Solus, Solus,
@@ -44,7 +45,7 @@ impl Distribution {
Some("alpine") => Distribution::Alpine, Some("alpine") => Distribution::Alpine,
Some("centos") | Some("rhel") | Some("ol") => Distribution::CentOS, Some("centos") | Some("rhel") | Some("ol") => Distribution::CentOS,
Some("clear-linux-os") => Distribution::ClearLinux, Some("clear-linux-os") => Distribution::ClearLinux,
Some("fedora") => Distribution::Fedora, Some("fedora") | Some("nobara") => Distribution::Fedora,
Some("void") => Distribution::Void, Some("void") => Distribution::Void,
Some("debian") | Some("pureos") => Distribution::Debian, Some("debian") | Some("pureos") => Distribution::Debian,
Some("arch") | Some("anarchy") | Some("manjaro-arm") | Some("garuda") | Some("artix") => Distribution::Arch, Some("arch") | Some("anarchy") | Some("manjaro-arm") | Some("garuda") | Some("artix") => Distribution::Arch,
@@ -53,6 +54,7 @@ impl Distribution {
Some("exherbo") => Distribution::Exherbo, Some("exherbo") => Distribution::Exherbo,
Some("nixos") => Distribution::NixOS, Some("nixos") => Distribution::NixOS,
Some("neon") => Distribution::KDENeon, Some("neon") => Distribution::KDENeon,
Some("openmandriva") => Distribution::OpenMandriva,
_ => { _ => {
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") {
@@ -105,6 +107,7 @@ impl Distribution {
Distribution::NixOS => upgrade_nixos(ctx), Distribution::NixOS => upgrade_nixos(ctx),
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),
} }
} }
@@ -218,6 +221,28 @@ fn upgrade_suse(ctx: &ExecutionContext) -> Result<()> {
Ok(()) Ok(())
} }
fn upgrade_openmandriva(ctx: &ExecutionContext) -> Result<()> {
if let Some(sudo) = &ctx.sudo() {
let mut command = ctx.run_type().execute(&sudo);
command.arg(which("dnf").unwrap().to_path_buf()).arg("upgrade");
if let Some(args) = ctx.config().dnf_arguments() {
command.args(args.split_whitespace());
}
if ctx.config().yes(Step::System) {
command.arg("-y");
}
command.check_run()?;
} 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() {
let mut command = ctx.run_type().execute(&sudo); let mut command = ctx.run_type().execute(&sudo);
@@ -349,6 +374,17 @@ fn upgrade_solus(ctx: &ExecutionContext) -> Result<()> {
Ok(()) Ok(())
} }
pub fn run_pacdef(ctx: &ExecutionContext) -> Result<()> {
let pacdef = require("pacdef")?;
print_separator("pacdef");
ctx.run_type().execute(&pacdef).arg("sync").check_run()?;
println!();
ctx.run_type().execute(&pacdef).arg("review").check_run()
}
pub fn run_pacstall(ctx: &ExecutionContext) -> Result<()> { pub fn run_pacstall(ctx: &ExecutionContext) -> Result<()> {
let pacstall = require("pacstall")?; let pacstall = require("pacstall")?;
@@ -492,44 +528,50 @@ pub fn flatpak_update(ctx: &ExecutionContext) -> Result<()> {
let flatpak = require("flatpak")?; let flatpak = require("flatpak")?;
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"))?;
let cleanup = ctx.config().cleanup(); let cleanup = ctx.config().cleanup();
let yes = ctx.config().yes(Step::Flatpak);
let run_type = ctx.run_type(); let run_type = ctx.run_type();
print_separator("Flatpak User Packages"); print_separator("Flatpak User Packages");
run_type let mut update_args = vec!["update", "--user"];
.execute(&flatpak) if yes {
.args(&["update", "--user", "-y"]) update_args.push("-y");
.check_run()?; }
run_type.execute(&flatpak).args(&update_args).check_run()?;
if cleanup { if cleanup {
run_type let mut cleanup_args = vec!["uninstall", "--user", "--unused"];
.execute(&flatpak) if yes {
.args(&["uninstall", "--user", "--unused"]) cleanup_args.push("-y");
.check_run()?; }
run_type.execute(&flatpak).args(&cleanup_args).check_run()?;
} }
print_separator("Flatpak System Packages"); print_separator("Flatpak System Packages");
if ctx.config().flatpak_use_sudo() || std::env::var("SSH_CLIENT").is_ok() { if ctx.config().flatpak_use_sudo() || std::env::var("SSH_CLIENT").is_ok() {
run_type let mut update_args = vec!["update", "--system"];
.execute(&sudo) if yes {
.arg(&flatpak) update_args.push("-y");
.args(&["update", "--system", "-y"]) }
.check_run()?; run_type.execute(&sudo).arg(&flatpak).args(&update_args).check_run()?;
if cleanup { if cleanup {
run_type let mut cleanup_args = vec!["uninstall", "--system", "--unused"];
.execute(sudo) if yes {
.arg(flatpak) cleanup_args.push("-y");
.args(&["uninstall", "--system", "--unused"]) }
.check_run()?; run_type.execute(sudo).arg(flatpak).args(&cleanup_args).check_run()?;
} }
} else { } else {
run_type let mut update_args = vec!["update", "--system"];
.execute(&flatpak) if yes {
.args(&["update", "--system", "-y"]) update_args.push("-y");
.check_run()?; }
run_type.execute(&flatpak).args(&update_args).check_run()?;
if cleanup { if cleanup {
run_type let mut cleanup_args = vec!["uninstall", "--system", "--unused"];
.execute(flatpak) if yes {
.args(&["uninstall", "--system", "--unused"]) cleanup_args.push("-y");
.check_run()?; }
run_type.execute(flatpak).args(&cleanup_args).check_run()?;
} }
} }
@@ -558,6 +600,15 @@ pub fn run_pihole_update(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()
run_type.execute(sudo).arg(pihole).arg("-up").check_run() run_type.execute(sudo).arg(pihole).arg("-up").check_run()
} }
pub fn run_protonup_update(ctx: &ExecutionContext) -> Result<()> {
let protonup = require("protonup")?;
print_separator("protonup");
ctx.run_type().execute(protonup).check_run()?;
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) {

View File

@@ -210,6 +210,10 @@ pub fn run_brew_formula(ctx: &ExecutionContext, variant: BrewVariant) -> Result<
variant.execute(run_type).arg("cleanup").check_run()?; variant.execute(run_type).arg("cleanup").check_run()?;
} }
if ctx.config().brew_autoremove() {
variant.execute(run_type).arg("autoremove").check_run()?;
}
Ok(()) Ok(())
} }
@@ -251,6 +255,24 @@ pub fn run_brew_cask(ctx: &ExecutionContext, variant: BrewVariant) -> Result<()>
Ok(()) Ok(())
} }
pub fn run_guix(ctx: &ExecutionContext) -> Result<()> {
let guix = require("guix")?;
let run_type = ctx.run_type();
let output = Command::new(&guix).arg("pull").check_output();
debug!("guix pull output: {:?}", output);
let should_upgrade = output.is_ok();
debug!("Can Upgrade Guix: {:?}", should_upgrade);
print_separator("Guix");
if should_upgrade {
return run_type.execute(&guix).args(&["package", "-u"]).check_run();
}
Err(SkipStep(String::from("Guix Pull Failed, Skipping")).into())
}
pub fn run_nix(ctx: &ExecutionContext) -> Result<()> { pub fn run_nix(ctx: &ExecutionContext) -> Result<()> {
let nix = require("nix")?; let nix = require("nix")?;
let nix_channel = require("nix-channel")?; let nix_channel = require("nix-channel")?;
@@ -274,6 +296,16 @@ pub fn run_nix(ctx: &ExecutionContext) -> Result<()> {
} }
} }
#[cfg(target_os = "macos")]
{
if let Ok(..) = require("darwin-rebuild") {
return Err(SkipStep(String::from(
"Nix-darwin on macOS must be upgraded via darwin-rebuild switch",
))
.into());
}
}
let run_type = ctx.run_type(); let run_type = ctx.run_type();
if should_self_upgrade { if should_self_upgrade {
@@ -391,6 +423,14 @@ pub fn run_sdkman(base_dirs: &BaseDirs, cleanup: bool, run_type: RunType) -> Res
Ok(()) Ok(())
} }
pub fn run_bun(ctx: &ExecutionContext) -> Result<()> {
let bun = require("bun")?;
print_separator("Bun");
ctx.run_type().execute(&bun).arg("upgrade").check_run()
}
pub fn reboot() { pub fn reboot() {
print!("Rebooting..."); print!("Rebooting...");
Command::new("sudo").arg("reboot").spawn().unwrap().wait().unwrap(); Command::new("sudo").arg("reboot").spawn().unwrap().wait().unwrap();