mirror of
https://github.com/danbulant/dots-hyprland
synced 2026-05-19 04:08:48 +00:00
308 lines
10 KiB
Bash
308 lines
10 KiB
Bash
#!/bin/bash
|
|
# This script updates the dotfiles by fetching the latest version from the Git repository and then replacing files
|
|
# that have not been modified by the user to preserve changes. The remaining files will be replaced with the new ones.
|
|
|
|
source ./scriptdata/environment-variables
|
|
|
|
set -euo pipefail
|
|
cd "$(dirname "$0")"
|
|
export base="$(pwd)"
|
|
|
|
# Define colors
|
|
GREEN="\033[0;32m"
|
|
RED="\033[0;31m"
|
|
BLUE="\033[0;34m"
|
|
CYAN="\033[0;36m"
|
|
YELLOW="\033[1;33m"
|
|
MAGENTA="\033[0;35m"
|
|
RESET="\033[0m"
|
|
|
|
# Define paths to update
|
|
folders=(".config" ".local/bin" ".local/share" ".local/state")
|
|
excludes=(".config/hypr/custom" ".config/ags/user_options.js" ".config/hypr/hyprland.conf")
|
|
|
|
get_checksum() {
|
|
# Get the checksum of a specific file
|
|
local file="$1"
|
|
md5sum "$file" | awk '{print $1}'
|
|
}
|
|
|
|
file_in_excludes() {
|
|
# Check if a file is in the exclude_folders
|
|
local file="$1"
|
|
for exc in "${excludes[@]}"; do
|
|
if [[ $file == "$exc"* ]]; then
|
|
return 0
|
|
fi
|
|
done
|
|
return 1
|
|
}
|
|
|
|
get_destination() {
|
|
# Get the correct destination of the file based on XDG base dirs
|
|
local file="$1"
|
|
local localdir="$(echo $file | cut -d/ -f1-2)"
|
|
local everything_else="$(echo $file | cut -d/ -f3-)"
|
|
# Check if path is config
|
|
if [ "$(echo $file | cut -d/ -f1)" = ".config" ]; then
|
|
printf "$XDG_CONFIG_HOME/$(echo $file | cut -d/ -f2-)"
|
|
|
|
# Local directory
|
|
elif [ "$localdir" = ".local/bin" ]; then
|
|
printf "$XDG_BIN_HOME/$everything_else"
|
|
|
|
# There are no files in either of the following right now, but putting it here just in case as .local was specified
|
|
elif [ "$localdir" = ".local/share" ]; then
|
|
printf "$XDG_DATA_HOME/$everything_else"
|
|
elif [ "$localdir" = ".local/state" ]; then
|
|
printf "$XDG_STATE_HOME/$everything_else"
|
|
fi
|
|
}
|
|
|
|
# Greetings!
|
|
cat << 'EOF'
|
|
###################################################################################################
|
|
| |
|
|
| Hi there! |
|
|
| |
|
|
| This script will update your dotfiles (.config, .local, etc) by retrieving the latest version |
|
|
| from the Git repository and then replacing the old config files with the updated ones. |
|
|
| To preserve your customizations, it will ask you if you wanna keep some customized |
|
|
| files untouched. |
|
|
| |
|
|
###################################################################################################
|
|
EOF
|
|
|
|
read -rp "Do you want to continue? [Y/n] " REPLY
|
|
echo
|
|
if [[ $REPLY =~ ^[Nn]$ ]]; then
|
|
echo -e "${RED}Exiting.${RESET}"
|
|
exit 0
|
|
fi
|
|
|
|
# End of Greetings
|
|
|
|
current_branch=$(git rev-parse --abbrev-ref HEAD)
|
|
|
|
# fetch the latest version of the repository
|
|
if ! git fetch; then
|
|
echo -e "${RED}Failed to fetch the latest version of the repository. Exiting...${RESET}"
|
|
exit 1
|
|
fi
|
|
|
|
# Check if there are any changes
|
|
if [[ $(git rev-list HEAD...origin/"$current_branch" --count) -eq 0 ]]; then
|
|
echo -e "${GREEN}Repository is already up-to-date. Do not run git pull before this script. Exiting...${RESET}"
|
|
exit 0
|
|
fi
|
|
echo -e "${CYAN}Excluding files and folders that remain untouched:${RESET} ${excludes[@]}"
|
|
|
|
# Then check which files have been customized by the user since the last update to preserve user configurations
|
|
modified_files=()
|
|
|
|
# Find all files in the specified folders and their subfolders
|
|
while IFS= read -r -d '' file; do
|
|
# If the file is not in the home directory, skip it
|
|
if [[ ! -f "$(get_destination $file)" ]] || file_in_excludes "$file"; then
|
|
echo -e "${YELLOW}Skipping $file${RESET}"
|
|
continue
|
|
fi
|
|
|
|
# Calculate checksums
|
|
base_checksum=$(get_checksum "$base/$file")
|
|
home_checksum=$(get_checksum "$(get_destination $file)")
|
|
|
|
# Compare checksums and add to modified_files if necessary
|
|
if [[ $base_checksum != $home_checksum ]]; then
|
|
modified_files+=("$file")
|
|
fi
|
|
done < <(find "${folders[@]}" -type f -print0)
|
|
|
|
echo
|
|
|
|
# Output all modified files
|
|
if [[ ${#modified_files[@]} -gt 0 ]]; then
|
|
echo -e "${MAGENTA}Customized Files detected: ${RESET}The following files have been customized by you or your system:"
|
|
for file in "${modified_files[@]}"; do
|
|
echo -e "${BLUE}$file${RESET}"
|
|
done
|
|
else
|
|
read -rp "${YELLOW}No files detected that have been customized since the last update. All files will be replaced. Are you sure you want to continue? [Y/n] ${RESET}" REPLY
|
|
echo
|
|
if [[ $REPLY =~ ^[Nn]$ ]]; then
|
|
echo -e "${RED}Exiting.${RESET}"
|
|
exit 0
|
|
fi
|
|
fi
|
|
|
|
cat << 'EOF'
|
|
Do you want to keep these files untouched?
|
|
[Y] Yes, keep them.
|
|
[n] No, replace them.
|
|
[i] Check the files individually.
|
|
EOF
|
|
read -rp "Answer: " REPLY
|
|
echo
|
|
|
|
case $REPLY in
|
|
[Nn])
|
|
echo -e "${RED}Replacing all files.${RESET}"
|
|
modified_files=()
|
|
;;
|
|
[Ii])
|
|
new_modified_files=()
|
|
replaced_files=()
|
|
for file in "${modified_files[@]}"; do
|
|
read -rp "Do you want to keep $file untouched? [Y/n] " REPLY
|
|
echo
|
|
if [[ $REPLY =~ ^[Nn]$ ]]; then
|
|
replaced_files+=("$file")
|
|
else
|
|
new_modified_files+=("$file")
|
|
fi
|
|
done
|
|
modified_files=("${new_modified_files[@]}")
|
|
echo -e "${CYAN}_____________________________________________________${RESET}"
|
|
echo -e "${MAGENTA}These User configured/modified files will be kept:${RESET}"
|
|
for file in "${modified_files[@]}"; do
|
|
echo -e "${BLUE}$file${RESET}"
|
|
done
|
|
echo -e "${CYAN}_____________________________________________________${RESET}"
|
|
echo -e "${MAGENTA}These User configured/modified files will be replaced:${RESET}"
|
|
for file in "${replaced_files[@]}"; do
|
|
echo -e "${BLUE}$file${RESET}"
|
|
done
|
|
echo -e "${CYAN}_____________________________________________________${RESET}"
|
|
read -rp "Do you want to continue? [y/N] " REPLY
|
|
echo
|
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
echo -e "${RED}Exiting...${RESET}"
|
|
exit 0
|
|
fi
|
|
;;
|
|
*)
|
|
echo -e "${GREEN}Keeping every customized file${RESET}"
|
|
;;
|
|
esac
|
|
|
|
# Update the repository
|
|
if ! git pull; then
|
|
echo -e "${RED}Git pull failed. Consider recloning the project or resolving conflicts manually.${RESET}"
|
|
read -rp "Should I clone the repository to a temporary folder in cache and copy the files from there? [y/N] " REPLY
|
|
echo
|
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
echo -e "${RED}Exiting...${RESET}"
|
|
exit 1
|
|
fi
|
|
|
|
mkdir -p ./cache
|
|
temp_folder=$(mktemp -d -p ./cache)
|
|
git clone --branch "$current_branch" https://github.com/end-4/dots-hyprland/ --depth=1 "$temp_folder"
|
|
# Replace the existing dotfiles with the new ones
|
|
for folder in "${folders[@]}"; do
|
|
find "$temp_folder/$folder" -print0 | while IFS= read -r -d '' file; do
|
|
file=${file//$temp_folder\//}
|
|
if [[ -d "$temp_folder/$file" ]]; then
|
|
mkdir -p "$(get_destination $file)"
|
|
fi
|
|
if [[ -f "$temp_folder/$file" ]] && ! file_in_excludes "$file" && [[ ! " ${modified_files[*]} " =~ " $file " ]]; then
|
|
destination=$(get_destination $file)
|
|
echo -e "${BLUE}Replacing $destination ...${RESET}"
|
|
mkdir -p "$(dirname "$destination")"
|
|
cp -f "$temp_folder/$file" "$destination"
|
|
fi
|
|
done
|
|
done
|
|
|
|
deleted_files=()
|
|
renamed_files=()
|
|
|
|
# Extract deleted files and save to variable
|
|
deleted_files=$(git diff --name-status HEAD origin/$current_branch | awk '$1 == "D" {print $2}')
|
|
|
|
# Extract renamed files and save to variable
|
|
renamed_files=$(git diff --name-status HEAD origin/$current_branch | awk '$1 ~ /^R/ {print $2}')
|
|
|
|
|
|
files_to_remove=()
|
|
|
|
for file in $deleted_files; do
|
|
|
|
if ! file_in_excludes "$file" && [[ ! " ${modified_files[*]} " =~ " $file " ]]; then
|
|
files_to_remove+=("$file")
|
|
fi
|
|
done
|
|
for file in $renamed_files; do
|
|
if ! file_in_excludes "$file" && [[ ! " ${modified_files[*]} " =~ " $file " ]]; then
|
|
files_to_remove+=("$file")
|
|
fi
|
|
done
|
|
|
|
# Remove files
|
|
for file in "${files_to_remove[@]}"; do
|
|
echo -e "${YELLOW}Removing $file ...${RESET}"
|
|
homefile="$(get_destination $file)"
|
|
if [[ -f "$homefile" ]]; then
|
|
rm -rf "$homefile"
|
|
fi
|
|
done
|
|
|
|
echo -e "${GREEN}New dotfiles have been copied. Cleaning up temporary folder...${RESET}"
|
|
rm -rf "$temp_folder"
|
|
echo -e "${GREEN}Done. You may exit now.${RESET}"
|
|
exit 0
|
|
fi
|
|
|
|
|
|
# Check git diff to determine which files have been removed and which have been renamed
|
|
deleted_files=()
|
|
renamed_files=()
|
|
|
|
# Extract deleted files and save to variable
|
|
deleted_files=$(git diff --name-status @{1} | awk '$1 == "D" {print $2}')
|
|
|
|
# Extract renamed files and save to variable
|
|
renamed_files=$(git diff --name-status @{1} | awk '$1 ~ /^R/ {print $2}')
|
|
|
|
|
|
files_to_remove=()
|
|
|
|
for file in $deleted_files; do
|
|
|
|
if ! file_in_excludes "$file" && [[ ! " ${modified_files[*]} " =~ " $file " ]]; then
|
|
files_to_remove+=("$file")
|
|
fi
|
|
done
|
|
for file in $renamed_files; do
|
|
if ! file_in_excludes "$file" && [[ ! " ${modified_files[*]} " =~ " $file " ]]; then
|
|
files_to_remove+=("$file")
|
|
fi
|
|
done
|
|
|
|
# Remove files
|
|
for file in "${files_to_remove[@]}"; do
|
|
echo -e "${YELLOW}Removing $file ...${RESET}"
|
|
homefile=$(get_destination $file)
|
|
if [[ -f "$homefile" ]]; then
|
|
rm -rf "$homefile"
|
|
fi
|
|
done
|
|
|
|
|
|
# Replace unmodified files
|
|
for folder in "${folders[@]}"; do
|
|
find "$folder" -print0 | while IFS= read -r -d '' file; do
|
|
if [[ -d "$file" ]]; then
|
|
mkdir -p "$(get_destination $file)"
|
|
fi
|
|
if [[ -f "$file" ]] && ! file_in_excludes "$file" && [[ ! " ${modified_files[*]} " =~ " $file " ]]; then
|
|
destination="$(get_destination $file)"
|
|
echo -e "${BLUE}Replacing \"$destination\" ...${RESET}"
|
|
mkdir -p "$(dirname "$destination")"
|
|
cp -f "$base/$file" "$destination"
|
|
fi
|
|
done
|
|
done
|
|
|
|
echo -e "${GREEN}Done. You may exit now.${RESET}"
|
|
|