313 lines
6.1 KiB
Bash
Executable File
313 lines
6.1 KiB
Bash
Executable File
#!/usr/bin/env zsh
|
|
|
|
set -e
|
|
|
|
DISTRO="$(sed -n 's/^NAME="\([^"]\+\)"/\1/p' /etc/os-release)"
|
|
|
|
SCRIPT_FILE="$(readlink -f -- "$0")"
|
|
SCRIPT_NAME="$(basename -- "$SCRIPT_FILE")"
|
|
SCRIPT_DIR="$(dirname -- "$SCRIPT_FILE")"
|
|
|
|
SOURCE_DIR="$SCRIPT_DIR"
|
|
DEST_DIR="$HOME"
|
|
|
|
PRINT_HELP=false
|
|
FORCE=false
|
|
REMOVE_EXISTING=false
|
|
IGNORE_EXISTING=false
|
|
ERROR=false
|
|
|
|
# Define packages
|
|
typeset -a PKGS
|
|
PKGS=(
|
|
"alacritty"
|
|
"dunst"
|
|
"fish"
|
|
"i3"
|
|
"i3lock"
|
|
"i3status"
|
|
"jq"
|
|
"lf"
|
|
"picom"
|
|
"rofi"
|
|
"startx"
|
|
"tmux"
|
|
"zsh"
|
|
)
|
|
|
|
# Define paths to symlink
|
|
typeset -a SYMLINKS
|
|
SYMLINKS=(
|
|
".config/alacritty"
|
|
".config/dolphinrc"
|
|
".config/dunst"
|
|
".config/fish"
|
|
".config/foot"
|
|
".config/frogminer"
|
|
".config/ghostty"
|
|
".config/i3"
|
|
".config/i3status"
|
|
".config/kde-mimeapps.list"
|
|
".config/kglobalshortcutsrc"
|
|
".config/klipperrc"
|
|
".config/kwinrc"
|
|
".config/lf"
|
|
".config/opencode"
|
|
".config/picom"
|
|
".config/pipewire"
|
|
".config/rofi"
|
|
".config/strawberry"
|
|
".config/tmux"
|
|
".config/vlc"
|
|
".config/wezterm"
|
|
".config/yay"
|
|
".config/zed"
|
|
".local/bin"
|
|
".local/share/fonts"
|
|
".local/share/konsole"
|
|
".gdbinit"
|
|
".vimrc"
|
|
".xinit-scripts"
|
|
".xinitrc"
|
|
".Xresources"
|
|
)
|
|
|
|
typeset -a COPIES
|
|
COPIES=(
|
|
".config/gtk-3.0"
|
|
".config/gtk-4.0"
|
|
".gtkrc-2.0"
|
|
)
|
|
|
|
typeset -A SYMLINK_MAP
|
|
SYMLINK_MAP[zsh/rc]=".zshrc"
|
|
|
|
error() {
|
|
msg="$1"
|
|
ERROR=true
|
|
echo "Error: $msg" >&2
|
|
}
|
|
|
|
check_packages_installed() {
|
|
for pkg in "${PKGS[@]}"; do
|
|
if ! type "$pkg" >/dev/null; then
|
|
error "missing $pkg"
|
|
fi
|
|
done
|
|
}
|
|
|
|
remove_symlink() {
|
|
local link src
|
|
link="${DEST_DIR}/$1"
|
|
|
|
if test -L "$link"; then
|
|
src="$(readlink -f -- "$link")"
|
|
echo "Removing symlink: $link -> $src"
|
|
rm "$link"
|
|
elif test -e "$link"; then
|
|
error "object to be removed is not a symlink:"
|
|
error "${link}: $(stat -c '%F' -- "$link")"
|
|
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
remove_all_symlinks() {
|
|
for link in "${SYMLINKS[@]}"; do
|
|
remove_symlink "$link"
|
|
done
|
|
|
|
for src dst in ${(kv)SYMLINK_MAP}; do
|
|
remove_symlink "$dst"
|
|
done
|
|
}
|
|
|
|
create_symlink() {
|
|
local rel_src rel_dst src dst dst_parent
|
|
|
|
rel_src="$1"
|
|
rel_dst="$2"
|
|
|
|
if test -z "$rel_src"; then
|
|
error "missing src argument:"
|
|
error "$0 $@"
|
|
return 1
|
|
fi
|
|
|
|
if test -z "$rel_dst"; then
|
|
error "missing dst argument:"
|
|
error "$0 $@"
|
|
return 1
|
|
fi
|
|
|
|
src="${SCRIPT_DIR}/$rel_src"
|
|
dst="${DEST_DIR}/$rel_dst"
|
|
dst_parent="$(dirname -- "$dst")"
|
|
|
|
if ! test -e "$src"; then
|
|
error "the following source path does not exist:"
|
|
error "$src"
|
|
return 1
|
|
fi
|
|
|
|
if ! test -d "$dst_parent"; then
|
|
echo "Creating parent: $dst_parent"
|
|
mkdir -p "$dst_parent"
|
|
fi
|
|
|
|
if test -L "$dst"; then
|
|
if $FORCE; then
|
|
if test "$(readlink -f "$dst")" != "$src"; then
|
|
remove_symlink "$2"
|
|
else
|
|
return 0
|
|
fi
|
|
elif $IGNORE_EXISTING; then
|
|
return 0
|
|
else
|
|
error "symbolic link already exists:"
|
|
error "$dst"
|
|
return 1
|
|
fi
|
|
elif test -e "$dst"; then
|
|
error "path already exists that is not a symlink:"
|
|
error "${dst}: $(stat -c '%F' -- "$dst")"
|
|
return 1
|
|
fi
|
|
|
|
echo "Creating link: $dst -> $rel_src"
|
|
ln -s "$src" "$dst"
|
|
}
|
|
|
|
remove_path() {
|
|
local target
|
|
target="$1"
|
|
|
|
echo "Trashing item: $target"
|
|
gio trash "$target"
|
|
}
|
|
|
|
copy_item() {
|
|
local rel_src rel_dst src dst dst_parent
|
|
|
|
rel_src="$1"
|
|
rel_dst="$2"
|
|
|
|
if test -z "$rel_src"; then
|
|
error "missing src argument:"
|
|
error "$0 $@"
|
|
return 1
|
|
fi
|
|
|
|
if test -z "$rel_dst"; then
|
|
error "missing dst argument:"
|
|
error "$0 $@"
|
|
return 1
|
|
fi
|
|
|
|
src="${SCRIPT_DIR}/$rel_src"
|
|
dst="${DEST_DIR}/$rel_dst"
|
|
dst_parent="$(dirname -- "$dst")"
|
|
|
|
if ! test -e "$src"; then
|
|
error "the following source path does not exist:"
|
|
error "$src"
|
|
return 1
|
|
fi
|
|
|
|
if ! test -d "$dst_parent"; then
|
|
echo "Creating parent: $dst_parent"
|
|
mkdir -p "$dst_parent"
|
|
fi
|
|
|
|
if test -e "$dst"; then
|
|
if $FORCE; then
|
|
remove_path "$dst"
|
|
elif $IGNORE_EXISTING; then
|
|
return 0
|
|
else
|
|
error "path already exists:"
|
|
error "${dst}"
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
echo "Copying item: from $rel_src to ${dst_parent}/"
|
|
cp -r "$src" "${dst_parent}/"
|
|
}
|
|
|
|
create_all_symlinks() {
|
|
for link in "${SYMLINKS[@]}"; do
|
|
create_symlink "$link" "$link"
|
|
done
|
|
|
|
for src dst in ${(kv)SYMLINK_MAP}; do
|
|
create_symlink "$src" "$dst"
|
|
done
|
|
}
|
|
|
|
copy_all_items() {
|
|
for item in "${COPIES[@]}"; do
|
|
copy_item "$item" "$item"
|
|
done
|
|
}
|
|
|
|
check_terminfo() {
|
|
if ! infocmp tmux-256color > /dev/null; then
|
|
error "Missing terminfo for tmux-256color. Try installing ncurses-term."
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
|
|
print_help() {
|
|
echo "Usage: $SCRIPT_NAME [...]"
|
|
echo ""
|
|
echo "Options:"
|
|
echo " -h, --help Print this help message"
|
|
echo " -f, --force Overwrite any existing links"
|
|
echo " -i, --ignore-existing Ignore existing symlinks"
|
|
echo " -r, --remove-existing Remove any existing symlinks"
|
|
}
|
|
|
|
while [ $# -gt 0 ]; do
|
|
case $1 in
|
|
-h|--help)
|
|
PRINT_HELP=true
|
|
shift
|
|
;;
|
|
-f|--force)
|
|
FORCE=true
|
|
shift
|
|
;;
|
|
-r|--remove-existing)
|
|
REMOVE_EXISTING=true
|
|
shift
|
|
;;
|
|
-i|--ignore-existing)
|
|
IGNORE_EXISTING=true
|
|
shift
|
|
;;
|
|
*)
|
|
error "unknown option: $1"
|
|
PRINT_HELP=true
|
|
shift
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if $PRINT_HELP; then
|
|
print_help
|
|
elif $REMOVE_EXISTING; then
|
|
remove_all_symlinks
|
|
else
|
|
check_terminfo
|
|
check_packages_installed
|
|
create_all_symlinks
|
|
copy_all_items
|
|
fi
|
|
|
|
if $ERROR; then
|
|
exit 1
|
|
fi
|