2020-04-03 12:19:55 +03:00
#![ allow(unused_imports) ]
2022-01-15 06:50:42 +02:00
2024-12-07 09:09:52 +02:00
use std ::ffi ::OsStr ;
2022-01-15 06:50:42 +02:00
use std ::path ::PathBuf ;
use std ::process ::Command ;
use std ::{ env , path ::Path } ;
use std ::{ fs , io ::Write } ;
2022-11-11 09:39:29 -05:00
use color_eyre ::eyre ::eyre ;
use color_eyre ::eyre ::Context ;
use color_eyre ::eyre ::Result ;
2024-10-03 12:47:35 +02:00
use rust_i18n ::t ;
2023-12-31 04:38:39 +01:00
use semver ::Version ;
2022-01-15 06:50:42 +02:00
use tempfile ::tempfile_in ;
2023-01-29 19:19:27 +00:00
use tracing ::{ debug , error } ;
2022-01-15 06:50:42 +02:00
2022-11-08 05:54:35 -05:00
use crate ::command ::{ CommandExt , Utf8Output } ;
2020-02-08 22:13:56 +02:00
use crate ::execution_context ::ExecutionContext ;
2023-05-25 15:09:23 +08:00
use crate ::executor ::ExecutorOutput ;
2019-08-22 21:46:06 +03:00
use crate ::terminal ::{ print_separator , shell } ;
2024-10-03 12:47:35 +02:00
use crate ::utils ::{ self , check_is_python_2_or_shim , get_require_sudo_string , require , require_option , which , PathExt } ;
2023-04-17 16:19:59 +02:00
use crate ::Step ;
2023-05-01 00:02:13 +05:30
use crate ::HOME_DIR ;
2021-02-08 06:31:14 +02:00
use crate ::{
2023-01-29 19:19:27 +00:00
error ::{ SkipStep , StepFailed , TopgradeError } ,
2021-02-08 06:31:14 +02:00
terminal ::print_warning ,
} ;
2018-08-19 14:45:23 +03:00
2024-01-24 03:32:00 +01:00
#[ cfg(target_os = " linux " ) ]
pub fn is_wsl ( ) -> Result < bool > {
let output = Command ::new ( " uname " ) . arg ( " -r " ) . output_checked_utf8 ( ) ? . stdout ;
debug! ( " Uname output: {} " , output ) ;
Ok ( output . contains ( " microsoft " ) )
}
#[ cfg(not(target_os = " linux " )) ]
pub fn is_wsl ( ) -> Result < bool > {
Ok ( false )
}
2021-03-22 09:00:56 +02:00
pub fn run_cargo_update ( ctx : & ExecutionContext ) -> Result < ( ) > {
2021-05-05 13:52:12 +03:00
let cargo_dir = env ::var_os ( " CARGO_HOME " )
2025-02-02 19:24:57 -08:00
. map_or_else ( | | HOME_DIR . join ( " .cargo " ) , PathBuf ::from )
2021-05-05 13:52:12 +03:00
. require ( ) ? ;
2023-05-27 17:41:42 +08:00
require ( " cargo " ) . or_else ( | _ | {
2021-06-04 14:17:40 +03:00
require_option (
cargo_dir . join ( " bin/cargo " ) . if_exists ( ) ,
String ::from ( " No cargo detected " ) ,
)
} ) ? ;
2021-05-05 13:52:12 +03:00
let toml_file = cargo_dir . join ( " .crates.toml " ) . require ( ) ? ;
2021-03-22 09:00:56 +02:00
2021-05-05 13:52:12 +03:00
if fs ::metadata ( & toml_file ) ? . len ( ) = = 0 {
return Err ( SkipStep ( format! ( " {} exists but empty " , & toml_file . display ( ) ) ) . into ( ) ) ;
2021-03-22 09:00:56 +02:00
}
2021-02-13 06:39:06 +02:00
2019-01-13 23:20:32 +02:00
print_separator ( " Cargo " ) ;
2023-05-27 17:41:42 +08:00
let cargo_update = require ( " cargo-install-update " )
2021-06-04 14:17:40 +03:00
. ok ( )
. or_else ( | | cargo_dir . join ( " bin/cargo-install-update " ) . if_exists ( ) ) ;
2025-02-02 19:24:57 -08:00
let Some ( cargo_update ) = cargo_update else {
let message = String ::from ( " cargo-update isn't installed so Topgrade can't upgrade cargo packages. \n Install cargo-update by running `cargo install cargo-update` " ) ;
print_warning ( & message ) ;
return Err ( SkipStep ( message ) . into ( ) ) ;
2021-02-08 06:31:14 +02:00
} ;
2021-03-22 09:00:56 +02:00
ctx . run_type ( )
2019-01-13 23:20:32 +02:00
. execute ( cargo_update )
2022-10-23 11:34:30 +00:00
. args ( [ " install-update " , " --git " , " --all " ] )
2023-03-03 19:58:15 +08:00
. status_checked ( ) ? ;
if ctx . config ( ) . cleanup ( ) {
2023-05-27 17:41:42 +08:00
let cargo_cache = require ( " cargo-cache " )
2023-03-03 19:58:15 +08:00
. ok ( )
. or_else ( | | cargo_dir . join ( " bin/cargo-cache " ) . if_exists ( ) ) ;
2025-02-02 19:24:57 -08:00
if let Some ( e ) = cargo_cache {
ctx . run_type ( ) . execute ( e ) . args ( [ " -a " ] ) . status_checked ( ) ? ;
} else {
let message = String ::from ( " cargo-cache isn't installed so Topgrade can't cleanup cargo packages. \n Install cargo-cache by running `cargo install cargo-cache` " ) ;
print_warning ( message ) ;
2023-03-03 19:58:15 +08:00
}
}
Ok ( ( ) )
2018-08-19 14:45:23 +03:00
}
2023-05-25 15:09:23 +08:00
pub fn run_flutter_upgrade ( ctx : & ExecutionContext ) -> Result < ( ) > {
2023-05-27 17:41:42 +08:00
let flutter = require ( " flutter " ) ? ;
2019-11-20 13:35:41 +02:00
2019-11-20 14:41:05 +02:00
print_separator ( " Flutter " ) ;
2023-05-25 15:09:23 +08:00
ctx . run_type ( ) . execute ( flutter ) . arg ( " upgrade " ) . status_checked ( )
2022-11-23 15:23:00 +00:00
}
2023-05-25 15:09:23 +08:00
pub fn run_gem ( ctx : & ExecutionContext ) -> Result < ( ) > {
2023-05-27 17:41:42 +08:00
let gem = require ( " gem " ) ? ;
2023-05-01 00:02:13 +05:30
HOME_DIR . join ( " .gem " ) . require ( ) ? ;
2018-09-06 16:46:49 +03:00
2022-11-24 20:21:03 +01:00
print_separator ( " Gems " ) ;
2018-09-06 16:46:49 +03:00
2023-05-25 15:09:23 +08:00
let mut command = ctx . run_type ( ) . execute ( gem ) ;
2020-08-01 15:13:04 +03:00
command . arg ( " update " ) ;
if env ::var_os ( " RBENV_SHELL " ) . is_none ( ) {
debug! ( " Detected rbenv. Avoiding --user-install " ) ;
command . arg ( " --user-install " ) ;
}
2022-11-08 05:54:35 -05:00
command . status_checked ( )
2018-09-06 16:46:49 +03:00
}
2023-01-29 19:19:27 +00:00
pub fn run_rubygems ( ctx : & ExecutionContext ) -> Result < ( ) > {
2023-05-01 00:02:13 +05:30
HOME_DIR . join ( " .gem " ) . require ( ) ? ;
2023-02-02 21:48:48 +00:00
let gem = require ( " gem " ) ? ;
2022-11-24 20:21:03 +01:00
print_separator ( " RubyGems " ) ;
2023-02-02 21:48:48 +00:00
let gem_path_str = gem . as_os_str ( ) ;
2024-06-06 14:37:06 +03:00
if gem_path_str . to_str ( ) . unwrap ( ) . contains ( " asdf " )
2024-08-18 03:28:22 +01:00
| | gem_path_str . to_str ( ) . unwrap ( ) . contains ( " mise " )
2024-06-06 14:37:06 +03:00
| | gem_path_str . to_str ( ) . unwrap ( ) . contains ( " .rbenv " )
| | gem_path_str . to_str ( ) . unwrap ( ) . contains ( " .rvm " )
{
2023-02-02 21:48:48 +00:00
ctx . run_type ( )
. execute ( gem )
. args ( [ " update " , " --system " ] )
. status_checked ( ) ? ;
2023-06-13 22:15:57 +08:00
} else {
2024-10-03 12:47:35 +02:00
let sudo = require_option ( ctx . sudo ( ) . as_ref ( ) , get_require_sudo_string ( ) ) ? ;
2023-05-27 17:41:42 +08:00
if ! Path ::new ( " /usr/lib/ruby/vendor_ruby/rubygems/defaults/operating_system.rb " ) . exists ( ) {
2023-01-29 19:19:27 +00:00
ctx . run_type ( )
. execute ( sudo )
. arg ( " -EH " )
2023-02-02 21:48:48 +00:00
. arg ( gem )
2023-01-29 19:19:27 +00:00
. args ( [ " update " , " --system " ] )
. status_checked ( ) ? ;
}
2022-12-15 20:27:27 +00:00
}
2023-06-13 22:15:57 +08:00
2023-01-29 19:19:27 +00:00
Ok ( ( ) )
2022-11-24 20:21:03 +01:00
}
2021-10-25 12:54:27 -06:00
pub fn run_haxelib_update ( ctx : & ExecutionContext ) -> Result < ( ) > {
2023-05-27 17:41:42 +08:00
let haxelib = require ( " haxelib " ) ? ;
2021-10-25 12:54:27 -06:00
let haxelib_dir =
2022-11-08 05:54:35 -05:00
PathBuf ::from ( std ::str ::from_utf8 ( & Command ::new ( & haxelib ) . arg ( " config " ) . output_checked ( ) ? . stdout ) ? . trim ( ) )
. require ( ) ? ;
2021-10-25 12:54:27 -06:00
let directory_writable = tempfile_in ( & haxelib_dir ) . is_ok ( ) ;
debug! ( " {:?} writable: {} " , haxelib_dir , directory_writable ) ;
print_separator ( " haxelib " ) ;
let mut command = if directory_writable {
ctx . run_type ( ) . execute ( & haxelib )
} else {
2024-10-03 12:47:35 +02:00
let sudo = require_option ( ctx . sudo ( ) . as_ref ( ) , get_require_sudo_string ( ) ) ? ;
2023-06-13 22:15:57 +08:00
let mut c = ctx . run_type ( ) . execute ( sudo ) ;
2021-10-25 12:54:27 -06:00
c . arg ( & haxelib ) ;
c
} ;
2022-11-08 05:54:35 -05:00
command . arg ( " update " ) . status_checked ( )
2021-10-25 12:54:27 -06:00
}
2020-07-30 06:27:29 +03:00
pub fn run_sheldon ( ctx : & ExecutionContext ) -> Result < ( ) > {
2023-05-27 17:41:42 +08:00
let sheldon = require ( " sheldon " ) ? ;
2020-07-30 06:27:29 +03:00
print_separator ( " Sheldon " ) ;
2022-11-08 05:54:35 -05:00
ctx . run_type ( )
. execute ( sheldon )
. args ( [ " lock " , " --update " ] )
. status_checked ( )
2020-07-30 06:27:29 +03:00
}
2023-05-25 15:09:23 +08:00
pub fn run_fossil ( ctx : & ExecutionContext ) -> Result < ( ) > {
2023-05-27 17:41:42 +08:00
let fossil = require ( " fossil " ) ? ;
2021-02-17 16:46:29 +02:00
print_separator ( " Fossil " ) ;
2023-05-25 15:09:23 +08:00
ctx . run_type ( ) . execute ( fossil ) . args ( [ " all " , " sync " ] ) . status_checked ( )
2021-02-17 16:46:29 +02:00
}
2023-05-25 15:09:23 +08:00
pub fn run_micro ( ctx : & ExecutionContext ) -> Result < ( ) > {
2023-05-27 17:41:42 +08:00
let micro = require ( " micro " ) ? ;
2021-02-15 20:43:36 +01:00
print_separator ( " micro " ) ;
2023-05-25 15:09:23 +08:00
let stdout = ctx
. run_type ( )
2022-11-08 05:54:35 -05:00
. execute ( micro )
. args ( [ " -plugin " , " update " ] )
. output_checked_utf8 ( ) ?
. stdout ;
2021-09-02 07:27:09 +03:00
std ::io ::stdout ( ) . write_all ( stdout . as_bytes ( ) ) ? ;
2021-02-15 20:43:36 +01:00
if stdout . contains ( " Nothing to install / update " ) | | stdout . contains ( " One or more plugins installed " ) {
Ok ( ( ) )
} else {
2022-11-11 09:39:29 -05:00
Err ( eyre! ( " micro output does not indicate success: {} " , stdout ) )
2021-02-15 20:43:36 +01:00
}
}
2018-10-29 14:32:33 +02:00
#[ cfg(not(any(
target_os = " freebsd " ,
target_os = " openbsd " ,
target_os = " netbsd " ,
target_os = " dragonfly "
) ) ) ]
2023-05-25 15:09:23 +08:00
pub fn run_apm ( ctx : & ExecutionContext ) -> Result < ( ) > {
2023-05-27 17:41:42 +08:00
let apm = require ( " apm " ) ? ;
2018-08-19 14:45:23 +03:00
2019-01-13 23:20:32 +02:00
print_separator ( " Atom Package Manager " ) ;
2018-08-19 14:45:23 +03:00
2023-05-25 15:09:23 +08:00
ctx . run_type ( )
2022-11-08 05:54:35 -05:00
. execute ( apm )
. args ( [ " upgrade " , " --confirm=false " ] )
. status_checked ( )
2018-08-19 14:45:23 +03:00
}
2024-08-20 03:18:27 +02:00
pub fn run_aqua ( ctx : & ExecutionContext ) -> Result < ( ) > {
let aqua = require ( " aqua " ) ? ;
print_separator ( " Aqua " ) ;
if ctx . run_type ( ) . dry ( ) {
2024-10-03 12:47:35 +02:00
println! ( " {} " , t! ( " Updating aqua ... " ) ) ;
println! ( " {} " , t! ( " Updating aqua installed cli tools ... " ) ) ;
2024-08-20 03:18:27 +02:00
Ok ( ( ) )
} else {
ctx . run_type ( ) . execute ( & aqua ) . arg ( " update-aqua " ) . status_checked ( ) ? ;
ctx . run_type ( ) . execute ( & aqua ) . arg ( " update " ) . status_checked ( )
}
}
2023-04-05 15:42:47 +03:00
pub fn run_rustup ( ctx : & ExecutionContext ) -> Result < ( ) > {
2023-05-27 17:41:42 +08:00
let rustup = require ( " rustup " ) ? ;
2018-08-19 14:45:23 +03:00
2019-01-13 23:20:32 +02:00
print_separator ( " rustup " ) ;
2023-04-05 15:42:47 +03:00
ctx . run_type ( ) . execute ( rustup ) . arg ( " update " ) . status_checked ( )
2018-08-19 14:45:23 +03:00
}
2024-05-13 05:52:13 -07:00
pub fn run_rye ( ctx : & ExecutionContext ) -> Result < ( ) > {
let rye = require ( " rye " ) ? ;
print_separator ( " Rye " ) ;
ctx . run_type ( ) . execute ( rye ) . args ( [ " self " , " update " ] ) . status_checked ( )
}
2024-03-15 18:35:47 -07:00
pub fn run_elan ( ctx : & ExecutionContext ) -> Result < ( ) > {
let elan = require ( " elan " ) ? ;
print_separator ( " elan " ) ;
2024-12-12 02:19:03 +01:00
let disabled_error_msg = " self-update is disabled " ;
let executor_output = ctx . run_type ( ) . execute ( & elan ) . args ( [ " self " , " update " ] ) . output ( ) ? ;
match executor_output {
ExecutorOutput ::Wet ( command_output ) = > {
if command_output . status . success ( ) {
// Flush the captured output
std ::io ::stdout ( ) . lock ( ) . write_all ( & command_output . stdout ) . unwrap ( ) ;
std ::io ::stderr ( ) . lock ( ) . write_all ( & command_output . stderr ) . unwrap ( ) ;
} else {
let stderr_as_str = std ::str ::from_utf8 ( & command_output . stderr ) . unwrap ( ) ;
if stderr_as_str . contains ( disabled_error_msg ) {
// `elan` is externally managed, we cannot do the update. Users
// won't see any error message because Topgrade captures them
// all.
} else {
// `elan` is NOT externally managed, `elan self update` can
// be performed, but the invocation failed, so we report the
// error to the user and error out.
std ::io ::stdout ( ) . lock ( ) . write_all ( & command_output . stdout ) . unwrap ( ) ;
std ::io ::stderr ( ) . lock ( ) . write_all ( & command_output . stderr ) . unwrap ( ) ;
return Err ( StepFailed . into ( ) ) ;
}
}
}
ExecutorOutput ::Dry = > { /* nothing needed because in a dry run */ }
}
2024-03-15 18:35:47 -07:00
ctx . run_type ( ) . execute ( & elan ) . arg ( " update " ) . status_checked ( )
}
2023-05-25 15:09:23 +08:00
pub fn run_juliaup ( ctx : & ExecutionContext ) -> Result < ( ) > {
2023-05-27 17:41:42 +08:00
let juliaup = require ( " juliaup " ) ? ;
2022-11-24 14:17:58 -05:00
print_separator ( " juliaup " ) ;
2023-05-01 00:02:13 +05:30
if juliaup . canonicalize ( ) ? . is_descendant_of ( & HOME_DIR ) {
2023-05-25 15:09:23 +08:00
ctx . run_type ( )
. execute ( & juliaup )
. args ( [ " self " , " update " ] )
. status_checked ( ) ? ;
2022-11-24 14:17:58 -05:00
}
2023-05-25 15:09:23 +08:00
ctx . run_type ( ) . execute ( & juliaup ) . arg ( " update " ) . status_checked ( )
2022-11-24 14:17:58 -05:00
}
2020-08-28 16:16:23 +03:00
pub fn run_choosenim ( ctx : & ExecutionContext ) -> Result < ( ) > {
2023-05-27 17:41:42 +08:00
let choosenim = require ( " choosenim " ) ? ;
2020-08-28 16:16:23 +03:00
print_separator ( " choosenim " ) ;
let run_type = ctx . run_type ( ) ;
2022-11-08 05:54:35 -05:00
run_type . execute ( & choosenim ) . args ( [ " update " , " self " ] ) . status_checked ( ) ? ;
run_type . execute ( & choosenim ) . args ( [ " update " , " stable " ] ) . status_checked ( )
2020-08-28 16:16:23 +03:00
}
2023-05-25 15:09:23 +08:00
pub fn run_krew_upgrade ( ctx : & ExecutionContext ) -> Result < ( ) > {
2023-05-27 17:41:42 +08:00
let krew = require ( " kubectl-krew " ) ? ;
2020-06-29 05:13:31 +02:00
print_separator ( " Krew " ) ;
2023-05-25 15:09:23 +08:00
ctx . run_type ( ) . execute ( krew ) . args ( [ " upgrade " ] ) . status_checked ( )
2020-06-29 05:13:31 +02:00
}
2023-05-25 15:09:23 +08:00
pub fn run_gcloud_components_update ( ctx : & ExecutionContext ) -> Result < ( ) > {
2023-05-27 17:41:42 +08:00
let gcloud = require ( " gcloud " ) ? ;
2020-11-15 20:07:42 -08:00
2022-11-04 09:48:05 -04:00
if gcloud . starts_with ( " /snap " ) {
Ok ( ( ) )
} else {
print_separator ( " gcloud " ) ;
2020-11-15 20:07:42 -08:00
2023-05-25 15:09:23 +08:00
ctx . run_type ( )
2022-11-04 09:48:05 -04:00
. execute ( gcloud )
. args ( [ " components " , " update " , " --quiet " ] )
2022-11-08 05:54:35 -05:00
. status_checked ( )
2022-11-04 09:48:05 -04:00
}
2020-11-15 20:07:42 -08:00
}
2023-05-25 15:09:23 +08:00
pub fn run_jetpack ( ctx : & ExecutionContext ) -> Result < ( ) > {
2023-05-27 17:41:42 +08:00
let jetpack = require ( " jetpack " ) ? ;
2018-10-18 16:05:27 +03:00
2019-01-13 23:20:32 +02:00
print_separator ( " Jetpack " ) ;
2018-10-18 16:05:27 +03:00
2023-05-25 15:09:23 +08:00
ctx . run_type ( )
. execute ( jetpack )
. args ( [ " global " , " update " ] )
. status_checked ( )
2018-10-18 16:05:27 +03:00
}
2020-09-25 01:00:06 +08:00
pub fn run_rtcl ( ctx : & ExecutionContext ) -> Result < ( ) > {
2023-05-27 17:41:42 +08:00
let rupdate = require ( " rupdate " ) ? ;
2020-09-25 01:00:06 +08:00
print_separator ( " rtcl " ) ;
2022-11-08 05:54:35 -05:00
ctx . run_type ( ) . execute ( rupdate ) . status_checked ( )
2020-09-25 01:00:06 +08:00
}
2022-10-10 20:24:41 +00:00
pub fn run_opam_update ( ctx : & ExecutionContext ) -> Result < ( ) > {
2023-05-27 17:41:42 +08:00
let opam = require ( " opam " ) ? ;
2018-09-03 13:45:01 +02:00
2019-01-13 23:20:32 +02:00
print_separator ( " OCaml Package Manager " ) ;
2018-09-03 13:45:01 +02:00
2022-11-08 05:54:35 -05:00
ctx . run_type ( ) . execute ( & opam ) . arg ( " update " ) . status_checked ( ) ? ;
2023-10-10 02:08:46 +02:00
let mut command = ctx . run_type ( ) . execute ( & opam ) ;
command . arg ( " upgrade " ) ;
if ctx . config ( ) . yes ( Step ::Opam ) {
command . arg ( " --yes " ) ;
}
command . status_checked ( ) ? ;
2022-10-10 20:24:41 +00:00
if ctx . config ( ) . cleanup ( ) {
2022-11-08 05:54:35 -05:00
ctx . run_type ( ) . execute ( & opam ) . arg ( " clean " ) . status_checked ( ) ? ;
2022-10-10 20:24:41 +00:00
}
Ok ( ( ) )
2018-09-03 13:45:01 +02:00
}
2022-12-15 11:39:25 +00:00
pub fn run_vcpkg_update ( ctx : & ExecutionContext ) -> Result < ( ) > {
2023-05-27 17:41:42 +08:00
let vcpkg = require ( " vcpkg " ) ? ;
2019-01-13 23:20:32 +02:00
print_separator ( " vcpkg " ) ;
2018-11-10 20:22:26 +02:00
2022-12-15 11:39:25 +00:00
#[ cfg(unix) ]
let is_root_install = ! & vcpkg . starts_with ( " /home " ) ;
#[ cfg(not(unix)) ]
let is_root_install = false ;
let mut command = if is_root_install {
ctx . run_type ( ) . execute ( & vcpkg )
} else {
2024-10-03 12:47:35 +02:00
let sudo = require_option ( ctx . sudo ( ) . as_ref ( ) , get_require_sudo_string ( ) ) ? ;
2023-06-13 22:15:57 +08:00
let mut c = ctx . run_type ( ) . execute ( sudo ) ;
2022-12-15 11:39:25 +00:00
c . arg ( & vcpkg ) ;
c
} ;
command . args ( [ " upgrade " , " --no-dry-run " ] ) . status_checked ( )
2018-11-10 20:22:26 +02:00
}
2025-01-09 10:35:45 +08:00
/// Make VSCodium a separate step because:
///
/// 1. Users could use both VSCode and VSCoium
/// 2. Just in case, VSCodium could have incompatible changes with VSCode
pub fn run_vscodium_extensions_update ( ctx : & ExecutionContext ) -> Result < ( ) > {
// Calling vscodoe in WSL may install a server instead of updating extensions (https://github.com/topgrade-rs/topgrade/issues/594#issuecomment-1782157367)
if is_wsl ( ) ? {
return Err ( SkipStep ( String ::from ( " Should not run in WSL " ) ) . into ( ) ) ;
}
let vscodium = require ( " codium " ) ? ;
// VSCode has update command only since 1.86 version ("january 2024" update), disable the update for prior versions
// Use command `code --version` which returns 3 lines: version, git commit, instruction set. We parse only the first one
//
// This should apply to VSCodium as well.
let version : Result < Version > = match Command ::new ( & vscodium )
. arg ( " --version " )
. output_checked_utf8 ( ) ?
. stdout
. lines ( )
. next ( )
{
2025-02-02 19:24:57 -08:00
Some ( item ) = > Version ::parse ( item ) . map_err ( std ::convert ::Into ::into ) ,
2025-01-09 10:35:45 +08:00
_ = > return Err ( SkipStep ( String ::from ( " Cannot find vscodium version " ) ) . into ( ) ) ,
} ;
if ! matches! ( version , Ok ( version ) if version > = Version ::new ( 1 , 86 , 0 ) ) {
return Err ( SkipStep ( String ::from (
" Too old vscodium version to have update extensions command " ,
) )
. into ( ) ) ;
}
print_separator ( " VSCodium extensions " ) ;
ctx . run_type ( )
. execute ( vscodium )
. arg ( " --update-extensions " )
. status_checked ( )
}
2024-01-24 03:32:00 +01:00
pub fn run_vscode_extensions_update ( ctx : & ExecutionContext ) -> Result < ( ) > {
// Calling vscode in WSL may install a server instead of updating extensions (https://github.com/topgrade-rs/topgrade/issues/594#issuecomment-1782157367)
if is_wsl ( ) ? {
return Err ( SkipStep ( String ::from ( " Should not run in WSL " ) ) . into ( ) ) ;
}
2023-08-14 03:22:26 +02:00
let vscode = require ( " code " ) ? ;
2024-01-24 03:32:00 +01:00
// Vscode has update command only since 1.86 version ("january 2024" update), disable the update for prior versions
// Use command `code --version` which returns 3 lines: version, git commit, instruction set. We parse only the first one
2024-03-24 11:48:17 +08:00
let version : Result < Version > = match Command ::new ( & vscode )
2024-01-24 03:32:00 +01:00
. arg ( " --version " )
2023-08-14 03:22:26 +02:00
. output_checked_utf8 ( ) ?
2024-01-24 03:32:00 +01:00
. stdout
. lines ( )
. next ( )
{
2025-02-02 19:24:57 -08:00
Some ( item ) = > Version ::parse ( item ) . map_err ( std ::convert ::Into ::into ) ,
2024-01-24 03:32:00 +01:00
_ = > return Err ( SkipStep ( String ::from ( " Cannot find vscode version " ) ) . into ( ) ) ,
} ;
2023-08-14 03:22:26 +02:00
2024-01-24 03:32:00 +01:00
if ! matches! ( version , Ok ( version ) if version > = Version ::new ( 1 , 86 , 0 ) ) {
return Err ( SkipStep ( String ::from ( " Too old vscode version to have update extensions command " ) ) . into ( ) ) ;
2023-08-14 03:22:26 +02:00
}
2024-01-24 03:32:00 +01:00
print_separator ( " Visual Studio Code extensions " ) ;
ctx . run_type ( )
. execute ( vscode )
. arg ( " --update-extensions " )
. status_checked ( )
2023-08-14 03:22:26 +02:00
}
2023-05-25 15:09:23 +08:00
pub fn run_pipx_update ( ctx : & ExecutionContext ) -> Result < ( ) > {
2023-05-27 17:41:42 +08:00
let pipx = require ( " pipx " ) ? ;
2019-01-13 23:20:32 +02:00
print_separator ( " pipx " ) ;
2018-10-31 13:01:57 +02:00
2024-03-01 07:06:23 +00:00
let mut command_args = vec! [ " upgrade-all " , " --include-injected " ] ;
2023-12-31 04:38:39 +01:00
// pipx version 1.4.0 introduced a new command argument `pipx upgrade-all --quiet`
// (see https://pipx.pypa.io/stable/docs/#pipx-upgrade-all)
2024-03-24 11:48:17 +08:00
let version_str = Command ::new ( & pipx )
2023-12-31 04:38:39 +01:00
. args ( [ " --version " ] )
. output_checked_utf8 ( )
. map ( | s | s . stdout . trim ( ) . to_owned ( ) ) ;
let version = Version ::parse ( & version_str ? ) ;
if matches! ( version , Ok ( version ) if version > = Version ::new ( 1 , 4 , 0 ) ) {
2025-02-02 19:24:57 -08:00
command_args . push ( " --quiet " ) ;
2023-12-31 04:38:39 +01:00
}
ctx . run_type ( ) . execute ( pipx ) . args ( command_args ) . status_checked ( )
2018-10-31 13:01:57 +02:00
}
2022-01-15 06:50:42 +02:00
pub fn run_conda_update ( ctx : & ExecutionContext ) -> Result < ( ) > {
2023-05-27 17:41:42 +08:00
let conda = require ( " conda " ) ? ;
2022-01-24 22:05:52 +02:00
2024-03-24 11:48:17 +08:00
let output = Command ::new ( & conda )
2022-10-23 11:34:30 +00:00
. args ( [ " config " , " --show " , " auto_activate_base " ] )
2022-11-08 05:54:35 -05:00
. output_checked_utf8 ( ) ? ;
debug! ( " Conda output: {} " , output . stdout ) ;
if output . stdout . contains ( " False " ) {
2022-01-24 22:05:52 +02:00
return Err ( SkipStep ( " auto_activate_base is set to False " . to_string ( ) ) . into ( ) ) ;
}
2022-01-15 06:50:42 +02:00
print_separator ( " Conda " ) ;
2023-04-17 16:19:59 +02:00
let mut command = ctx . run_type ( ) . execute ( conda ) ;
2023-07-14 17:11:18 +01:00
command . args ( [ " update " , " --all " , " -n " , " base " ] ) ;
2023-04-17 16:19:59 +02:00
if ctx . config ( ) . yes ( Step ::Conda ) {
command . arg ( " --yes " ) ;
}
command . status_checked ( )
}
2024-09-26 07:19:32 +01:00
pub fn run_pixi_update ( ctx : & ExecutionContext ) -> Result < ( ) > {
let pixi = require ( " pixi " ) ? ;
print_separator ( " Pixi " ) ;
ctx . run_type ( ) . execute ( pixi ) . args ( [ " self-update " ] ) . status_checked ( )
}
2023-04-17 16:19:59 +02:00
pub fn run_mamba_update ( ctx : & ExecutionContext ) -> Result < ( ) > {
2023-05-27 17:41:42 +08:00
let mamba = require ( " mamba " ) ? ;
2023-04-17 16:19:59 +02:00
print_separator ( " Mamba " ) ;
let mut command = ctx . run_type ( ) . execute ( mamba ) ;
2023-07-14 17:11:18 +01:00
command . args ( [ " update " , " --all " , " -n " , " base " ] ) ;
2023-04-17 16:19:59 +02:00
if ctx . config ( ) . yes ( Step ::Mamba ) {
command . arg ( " --yes " ) ;
}
command . status_checked ( )
2022-01-15 06:50:42 +02:00
}
2023-08-13 04:05:07 +02:00
pub fn run_miktex_packages_update ( ctx : & ExecutionContext ) -> Result < ( ) > {
let miktex = require ( " miktex " ) ? ;
print_separator ( " miktex " ) ;
ctx . run_type ( )
. execute ( miktex )
. args ( [ " packages " , " update " ] )
. status_checked ( )
}
2023-05-25 15:09:23 +08:00
pub fn run_pip3_update ( ctx : & ExecutionContext ) -> Result < ( ) > {
2023-06-23 17:02:58 +08:00
let py = require ( " python " ) . and_then ( check_is_python_2_or_shim ) ;
let py3 = require ( " python3 " ) . and_then ( check_is_python_2_or_shim ) ;
let python3 = match ( py , py3 ) {
// prefer `python` if it is available and is a valid Python 3.
( Ok ( py ) , _ ) = > py ,
( Err ( _ ) , Ok ( py3 ) ) = > py3 ,
( Err ( py_err ) , Err ( py3_err ) ) = > {
2025-02-02 19:24:57 -08:00
return Err ( SkipStep ( format! ( " Skip due to following reasons: {py_err} {py3_err} " ) ) . into ( ) ) ;
2023-06-23 17:02:58 +08:00
}
} ;
2022-05-01 20:47:14 +03:00
Command ::new ( & python3 )
2022-10-23 11:34:30 +00:00
. args ( [ " -m " , " pip " ] )
2022-11-08 05:54:35 -05:00
. output_checked_utf8 ( )
2023-09-17 03:40:04 -04:00
. map_err ( | _ | SkipStep ( " pip does not exist " . to_string ( ) ) ) ? ;
2022-05-01 20:47:14 +03:00
2023-12-30 18:23:33 +08:00
let check_extern_managed_script = " import sysconfig; from os import path; print('Y') if path.isfile(path.join(sysconfig.get_path('stdlib'), 'EXTERNALLY-MANAGED')) else print('N') " ;
let output = Command ::new ( & python3 )
. args ( [ " -c " , check_extern_managed_script ] )
. output_checked_utf8 ( ) ? ;
let stdout = output . stdout . trim ( ) ;
let extern_managed = match stdout {
" N " = > false ,
" Y " = > true ,
_ = > unreachable! ( " unexpected output from `check_extern_managed_script` " ) ,
} ;
let allow_break_sys_pkg = match Command ::new ( & python3 )
. args ( [ " -m " , " pip " , " config " , " get " , " global.break-system-packages " ] )
2023-02-23 14:01:26 -08:00
. output_checked_utf8 ( )
2023-12-30 18:23:33 +08:00
{
Ok ( output ) = > {
let stdout = output . stdout . trim ( ) ;
stdout
. parse ::< bool > ( )
. expect ( " unexpected output that is not `true` or `false` " )
}
// it can fail because this key may not be set
//
// ```sh
// $ pip --version
// pip 23.0.1 from /usr/lib/python3/dist-packages/pip (python 3.11)
//
// $ pip config get global.break-system-packages
// ERROR: No such key - global.break-system-packages
//
// $ echo $?
// 1
// ```
Err ( _ ) = > false ,
} ;
debug! ( " pip3 externally managed: {} " , extern_managed ) ;
debug! ( " pip3 global.break-system-packages: {} " , allow_break_sys_pkg ) ;
// Even though pip3 is externally managed, we should still update it if
// `global.break-system-packages` is true.
if extern_managed & & ! allow_break_sys_pkg {
return Err ( SkipStep (
" Skip pip3 update as it is externally managed and global.break-system-packages is not true " . to_string ( ) ,
)
. into ( ) ) ;
}
2023-02-23 14:01:26 -08:00
2021-03-02 10:39:49 +01:00
print_separator ( " pip3 " ) ;
2023-05-27 17:41:42 +08:00
if env ::var ( " VIRTUAL_ENV " ) . is_ok ( ) {
2024-01-31 01:07:38 +00:00
print_warning ( " This step is skipped when running inside a virtual environment " ) ;
2021-06-26 15:04:49 +03:00
return Err ( SkipStep ( " Does not run inside a virtual environment " . to_string ( ) ) . into ( ) ) ;
}
2021-03-02 10:39:49 +01:00
2023-05-25 15:09:23 +08:00
ctx . run_type ( )
2022-05-01 20:47:14 +03:00
. execute ( & python3 )
2022-10-23 11:34:30 +00:00
. args ( [ " -m " , " pip " , " install " , " --upgrade " , " --user " , " pip " ] )
2022-11-08 05:54:35 -05:00
. status_checked ( )
2021-03-02 10:39:49 +01:00
}
2023-01-29 19:19:27 +00:00
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 ( ( ) )
}
2024-01-28 13:03:30 +08:00
2023-05-20 23:03:59 +05:30
pub fn run_pip_review_local_update ( ctx : & ExecutionContext ) -> Result < ( ) > {
let pip_review = require ( " pip-review " ) ? ;
print_separator ( " pip-review (local) " ) ;
if ! ctx . config ( ) . enable_pip_review_local ( ) {
print_warning (
" Pip-review (local) is disabled by default. Enable it by setting enable_pip_review_local=true in the configuration. " ,
) ;
return Err ( SkipStep ( String ::from ( " Pip-review (local) is disabled by default " ) ) . into ( ) ) ;
}
ctx . run_type ( )
. execute ( pip_review )
. arg ( " --local " )
. arg ( " --auto " )
. status_checked_with_codes ( & [ 1 ] ) ? ;
Ok ( ( ) )
}
2024-01-28 13:03:30 +08:00
2023-01-29 19:19:27 +00:00
pub fn run_pipupgrade_update ( ctx : & ExecutionContext ) -> Result < ( ) > {
let pipupgrade = require ( " pipupgrade " ) ? ;
print_separator ( " Pipupgrade " ) ;
2023-05-30 03:04:23 -04:00
if ! ctx . config ( ) . enable_pipupgrade ( ) {
2023-01-29 19:19:27 +00:00
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 ( ) ) ;
}
2023-05-30 03:04:23 -04:00
ctx . run_type ( )
. execute ( pipupgrade )
. args ( ctx . config ( ) . pipupgrade_arguments ( ) . split_whitespace ( ) )
. status_checked ( ) ? ;
2023-01-29 19:19:27 +00:00
Ok ( ( ) )
}
2024-01-28 13:03:30 +08:00
2023-05-25 15:09:23 +08:00
pub fn run_stack_update ( ctx : & ExecutionContext ) -> Result < ( ) > {
2023-05-27 17:41:42 +08:00
if require ( " ghcup " ) . is_ok ( ) {
2022-10-30 12:34:14 -04:00
// `ghcup` is present and probably(?) being used to install `stack`.
// Don't upgrade `stack`, let `ghcup` handle it. Per `ghcup install stack`:
// !!! Additionally, you should upgrade stack only through ghcup and not use 'stack upgrade' !!!
return Ok ( ( ) ) ;
}
2023-05-27 17:41:42 +08:00
let stack = require ( " stack " ) ? ;
2019-10-07 19:13:29 +02:00
print_separator ( " stack " ) ;
2023-05-25 15:09:23 +08:00
ctx . run_type ( ) . execute ( stack ) . arg ( " upgrade " ) . status_checked ( )
2019-10-07 19:13:29 +02:00
}
2023-05-25 15:09:23 +08:00
pub fn run_ghcup_update ( ctx : & ExecutionContext ) -> Result < ( ) > {
2023-05-27 17:41:42 +08:00
let ghcup = require ( " ghcup " ) ? ;
2022-10-30 12:34:14 -04:00
print_separator ( " ghcup " ) ;
2023-05-25 15:09:23 +08:00
ctx . run_type ( ) . execute ( ghcup ) . arg ( " upgrade " ) . status_checked ( )
2022-10-30 12:34:14 -04:00
}
2020-06-03 22:12:27 +03:00
pub fn run_tlmgr_update ( ctx : & ExecutionContext ) -> Result < ( ) > {
cfg_if ::cfg_if! {
2022-04-23 01:50:17 +05:30
if #[ cfg(any(target_os = " linux " , target_os = " android " )) ] {
2020-06-03 22:12:27 +03:00
if ! ctx . config ( ) . enable_tlmgr_linux ( ) {
2022-04-23 01:50:17 +05:30
return Err ( SkipStep ( String ::from ( " tlmgr must be explicity enabled in the configuration to run in Android/Linux " ) ) . into ( ) ) ;
2020-06-03 22:12:27 +03:00
}
}
}
2023-05-27 17:41:42 +08:00
let tlmgr = require ( " tlmgr " ) ? ;
let kpsewhich = require ( " kpsewhich " ) ? ;
2019-12-12 20:24:22 +02:00
let tlmgr_directory = {
let mut d = PathBuf ::from (
2022-11-08 05:54:35 -05:00
& Command ::new ( kpsewhich )
. arg ( " -var-value=SELFAUTOPARENT " )
. output_checked_utf8 ( ) ?
. stdout
. trim ( ) ,
2019-12-12 20:24:22 +02:00
) ;
d . push ( " tlpkg " ) ;
d
}
. require ( ) ? ;
let directory_writable = tempfile_in ( & tlmgr_directory ) . is_ok ( ) ;
debug! ( " {:?} writable: {} " , tlmgr_directory , directory_writable ) ;
print_separator ( " TeX Live package manager " ) ;
let mut command = if directory_writable {
2020-06-03 22:12:27 +03:00
ctx . run_type ( ) . execute ( & tlmgr )
2019-12-12 20:24:22 +02:00
} else {
2024-10-03 12:47:35 +02:00
let sudo = require_option ( ctx . sudo ( ) . as_ref ( ) , get_require_sudo_string ( ) ) ? ;
2023-06-13 22:15:57 +08:00
let mut c = ctx . run_type ( ) . execute ( sudo ) ;
2019-12-12 20:24:22 +02:00
c . arg ( & tlmgr ) ;
c
} ;
2022-10-23 11:34:30 +00:00
command . args ( [ " update " , " --self " , " --all " ] ) ;
2019-12-12 20:24:22 +02:00
2022-11-08 05:54:35 -05:00
command . status_checked ( )
2019-12-12 20:24:22 +02:00
}
2023-05-25 15:09:23 +08:00
pub fn run_chezmoi_update ( ctx : & ExecutionContext ) -> Result < ( ) > {
2023-05-27 17:41:42 +08:00
let chezmoi = require ( " chezmoi " ) ? ;
2023-05-01 00:02:13 +05:30
HOME_DIR . join ( " .local/share/chezmoi " ) . require ( ) ? ;
2021-07-19 07:29:34 +02:00
print_separator ( " chezmoi " ) ;
2023-05-25 15:09:23 +08:00
ctx . run_type ( ) . execute ( chezmoi ) . arg ( " update " ) . status_checked ( )
2021-07-19 07:29:34 +02:00
}
2023-05-25 15:09:23 +08:00
pub fn run_myrepos_update ( ctx : & ExecutionContext ) -> Result < ( ) > {
2023-05-27 17:41:42 +08:00
let myrepos = require ( " mr " ) ? ;
2023-05-01 00:02:13 +05:30
HOME_DIR . join ( " .mrconfig " ) . require ( ) ? ;
2019-05-15 11:33:22 +02:00
print_separator ( " myrepos " ) ;
2023-05-25 15:09:23 +08:00
ctx . run_type ( )
2019-05-15 11:33:22 +02:00
. execute ( & myrepos )
. arg ( " --directory " )
2023-05-01 00:02:13 +05:30
. arg ( & * HOME_DIR )
2019-05-15 11:33:22 +02:00
. arg ( " checkout " )
2022-11-08 05:54:35 -05:00
. status_checked ( ) ? ;
2023-05-25 15:09:23 +08:00
ctx . run_type ( )
2019-05-15 11:33:22 +02:00
. execute ( & myrepos )
. arg ( " --directory " )
2023-05-01 00:02:13 +05:30
. arg ( & * HOME_DIR )
2019-05-15 11:33:22 +02:00
. arg ( " update " )
2022-11-08 05:54:35 -05:00
. status_checked ( )
2019-05-15 11:33:22 +02:00
}
2020-02-08 22:13:56 +02:00
pub fn run_custom_command ( name : & str , command : & str , ctx : & ExecutionContext ) -> Result < ( ) > {
2018-12-05 11:34:08 +02:00
print_separator ( name ) ;
2023-03-17 21:58:58 +05:30
let mut exec = ctx . run_type ( ) . execute ( shell ( ) ) ;
#[ cfg(unix) ]
let command = if let Some ( command ) = command . strip_prefix ( " -i " ) {
exec . arg ( " -i " ) ;
command
} else {
command
} ;
exec . arg ( " -c " ) . arg ( command ) . status_checked ( )
2018-08-19 14:45:23 +03:00
}
2018-10-02 13:45:29 +03:00
2020-03-08 21:38:25 +02:00
pub fn run_composer_update ( ctx : & ExecutionContext ) -> Result < ( ) > {
2023-05-27 17:41:42 +08:00
let composer = require ( " composer " ) ? ;
2019-01-13 23:20:32 +02:00
let composer_home = Command ::new ( & composer )
2022-10-23 11:34:30 +00:00
. args ( [ " global " , " config " , " --absolute " , " --quiet " , " home " ] )
2022-11-08 05:54:35 -05:00
. output_checked_utf8 ( )
2024-10-03 12:47:35 +02:00
. map_err ( | e | ( SkipStep ( t! ( " Error getting the composer directory: {error} " , error = e ) . to_string ( ) ) ) )
2022-11-08 05:54:35 -05:00
. map ( | s | PathBuf ::from ( s . stdout . trim ( ) ) ) ?
2019-12-11 23:05:38 +02:00
. require ( ) ? ;
2019-01-13 23:20:32 +02:00
2023-05-01 00:02:13 +05:30
if ! composer_home . is_descendant_of ( & HOME_DIR ) {
2024-10-03 12:47:35 +02:00
return Err ( SkipStep (
t! (
" Composer directory {composer_home} isn't a descendant of the user's home directory " ,
composer_home = composer_home . display ( )
)
. to_string ( ) ,
)
2020-08-21 23:04:36 +03:00
. into ( ) ) ;
2019-01-13 23:20:32 +02:00
}
2018-12-17 10:53:05 +02:00
2024-10-03 12:47:35 +02:00
print_separator ( t! ( " Composer " ) ) ;
2018-12-17 10:53:05 +02:00
2020-03-08 21:38:25 +02:00
if ctx . config ( ) . composer_self_update ( ) {
cfg_if ::cfg_if! {
if #[ cfg(unix) ] {
// If self-update fails without sudo then there's probably an update
let has_update = match ctx . run_type ( ) . execute ( & composer ) . arg ( " self-update " ) . output ( ) ? {
ExecutorOutput ::Wet ( output ) = > ! output . status . success ( ) ,
_ = > false
} ;
if has_update {
2024-10-03 12:47:35 +02:00
let sudo = require_option ( ctx . sudo ( ) . as_ref ( ) , get_require_sudo_string ( ) ) ? ;
2020-03-08 21:38:25 +02:00
ctx . run_type ( )
2023-06-13 22:15:57 +08:00
. execute ( sudo )
2020-03-08 21:38:25 +02:00
. arg ( & composer )
. arg ( " self-update " )
2022-11-08 05:54:35 -05:00
. status_checked ( ) ? ;
2020-03-08 21:38:25 +02:00
}
} else {
2022-11-08 05:54:35 -05:00
ctx . run_type ( ) . execute ( & composer ) . arg ( " self-update " ) . status_checked ( ) ? ;
2020-03-08 21:38:25 +02:00
}
}
}
2022-11-08 05:54:35 -05:00
let output = ctx . run_type ( ) . execute ( & composer ) . args ( [ " global " , " update " ] ) . output ( ) ? ;
if let ExecutorOutput ::Wet ( output ) = output {
let output : Utf8Output = output . try_into ( ) ? ;
print! ( " {} \n {} " , output . stdout , output . stderr ) ;
if output . stdout . contains ( " valet " ) | | output . stderr . contains ( " valet " ) {
2023-05-27 17:41:42 +08:00
if let Some ( valet ) = which ( " valet " ) {
2022-11-08 05:54:35 -05:00
ctx . run_type ( ) . execute ( valet ) . arg ( " install " ) . status_checked ( ) ? ;
}
2020-02-10 21:10:06 +01:00
}
2018-10-02 13:45:29 +03:00
}
2019-01-13 23:20:32 +02:00
Ok ( ( ) )
2018-10-02 13:45:29 +03:00
}
2020-12-26 06:43:45 +02:00
pub fn run_dotnet_upgrade ( ctx : & ExecutionContext ) -> Result < ( ) > {
2023-05-27 17:41:42 +08:00
let dotnet = require ( " dotnet " ) ? ;
2020-12-26 06:43:45 +02:00
2023-05-25 15:24:53 +08:00
// Skip when the `dotnet tool list` subcommand fails.
// (This is expected when a dotnet runtime is installed but no SDK.)
2023-01-29 19:19:27 +00:00
let output = match ctx
. run_type ( )
. execute ( & dotnet )
. args ( [ " tool " , " list " , " --global " ] )
2023-10-12 14:37:52 +08:00
// dotnet will print a greeting message on its first run, from this question:
// https://stackoverflow.com/q/70493706/14092446
// Setting `DOTNET_NOLOGO` to `true` should disable it
. env ( " DOTNET_NOLOGO " , " true " )
2023-01-29 19:19:27 +00:00
. output_checked_utf8 ( )
{
Ok ( output ) = > output ,
Err ( _ ) = > {
2024-10-03 12:47:35 +02:00
return Err ( SkipStep (
t! ( " Error running `dotnet tool list`. This is expected when a dotnet runtime is installed but no SDK. " )
. to_string ( ) ,
)
2024-01-28 13:03:30 +08:00
. into ( ) ) ;
2022-12-18 14:12:36 +00:00
}
2023-01-29 19:19:27 +00:00
} ;
2020-12-26 06:43:45 +02:00
2024-04-14 03:10:08 +02:00
let mut in_header = true ;
2023-05-25 15:24:53 +08:00
let mut packages = output
. stdout
. lines ( )
// Skip the header:
//
// Package Id Version Commands
// -------------------------------------
2024-04-14 03:10:08 +02:00
. skip_while ( | line | {
// The .NET SDK respects locale, so the header can be printed
// in languages other than English. The separator should hopefully
// always be at least 10 -'s long.
if in_header & & line . starts_with ( " ---------- " ) {
in_header = false ;
true
} else {
in_header
}
} )
2023-05-25 15:24:53 +08:00
. filter ( | line | ! line . is_empty ( ) )
. peekable ( ) ;
2020-12-26 06:43:45 +02:00
2023-01-29 19:19:27 +00:00
if packages . peek ( ) . is_none ( ) {
2024-10-03 12:47:35 +02:00
return Err ( SkipStep ( t! ( " No dotnet global tools installed " ) . to_string ( ) ) . into ( ) ) ;
2023-01-29 19:19:27 +00:00
}
2020-12-26 06:43:45 +02:00
2023-01-29 19:19:27 +00:00
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 ( )
2025-02-02 19:24:57 -08:00
. with_context ( | | format! ( " Failed to update .NET package {package_name:?} " ) ) ? ;
2022-12-18 14:12:36 +00:00
}
2023-01-29 19:19:27 +00:00
2020-12-26 06:43:45 +02:00
Ok ( ( ) )
}
2021-03-14 13:12:38 +03:00
2022-12-14 09:12:39 +01:00
pub fn run_helix_grammars ( ctx : & ExecutionContext ) -> Result < ( ) > {
2024-02-23 07:39:31 +08:00
let helix = require ( " helix " ) . or ( require ( " hx " ) ) ? ;
2022-12-14 09:12:39 +01:00
print_separator ( " Helix " ) ;
ctx . run_type ( )
2024-02-23 04:56:08 +05:30
. execute ( & helix )
. args ( [ " --grammar " , " fetch " ] )
2022-12-14 09:12:39 +01:00
. status_checked ( )
. with_context ( | | " Failed to download helix grammars! " ) ? ;
ctx . run_type ( )
2024-02-23 04:56:08 +05:30
. execute ( & helix )
. args ( [ " --grammar " , " build " ] )
2022-12-14 09:12:39 +01:00
. status_checked ( )
. with_context ( | | " Failed to build helix grammars! " ) ? ;
Ok ( ( ) )
}
2023-05-25 15:09:23 +08:00
pub fn run_raco_update ( ctx : & ExecutionContext ) -> Result < ( ) > {
2023-05-27 17:41:42 +08:00
let raco = require ( " raco " ) ? ;
2021-03-14 13:12:38 +03:00
2024-10-03 12:47:35 +02:00
print_separator ( t! ( " Racket Package Manager " ) ) ;
2021-03-14 13:12:38 +03:00
2023-05-25 15:09:23 +08:00
ctx . run_type ( )
. execute ( raco )
. args ( [ " pkg " , " update " , " --all " ] )
. status_checked ( )
2021-03-14 13:12:38 +03:00
}
2021-05-29 01:59:27 -03:00
pub fn bin_update ( ctx : & ExecutionContext ) -> Result < ( ) > {
2023-05-27 17:41:42 +08:00
let bin = require ( " bin " ) ? ;
2021-05-29 01:59:27 -03:00
print_separator ( " Bin " ) ;
2022-11-08 05:54:35 -05:00
ctx . run_type ( ) . execute ( bin ) . arg ( " update " ) . status_checked ( )
2021-05-29 01:59:27 -03:00
}
2021-11-15 07:09:02 +01:00
pub fn spicetify_upgrade ( ctx : & ExecutionContext ) -> Result < ( ) > {
2023-07-14 21:44:06 +05:30
// As of 04-07-2023 NixOS packages Spicetify with the `spicetify-cli` binary name
let spicetify = require ( " spicetify " ) . or ( require ( " spicetify-cli " ) ) ? ;
2021-11-15 07:09:02 +01:00
print_separator ( " Spicetify " ) ;
2022-11-08 05:54:35 -05:00
ctx . run_type ( ) . execute ( spicetify ) . arg ( " upgrade " ) . status_checked ( )
2021-11-15 07:09:02 +01:00
}
2022-03-08 00:16:52 +01:00
pub fn run_ghcli_extensions_upgrade ( ctx : & ExecutionContext ) -> Result < ( ) > {
2023-05-27 17:41:42 +08:00
let gh = require ( " gh " ) ? ;
2022-11-08 05:54:35 -05:00
let result = Command ::new ( & gh ) . args ( [ " extensions " , " list " ] ) . output_checked_utf8 ( ) ;
2022-03-29 03:17:15 +03:00
if result . is_err ( ) {
debug! ( " GH result {:?} " , result ) ;
2024-10-03 12:47:35 +02:00
return Err ( SkipStep ( t! ( " GH failed " ) . to_string ( ) ) . into ( ) ) ;
2022-03-29 03:17:15 +03:00
}
2022-03-08 00:16:52 +01:00
2024-10-03 12:47:35 +02:00
print_separator ( t! ( " GitHub CLI Extensions " ) ) ;
2022-03-08 00:16:52 +01:00
ctx . run_type ( )
. execute ( & gh )
2022-10-23 11:34:30 +00:00
. args ( [ " extension " , " upgrade " , " --all " ] )
2022-11-08 05:54:35 -05:00
. status_checked ( )
2022-03-08 00:16:52 +01:00
}
2022-10-10 18:29:56 +00:00
pub fn update_julia_packages ( ctx : & ExecutionContext ) -> Result < ( ) > {
2023-05-27 17:41:42 +08:00
let julia = require ( " julia " ) ? ;
2022-10-10 18:29:56 +00:00
2024-10-03 12:47:35 +02:00
print_separator ( t! ( " Julia Packages " ) ) ;
2022-10-10 18:29:56 +00:00
2024-11-19 01:17:51 +00:00
let mut executor = ctx . run_type ( ) . execute ( julia ) ;
executor . arg ( if ctx . config ( ) . julia_use_startup_file ( ) {
" --startup-file=yes "
} else {
" --startup-file=no "
} ) ;
executor . args ( [ " -e " , " using Pkg; Pkg.update() " ] ) . status_checked ( )
2022-10-10 18:29:56 +00:00
}
2022-12-08 22:47:57 +01:00
2023-05-25 15:09:23 +08:00
pub fn run_helm_repo_update ( ctx : & ExecutionContext ) -> Result < ( ) > {
2023-05-27 17:41:42 +08:00
let helm = require ( " helm " ) ? ;
2022-12-08 22:47:57 +01:00
print_separator ( " Helm " ) ;
2023-01-29 19:19:27 +00:00
let no_repo = " no repositories found " ;
let mut success = true ;
2023-05-25 15:09:23 +08:00
let mut exec = ctx . run_type ( ) . execute ( helm ) ;
2023-01-29 19:19:27 +00:00
if let Err ( e ) = exec . arg ( " repo " ) . arg ( " update " ) . status_checked ( ) {
2024-10-03 12:47:35 +02:00
error! ( " Updating repositories failed: {e} " ) ;
2023-01-29 19:19:27 +00:00
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 ) )
}
2022-12-08 22:47:57 +01:00
}
2023-05-05 16:17:42 +08:00
2023-05-25 15:09:23 +08:00
pub fn run_stew ( ctx : & ExecutionContext ) -> Result < ( ) > {
2023-05-05 16:17:42 +08:00
let stew = require ( " stew " ) ? ;
print_separator ( " stew " ) ;
2023-05-25 15:09:23 +08:00
ctx . run_type ( ) . execute ( stew ) . args ( [ " upgrade " , " --all " ] ) . status_checked ( )
2023-05-05 16:17:42 +08:00
}
2023-06-23 17:03:57 +08:00
pub fn run_bob ( ctx : & ExecutionContext ) -> Result < ( ) > {
let bob = require ( " bob " ) ? ;
print_separator ( " Bob " ) ;
ctx . run_type ( ) . execute ( bob ) . args ( [ " update " , " --all " ] ) . status_checked ( )
}
2024-01-28 13:03:30 +08:00
pub fn run_certbot ( ctx : & ExecutionContext ) -> Result < ( ) > {
2024-10-03 12:47:35 +02:00
let sudo = require_option ( ctx . sudo ( ) . as_ref ( ) , get_require_sudo_string ( ) ) ? ;
2024-01-28 13:03:30 +08:00
let certbot = require ( " certbot " ) ? ;
print_separator ( " Certbot " ) ;
let mut cmd = ctx . run_type ( ) . execute ( sudo ) ;
cmd . arg ( certbot ) ;
cmd . arg ( " renew " ) ;
cmd . status_checked ( )
}
2024-03-19 14:10:47 +08:00
/// Run `$ freshclam` to update ClamAV signature database
///
/// doc: https://docs.clamav.net/manual/Usage/SignatureManagement.html#freshclam
pub fn run_freshclam ( ctx : & ExecutionContext ) -> Result < ( ) > {
let freshclam = require ( " freshclam " ) ? ;
2024-10-03 12:47:35 +02:00
print_separator ( t! ( " Update ClamAV Database(FreshClam) " ) ) ;
2024-03-19 14:10:47 +08:00
ctx . run_type ( ) . execute ( freshclam ) . status_checked ( )
}
2024-04-07 11:03:33 +08:00
/// Involve `pio upgrade` to update PlatformIO core.
pub fn run_platform_io ( ctx : & ExecutionContext ) -> Result < ( ) > {
// We use the full path because by default the binary is not in `PATH`:
// https://github.com/topgrade-rs/topgrade/issues/754#issuecomment-2020537559
#[ cfg(unix) ]
fn bin_path ( ) -> PathBuf {
HOME_DIR . join ( " .platformio/penv/bin/pio " )
}
#[ cfg(windows) ]
fn bin_path ( ) -> PathBuf {
HOME_DIR . join ( " .platformio/penv/Scripts/pio.exe " )
}
let bin_path = require ( bin_path ( ) ) ? ;
print_separator ( " PlatformIO Core " ) ;
ctx . run_type ( ) . execute ( bin_path ) . arg ( " upgrade " ) . status_checked ( )
}
2024-06-30 22:41:09 +08:00
/// Run `lensfun-update-data` to update lensfun database.
///
/// `sudo` will be used if `use_sudo` configuration entry is set to true.
pub fn run_lensfun_update_data ( ctx : & ExecutionContext ) -> Result < ( ) > {
const SEPARATOR : & str = " Lensfun's database update " ;
let lensfun_update_data = require ( " lensfun-update-data " ) ? ;
const EXIT_CODE_WHEN_NO_UPDATE : i32 = 1 ;
if ctx . config ( ) . lensfun_use_sudo ( ) {
2024-10-03 12:47:35 +02:00
let sudo = require_option ( ctx . sudo ( ) . as_ref ( ) , get_require_sudo_string ( ) ) ? ;
2024-06-30 22:41:09 +08:00
print_separator ( SEPARATOR ) ;
ctx . run_type ( )
. execute ( sudo )
. arg ( lensfun_update_data )
// `lensfun-update-data` returns 1 when there is no update available
// which should be considered success
. status_checked_with_codes ( & [ EXIT_CODE_WHEN_NO_UPDATE ] )
} else {
print_separator ( SEPARATOR ) ;
ctx . run_type ( )
. execute ( lensfun_update_data )
. status_checked_with_codes ( & [ EXIT_CODE_WHEN_NO_UPDATE ] )
}
}
2024-07-07 10:37:07 +08:00
pub fn run_poetry ( ctx : & ExecutionContext ) -> Result < ( ) > {
let poetry = require ( " poetry " ) ? ;
2024-12-07 09:09:52 +02:00
#[ cfg(unix) ]
fn get_interpreter ( poetry : & PathBuf ) -> Result < PathBuf > {
use std ::os ::unix ::ffi ::OsStrExt ;
let script = fs ::read ( poetry ) ? ;
if let Some ( r ) = script . iter ( ) . position ( | & b | b = = b '\n' ) {
let first_line = & script [ .. r ] ;
if first_line . starts_with ( b " #! " ) {
return Ok ( OsStr ::from_bytes ( & first_line [ 2 .. ] ) . into ( ) ) ;
}
}
Err ( eyre! ( " Could not find shebang " ) )
}
#[ cfg(windows) ]
fn get_interpreter ( poetry : & PathBuf ) -> Result < PathBuf > {
let data = fs ::read ( poetry ) ? ;
// https://bitbucket.org/vinay.sajip/simple_launcher/src/master/compare_launchers.py
let pos = match data . windows ( 4 ) . rposition ( | b | b = = b " PK \x05 \x06 " ) {
Some ( i ) = > i ,
None = > return Err ( eyre! ( " Not a ZIP archive " ) ) ,
} ;
let cdr_size = match data . get ( pos + 12 .. pos + 16 ) {
Some ( b ) = > u32 ::from_le_bytes ( b . try_into ( ) . unwrap ( ) ) as usize ,
None = > return Err ( eyre! ( " Invalid CDR size " ) ) ,
} ;
let cdr_offset = match data . get ( pos + 16 .. pos + 20 ) {
Some ( b ) = > u32 ::from_le_bytes ( b . try_into ( ) . unwrap ( ) ) as usize ,
None = > return Err ( eyre! ( " Invalid CDR offset " ) ) ,
} ;
if pos < cdr_size + cdr_offset {
return Err ( eyre! ( " Invalid ZIP archive " ) ) ;
}
let arc_pos = pos - cdr_size - cdr_offset ;
let shebang = match data [ .. arc_pos ] . windows ( 2 ) . rposition ( | b | b = = b " #! " ) {
Some ( l ) = > & data [ l + 2 .. arc_pos - 1 ] ,
None = > return Err ( eyre! ( " Could not find shebang " ) ) ,
} ;
// shebang line is utf8
Ok ( std ::str ::from_utf8 ( shebang ) ? . into ( ) )
}
if ctx . config ( ) . poetry_force_self_update ( ) {
debug! ( " forcing poetry self update " ) ;
} else {
let interpreter = match get_interpreter ( & poetry ) {
Ok ( p ) = > p ,
Err ( e ) = > {
return Err ( SkipStep ( format! ( " Could not find interpreter for {} : {} " , poetry . display ( ) , e ) ) . into ( ) )
}
} ;
debug! ( " poetry interpreter: {} " , interpreter . display ( ) ) ;
let check_official_install_script =
" import sys; from os import path; print('Y') if path.isfile(path.join(sys.prefix, 'poetry_env')) else print('N') " ;
let output = Command ::new ( & interpreter )
. args ( [ " -c " , check_official_install_script ] )
. output_checked_utf8 ( ) ? ;
let stdout = output . stdout . trim ( ) ;
let official_install = match stdout {
" N " = > false ,
" Y " = > true ,
_ = > unreachable! ( " unexpected output from `check_official_install_script` " ) ,
} ;
debug! ( " poetry is official install: {} " , official_install ) ;
if ! official_install {
return Err ( SkipStep ( " Not installed with the official script " . to_string ( ) ) . into ( ) ) ;
}
}
2024-07-07 10:37:07 +08:00
print_separator ( " Poetry " ) ;
2024-12-07 09:09:52 +02:00
ctx . run_type ( )
. execute ( & poetry )
. args ( [ " self " , " update " ] )
. status_checked ( )
2024-07-07 10:37:07 +08:00
}
2024-07-23 07:26:08 +08:00
2024-08-24 22:22:27 -04:00
pub fn run_uv ( ctx : & ExecutionContext ) -> Result < ( ) > {
let uv_exec = require ( " uv " ) ? ;
print_separator ( " uv " ) ;
2024-10-29 01:40:31 -06:00
// try uv self --help first - if it succeeds, we call uv self update
let result = ctx
. run_type ( )
2024-08-24 22:22:27 -04:00
. execute ( & uv_exec )
2024-10-29 01:40:31 -06:00
. args ( [ " self " , " --help " ] )
. output_checked ( ) ;
2024-08-24 22:22:27 -04:00
2024-10-29 01:40:31 -06:00
if result . is_ok ( ) {
ctx . run_type ( )
. execute ( & uv_exec )
. args ( [ " self " , " update " ] )
2024-12-10 20:55:32 +08:00
. status_checked ( ) ? ;
2024-10-29 01:40:31 -06:00
}
2024-08-24 22:22:27 -04:00
ctx . run_type ( )
. execute ( & uv_exec )
. args ( [ " tool " , " upgrade " , " --all " ] )
. status_checked ( )
}
2024-07-23 07:26:08 +08:00
/// Involve `zvm upgrade` to update ZVM
pub fn run_zvm ( ctx : & ExecutionContext ) -> Result < ( ) > {
let zvm = require ( " zvm " ) ? ;
print_separator ( " ZVM " ) ;
ctx . run_type ( ) . execute ( zvm ) . arg ( " upgrade " ) . status_checked ( )
}
2024-08-26 22:21:17 +08:00
pub fn run_bun ( ctx : & ExecutionContext ) -> Result < ( ) > {
let bun = require ( " bun " ) ? ;
print_separator ( " Bun " ) ;
ctx . run_type ( ) . execute ( bun ) . arg ( " upgrade " ) . status_checked ( )
}