Always-on and machine hooks already live in .zshenv / local.zsh. Drop the empty stub, remove it on deploy, and leave real .zprofile files to optional migration into local.zsh only.
447 lines
16 KiB
Bash
Executable File
447 lines
16 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
set -euo pipefail
|
|
|
|
# Save the original working directory
|
|
ORIGINAL_DIR="$(pwd)"
|
|
|
|
# Flags to determine if the arguments were passed
|
|
cp_hist_flag=false
|
|
noninteractive_flag=false
|
|
|
|
# Loop through all arguments
|
|
for arg in "$@"
|
|
do
|
|
case $arg in
|
|
--cp-hist|-c)
|
|
cp_hist_flag=true
|
|
;;
|
|
--non-interactive|-n)
|
|
noninteractive_flag=true
|
|
;;
|
|
*)
|
|
echo "Unknown option: $arg" >&2
|
|
exit 2
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [ -f ~/.gitconfig ]; then
|
|
cp ~/.gitconfig ~/.gitconfig.backup
|
|
echo "Backup of .gitconfig created."
|
|
else
|
|
echo ".gitconfig does not exist, no backup created."
|
|
fi
|
|
|
|
# Function to detect the operating system
|
|
detect_os() {
|
|
if [[ "$OSTYPE" == "darwin"* ]]; then
|
|
echo "macos"
|
|
elif [[ -f /etc/os-release ]]; then
|
|
. /etc/os-release
|
|
echo "$ID"
|
|
else
|
|
echo "unknown"
|
|
fi
|
|
}
|
|
|
|
run_as_root() {
|
|
if (( EUID == 0 )); then
|
|
"$@"
|
|
elif command -v sudo &> /dev/null; then
|
|
sudo "$@"
|
|
else
|
|
echo "Error: sudo is required to run: $*" >&2
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
has_trash_command() {
|
|
if [[ "$OSTYPE" == darwin* ]]; then
|
|
command -v trash &> /dev/null || command -v rmtrash &> /dev/null
|
|
else
|
|
command -v gio &> /dev/null || command -v trash-put &> /dev/null
|
|
fi
|
|
}
|
|
|
|
install_eza_binary() {
|
|
local archive
|
|
local binary
|
|
local target
|
|
|
|
case $(uname -m) in
|
|
x86_64|amd64)
|
|
target="x86_64-unknown-linux-gnu"
|
|
;;
|
|
aarch64|arm64)
|
|
target="aarch64-unknown-linux-gnu"
|
|
;;
|
|
armv7*)
|
|
target="arm-unknown-linux-gnueabihf"
|
|
;;
|
|
*)
|
|
echo "Error: no prebuilt eza binary is available for $(uname -m)." >&2
|
|
return 1
|
|
;;
|
|
esac
|
|
|
|
archive=$(mktemp)
|
|
binary=$(mktemp)
|
|
trap 'rm -f "${archive:-}" "${binary:-}"' EXIT
|
|
curl -fsSL "https://github.com/eza-community/eza/releases/latest/download/eza_${target}.tar.gz" -o "$archive"
|
|
tar -xOzf "$archive" ./eza > "$binary"
|
|
run_as_root install -m 755 "$binary" /usr/local/bin/eza
|
|
rm -f "$archive" "$binary"
|
|
trap - EXIT
|
|
}
|
|
|
|
# Install eza using package manager or fallback methods
|
|
install_eza() {
|
|
local os
|
|
os=$(detect_os)
|
|
echo "Installing eza..."
|
|
|
|
case $os in
|
|
macos)
|
|
if ! command -v brew &> /dev/null; then
|
|
echo "Homebrew is not installed. Installing Homebrew..."
|
|
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
|
fi
|
|
brew install eza
|
|
;;
|
|
ubuntu|debian)
|
|
run_as_root apt-get update
|
|
if ! run_as_root apt-get install -y eza; then
|
|
echo "Package manager installation failed, attempting fallback..."
|
|
install_eza_binary
|
|
fi
|
|
;;
|
|
fedora)
|
|
if ! run_as_root dnf install -y eza; then
|
|
echo "Package manager installation failed, attempting fallback..."
|
|
install_eza_binary
|
|
fi
|
|
;;
|
|
centos|rhel)
|
|
if ! run_as_root yum install -y eza; then
|
|
echo "Package manager installation failed, attempting fallback..."
|
|
install_eza_binary
|
|
fi
|
|
;;
|
|
arch|manjaro)
|
|
if ! run_as_root pacman -Syu --noconfirm eza; then
|
|
echo "Package manager installation failed, attempting fallback..."
|
|
install_eza_binary
|
|
fi
|
|
;;
|
|
*)
|
|
echo "Unsupported operating system for package manager installation, using fallback..."
|
|
install_eza_binary
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# Helper: install zoxide if the package manager couldn't provide it
|
|
install_zoxide_binary() {
|
|
curl -sSfL https://raw.githubusercontent.com/ajeetdsouza/zoxide/main/install.sh |
|
|
sh -s -- --bin-dir /usr/local/bin --man-dir /usr/local/share/man
|
|
}
|
|
|
|
install_zoxide_fallback() {
|
|
local os
|
|
os=$(detect_os)
|
|
echo "Attempting fallback installation of zoxide..."
|
|
case $os in
|
|
macos)
|
|
brew install zoxide
|
|
;;
|
|
fedora)
|
|
run_as_root dnf install -y zoxide || install_zoxide_binary
|
|
;;
|
|
centos|rhel)
|
|
if command -v dnf &> /dev/null && run_as_root dnf install -y zoxide; then :; else
|
|
install_zoxide_binary
|
|
fi
|
|
;;
|
|
arch|manjaro)
|
|
run_as_root pacman -S --needed --noconfirm zoxide
|
|
;;
|
|
*)
|
|
install_zoxide_binary
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# Core: install required packages via the preferred package manager, then fall back where needed
|
|
install_packages() {
|
|
local os
|
|
local base_packages=(zsh git wget fontconfig autoconf)
|
|
os=$(detect_os)
|
|
|
|
case $os in
|
|
macos)
|
|
if ! command -v brew &> /dev/null; then
|
|
echo "Homebrew is not installed. Installing Homebrew..."
|
|
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
|
fi
|
|
brew install "${base_packages[@]}"
|
|
command -v trash &> /dev/null || brew install rmtrash
|
|
;;
|
|
ubuntu|debian)
|
|
run_as_root apt-get update
|
|
run_as_root apt-get install -y "${base_packages[@]}" curl tar libglib2.0-bin
|
|
;;
|
|
fedora)
|
|
run_as_root dnf install -y "${base_packages[@]}" curl tar glib2
|
|
;;
|
|
centos|rhel)
|
|
run_as_root yum install -y "${base_packages[@]}" curl tar glib2
|
|
;;
|
|
arch|manjaro)
|
|
run_as_root pacman -Syu --noconfirm "${base_packages[@]}" curl tar glib2
|
|
;;
|
|
*)
|
|
echo "Unsupported operating system. Please install ${base_packages[*]} manually."
|
|
;;
|
|
esac
|
|
|
|
# Fallbacks for any tools that are still missing after the package-manager step
|
|
command -v eza &> /dev/null || install_eza
|
|
command -v zoxide &> /dev/null || install_zoxide_fallback
|
|
|
|
local command_name
|
|
for command_name in zsh git wget curl tar fc-cache eza zoxide autoconf; do
|
|
if ! command -v "$command_name" &> /dev/null; then
|
|
echo "Error: required command was not installed: $command_name" >&2
|
|
return 1
|
|
fi
|
|
done
|
|
|
|
if ! has_trash_command; then
|
|
echo "Error: no command is available for moving files to Trash" >&2
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Check if required packages are installed, if not, install them
|
|
if command -v zsh &> /dev/null && command -v git &> /dev/null && command -v wget &> /dev/null && command -v curl &> /dev/null && command -v tar &> /dev/null && command -v fc-cache &> /dev/null && command -v eza &> /dev/null && command -v zoxide &> /dev/null && command -v autoconf &> /dev/null && has_trash_command; then
|
|
echo -e "ZSH, Git, wget, curl, tar, fontconfig, eza, zoxide, autoconf, and Trash support are already installed\n"
|
|
else
|
|
echo "Installing required packages..."
|
|
install_packages
|
|
echo -e "zsh, wget, curl, tar, git, fontconfig, eza, zoxide, autoconf, and Trash support installed\n"
|
|
fi
|
|
|
|
if [ -f ~/.gitconfig.backup ]; then
|
|
mv ~/.gitconfig.backup ~/.gitconfig
|
|
echo "Restored .gitconfig from backup."
|
|
else
|
|
echo "No .gitconfig backup found to restore."
|
|
fi
|
|
|
|
|
|
ZSH="$HOME/.oh-my-zsh"
|
|
EASYZSH_RAW_BASE="${EASYZSH_RAW_BASE:-https://git.miomio.moe/mio/easyzsh/raw/branch/master}"
|
|
|
|
# Stage shell stubs, then deploy.sh installs them.
|
|
# On download failure, leave existing ~/.zshrc and ~/.zshenv untouched.
|
|
easyzsh_stage=$(mktemp -d "$HOME/.easyzsh-stage.XXXXXX")
|
|
zshrc_download=$(mktemp "$HOME/.zshrc.download.XXXXXX")
|
|
zshenv_download=$(mktemp "$HOME/.zshenv.download.XXXXXX")
|
|
trap 'rm -rf "$easyzsh_stage"; rm -f "$zshrc_download" "$zshenv_download"' EXIT
|
|
|
|
download_easyzsh_file() {
|
|
local rel="$1"
|
|
local dest="$easyzsh_stage/$rel"
|
|
mkdir -p "$(dirname "$dest")"
|
|
if ! wget -q "${EASYZSH_RAW_BASE}/${rel}" -O "$dest"; then
|
|
echo "Failed to download ${rel} from ${EASYZSH_RAW_BASE}" >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
echo -e "Downloading easyzsh shell stubs\n"
|
|
for rel in \
|
|
deploy.sh \
|
|
.zshenv \
|
|
.zshrc
|
|
do
|
|
download_easyzsh_file "$rel"
|
|
done
|
|
# Keep failure-detection temps in sync with legacy test expectations.
|
|
cp "$easyzsh_stage/.zshrc" "$zshrc_download"
|
|
cp "$easyzsh_stage/.zshenv" "$zshenv_download"
|
|
chmod +x "$easyzsh_stage/deploy.sh"
|
|
|
|
echo -e "Installing oh-my-zsh\n"
|
|
if [ -d "$ZSH" ]; then
|
|
echo -e "oh-my-zsh is already installed\n"
|
|
git -C "$ZSH" remote set-url origin https://github.com/ohmyzsh/ohmyzsh.git
|
|
else
|
|
git clone --depth=1 https://github.com/ohmyzsh/ohmyzsh.git "$ZSH"
|
|
fi
|
|
|
|
# deploy.sh backs up existing stubs and never overwrites ~/.config/zsh/local.zsh
|
|
bash "$easyzsh_stage/deploy.sh" --migrate-zprofile
|
|
trap - EXIT
|
|
rm -rf "$easyzsh_stage"
|
|
rm -f "$zshrc_download" "$zshenv_download"
|
|
|
|
mkdir -p ~/.cache/zsh/ # this will be used to store .zcompdump zsh completion cache files which normally clutter $HOME
|
|
mkdir -p ~/.fonts # Create .fonts if doesn't exist
|
|
|
|
if [ -f ~/.zcompdump ]; then
|
|
mv ~/.zcompdump* ~/.cache/zsh/
|
|
fi
|
|
|
|
if [ -d "$ZSH/plugins/zsh-autosuggestions" ]; then
|
|
git -C "$ZSH/plugins/zsh-autosuggestions" pull
|
|
else
|
|
git clone --depth=1 https://github.com/zsh-users/zsh-autosuggestions "$ZSH/plugins/zsh-autosuggestions"
|
|
fi
|
|
|
|
if [ -d "$ZSH/custom/plugins/zsh-syntax-highlighting" ]; then
|
|
git -C "$ZSH/custom/plugins/zsh-syntax-highlighting" pull
|
|
else
|
|
git clone --depth=1 https://github.com/zsh-users/zsh-syntax-highlighting.git "$ZSH/custom/plugins/zsh-syntax-highlighting"
|
|
fi
|
|
|
|
if [ -d "$ZSH/custom/plugins/zsh-completions" ]; then
|
|
git -C "$ZSH/custom/plugins/zsh-completions" pull
|
|
else
|
|
git clone --depth=1 https://github.com/zsh-users/zsh-completions "$ZSH/custom/plugins/zsh-completions"
|
|
fi
|
|
|
|
if [ -d "$ZSH/custom/plugins/zsh-history-substring-search" ]; then
|
|
git -C "$ZSH/custom/plugins/zsh-history-substring-search" pull
|
|
else
|
|
git clone --depth=1 https://github.com/zsh-users/zsh-history-substring-search "$ZSH/custom/plugins/zsh-history-substring-search"
|
|
fi
|
|
|
|
|
|
# INSTALL FONTS
|
|
|
|
echo -e "Installing Nerd Fonts version of Hack, Roboto Mono, DejaVu Sans Mono\n"
|
|
|
|
# Check and download Hack font if it doesn't exist
|
|
if [ ! -f ~/.fonts/HackNerdFont-Regular.ttf ]; then
|
|
echo "Downloading Hack Nerd Font..."
|
|
wget -q --show-progress -N https://github.com/ryanoasis/nerd-fonts/raw/master/patched-fonts/Hack/Regular/HackNerdFont-Regular.ttf -P ~/.fonts/
|
|
else
|
|
echo "Hack Nerd Font already exists, skipping download."
|
|
fi
|
|
|
|
# Check and download Roboto Mono font if it doesn't exist
|
|
if [ ! -f ~/.fonts/RobotoMonoNerdFont-Regular.ttf ]; then
|
|
echo "Downloading Roboto Mono Nerd Font..."
|
|
wget -q --show-progress -N https://github.com/ryanoasis/nerd-fonts/raw/master/patched-fonts/RobotoMono/Regular/RobotoMonoNerdFont-Regular.ttf -P ~/.fonts/
|
|
else
|
|
echo "Roboto Mono Nerd Font already exists, skipping download."
|
|
fi
|
|
|
|
# Check and download DejaVu Sans Mono font if it doesn't exist
|
|
if [ ! -f ~/.fonts/DejaVuSansMNerdFont-Regular.ttf ]; then
|
|
echo "Downloading DejaVu Sans Mono Nerd Font..."
|
|
wget -q --show-progress -N https://github.com/ryanoasis/nerd-fonts/raw/master/patched-fonts/DejaVuSansMono/Regular/DejaVuSansMNerdFont-Regular.ttf -P ~/.fonts/
|
|
else
|
|
echo "DejaVu Sans Mono Nerd Font already exists, skipping download."
|
|
fi
|
|
|
|
fc-cache -fv ~/.fonts
|
|
|
|
if [ -d "$ZSH/custom/themes/powerlevel10k" ]; then
|
|
git -C "$ZSH/custom/themes/powerlevel10k" pull
|
|
else
|
|
git clone --depth=1 https://github.com/romkatv/powerlevel10k.git "$ZSH/custom/themes/powerlevel10k"
|
|
fi
|
|
curl -fsSL https://git.miomio.moe/mio/easyzsh/raw/branch/master/patch.sh | bash -s -- p10k
|
|
|
|
if [ -d ~/.fzf ]; then
|
|
git -C ~/.fzf pull
|
|
~/.fzf/install --all --key-bindings --completion --no-update-rc
|
|
else
|
|
git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf
|
|
~/.fzf/install --all --key-bindings --completion --no-update-rc
|
|
fi
|
|
|
|
if [ -d "$ZSH/custom/plugins/k" ]; then
|
|
git -C "$ZSH/custom/plugins/k" pull
|
|
else
|
|
git clone --depth 1 https://github.com/supercrabtree/k "$ZSH/custom/plugins/k"
|
|
fi
|
|
|
|
if [ -d "$ZSH/custom/plugins/fzf-tab" ]; then
|
|
git -C "$ZSH/custom/plugins/fzf-tab" pull
|
|
else
|
|
git clone --depth 1 https://github.com/Aloxaf/fzf-tab "$ZSH/custom/plugins/fzf-tab"
|
|
fi
|
|
|
|
# Import existing z data into zoxide if available
|
|
if command -v zoxide &> /dev/null; then
|
|
for z_file in ~/.z ~/.local/share/z/data ~/.zlua ~/.fasd; do
|
|
if [ -f "$z_file" ]; then
|
|
echo -e "Importing existing z data from $z_file into zoxide\n"
|
|
zoxide import --from=z "$z_file" 2>/dev/null || echo "Failed to import $z_file, continuing..."
|
|
break
|
|
fi
|
|
done
|
|
fi
|
|
|
|
|
|
|
|
# if git clone --depth 1 https://github.com/todotxt/todo.txt-cli.git ~/.config/ezsh/todo; then :
|
|
# else
|
|
# cd ~/.config/ezsh/todo && git fetch --all && git reset --hard origin/master
|
|
# fi
|
|
# mkdir ~/.config/ezsh/todo/bin ; cp -f ~/.config/ezsh/todo/todo.sh ~/.config/ezsh/todo/bin/todo.sh # cp todo.sh to ./bin so only it is included in $PATH
|
|
# #touch ~/.todo/config # needs it, otherwise spits error , yeah a bug in todo
|
|
# ln -s ~/.config/ezsh/todo ~/.todo
|
|
# if [ ! -L ~/.config/ezsh/todo/bin/todo.sh ]; then
|
|
# echo -e "Installing todo.sh in ~/.config/ezsh/todo\n"
|
|
# mkdir -p ~/.config/ezsh/bin
|
|
# mkdir -p ~/.config/ezsh/todo
|
|
# wget -q --show-progress "https://github.com/todotxt/todo.txt-cli/releases/download/v2.12.0/todo.txt_cli-2.12.0.tar.gz" -P ~/.config/ezsh/
|
|
# tar xvf ~/.config/ezsh/todo.txt_cli-2.12.0.tar.gz -C ~/.config/ezsh/todo --strip 1 && rm ~/.config/ezsh/todo.txt_cli-2.12.0.tar.gz
|
|
# ln -s -f ~/.config/ezsh/todo/todo.sh ~/.config/ezsh/bin/todo.sh # so only .../bin is included in $PATH
|
|
# ln -s -f ~/.config/ezsh/todo/todo.cfg ~/.todo.cfg # it expects it there or ~/todo.cfg or ~/.todo/config
|
|
# else
|
|
# echo -e "todo.sh is already instlled in ~/.config/ezsh/todo/bin/\n"
|
|
# fi
|
|
if [ "$cp_hist_flag" = true ]; then
|
|
echo -e "\nCopying bash_history to zsh_history\n"
|
|
if command -v python &>/dev/null; then
|
|
wget -q --show-progress https://gist.githubusercontent.com/muendelezaji/c14722ab66b505a49861b8a74e52b274/raw/49f0fb7f661bdf794742257f58950d209dd6cb62/bash-to-zsh-hist.py
|
|
cat ~/.bash_history | python bash-to-zsh-hist.py >> ~/.zsh_history
|
|
else
|
|
if command -v python3 &>/dev/null; then
|
|
wget -q --show-progress https://gist.githubusercontent.com/muendelezaji/c14722ab66b505a49861b8a74e52b274/raw/49f0fb7f661bdf794742257f58950d209dd6cb62/bash-to-zsh-hist.py
|
|
cat ~/.bash_history | python3 bash-to-zsh-hist.py >> ~/.zsh_history
|
|
else
|
|
printf "Python is not installed, can't copy bash_history to zsh_history\n"
|
|
fi
|
|
fi
|
|
else
|
|
echo -e "\nNot copying bash_history to zsh_history, as --cp-hist or -c is not supplied\n"
|
|
fi
|
|
|
|
if [ "$noninteractive_flag" = true ]; then
|
|
echo -e "Installation complete, exit terminal and enter a new zsh session\n"
|
|
echo -e "Make sure to change zsh to default shell by running: chsh -s $(command -v zsh)"
|
|
echo -e "In a new zsh session manually run: build-fzf-tab-module"
|
|
else
|
|
# source ~/.zshrc
|
|
echo -e "\nAdministrator access is needed to change the default shell\n"
|
|
|
|
if run_as_root chsh -s "$(command -v zsh)" "${USER:-$(id -un)}" && /bin/zsh -i -c 'omz update'; then
|
|
echo -e "Installation complete, exit terminal and enter a new zsh session"
|
|
echo -e "In a new zsh session manually run: build-fzf-tab-module"
|
|
else
|
|
echo -e "Something is wrong"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# Restore original working directory
|
|
cd "$ORIGINAL_DIR"
|
|
exit
|