diff --git a/sdata/lib/environment-variables.sh b/sdata/lib/environment-variables.sh index 5344be4c7..9b2a8ce91 100644 --- a/sdata/lib/environment-variables.sh +++ b/sdata/lib/environment-variables.sh @@ -5,6 +5,7 @@ XDG_CONFIG_HOME=${XDG_CONFIG_HOME:-$HOME/.config} XDG_DATA_HOME=${XDG_DATA_HOME:-$HOME/.local/share} XDG_STATE_HOME=${XDG_STATE_HOME:-$HOME/.local/state} BACKUP_DIR=${BACKUP_DIR:-$HOME/ii-original-dots-backup} +INSTALLED_LISTFILE=${INSTALLED_LISTFILE:-$XDG_CONFIG_HOME/illogical-impulse/installed_listfile} STY_RED='\e[31m' diff --git a/sdata/lib/functions.sh b/sdata/lib/functions.sh index 54d4c3b73..a79e5256b 100644 --- a/sdata/lib/functions.sh +++ b/sdata/lib/functions.sh @@ -415,3 +415,13 @@ function ensure_cmds(){ install_cmds "${not_found_cmds[@]}" fi } + +function dedup_and_sort_listfile(){ + if test -f "$1"; then + echo "File not found: $1" >&2; return 2 + else + temp="$(mktemp)" + sort -u -- "$1" > "$temp" + mv -f -- "$temp" "$2" + fi +} diff --git a/sdata/subcmd-install/3.files-exp.sh b/sdata/subcmd-install/3.files-exp.sh index e924ef1d5..94567af4c 100644 --- a/sdata/subcmd-install/3.files-exp.sh +++ b/sdata/subcmd-install/3.files-exp.sh @@ -217,16 +217,16 @@ for pattern in "${patterns[@]}"; do case "$mode" in "sync") if [[ -d "$from" ]]; then - warning_rsync_delete + warning_overwrite v rsync -av --delete "${excludes[@]}" "$from/" "$to/" else - warning_rsync_normal + warning_overwrite # For files, don't use trailing slash and don't use --delete v rsync -av "${excludes[@]}" "$from" "$to" fi ;; "soft") - warning_rsync_normal + warning_overwrite if [[ -d "$from" ]]; then v rsync -av "${excludes[@]}" "$from/" "$to/" else diff --git a/sdata/subcmd-install/3.files-legacy.sh b/sdata/subcmd-install/3.files-legacy.sh index ebf549734..6c2d7ddf4 100644 --- a/sdata/subcmd-install/3.files-legacy.sh +++ b/sdata/subcmd-install/3.files-legacy.sh @@ -3,7 +3,44 @@ # shellcheck shell=bash -function copy_file_s_t(){ +function gen_firstrun(){ + x mkdir -p "$(dirname ${FIRSTRUN_FILE})" + x mkdir -p "$(dirname ${INSTALLED_LISTFILE})" + x touch "${FIRSTRUN_FILE}" + realpath -se "${FIRSTRUN_FILE}" >> "${INSTALLED_LISTFILE}" +} +cp_file(){ + # NOTE: This function is only for using in other functions + x mkdir -p "$(dirname $2)" + x mkdir -p "$(dirname ${INSTALLED_LISTFILE})" + x cp -f "$1" "$2" + realpath -se "$2" >> "${INSTALLED_LISTFILE}" +} +rsync_dir(){ + # NOTE: This function is only for using in other functions + x mkdir -p "$2" + x mkdir -p "$(dirname ${INSTALLED_LISTFILE})" + local dest="$(realpath -se $2)" + rsync -a --out-format='%i %n' "$1"/ "$2"/ | awk -v d="$dest" '$1 ~ /^>/{ sub(/^[^ ]+ /,""); printf d "/" $0 "\n" }' >> "${INSTALLED_LISTFILE}" +} +rsync_dir__sync(){ + # NOTE: This function is only for using in other functions + x mkdir -p "$2" + x mkdir -p "$(dirname ${INSTALLED_LISTFILE})" + local dest="$(realpath -se $2)" + rsync -a --delete --out-format='%i %n' "$1"/ "$2"/ | awk -v d="$dest" '$1 ~ /^>/{ sub(/^[^ ]+ /,""); printf d "/" $0 "\n" }' >> "${INSTALLED_LISTFILE}" +} +function install_file(){ + # NOTE: Do not add prefix `v` or `x` when using this function + local s=$1 + local t=$2 + if [ -f $t ];then + warning_overwrite + fi + v cp_file $s $t +} +function install_file__auto_backup(){ + # NOTE: Do not add prefix `v` or `x` when using this function local s=$1 local t=$2 if [ -f $t ];then @@ -11,30 +48,49 @@ function copy_file_s_t(){ if ${INSTALL_FIRSTRUN};then echo -e "${STY_BLUE}[$0]: It seems to be the firstrun.${STY_RST}" v mv $t $t.old - v cp -f $s $t + v cp_file $s $t else echo -e "${STY_BLUE}[$0]: It seems not a firstrun.${STY_RST}" - v cp -f $s $t.new + v cp_file $s $t.new fi else echo -e "${STY_GREEN}[$0]: \"$t\" does not exist yet.${STY_RST}" - v cp $s $t + v cp_file $s $t fi } -function copy_dir_s_t(){ +function install_dir(){ + # NOTE: Do not add prefix `v` or `x` when using this function + local s=$1 + local t=$2 + if [ -d $t ];then + warning_overwrite + fi + rsync_dir $s $t +} +function install_dir__sync(){ + # NOTE: Do not add prefix `v` or `x` when using this function + local s=$1 + local t=$2 + if [ -d $t ];then + warning_overwrite + fi + rsync_dir__sync $s $t +} +function install_dir__skip_existed(){ + # NOTE: Do not add prefix `v` or `x` when using this function local s=$1 local t=$2 if [ -d $t ];then echo -e "${STY_BLUE}[$0]: \"$t\" already exists, will not do anything.${STY_RST}" else echo -e "${STY_YELLOW}[$0]: \"$t\" does not exist yet.${STY_RST}" - v rsync -av --delete $s/ $t/ + v rsync_dir $s $t fi } ##################################################################################### # In case some dirs does not exists -v mkdir -p $XDG_BIN_HOME $XDG_CACHE_HOME $XDG_CONFIG_HOME $XDG_DATA_HOME/icons +v mkdir -p $XDG_BIN_HOME $XDG_CACHE_HOME $XDG_CONFIG_HOME $XDG_DATA_HOME case "${INSTALL_FIRSTRUN}" in # When specify --firstrun @@ -60,11 +116,11 @@ case "${SKIP_MISCCONF}" in for i in $(find dots/.config/ -mindepth 1 -maxdepth 1 ! -name 'quickshell' ! -name 'fish' ! -name 'hypr' ! -name 'fontconfig' -exec basename {} \;); do # i="dots/.config/$i" echo "[$0]: Found target: dots/.config/$i" - if [ -d "dots/.config/$i" ];then warning_rsync_delete; v rsync -av --delete "dots/.config/$i/" "$XDG_CONFIG_HOME/$i/" - elif [ -f "dots/.config/$i" ];then warning_rsync_normal; v rsync -av "dots/.config/$i" "$XDG_CONFIG_HOME/$i" + if [ -d "dots/.config/$i" ];then install_dir__sync "dots/.config/$i" "$XDG_CONFIG_HOME/$i" + elif [ -f "dots/.config/$i" ];then install_file "dots/.config/$i" "$XDG_CONFIG_HOME/$i" fi done - warning_rsync_delete; v rsync -av "dots/.local/share/konsole/" "${XDG_DATA_HOME:-$HOME/.local/share}"/konsole/ + install_dir "dots/.local/share/konsole" "${XDG_DATA_HOME:-$HOME/.local/share}"/konsole ;; esac @@ -72,14 +128,14 @@ case "${SKIP_QUICKSHELL}" in true) sleep 0;; *) # Should overwriting the whole directory not only ~/.config/quickshell/ii/ cuz https://github.com/end-4/dots-hyprland/issues/2294#issuecomment-3448671064 - warning_rsync_delete; v rsync -av --delete dots/.config/quickshell/ "$XDG_CONFIG_HOME"/quickshell/ + install_dir__sync dots/.config/quickshell "$XDG_CONFIG_HOME"/quickshell ;; esac case "${SKIP_FISH}" in true) sleep 0;; *) - warning_rsync_delete; v rsync -av --delete dots/.config/fish/ "$XDG_CONFIG_HOME"/fish/ + install_dir__sync dots/.config/fish "$XDG_CONFIG_HOME"/fish ;; esac @@ -87,8 +143,8 @@ case "${SKIP_FONTCONFIG}" in true) sleep 0;; *) case "$FONTSET_DIR_NAME" in - "") warning_rsync_delete; v rsync -av --delete dots/.config/fontconfig/ "$XDG_CONFIG_HOME"/fontconfig/ ;; - *) warning_rsync_delete; v rsync -av --delete dots-extra/fontsets/$FONTSET_DIR_NAME/ "$XDG_CONFIG_HOME"/fontconfig/ ;; + "") install_dir__sync dots/.config/fontconfig "$XDG_CONFIG_HOME"/fontconfig ;; + *) install_dir__sync dots-extra/fontsets/$FONTSET_DIR_NAME "$XDG_CONFIG_HOME"/fontconfig ;; esac;; esac @@ -96,30 +152,26 @@ esac case "${SKIP_HYPRLAND}" in true) sleep 0;; *) - if ! [ -d "$XDG_CONFIG_HOME"/hypr ]; then v mkdir -p "$XDG_CONFIG_HOME"/hypr ; fi - warning_rsync_delete; v rsync -av --delete dots/.config/hypr/hyprland/ "$XDG_CONFIG_HOME"/hypr/hyprland/ + install_dir__sync dots/.config/hypr/hyprland "$XDG_CONFIG_HOME"/hypr/hyprland for i in hypr{land,lock}.conf {monitors,workspaces}.conf ; do - copy_file_s_t "dots/.config/hypr/$i" "${XDG_CONFIG_HOME}/hypr/$i" + install_file__auto_backup "dots/.config/hypr/$i" "${XDG_CONFIG_HOME}/hypr/$i" done for i in hypridle.conf ; do if [[ "${INSTALL_VIA_NIX}" == true ]]; then - copy_file_s_t "dots-extra/via-nix/$i" "${XDG_CONFIG_HOME}/hypr/$i" + install_file__auto_backup "dots-extra/via-nix/$i" "${XDG_CONFIG_HOME}/hypr/$i" else - copy_file_s_t "dots/.config/hypr/$i" "${XDG_CONFIG_HOME}/hypr/$i" + install_file__auto_backup "dots/.config/hypr/$i" "${XDG_CONFIG_HOME}/hypr/$i" fi done if [ "$OS_GROUP_ID" = "fedora" ];then v bash -c "printf \"# For fedora to setup polkit\nexec-once = /usr/libexec/kf6/polkit-kde-authentication-agent-1\n\" >> ${XDG_CONFIG_HOME}/hypr/hyprland/execs.conf" fi - copy_dir_s_t "dots/.config/hypr/custom" "${XDG_CONFIG_HOME}/hypr/custom" + install_dir__skip_existed "dots/.config/hypr/custom" "${XDG_CONFIG_HOME}/hypr/custom" ;; esac -declare -a arg_excludes=() -# some foldes (eg. .local/bin) should be processed separately to avoid `--delete' for rsync, -# since the files here come from different places, not only about one program. -# v rsync -av "dots/.local/bin/" "$XDG_BIN_HOME" # No longer needed since scripts are no longer in ~/.local/bin -v cp -f "dots/.local/share/icons/illogical-impulse.svg" "${XDG_DATA_HOME}"/icons/illogical-impulse.svg +install_file "dots/.local/share/icons/illogical-impulse.svg" "${XDG_DATA_HOME}"/icons/illogical-impulse.svg -v touch "${FIRSTRUN_FILE}" +v dedup_and_sort_listfile "${INSTALLED_LISTFILE}" "${INSTALLED_LISTFILE}" +v gen_firstrun diff --git a/sdata/subcmd-install/3.files.sh b/sdata/subcmd-install/3.files.sh index 07ade39f3..33f3e7eeb 100644 --- a/sdata/subcmd-install/3.files.sh +++ b/sdata/subcmd-install/3.files.sh @@ -4,15 +4,9 @@ printf "${STY_CYAN}[$0]: 3. Copying config files\n${STY_RST}" # shellcheck shell=bash -function warning_rsync_delete(){ +function warning_overwrite(){ printf "${STY_YELLOW}" - printf "The command below uses --delete for rsync which overwrites the destination folder.\n" - printf "${STY_RST}" -} - -function warning_rsync_normal(){ - printf "${STY_YELLOW}" - printf "The command below uses rsync which overwrites the destination.\n" + printf "The command below overwrites the destination.\n" printf "${STY_RST}" }