542 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			542 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
| #!/usr/bin/env bash
 | |
| 
 | |
| running=0
 | |
| 
 | |
| _check_running() {
 | |
|     if [ $running -ne 0 ]; then
 | |
|         _unlock
 | |
|         exit $running
 | |
|     fi
 | |
| }
 | |
| 
 | |
| _onkill() {
 | |
|     running=1
 | |
| }
 | |
| 
 | |
| _lock() {
 | |
|     if [ -f ~/.config/dotfiles/.data/update_lock ]; then
 | |
|         return 1
 | |
|     fi
 | |
| 
 | |
|     touch ~/.config/dotfiles/.data/update_lock
 | |
| }
 | |
| 
 | |
| _lock_or_error_message() {
 | |
|     _lock
 | |
|     local value=$?
 | |
| 
 | |
|     if [ $value -ne 0 ]; then
 | |
|         echo -e "\033[31;1merror:\033[0m update seems to be already running"
 | |
|         echo -e "\033[1minfo:\033[0m if you're sure it's not running, run \`update force-unlock\`"
 | |
|         return $value
 | |
|     fi
 | |
| }
 | |
| 
 | |
| _unlock() {
 | |
|     rm -rf ~/.config/dotfiles/.data/update_lock
 | |
| }
 | |
| 
 | |
| _check_date_if_format() {
 | |
|     local format=`_date_format`
 | |
| 
 | |
|     if [ "$format" != "" ]; then
 | |
|         _check_date $format $1
 | |
|     fi
 | |
| }
 | |
| 
 | |
| _date_format() {
 | |
| 
 | |
|     if [ "$UPDATE_CHECK_TYPE" = "sliding" ]; then
 | |
|         echo "+%s"
 | |
|     else
 | |
|         case $UPDATE_CHECK in
 | |
|             "daily") echo +%d/%m/%Y;;
 | |
|             "weekly") echo +%V/%Y;;
 | |
|             "monthly") echo +%m/%Y;;
 | |
|         esac
 | |
|     fi
 | |
| 
 | |
| }
 | |
| 
 | |
| _check_date_file() {
 | |
|     mkdir -p ~/.config/dotfiles/.data
 | |
|     touch ~/.config/dotfiles/.data/update_date
 | |
| }
 | |
| 
 | |
| _sentence() {
 | |
|     local subject0=("Your" "The" "This")
 | |
|     local subject1=("system" "machine" "pc" "computer")
 | |
|     local adjective=("awesome" "incredible" "amazing" "brave" "hard working" "loyal" "nice" "polite" "powerful" "pro-active" "reliable" "fabulous" "fantastic" "incredible" "outstanding" "remarkable" "spectacular" "splendid" "super" "happy" "cheerful")
 | |
|     local verb=("is" "seems" "looks" "appears to be")
 | |
|     local no_verb=("is not" "doesn't seem" "doesn't look" "appears not to be")
 | |
|     local adverb=("up-to-date" "ready" "updated")
 | |
|     local dot=("." "!" "...")
 | |
| 
 | |
|     local n_subject0=`shuf -i0-"$((${#subject0[@]}-1))" -n1`
 | |
|     local n_subject1=`shuf -i0-"$((${#subject1[@]}-1))" -n1`
 | |
|     local n_adjective=`shuf -i0-"$((${#adjective[@]}-1))" -n1`
 | |
|     local n_adverb=`shuf -i0-"$((${#adverb[@]}-1))" -n1`
 | |
|     local n_dot=`shuf -i0-"$((${#dot[@]}-1))" -n1`
 | |
| 
 | |
|     if [ $1 = "updated" ];  then
 | |
|         local color="32"
 | |
|         local n_verb=`shuf -i0-"$((${#verb[@]}-1))" -n1`
 | |
|         local s_verb=${verb[$n_verb]}
 | |
|         local end=""
 | |
|     elif [ $1 = "not_updated" ]; then
 | |
|         local color="31"
 | |
|         local n_verb=`shuf -i0-"$((${#no_verb[@]}-1))" -n1`
 | |
|         local s_verb=${no_verb[$n_verb]}
 | |
|         local end="Run \`update\` to update your system."
 | |
|     fi
 | |
| 
 | |
|     echo -e "\033[$color;1m${subject0[$n_subject0]} ${adjective[$n_adjective]} ${subject1[$n_subject1]} $s_verb ${adverb[$n_adverb]}${dot[$n_dot]} ${end}\033[0m"
 | |
| }
 | |
| 
 | |
| _check_date() {
 | |
| 
 | |
|     _check_date_file
 | |
| 
 | |
|     local old_date=`cat ~/.config/dotfiles/.data/update_date`
 | |
|     local new_date=`date $1`
 | |
|     local updated=0
 | |
| 
 | |
|     if [ "$UPDATE_CHECK_TYPE" = "sliding" ]; then
 | |
|         local diff=$(($new_date - $old_date))
 | |
|         case $UPDATE_CHECK in
 | |
|             "daily") [ $diff -lt 86400 ] && updated=1;;
 | |
|             "weekly") [ $diff -lt 604800 ] && updated=1;;
 | |
|             "monthly") [$diff -lt 18748800 ] && updated=1;;
 | |
|         esac
 | |
|     else
 | |
|         if [ "$new_date" = "$old_date" ] ; then
 | |
|             updated=1
 | |
|         fi
 | |
|     fi
 | |
| 
 | |
|     if [ $updated -eq 0 ] && [ ! -f ~/.config/dotfiles/.data/update_lock ]; then
 | |
|         _sentence not_updated
 | |
|     elif [ "$UPDATE_CHECK_ALWAYS" = "true" ] || [ "$2" = "force" ]; then
 | |
|         _sentence updated
 | |
|     fi
 | |
| 
 | |
| }
 | |
| 
 | |
| # Returns 0 if $1 > $2
 | |
| _semver_greater() {
 | |
|     local major_1=$(echo $1 | cut -d '.' -f 1)
 | |
|     local minor_1=$(echo $1 | cut -d '.' -f 2)
 | |
|     local patch_1=$(echo $1 | cut -d '.' -f 3)
 | |
|     local major_2=$(echo $2 | cut -d '.' -f 1)
 | |
|     local minor_2=$(echo $2 | cut -d '.' -f 2)
 | |
|     local patch_2=$(echo $2 | cut -d '.' -f 3)
 | |
| 
 | |
|     if [ $major_1 -gt $major_2 ]; then
 | |
|         return 0
 | |
|     elif [ $major_1 -eq $major_2 ] && [ $minor_1 -gt $minor_2 ]; then
 | |
|         return 0
 | |
|     elif [ $major_1 -eq $major_2 ] && [ $minor_1 -eq $minor_2 ] && [ $patch_1 -gt $patch_2 ]; then
 | |
|         return 0
 | |
|     else
 | |
|         return 1
 | |
|     fi
 | |
| }
 | |
| 
 | |
| update-system() {
 | |
| 
 | |
|     if [ -f ~/.config/dotfiles/.data/noroot ]; then
 | |
|         # If this file exists, it means root is not available: skip the system update
 | |
|         echo -e "\033[33;1m=== You don't have root, skipping system update ===\033[0m"
 | |
|         return
 | |
|     fi
 | |
| 
 | |
|     echo -e "\033[32;1m=== Starting system update, please enter your password ===\033[0m"
 | |
|     sudo true
 | |
|     if [ $? -ne 0 ]; then
 | |
|         echo "Could not get sudo..."
 | |
|         return 1
 | |
|     fi
 | |
| 
 | |
|     echo -e "\033[32;1m=== Updating system ===\033[0m"
 | |
|     local start=`date +%s`
 | |
| 
 | |
|     # Debian based systems
 | |
|     command -v apt > /dev/null 2>&1
 | |
|     if [ $? -eq 0 ]; then
 | |
|         sudo apt update -y
 | |
|         if [ $? -eq 0 ]; then
 | |
|             sudo apt upgrade -y
 | |
|             if [ $? -eq 0 ]; then
 | |
|                 sudo apt autoremove -y
 | |
|             fi
 | |
|         fi
 | |
|     fi
 | |
| 
 | |
|     # Archlinux based systems
 | |
|     command -v yay > /dev/null 2>&1
 | |
| 
 | |
|     if [ $? -eq 0 ]; then
 | |
|         yay -Syu --noconfirm
 | |
|         yay -Syua --noconfirm
 | |
|     else
 | |
|         command -v pacman > /dev/null 2>&1
 | |
| 
 | |
|         if [ $? -eq 0 ]; then
 | |
|             sudo pacman -Syu --noconfirm
 | |
|         fi
 | |
|     fi
 | |
| 
 | |
|     # Fedora based systems
 | |
|     command -v dnf > /dev/null 2>&1
 | |
|     if [ $? -eq 0 ]; then
 | |
|         sudo dnf upgrade
 | |
|     fi
 | |
| 
 | |
|     local seconds=$((`date +%s` - $start))
 | |
|     local formatted=`date -ud "@$seconds" +'%H hours %M minutes %S seconds'`
 | |
|     echo -e "\033[32;1m=== System updated in $formatted ===\033[0m"
 | |
| }
 | |
| 
 | |
| update-rust() {
 | |
| 
 | |
|     # Update rust if installed
 | |
|     command -v rustup > /dev/null 2>&1
 | |
|     if [ $? -ne 0 ]; then
 | |
|         return
 | |
|     fi
 | |
| 
 | |
|     local start=`date +%s`
 | |
|     echo -e "\033[32;1m=== Updating rustup ===\033[0m"
 | |
|     rustup self update
 | |
| 
 | |
|     echo -e "\033[32;1m=== Updating rust ===\033[0m"
 | |
|     rustup update
 | |
| 
 | |
|     cargo install-update --help > /dev/null 2>&1
 | |
| 
 | |
|     # Program to update cargo programs is not installed
 | |
|     if [ $? -ne 0 ]; then
 | |
| 
 | |
|         echo -e "\033[33;1m=== To allow updating rust packages, run \`cargo install install-update\`===\033[0m"
 | |
| 
 | |
|     fi
 | |
| 
 | |
|     # If the user has no root, and if he doesn't have openssl, we won't install cargo update.
 | |
|     # Before running cargo update, we check again that it is installed.
 | |
|     cargo install-update --help > /dev/null 2>&1
 | |
|     if [ $? -eq 0 ]; then
 | |
|         echo -e "\033[32;1m=== Updating rust packages ===\033[0m"
 | |
|         cargo install-update -ag
 | |
|     fi
 | |
| 
 | |
|     local seconds=$((`date +%s` - $start))
 | |
|     local formatted=`date -ud "@$seconds" +'%H hours %M minutes %S seconds'`
 | |
|     echo -e "\033[32;1m=== Rust updated in $formatted ===\033[0m"
 | |
| 
 | |
| }
 | |
| 
 | |
| update-wasm() {
 | |
|     command -v wasmer > /dev/null 2>&1
 | |
|     if [ $? -ne 0 ]; then
 | |
|         return
 | |
|     fi
 | |
| 
 | |
|     local start=`date +%s`
 | |
|     echo -e "\033[32;1m=== Updating wasmer ===\033[0m"
 | |
| 
 | |
|     local old_path=$PWD
 | |
| 
 | |
|     # Protect dotfiles from being modified by wasmer self-update
 | |
|     cd ~/.config/dotfiles
 | |
|     git stash > /dev/null 2>&1
 | |
|     wasmer self-update
 | |
|     git checkout zshrc > /dev/null 2>&1
 | |
|     git stash pop > /dev/null 2>&1
 | |
|     cd $old_path
 | |
| 
 | |
|     command -v wapm > /dev/null 2>&1
 | |
|     if [ $? -ne 0 ]; then
 | |
|         return
 | |
|     fi
 | |
| 
 | |
|     echo -e "\033[32;1m=== Updating wapm packages ===\033[0m"
 | |
| 
 | |
|     local output=$(wapm list -g | grep '^ _/' | cut -d '|' -f 1 | cut -d '/' -f 2 | while read package; do
 | |
|         local package_trimmed=$(echo $package | tr -d '[:space:]')
 | |
|         local current_version=$(wapm list -g | grep "^ _/$package_trimmed " | cut -d '|' -f 2 | tr -d '[:space:]')
 | |
|         local last_version=$(wapm search $package_trimmed | grep $package_trimmed | cut -d '|' -f 4 | tr -d '[:space:'])
 | |
|         local needs_update="No"
 | |
|         if _semver_greater $last_version $current_version; then
 | |
|             needs_update="Yes"
 | |
|         fi
 | |
|         echo $package_trimmed@$current_version@$last_version@$needs_update
 | |
|     done | column -t -s "@" -N "Package,Installed,Latest,Needs update")
 | |
| 
 | |
|     if [ "$output" != "" ]; then
 | |
|         echo -e "$output\n"
 | |
|     else
 | |
|         echo "No packages need updating."
 | |
|     fi
 | |
| 
 | |
|     local update_packages=0
 | |
|     for package in $(echo "$output" | tail -n +2 | grep 'Yes' | cut -d ' ' -f 1); do
 | |
|         echo Updating $package
 | |
|         wapm install -g $package
 | |
|         update_packages=$(($update_packages + 1))
 | |
|     done
 | |
| 
 | |
|     if [ $update_packages -gt 1 ]; then
 | |
|         echo "1 package updated."
 | |
|     elif [ $update_packages -gt 0 ]; then
 | |
|         echo "$update_packages packages updated."
 | |
|     fi
 | |
| 
 | |
|     local seconds=$((`date +%s` - $start))
 | |
|     local formatted=`date -ud "@$seconds" +'%H hours %M minutes %S seconds'`
 | |
|     echo -e "\033[32;1m=== Wapm packages updated in $formatted ===\033[0m"
 | |
| 
 | |
| }
 | |
| 
 | |
| update-npm() {
 | |
| 
 | |
|     # Update node packages if installed
 | |
|     command -v npm > /dev/null 2>&1
 | |
|     if [ $? -ne 0 ]; then
 | |
|         return
 | |
|     fi
 | |
| 
 | |
|     if [ ! -d ~/.npmbin ]; then
 | |
|         return
 | |
|     fi
 | |
| 
 | |
|     local start=`date +%s`
 | |
|     echo -e "\033[32;1m=== Updating node packages ===\033[0m"
 | |
|     npm update -g
 | |
| 
 | |
|     local seconds=$((`date +%s` - $start))
 | |
|     local formatted=`date -ud "@$seconds" +'%H hours %M minutes %S seconds'`
 | |
|     echo -e "\033[32;1m=== Node packages updated in $formatted ===\033[0m"
 | |
| }
 | |
| 
 | |
| update-dotfiles() {
 | |
|     local start=`date +%s`
 | |
| 
 | |
|     local current_dir=$PWD
 | |
| 
 | |
|     echo -e "\033[32;1m=== Updating dotfiles ===\033[0m"
 | |
|     cd ~/.config/dotfiles && git pull
 | |
| 
 | |
|     if [ -d ~/.config/oh-my-zsh ]; then
 | |
|         echo -e "\033[32;1m=== Updating oh-my-zsh ===\033[0m"
 | |
|         cd ~/.config/oh-my-zsh && git pull
 | |
|     fi
 | |
| 
 | |
|     if [ -d ~/.config/awesome/.git ]; then
 | |
|         echo -e "\033[32;1m=== Updating awesome config ===\033[0m"
 | |
|         cd ~/.config/awesome/ && git pull
 | |
|     fi
 | |
| 
 | |
|     cd $current_dir
 | |
| 
 | |
|     local seconds=$((`date +%s` - $start))
 | |
|     local formatted=`date -ud "@$seconds" +'%H hours %M minutes %S seconds'`
 | |
|     echo -e "\033[32;1m=== Dotfiles updated in $formatted ===\033[0m"
 | |
| }
 | |
| 
 | |
| update-neovim() {
 | |
|     command -v nvim > /dev/null 2>&1
 | |
|     if [ $? -ne 0 ]; then
 | |
|         return
 | |
|     fi
 | |
| 
 | |
|     local start=`date +%s`
 | |
|     echo -e "\033[32;1m=== Updating neovim packages ===\033[0m"
 | |
| 
 | |
|     curl -fLo ~/.local/share/nvim/site/autoload/plug.vim --create-dirs \
 | |
|         https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim 2>/dev/null
 | |
| 
 | |
|     nvim +PlugUpdate +qall
 | |
| 
 | |
|     local seconds=$((`date +%s` - $start))
 | |
|     local formatted=`date -ud "@$seconds" +'%H hours %M minutes %S seconds'`
 | |
|     echo -e "\033[32;1m=== Neovim updated in $formatted ===\033[0m"
 | |
| }
 | |
| 
 | |
| update-postpone() {
 | |
|     local format=`_date_format`
 | |
| 
 | |
|     if [ $? -eq 0 ]; then
 | |
|         _check_date_file
 | |
|         date $format > ~/.config/dotfiles/.data/update_date
 | |
|     fi
 | |
| }
 | |
| 
 | |
| _print_help() {
 | |
|     echo -e "\033[32mupdate\033[0m"
 | |
|     echo -e "Thomas Forgione <thomas@forgione.fr>"
 | |
|     echo -e "A script that automatically updates your system"
 | |
|     echo
 | |
|    _print_usage
 | |
| }
 | |
| 
 | |
| _print_usage() {
 | |
|     echo -e "\033[33mUSAGE:\033[0m"
 | |
|     echo -e "    \033[32mupdate\033[0m                Auto-detect what to update and perform th update"
 | |
|     echo -e "    \033[32mupdate <subcommand>\033[0m   Calls the update subcommand"
 | |
|     echo
 | |
|     echo -e "\033[33mSUBCOMMANDS:\033[0m"
 | |
|     echo -e "    \033[32msystem\033[0m                Updates the system (Debian, Archlinux, Fedora)"
 | |
|     echo -e "    \033[32mrust\033[0m                  Updates rust and rust packages (requires rustup)"
 | |
|     echo -e "    \033[32mwasm\033[0m                  Updates wasmer and wapm packages"
 | |
|     echo -e "    \033[32mnpm\033[0m                   Updates npm packages (in ~/.config/npmbin)"
 | |
|     echo -e "    \033[32mdotfiles\033[0m              Updates the dotfiles"
 | |
|     echo -e "    \033[32mneovim\033[0m                Updates the neovim packages"
 | |
|     echo -e "    \033[32mcheck\033[0m                 Checks whether the system has been recently updated"
 | |
|     echo -e "    \033[32mstartup\033[0m               Same as \`update check\` but is silent in case of success"
 | |
|     echo -e "    \033[32mpostpone\033[0m              Skip the current update (disable check warnings)"
 | |
|     echo -e "    \033[32mforce-unlock\033[0m          Deletes the lock file"
 | |
| }
 | |
| 
 | |
| partial-test() {
 | |
|     case $1 in
 | |
|         "system") return 0;;
 | |
|         "rust") return 0;;
 | |
|         "wasm") return 0;;
 | |
|         "npm") return 0;;
 | |
|         "dotfiles") return 0;;
 | |
|         "neovim") return 0;;
 | |
|         "check") return 0;;
 | |
|         "startup") return 0;;
 | |
|         "postpone") return 0;;
 | |
|         "force-unlock") return 0;;
 | |
|         *) return 1;;
 | |
|     esac
 | |
| }
 | |
| 
 | |
| partial-requires-lock() {
 | |
|     case $1 in
 | |
|         "system") return 0;;
 | |
|         "rust") return 0;;
 | |
|         "wasm") return 0;;
 | |
|         "npm") return 0;;
 | |
|         "dotfiles") return 0;;
 | |
|         "neovim") return 0;;
 | |
|         "check") return 1;;
 | |
|         "startup") return 1;;
 | |
|         "postpone") return 1;;
 | |
|         "force-unlock") return 1;;
 | |
|         *) return 1;;
 | |
|     esac
 | |
| }
 | |
| 
 | |
| partial-update() {
 | |
|     case $1 in
 | |
|         "system") update-system;;
 | |
|         "rust") update-rust;;
 | |
|         "wasm") update-wasm;;
 | |
|         "npm") update-npm;;
 | |
|         "dotfiles") update-dotfiles;;
 | |
|         "neovim") update-neovim;;
 | |
|         "check") _check_date_if_format force;;
 | |
|         "startup") _check_date_if_format;;
 | |
|         "postpone") update-postpone;;
 | |
|         "force-unlock") _unlock;;
 | |
|         *) return 1
 | |
|     esac
 | |
| }
 | |
| 
 | |
| main() {
 | |
| 
 | |
|     if [ $# -eq 0 ]; then
 | |
|         _lock_or_error_message
 | |
|         local error_code=$?
 | |
|         if [ $error_code -ne 0 ]; then
 | |
|             exit $error_code
 | |
|         fi
 | |
| 
 | |
|         local start=`date +%s`
 | |
|         echo -e "\033[32;1m=== Starting full update ===\033[0m"
 | |
| 
 | |
|         # Update the system
 | |
|         _check_running
 | |
|         update-system
 | |
| 
 | |
|         # Update rust and rust packages
 | |
|         _check_running
 | |
|         update-rust
 | |
| 
 | |
|         # Update wasmer
 | |
|         _check_running
 | |
|         update-wasm
 | |
| 
 | |
|         # Update npm and npm packages
 | |
|         _check_running
 | |
|         update-npm
 | |
| 
 | |
|         # Update the dotfiles
 | |
|         _check_running
 | |
|         update-dotfiles
 | |
| 
 | |
|         # Update the neovim packages
 | |
|         _check_running
 | |
|         update-neovim
 | |
| 
 | |
|         _check_running
 | |
|         update-postpone
 | |
| 
 | |
|         _check_running
 | |
|         local seconds=$((`date +%s` - $start ))
 | |
|         local formatted=`date -ud "@$seconds" +'%H hours %M minutes %S seconds'`
 | |
|         echo -e "\033[32;1m=== Update finished in $formatted ===\033[0m"
 | |
| 
 | |
|         _check_running
 | |
|         _check_date_if_format force
 | |
| 
 | |
|         _check_running
 | |
|         _unlock
 | |
| 
 | |
|     else
 | |
| 
 | |
|         local lock_required=1
 | |
| 
 | |
|         for part in $@; do
 | |
| 
 | |
|             if [ $part == "-h" ] || [ $part == "--help" ]; then
 | |
|                 _print_help
 | |
|                 exit 0
 | |
|             fi
 | |
| 
 | |
|             partial-test $part
 | |
|             if [ $? -ne 0 ]; then
 | |
|                 echo -e "\033[1;31merror:\033[0m unrocognized update command \"$part\""
 | |
|                 _print_usage
 | |
|                 return 1
 | |
|             fi
 | |
| 
 | |
|             partial-requires-lock $part
 | |
|             lock_required=$(($lock_required * $?))
 | |
|         done
 | |
| 
 | |
|         if [ $lock_required -eq 0 ]; then
 | |
|             _lock_or_error_message
 | |
|             local error_code=$?
 | |
|             if [ $error_code -ne 0 ]; then
 | |
|                 exit $error_code
 | |
|             fi
 | |
|         fi
 | |
| 
 | |
|         for part in $@; do
 | |
|             _check_running
 | |
|             partial-update $part
 | |
|         done
 | |
| 
 | |
|         if [ $lock_required -eq 0 ]; then
 | |
|             _unlock
 | |
|         fi
 | |
|     fi
 | |
| }
 | |
| 
 | |
| trap _onkill 2 3
 | |
| main $@
 | |
| 
 |