#!/bin/bash # Environments LAPTOP="laptop" DESKTOP="desk" ENV_EXT_REGEXP=".*\.${LAPTOP}|.*\.${DESKTOP}" # Special filename for external config path DEST_FILENAME="dest" # Special configuration filename BASE_CONFIG="config_common" MERGE_CONFIG_FOLDER="config.d" FINAL_CONFIG="config" # Special directories with per-environment configuration merge I3_CONFIG="i3" POLYBAR_CONFIG="polybar" ARCH_PACKAGES="bootstrap" MERGE_DIRS="${I3_CONFIG} ${POLYBAR_CONFIG} ${ARCH_PACKAGES}" changed_files="$(git --git-dir=$HOME/.cfg/ --work-tree=$HOME diff-tree -r --name-status --no-commit-id HEAD^1 HEAD)" # Check if a file has been modified and deleted since last commit, if so perform an action # $1 : absolute path of the file # $2 : command to launch if file has been created of modifed # $3 : command to launch if file has been deleted function check_copy() { # When initializing, always copy files if [ ! -z ${INIT} ]; then echo -e "* Running \"$2\"" && eval "$2" return fi changed_file=`grep "${1#$HOME/}" <<< "${changed_files}"` if [ ! -z "${changed_file}" ]; then if echo "$changed_file" | grep -q -E "^D"; then echo "* $1 has been removed" echo -e "\t* Running \"$3\"" && eval "$3" fi if echo "$changed_file" | grep -q -E "^(A|M)"; then echo "* Changes detected in $(basename $1)" echo -e "\t* Running \"$2\"" && eval "$2" fi else echo "$1 not modified, no need to copy" fi } # Generates a `config` file in $1, by merging a required $1/{MERGE_CONFIG_FOLDER} file # with an optional `$1/config.d/$2` file. This is useful for having # a common base for multiple computer, and per-computer stuff. # $1 : path of the folder # $2 : optional current environment # $3 : if defined, prepend $2 instead of appending function merge_config() { echo -e "\n=== Generate ${m} config file ===" rm -f ${CONFIG}/${m}/${FINAL_CONFIG} # Copy common config cp ${CONFIG}/${m}/${BASE_CONFIG} ${CONFIG}/${m}/${FINAL_CONFIG} echo "${CONFIG}/${m}/${FINAL_CONFIG} created" # If there is an override folder, merge given env if [ ! -z ${2} ] && [ -d ${CONFIG}/${m}/${MERGE_CONFIG_FOLDER} ]; then for f in `find ${CONFIG}/${m}/config.d -type f -path "*${2}"`; do final_path=${CONFIG}/${m}/${FINAL_CONFIG} if [ -z $3 ]; then echo "Found ${f}, append to regular config file" cat "${f}" >> ${final_path} else echo "Found ${f}, prepend to regular config file" cat ${f} > /tmp/config echo -e '\n' >> /tmp/config cat ${final_path} >> /tmp/config mv /tmp/config ${final_path} fi done fi } function usage() { echo "${0}: manage package installation, environment divergence and external location for config, see README." echo "usage: [WM_RESTART=1] [INIT=1] $0 [${ENVIRONMENTS}]" exit 0 } # Use XDG_CONFIG_HOME if defined, default otherwise CONFIG=${XDG_CONFIG_HOME:-$HOME/.config} ENV=${1} for m in ${MERGE_DIRS}; do echo ${m} if [ -f "${CONFIG}/${m}/${MERGE_CONFIG_FOLDER}/above" ]; then merge_config $m ${ENV} true else merge_config $m ${ENV} fi done if [ ! -z "$INIT" ]; then echo -e "* Installing base Arch packages..." yay -Syu --needed --noconfirm - < ${CONFIG}/${ARCH_PACKAGES}/${FINAL_CONFIG} echo -e "* Changing shell to ZSH..." sudo chsh -s $(which zsh) # https://man.archlinux.org/man/rofi-dmenu.5 echo -e "* Symlink dmenu → rofi..." sudo ln -sf /usr/bin/rofi /usr/bin/dmenu echo -e "* Enabling required systemd units..." sudo systemctl enable --now NetworkManager sudo systemctl enable --now systemd-timesyncd # iwd will be used as a backend for NetworkManager sudo systemctl disable wpa_supplicant echo -e "* Ensure hardware clock is up to date..." sudo hwclock --systohc # So that "Open in Terminal" works inc Nemo echo -e "* Make 'Open Terminal' work in Nemo..." gsettings set org.cinnamon.desktop.default-applications.terminal exec i3-sensible-terminal # For screenshots echo -e "* Install pychee for uploading screenshots on Lychee..." pip install --break-system-packages pychee # Additionnal plugins for ZSH echo -e "* Install ZSH plugins for oh-my-zsh..." sudo git clone https://github.com/zsh-users/zsh-syntax-highlighting.git /usr/share/oh-my-zsh/plugins/zsh-syntax-highlighting sudo git clone https://github.com/zsh-users/zsh-autosuggestions /usr/share/oh-my-zsh/plugins/zsh-autosuggestions sudo git clone https://github.com/unixorn/fzf-zsh-plugin.git /usr/share/oh-my-zsh/plugins/fzf-zsh-plugin # Basic directory structure echo -e "* Create base home directories..." mkdir -p ~/documents ~/images/screenshots ~/videos ~/downloads fi if [ ! -z ${ENV} ]; then echo -e "\n=== Create symlink to *.${ENV} regular files ===" # Take all specific files and create a symlink pointing to it without the extension # This file will be used by applications for f in `find ${CONFIG} -type f -name "*.${ENV}"`; do echo "${f%.*} → ${f}" ln -sf ${f} ${f%.*} done # Take care of config files at home level, outside ${CONFIG} (e.g. Xresources) for f in `find ${HOME} -maxdepth 1 -mindepth 1 -type f -name "*.${ENV}"`; do echo "${f%.*} → ${f}" ln -sf ${f} ${f%.*} done fi echo -e "\n=== Copy changed configuration which resides in outer directory ===" # Destination files are regular files for f in `find ${CONFIG} -type f -name ${DEST_FILENAME}`; do DIR=`dirname "${f}"` DEST=`cat ${f}` # Get all files, either regular files or symlinks, which are not the destination file nor specific desktop/laptop files # This is because if desktop/laptop files exist, they already have a symlink pointing to them at this stage # We want to get the path relative to the directory we are searching in, so subfolders are kept when copying for config_file in `find ${DIR} -regextype posix-extended -mindepth 1 \( -type f -o -type l \) -not \( -regex "${ENV_EXT_REGEXP}" -o -name "${DEST_FILENAME}" \) -exec realpath --relative-to ${DIR} {} \;`; do # If we have to copy to a subfolder, extract it if echo ${config_file} | grep -q '/'; then subfolder=${config_file%/*} else subfolder='' fi filename=${config_file##*/} # Now copy to destination real_dest=${DEST}/${subfolder} sudo mkdir -p ${real_dest} absolute_source=`realpath "${DIR}/${config_file}"` check_copy "${absolute_source}" "sudo cp ${absolute_source} ${real_dest}" "sudo rm ${real_dest}/${filename}" done done if [ ! -z "${WM_RESTART}" ]; then echo -e "\n=== Restart graphical environment ===" # Reload i3 configuration i3-msg restart # Restart picom due to this bug https://github.com/yshui/picom/issues/166 killall picom; picom &>/dev/null & fi