2020-01-28 16:27:43 +02:00
#![ allow(unused_imports) ]
2020-04-03 11:47:51 +03:00
2022-01-14 22:46:10 +02:00
#[ cfg(unix) ]
use std ::os ::unix ::prelude ::MetadataExt ;
use std ::path ::PathBuf ;
use std ::process ::Command ;
2019-12-11 23:05:38 +02:00
use anyhow ::Result ;
2018-08-19 14:45:23 +03:00
use directories ::BaseDirs ;
2021-01-14 09:49:18 +02:00
use log ::debug ;
#[ cfg(unix) ]
use nix ::unistd ::Uid ;
2022-06-02 11:28:20 +03:00
use semver ::Version ;
2022-01-14 22:46:10 +02:00
use crate ::executor ::{ CommandExt , RunType } ;
use crate ::terminal ::print_separator ;
use crate ::utils ::{ require , PathExt } ;
use crate ::{ error ::SkipStep , execution_context ::ExecutionContext } ;
2018-08-19 14:45:23 +03:00
2021-04-06 09:52:34 +03:00
#[ allow(clippy::upper_case_acronyms) ]
2018-08-19 14:45:23 +03:00
struct NPM {
command : PathBuf ,
}
impl NPM {
fn new ( command : PathBuf ) -> Self {
2022-10-10 20:23:51 +00:00
Self { command }
2018-08-19 14:45:23 +03:00
}
2021-01-14 09:49:18 +02:00
#[ cfg(target_os = " linux " ) ]
2019-12-11 23:05:38 +02:00
fn root ( & self ) -> Result < PathBuf > {
2022-06-02 11:28:20 +03:00
let version = self . version ( ) ? ;
let args = if version < Version ::new ( 8 , 11 , 0 ) {
[ " root " , " -g " ]
} else {
[ " root " , " --location=global " ]
} ;
2019-01-01 22:22:07 +02:00
Command ::new ( & self . command )
2022-06-02 11:28:20 +03:00
. args ( args )
2019-01-01 22:22:07 +02:00
. check_output ( )
2021-01-15 06:59:13 +02:00
. map ( | s | PathBuf ::from ( s . trim ( ) ) )
2018-08-19 14:45:23 +03:00
}
2022-06-02 11:28:20 +03:00
fn version ( & self ) -> Result < Version > {
let version_str = Command ::new ( & self . command )
. args ( & [ " --version " ] )
. check_output ( )
. map ( | s | s . trim ( ) . to_owned ( ) ) ;
Version ::parse ( & version_str ? ) . map_err ( | err | err . into ( ) )
}
2021-06-09 10:52:48 +03:00
fn upgrade ( & self , run_type : RunType , use_sudo : bool ) -> Result < ( ) > {
2022-01-14 22:46:10 +02:00
print_separator ( " Node Package Manager " ) ;
2022-06-02 11:28:20 +03:00
let version = self . version ( ) ? ;
2022-10-10 20:23:51 +00:00
let args = if version < Version ::new ( 8 , 11 , 0 ) {
2022-06-02 11:28:20 +03:00
[ " update " , " -g " ]
} else {
[ " update " , " --location=global " ]
} ;
2021-06-09 10:52:48 +03:00
if use_sudo {
2022-10-10 20:23:51 +00:00
run_type . execute ( " sudo " ) . args ( args ) . check_run ( ) ? ;
2021-06-09 10:52:48 +03:00
} else {
2022-06-02 11:28:20 +03:00
run_type . execute ( & self . command ) . args ( args ) . check_run ( ) ? ;
2021-06-09 10:52:48 +03:00
}
2018-08-19 14:45:23 +03:00
Ok ( ( ) )
}
2020-01-28 16:27:43 +02:00
2021-01-14 09:49:18 +02:00
#[ cfg(target_os = " linux " ) ]
2021-10-25 22:27:35 +03:00
pub fn should_use_sudo ( & self ) -> Result < bool > {
let npm_root = self . root ( ) ? ;
2021-01-15 06:59:13 +02:00
if ! npm_root . exists ( ) {
return Err ( SkipStep ( format! ( " NPM root at {} doesn't exist " , npm_root . display ( ) , ) ) . into ( ) ) ;
}
2021-01-14 09:49:18 +02:00
let metadata = std ::fs ::metadata ( & npm_root ) ? ;
let uid = Uid ::effective ( ) ;
2021-10-25 22:27:35 +03:00
Ok ( metadata . uid ( ) ! = uid . as_raw ( ) & & metadata . uid ( ) = = 0 )
}
}
2022-10-10 20:08:11 +00:00
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 )
}
}
2021-10-25 22:27:35 +03:00
#[ cfg(target_os = " linux " ) ]
fn should_use_sudo ( npm : & NPM , ctx : & ExecutionContext ) -> Result < bool > {
if npm . should_use_sudo ( ) ? {
if ctx . config ( ) . npm_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 ( ) )
2020-01-28 16:27:43 +02:00
}
2021-10-25 22:27:35 +03:00
} else {
Ok ( false )
2018-08-19 14:45:23 +03:00
}
2021-10-25 22:27:35 +03:00
}
2022-10-10 20:08:11 +00:00
#[ 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 )
}
}
2021-10-25 22:27:35 +03:00
pub fn run_npm_upgrade ( ctx : & ExecutionContext ) -> Result < ( ) > {
2022-10-10 20:23:51 +00:00
let npm = require ( " pnpm " ) . or_else ( | _ | require ( " npm " ) ) . map ( NPM ::new ) ? ;
2018-08-19 14:45:23 +03:00
2021-10-25 22:27:35 +03:00
#[ cfg(target_os = " linux " ) ]
{
npm . upgrade ( ctx . run_type ( ) , should_use_sudo ( & npm , ctx ) ? )
}
#[ cfg(not(target_os = " linux " )) ]
{
npm . upgrade ( ctx . run_type ( ) , false )
}
2019-03-10 21:48:49 +02:00
}
2018-08-19 14:45:23 +03:00
2022-10-10 20:08:11 +00:00
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 )
}
}
2020-10-01 15:59:06 -04:00
pub fn deno_upgrade ( ctx : & ExecutionContext ) -> Result < ( ) > {
let deno = require ( " deno " ) ? ;
2021-09-02 18:53:48 +02:00
let deno_dir = ctx . base_dirs ( ) . home_dir ( ) . join ( " .deno " ) ;
if ! deno . canonicalize ( ) ? . is_descendant_of ( & deno_dir ) {
let skip_reason = SkipStep ( " Deno installed outside of .deno directory " . to_string ( ) ) ;
return Err ( skip_reason . into ( ) ) ;
}
2020-10-01 15:59:06 -04:00
print_separator ( " Deno " ) ;
ctx . run_type ( ) . execute ( & deno ) . arg ( " upgrade " ) . check_run ( )
}