# 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 install_required_packages { . "$MIAOU_BASH_DIR"/bin/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 mv /etc/skel/.bashrc /etc/skel/.bashrc.ORIGINAL echo 'fixing users .bashrc...DONE' fi 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 ln -sf "$source" "$target" echo "link $target updated" fi else if [[ -f "$target" ]]; then mv "$target" "$target$BACKUP_SUFFIX" echo "$target$BACKUP_SUFFIX saved!" fi mkdir -p "$(dirname "$target")" ln -s "$source" "$target" echo "link $target created" fi } function arch_profile { if ! cmp -s /etc/profile "$MIAOU_BASH_DIR"/etc/profile.arch; then cp "$MIAOU_BASH_DIR"/etc/profile.arch /etc/profile echo 'arch /etc/profile fixed!' fi } function debian_vimrc_restore_to_original { # FIXME: useful for deprecated version of miaou-bash, to remove in a few months! if [[ -f /etc/vim/vimrc.ORIGINAL ]]; then rm -f /etc/vim/vimrc mv /etc/vim/vimrc.ORIGINAL /etc/vim/vimrc echo "vimrc restored to original!" fi } function arch_vimrc { mkdir -p /etc/vim if ! grep -q '/etc/vim/vimrc.local' /etc/vimrc; then cat >>/etc/vimrc </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 -f /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 /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_bin_scripts { ln -sf "$MIAOU_BASH_DIR"/bin/miaou-bash /usr/bin/ ln -sf "$MIAOU_BASH_DIR"/bin/pkg_add /usr/bin/ } function create_sudoers { if [[ ! -f /etc/sudoers.d/miaou-bash ]]; then echo 'Defaults:%sudo env_keep += "MIAOU_BASH_DIR"' >/etc/sudoers.d/miaou-bash 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 mkdir /var/lib/miaou-bash -p cp "$MIAOU_BASH_DIR"/.semver_git_tag /var/lib/miaou-bash/semver_current fi } function fix_locales { local locale should_regenerate=false declare -a expected_locales=(en_US.utf8 es_ES.utf8 fr_FR.utf8) declare -A found_locales for locale in "${expected_locales[@]}"; do found_locales["$locale"]=false; done mapfile -t gen_locales < <(locale -a) for locale in "${gen_locales[@]}"; do if [[ -v found_locales["$locale"] ]]; then found_locales["$locale"]=true; fi done for locale in "${!found_locales[@]}"; do if [[ ${found_locales[$locale]} == 'false' ]]; then local language="${locale:0:5}" echo "Locale: $locale missing" . /opt/miaou-bash/tools/smart_write /etc/locale.gen "(^# ?)?${language}\.UTF-8 UTF-8" "${language}.UTF-8 UTF-8" should_regenerate=true fi done if [[ "$should_regenerate" == 'true' ]]; then locale-gen fi } # MAIN source "$MIAOU_BASH_DIR"/lib/functions.bash assert_root fetch_distro_like install_required_packages fix_users_bashrc fix_terminfo_ghostty fix_locales ghostty_global_config link_config_files link_bin_scripts create_sudoers fetch_mode apply_mode launch_hooks