Replace the local/ directory of split env/login/interactive files with one always-on local.zsh sourced from .zshenv. Deploy migrates old fragments and never overwrites local.zsh.
452 lines
16 KiB
Bash
Executable File
452 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 managed shell layout (stubs + ~/.config/zsh modules), then deploy.sh installs it.
|
|
# 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 layout\n"
|
|
for rel in \
|
|
deploy.sh \
|
|
.zshenv \
|
|
.zshrc \
|
|
.zprofile \
|
|
config/env/00-path.zsh \
|
|
config/interactive/10-bootstrap.zsh \
|
|
config/interactive/20-post-omz.zsh \
|
|
local.zsh.example
|
|
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/
|
|
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
|