MIAOU-BASH is a collection of scripts and configurations designed to enhance your terminal experience. As the name suggests, it is built on Bash and is designed to work on most modern GNU/Linux systems.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

247 lines
7.3 KiB

# CONSTANTS
readonly AZERTY_ZONES=(
'Europe/Paris'
'Indian/Reunion'
'Indian/Mayotte'
'America/Cayenne'
'America/Guadeloupe'
'America/Martinique'
'Pacific/Noumea'
'Pacific/Tahiti'
)
readonly REQUIRED_PKGS=(file jq vim git bash-completion)
readonly BACKUP_SUFFIX='.ORIGINAL'
# FUNCTIONS
function usr_bin_miaou_bash {
ln -sf "$MIAOU_BASH_DIR/bin/miaou-bash" /usr/bin/miaou-bash
}
function install_required_packages {
. "$MIAOU_BASH_DIR"/tools/pkg_add "${REQUIRED_PKGS[@]}"
}
function fix_users_bashrc {
if [[ -f /etc/skel/.bashrc ]] && ! cmp -s /etc/skel/.bashrc "$MIAOU_BASH_DIR"/etc/skel/.bashrc; then
echo 'fixing users .bashrc...'
local skel_count_lines
skel_count_lines=$(wc -l /etc/skel/.bashrc | cut -d' ' -f1)
local appended_regex="^${skel_count_lines}a"
# for pre-existant users
build_associative_user_homes
for user in "${!USER_HOMES[@]}"; do
local user_bashrc="${USER_HOMES[$user]}/.bashrc"
local first_change
echo "read: $user_bashrc"
[[ ! -f "$user_bashrc" ]] && continue
if cmp -s /etc/skel/.bashrc "$user_bashrc"; then
echo 'no change: replaced by skel'
sudo -u "$user" -- cp "$MIAOU_BASH_DIR"/etc/skel/.bashrc "$user_bashrc"
elif first_change=$(diff /etc/skel/.bashrc "$user_bashrc" | head -n1); then
echo 'no change: should not occur'
elif [[ $first_change =~ $appended_regex ]]; then
if new_lines=$(diff /etc/skel/.bashrc "$user_bashrc" | grep '^> ' | sed 's/^> //'); then
echo 'no new lines: should not occur'
else
sudo -u "$user" -- cp "$MIAOU_BASH_DIR"/etc/skel/.bashrc "$user_bashrc"
echo -e "$new_lines" | sudo -u "$user" -- tee -a "$user_bashrc"
echo "INFO: .bashrc for user <$user> merged succesfully"
fi
elif ! cmp -s "$MIAOU_BASH_DIR"/etc/skel/.bashrc "$user_bashrc"; then
local backup="$user_bashrc".ORIGINAL
sudo -u "$user" -- mv "$user_bashrc" "$backup"
sudo -u "$user" -- cp "$MIAOU_BASH_DIR"/etc/skel/.bashrc "$user_bashrc"
>&2 echo "WARN: .bashrc for user <$user> has forked from skeleton, please resolve conflict manually from backup: $backup"
fi
done
sudo mv /etc/skel/.bashrc /etc/skel/.bashrc.ORIGINAL
echo 'fixing users .bashrc...DONE'
fi
sudo ln -sf "$MIAOU_BASH_DIR"/etc/skel/.bashrc /etc/skel/.bashrc
}
function link_etc {
local source="$MIAOU_BASH_DIR/etc/$1"
local target="/etc/${2:-$1}"
if [[ -L "$target" ]]; then
if [[ "$(readlink "$target")" != "$source" ]]; then
sudo ln -sf "$source" "$target"
echo "link $target updated"
fi
else
if [[ -f "$target" ]]; then
sudo mv "$target" "$target$BACKUP_SUFFIX"
echo "$target$BACKUP_SUFFIX saved!"
fi
sudo mkdir -p "$(dirname "$target")"
sudo ln -s "$source" "$target"
echo "link $target created"
fi
}
function arch_profile {
if ! cmp -s /etc/profile "$MIAOU_BASH_DIR"/etc/profile.arch; then
sudo cp "$MIAOU_BASH_DIR"/etc/profile.arch /etc/profile
echo 'arch /etc/profile fixed!'
fi
}
function arch_vimrc {
mkdir -p /etc/vim
if ! grep -q '/etc/vim/vimrc.local' /etc/vimrc; then
cat >>/etc/vimrc <<EOF
" Source a global configuration file if available
if filereadable("/etc/vim/vimrc.local")
source /etc/vim/vimrc.local
endif
EOF
echo "vimrc source /etc/vim/vimrc.local if any"
fi
}
function is_arch_like {
[[ "$DISTRO_LIKE" == 'arch' ]]
}
function is_debian_like {
[[ "$DISTRO_LIKE" == 'debian' ]]
}
function link_config_files {
is_arch_like && arch_vimrc && arch_profile
link_etc vim/vimrc.core
link_etc vim/vimrc.miaou
link_etc vim/vimrc.rookie
if in_azerty_zone 2>/dev/null; then
link_etc vim/vimrc.azerty
link_etc vim/vimrc.local.azerty vim/vimrc.local
else
link_etc vim/vimrc.local
fi
link_etc profile.d/zz-miaou-bash.sh
link_etc bash.bashrc
link_etc bash_completion.d/miaou-bash.complete
link_etc inputrc # last command required to detect successful installation
}
function in_azerty_zone {
[[ -L /etc/localtime ]] || return 4
local zone
zone=$(readlink /etc/localtime)
zone="${zone#/usr/share/zoneinfo/}" # remove prefix
for i in "${AZERTY_ZONES[@]}"; do [[ "$zone" == "$i" ]] && return; done
return 5
}
function fix_terminfo_ghostty {
if ! infocmp xterm-ghostty >/dev/null 2>&1; then
tic -x "$MIAOU_BASH_DIR"/assets/terminfo/ghostty 2>/dev/null
echo 'terminfo ghostty succesfully compiled'
fi
}
function build_associative_user_homes {
if [[ ! -v USER_HOMES ]]; then
declare -gA USER_HOMES
while IFS=: read -r user _ uid _ _ home _; do
if [[ $uid -ge 1000 && $user != 'nobody' ]]; then
USER_HOMES[$user]="$home"
fi
done </etc/passwd
fi
}
function ghostty_global_config {
! command -v ghostty >/dev/null && return # ghostty not yet installed!
link_etc ghostty/config
if [[ ! -f /etc/skell/.config/ghostty/config ]]; then
# ghostty config skeleton for new users
mkdir -p /etc/skel/.config/ghostty
echo 'config-file = /etc/ghostty/config' >/etc/skel/.config/ghostty/config
fi
# change ghostty configuration for any normal user
build_associative_user_homes
for user in "${!USER_HOMES[@]}"; do
local user_home="${USER_HOMES[$user]}"
if [[ ! -d "$user_home" ]]; then
>&2 echo "WARNING: home directory: $user_home missing for user: $user! bypassing..."
continue
fi
local user_ghostty_config="$user_home"/.config/ghostty/config.ghostty
if [[ ! -f "$user_ghostty_config" ]]; then
sudo -u "$user" -- mkdir -p "$user_home"/.config/ghostty
echo -e "# global config\nconfig-file = /etc/ghostty/config\n" |
sudo -u "$user" -- tee "$user_ghostty_config" >/dev/null
echo "new predefined ghostty config file for user: $user"
elif ! grep -q 'config-file = /etc/ghostty/config' "$user_ghostty_config"; then
# prepend on top
echo -e "# global config\nconfig-file = /etc/ghostty/config\n" |
sudo -u "$user" -- tee "$user_ghostty_config".tmp >/dev/null
cat "$user_ghostty_config" |
sudo -u "$user" -- tee -a "$user_ghostty_config".tmp >/dev/null
rm "$user_ghostty_config"
sudo -u "$user" mv "$user_ghostty_config".tmp "$user_ghostty_config"
echo "modify pre-existant ghostty config file for user: $user"
fi
done
}
function link_miaou_bash {
sudo ln -sf "$MIAOU_BASH_DIR"/bin/miaou-bash /usr/bin/
}
function create_sudoers {
if [[ ! -f /etc/sudoers.d/miaou-bash ]]; then
echo 'Defaults:%sudo env_keep += "MIAOU_BASH_DIR"' | sudo tee /etc/sudoers.d/miaou-bash >/dev/null
sudo chmod 440 /etc/sudoers.d/miaou-bash
fi
}
function launch_hooks {
find "$MIAOU_BASH_DIR"/hooks.d -maxdepth 1 -name "after-upgrade*" -type f -executable |
sort |
while read -r hook; do
echo "Processing: $hook"
# shellcheck disable=SC1090
if ! miaou-bash "$hook" 3>/dev/null 2>&1; then
echo 'WARNING: hook failure, bypassed'
fi
echo ----------------------
done
}
function apply_mode {
if [[ "$MIAOU_BASH_MODE" == hosted ]]; then
sudo mkdir /var/lib/miaou-bash -p
sudo cp "$MIAOU_BASH_DIR"/.semver_git_tag /var/lib/miaou-bash/semver_current
fi
}
# MAIN
source "$MIAOU_BASH_DIR"/lib/functions.bash
assert_root
fetch_distro_like
install_required_packages
fix_users_bashrc
fix_terminfo_ghostty
ghostty_global_config
link_config_files
link_miaou_bash
create_sudoers
fetch_mode
apply_mode
launch_hooks