347 lines
10 KiB
Bash
Executable File
347 lines
10 KiB
Bash
Executable File
#!/bin/sh
|
|
# SPDX-License-Identifier: AGPL-3.0-only
|
|
# Copyright 2022 Sxmo Contributors
|
|
|
|
# include common definitions
|
|
# shellcheck source=scripts/core/sxmo_common.sh
|
|
. sxmo_common.sh
|
|
|
|
. /etc/profile.d/sxmo_init.sh
|
|
_sxmo_load_environments
|
|
|
|
smartdiff() {
|
|
if command -v colordiff > /dev/null; then
|
|
colordiff "$@"
|
|
else
|
|
diff "$@"
|
|
fi
|
|
}
|
|
|
|
fetchversion() {
|
|
head -n5 "$1" | grep -m1 "configversion: " | sed 's|.*configversion: \(.*\)|\1|'
|
|
}
|
|
|
|
resolvedifference() {
|
|
userfile="$1"
|
|
defaultfile="$2"
|
|
|
|
(
|
|
printf "\e[31mThe file \e[32m%s\e[31m differs\e[0m\n" "$userfile"
|
|
smartdiff -ud "$defaultfile" "$userfile"
|
|
) | more
|
|
|
|
printf "\e[31mMigration options for \e[32m%s\e[31m:\e[0m\n" "$userfile"
|
|
|
|
printf "1 - Use [d]efault. Apply the Sxmo default, discarding all your own changes.\n"
|
|
printf "2 - Open [e]ditor and merge the changes yourself; take care to set the same configversion.\n"
|
|
printf "3 - Use your [u]ser version as-is; you verified it's compatible. (Auto-updates configversion only).\n"
|
|
printf "4 - [i]gnore, do not resolve and don't change anything, ask again next time. (default)\n"
|
|
|
|
printf "\e[33mHow do you want to resolve this? Choose one of the options above [1234deui]\e[0m "
|
|
|
|
read -r reply < /dev/tty
|
|
abort=0
|
|
case "$reply" in
|
|
[1dD]*)
|
|
#use default
|
|
case "$userfile" in
|
|
*hooks*)
|
|
#just remove the user hook, will use default automatically
|
|
rm "$userfile"
|
|
abort=1 #no need for any further cleanup
|
|
;;
|
|
*)
|
|
cp "$defaultfile" "$userfile" || abort=1
|
|
;;
|
|
esac
|
|
;;
|
|
[2eE]*)
|
|
#open editor with both files and the diff
|
|
export DIFFTOOL="${DIFFTOOL:-vimdiff}"
|
|
if [ -n "$DIFFTOOL" ] && command -v "$DIFFTOOL" >/dev/null; then # ex vimdiff
|
|
set -- "$DIFFTOOL" "$defaultfile" "$userfile"
|
|
else
|
|
diff -u "$defaultfile" "$userfile" > "${XDG_RUNTIME_DIR}/migrate.diff"
|
|
# shellcheck disable=SC2086
|
|
set -- $EDITOR "$userfile" "$defaultfile" "${XDG_RUNTIME_DIR}/migrate.diff"
|
|
fi
|
|
|
|
if ! "$@"; then
|
|
#user may bail editor, in which case we ignore everything
|
|
abort=1
|
|
fi
|
|
|
|
if [ -z "$DIFFTOOL" ]; then
|
|
rm "${XDG_RUNTIME_DIR}/migrate.diff"
|
|
fi
|
|
;;
|
|
[3uU]*)
|
|
#update configversion automatically
|
|
refversion="$(fetchversion "$reffile")"
|
|
userversion="$(fetchversion "$userfile")"
|
|
if [ -n "$userversion" ]; then
|
|
sed -i "s/configversion: $userversion/configversion: $refversion/" "$userfile" || abort=1
|
|
elif [ -n "$refversion" ]; then
|
|
refline="$(head -n5 "$reffile" | grep -m1 "configversion: ")"
|
|
# fall back in case the userfile doesn't contain a configversion at all yet
|
|
sed -i "2i$refline" "$userfile" || abort=1
|
|
fi
|
|
;;
|
|
*)
|
|
abort=1
|
|
;;
|
|
esac
|
|
|
|
if [ "$abort" -eq 0 ]; then
|
|
#finish the migration, removing .needs-migration and moving to right place
|
|
case "$userfile" in
|
|
*needs-migration)
|
|
mv -f "$userfile" "${userfile%.needs-migration}"
|
|
;;
|
|
esac
|
|
fi
|
|
printf "\n"
|
|
}
|
|
|
|
checkconfigversion() {
|
|
userfile="$1"
|
|
reffile="$2"
|
|
if [ ! -e "$userfile" ] || [ ! -e "$reffile" ]; then
|
|
#if the userfile doesn't exist then we revert to default anyway so it's considered up to date
|
|
return 0
|
|
fi
|
|
|
|
refversion="$(fetchversion "$reffile")"
|
|
if [ -z "$refversion" ]; then
|
|
#no ref version found, check file diff instead
|
|
if diff "$reffile" "$userfile" > /dev/null; then
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
userversion="$(fetchversion "$userfile")"
|
|
if [ -z "$userversion" ]; then
|
|
#no user version found, check file contents instead
|
|
tmpreffile="${XDG_RUNTIME_DIR}/versioncheck"
|
|
grep -v "configversion: " "$reffile" > "$tmpreffile"
|
|
if diff "$tmpreffile" "$userfile" > /dev/null; then
|
|
rm "$tmpreffile"
|
|
return 0
|
|
else
|
|
rm "$tmpreffile"
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
[ "$refversion" = "$userversion" ]
|
|
}
|
|
|
|
defaultconfig() {
|
|
defaultfile="$1"
|
|
userfile="$2"
|
|
filemode="$3"
|
|
if [ -e "$userfile.needs-migration" ] && { [ "$MODE" = "interactive" ] || [ "$MODE" = "all" ]; }; then
|
|
resolvedifference "$userfile.needs-migration" "$defaultfile"
|
|
chmod "$filemode" "$userfile" 2> /dev/null
|
|
elif [ ! -r "$userfile" ]; then
|
|
mkdir -p "$(dirname "$userfile")"
|
|
sxmo_log "Installing default configuration $userfile..."
|
|
cp "$defaultfile" "$userfile"
|
|
chmod "$filemode" "$userfile"
|
|
elif [ "$MODE" = "reset" ]; then
|
|
if [ ! -e "$userfile.needs-migration" ]; then
|
|
mv "$userfile" "$userfile.needs-migration"
|
|
else
|
|
sxmo_log "$userfile was already flagged for needing migration; not overwriting the older one"
|
|
fi
|
|
cp "$defaultfile" "$userfile"
|
|
chmod "$filemode" "$userfile"
|
|
elif ! checkconfigversion "$userfile" "$defaultfile" || [ "$MODE" = "all" ]; then
|
|
case "$MODE" in
|
|
"interactive"|"all")
|
|
resolvedifference "$userfile" "$defaultfile"
|
|
;;
|
|
"sync")
|
|
sxmo_log "$userfile is out of date, disabling and marked as needing migration..."
|
|
[ ! -e "$userfile.needs-migration" ] && cp "$userfile" "$userfile.needs-migration" #never overwrite older .needs-migration files, they take precendence
|
|
chmod "$filemode" "$userfile.needs-migration"
|
|
cp "$defaultfile" "$userfile"
|
|
chmod "$filemode" "$userfile"
|
|
;;
|
|
esac
|
|
fi
|
|
}
|
|
|
|
checkhooks() {
|
|
if ! [ -e "$XDG_CONFIG_HOME/sxmo/hooks/" ]; then
|
|
return
|
|
fi
|
|
for hook in \
|
|
"$XDG_CONFIG_HOME/sxmo/hooks/"* \
|
|
${SXMO_DEVICE_NAME:+"$XDG_CONFIG_HOME/sxmo/hooks/$SXMO_DEVICE_NAME/"*}; do
|
|
{ [ -e "$hook" ] && [ -f "$hook" ];} || continue #sanity check because shell enters loop even when there are no files in dir (null glob)
|
|
|
|
[ -h "$hook" ] && continue # shallow symlink
|
|
|
|
if printf %s "$hook" | grep -q "/$SXMO_DEVICE_NAME/"; then
|
|
# We also compare the device user hook to the system
|
|
# default version
|
|
DEFAULT_PATH="$(xdg_data_path sxmo/default_hooks/"$SXMO_DEVICE_NAME"/):$(xdg_data_path sxmo/default_hooks/)"
|
|
else
|
|
# We dont want to compare a default user hook to the device
|
|
# system version
|
|
DEFAULT_PATH="$(xdg_data_path sxmo/default_hooks/)"
|
|
fi
|
|
|
|
if [ "$MODE" = "reset" ]; then
|
|
if [ ! -e "$hook.needs-migration" ]; then
|
|
mv "$hook" "$hook.needs-migration" #move the hook away
|
|
else
|
|
sxmo_log "$hook was already flagged for needing migration; not overwriting the older one"
|
|
rm "$hook"
|
|
fi
|
|
continue
|
|
fi
|
|
case "$hook" in
|
|
*.needs-migration)
|
|
defaulthook="$(PATH="$DEFAULT_PATH" command -v "$(basename "$hook" ".needs-migration")")"
|
|
[ "$MODE" = sync ] && continue # ignore this already synced hook
|
|
;;
|
|
*.backup)
|
|
#skip
|
|
continue
|
|
;;
|
|
*)
|
|
#if there is already one marked as needing migration, use that one instead and skip this one
|
|
[ -e "$hook.needs-migration" ] && continue
|
|
defaulthook="$(PATH="$DEFAULT_PATH" command -v "$(basename "$hook")")"
|
|
;;
|
|
esac
|
|
if [ -f "$defaulthook" ]; then
|
|
if diff "$hook" "$defaulthook" > /dev/null && [ "$MODE" != "sync" ]; then
|
|
printf "\e[33mHook %s is identical to the default, so you don't need a custom hook, remove it? [y/N]\e[0m" "$hook"
|
|
read -r reply < /dev/tty
|
|
if [ "y" = "$reply" ]; then
|
|
rm "$hook"
|
|
fi
|
|
elif ! checkconfigversion "$hook" "$defaulthook" || [ "$MODE" = "all" ]; then
|
|
case "$MODE" in
|
|
"interactive"|"all")
|
|
resolvedifference "$hook" "$defaulthook"
|
|
;;
|
|
"sync")
|
|
sxmo_log "$hook is out of date, disabling and marked as needing migration..."
|
|
#never overwrite older .needs-migration files, they take precendence
|
|
if [ ! -e "$hook.needs-migration" ]; then
|
|
mv "$hook" "$hook.needs-migration"
|
|
else
|
|
rm "$hook"
|
|
fi
|
|
;;
|
|
esac
|
|
fi
|
|
elif [ "$MODE" != "sync" ]; then
|
|
(
|
|
smartdiff -ud "/dev/null" "$hook"
|
|
printf "\e[31mThe hook \e[32m%s\e[31m does not exist (anymore), remove it? [y/N] \e[0m\n" "$hook"
|
|
) | more
|
|
read -r reply < /dev/tty
|
|
if [ "y" = "$reply" ]; then
|
|
rm "$hook"
|
|
fi
|
|
printf "\n"
|
|
fi
|
|
done
|
|
}
|
|
|
|
common() {
|
|
defaultconfig "$(xdg_data_path sxmo/appcfg/profile_template)" "$XDG_CONFIG_HOME/sxmo/profile" 644
|
|
defaultconfig "$(xdg_data_path sxmo/appcfg/fontconfig.conf)" "$XDG_CONFIG_HOME/fontconfig/conf.d/50-sxmo.conf" 644
|
|
}
|
|
|
|
sway() {
|
|
defaultconfig "$(xdg_data_path sxmo/appcfg/sway_template)" "$XDG_CONFIG_HOME/sxmo/sway" 644
|
|
defaultconfig "$(xdg_data_path sxmo/appcfg/foot.ini)" "$XDG_CONFIG_HOME/foot/foot.ini" 644
|
|
defaultconfig "$(xdg_data_path sxmo/appcfg/mako.conf)" "$XDG_CONFIG_HOME/mako/config" 644
|
|
defaultconfig "$(xdg_data_path sxmo/appcfg/bonsai_tree.json)" "$XDG_CONFIG_HOME/sxmo/bonsai_tree.json" 644
|
|
defaultconfig "$(xdg_data_path sxmo/appcfg/wob.ini)" "$XDG_CONFIG_HOME/wob/wob.ini" 644
|
|
defaultconfig "$(xdg_data_path sxmo/appcfg/conky.conf)" "$XDG_CONFIG_HOME/sxmo/conky.conf" 644
|
|
}
|
|
|
|
xorg() {
|
|
defaultconfig "$(xdg_data_path sxmo/appcfg/Xresources)" "$HOME/.Xresources" 644
|
|
defaultconfig "$(xdg_data_path sxmo/appcfg/xinit_template)" "$XDG_CONFIG_HOME/sxmo/xinit" 644
|
|
defaultconfig "$(xdg_data_path sxmo/appcfg/dunst.conf)" "$XDG_CONFIG_HOME/dunst/dunstrc" 644
|
|
defaultconfig "$(xdg_data_path sxmo/appcfg/bonsai_tree.json)" "$XDG_CONFIG_HOME/sxmo/bonsai_tree.json" 644
|
|
defaultconfig "$(xdg_data_path sxmo/appcfg/xob_styles.cfg)" "$XDG_CONFIG_HOME/xob/styles.cfg" 644
|
|
defaultconfig "$(xdg_data_path sxmo/appcfg/conky.conf)" "$XDG_CONFIG_HOME/sxmo/conky.conf" 644
|
|
}
|
|
|
|
|
|
#set default mode
|
|
[ -z "$*" ] && set -- interactive
|
|
|
|
# Don't allow running with sudo, or as root
|
|
if [ -n "$SUDO_USER" ]; then
|
|
echo "$0 can't be run with sudo, it must be run as your user" >&2
|
|
exit 127
|
|
fi
|
|
|
|
if [ "$USER" = "root" ]; then
|
|
echo "$0 can't be run as root, it must be run as your user" >&2
|
|
exit 127
|
|
fi
|
|
|
|
# Execute idempotent migrations
|
|
find "$(xdg_data_path sxmo/migrations)" -type f | sort -n | tr '\n' '\0' | xargs -0 sh
|
|
|
|
if [ -z "$*" ]; then
|
|
set -- sync interactive
|
|
fi
|
|
|
|
#modes may be chained
|
|
for MODE in "$@"; do
|
|
case "$MODE" in
|
|
"interactive"|"all")
|
|
common
|
|
sway
|
|
xorg
|
|
checkhooks
|
|
;;
|
|
"sync"|"reset")
|
|
case "$SXMO_WM" in
|
|
sway)
|
|
common
|
|
sway
|
|
;;
|
|
dwm)
|
|
common
|
|
xorg
|
|
;;
|
|
*)
|
|
common
|
|
sway
|
|
xorg
|
|
;;
|
|
esac
|
|
|
|
checkhooks
|
|
;;
|
|
"state")
|
|
NEED_MIGRATION="$(find "$XDG_CONFIG_HOME/" -name "*.needs-migration")"
|
|
if [ -n "$NEED_MIGRATION" ]; then
|
|
sxmo_log "The following configuration files need migration: $NEED_MIGRATION"
|
|
exit "$(echo "$NEED_MIGRATION" | wc -l)" #exit code represents number of files needing migration
|
|
else
|
|
sxmo_log "All configuration files are up to date"
|
|
fi
|
|
;;
|
|
*)
|
|
sxmo_log "Invalid mode: $MODE"
|
|
exit 2
|
|
;;
|
|
esac
|
|
done
|