Nura mit SXMO einrichten

  Lioh Möller   Lesezeit: 17 Minuten Auf Mastodon ansehen

Die Segel sind gesetzt. Mit diesem Post-Install-Skript richtest du Nura mit Sxmo schnell und nachvollziehbar nach den eigenen Vorlieben ein.

nura mit sxmo einrichten

Nach einer Neuinstallation von Nura (ehemals postmarketOS) mit Sxmo arbeite ich immer wieder dieselbe Liste ab: SSH aktivieren, Bash installieren, Vim und die Shell einrichten, Anwendungen nachinstallieren, ein dunkles Theme setzen und den Sxmo-App-Hook anpassen.

Das ist keine komplizierte Arbeit, aber sie ist repetitiv. Deshalb habe ich mir ein Bash-Skript gebaut, das diese Schritte zusammenfasst. Es installiert Nura nicht selbst. Es ist ein persönliches Post-Install-Skript, das ich nach einer frischen Installation einmal starte. Das vollständige Script findet ihr ergänzend auch am Ende des Artikels.

Was das Skript macht

Das Skript prüft zuerst, ob Bash bereits vorhanden ist. Falls nicht, läuft der kurze Startteil mit /bin/sh, installiert Bash über sudo apk add bash und startet sich selbst danach automatisch erneut mit Bash. So kann das Skript auch auf einem frischen System verwendet werden, auf dem Bash noch fehlt. Denn standardmässig wird Nura mit der ash-Shell ausgeliefert.

Danach erledigt es diese Punkte:

  • Installiert Bash, Bash-Completion, plocate, playerctl und cmus, einen Audioplayer für die Kommandozeile.
  • Installiert und aktiviert OpenSSH, sofern die Option --no-ssh nicht gesetzt wurde.
  • Erkennt systemd oder OpenRC und aktiviert sshd passend zum verwendeten Init-System.
  • Setzt Bash als Login-Shell für meinen Benutzer und root.
  • Richtet .bashrc, .bash_profile, .vimrc für meinen Benutzer sowie für root ein.
  • Setzt einen farbigen Prompt für meinen Benutzer und rm -i als Schutz vor versehentlichem Löschen.
  • Legt /usr/local/bin/vi als Symlink auf Vim an.
  • Richtet plocate inklusive locate-Symlink und Suchdatenbank ein.
  • Ergänzt in der SXMO-Sway-Konfiguration workspace_layout tabbed. Damit werden neue Fenster im Tab gestartet.
  • Installiert Firefox, Thunderbird, Kasts, Alligator, VLC und Elisa.
  • Aktiviert das KDE-Breeze-Dark-Farbschema und die dunklen Foot-Terminalfarben.
  • Setzt die nötigen Qt- und GTK-Variablen in /etc/environment um das Dark Theme zu bevorzugen.
  • Erstellt einen persönlichen SXMO-App-Hook unter ~/.config/sxmo/hooks/.
  • Ergänzt darin Alligator, Elisa und passt VLC sowie Telegram an.
  • Konfiguriert cmus mit dem Farbschema jellybeans und meinen gewünschten Tastenbelegungen.

Das Skript sichert bestehende Konfigurationen mit einem Suffix und überschreibt sie dann kontrolliert mit der neuen Version.

~/.bashrc.before-nura-sxmo-setup.bak
~/.vimrc.before-nura-sxmo-setup.bak
~/.config/sxmo/sway.before-nura-sxmo-setup.bak

Non-interactive Modus

Standardmässig fragt apk bei der Paketinstallation noch einmal mit Y/N nach. Das ist bewusst so, damit man sieht, was installiert wird. Für vollautomatische Durchläufe, etwa wenn ich das Skript im Hintergrund laufen lassen will, gibt es die Option --non-interactive.

Damit wird apk mit --no-interactive aufgerufen und fragt nicht mehr nach Bestätigung:

./setup-nura-sxmo.sh --non-interactive

Ich kann das auch mit anderen Optionen kombinieren, zum Beispiel:

./setup-nura-sxmo.sh \
  --no-ssh \
  --no-gui-apps \
  --non-interactive

So läuft das Skript komplett ohne Rückfragen durch, installiert aber nur die gewünschten Teile. Alle möglichen Optionen sind in der Hilfe beschrieben, welche jederzeit wie folgt angezeigt werden kann:

./setup-nura-sxmo.sh --help

Das Skript aufs Telefon bringen

Zum Herunterladen öffne ich ein Terminal und gebe folgenden Befehl ein:

wget https://codeberg.org/Lioh/setup-nura-sxmo.sh/raw/branch/main/setup-nura-sxmo.sh

Danach kann die Datei einfach mittels chmod +x setup-nura-sxmo.sh ausführbar gemacht werden.

Vor dem ersten richtigen Durchlauf empfehle ich das Skript mit --dry-run zu starten:

./setup-nura-sxmo.sh --dry-run

Dabei zeigt es an, welche Pakete installiert, welche Dateien verändert und welche Befehle ausgeführt würden. An dieser Stelle wird noch nichts verändert.

Wenn alles passt, starte ich den echten Durchlauf:

./setup-nura-sxmo.sh

Das Skript fragt nach meinem sudo-Passwort und führt danach die Einrichtung durch.

Für einen automatischen Durchlauf ohne Rückfragen nutze ich:

./setup-nura-sxmo.sh --non-interactive

Nach dem Durchlauf

Einige Änderungen greifen sofort, andere erst in einer neuen Sitzung.

Die Sway-Konfiguration lade ich direkt neu mittels 

sway reload

Für die neue Bash-Konfiguration öffne ich ein neues Terminal oder melde mich ab und wieder an.

Damit die Einträge aus /etc/environment für Qt und GTK zuverlässig greifen, melde ich mich einmal vollständig ab und wieder an. Ein Neustart funktioniert ebenfalls:

sudo reboot

Fazit

Das Skript nimmt mir nicht die Kontrolle über meine Nura-Installation ab. Es spart mir nur die immer gleichen Handgriffe nach einer Neuinstallation.

Der eigentliche Vorteil ist für mich nicht nur die Zeitersparnis. Die persönliche Konfiguration ist damit dokumentiert, nachvollziehbar und wiederholbar. Wenn ich das Gerät neu aufsetzen muss oder ein weiteres Gerät einrichte, kann ich denselben Stand mit einem kontrollierten Skriptlauf wiederherstellen.

#!/bin/sh
#
# setup-nura-sxmo.sh
# Basic personal setup for Nura + SXMO/Sway
#
# Bootstrap with /bin/sh because Bash may not be installed yet.

NON_INTERACTIVE_BOOTSTRAP=0
DRY_RUN_BOOTSTRAP=0

for argument in "$@"; do
  case "$argument" in
    --non-interactive) NON_INTERACTIVE_BOOTSTRAP=1 ;;
    --dry-run) DRY_RUN_BOOTSTRAP=1 ;;
  esac
done

if ! command -v bash >/dev/null 2>&1; then
  if [ "$DRY_RUN_BOOTSTRAP" -eq 1 ]; then
    printf '%s\n' \
      'Bash is not installed. A full dry-run requires Bash.' \
      '[DRY-RUN] Would install Bash with sudo apk add bash.'
    exit 0
  fi

  printf '%s\n' 'Bash is not installed yet. Installing Bash first ...'

  command -v sudo >/dev/null 2>&1 || {
    printf '%s\n' 'ERROR: sudo is required to install Bash.' >&2
    exit 1
  }

  command -v apk >/dev/null 2>&1 || {
    printf '%s\n' 'ERROR: This script expects apk.' >&2
    exit 1
  }

  if [ "$NON_INTERACTIVE_BOOTSTRAP" -eq 1 ]; then
    sudo apk --no-interactive add bash
  else
    sudo apk add bash
  fi

  [ "$?" -eq 0 ] || {
    printf '%s\n' 'ERROR: Failed to install Bash.' >&2
    exit 1
  }

  exec /bin/bash "$0" "$@"
fi

if [ -z "${BASH_VERSION:-}" ]; then
  exec /bin/bash "$0" "$@"
fi

set -Eeuo pipefail
IFS=$'\n\t'

TARGET_USER="${SUDO_USER:-${USER:-$(id -un)}}"
INSTALL_GUI_APPS=1
CHANGE_SHELL=1
SETUP_SSH=1
DRY_RUN=0
NON_INTERACTIVE=0

readonly BACKUP_SUFFIX=".before-nura-sxmo-setup.bak"
readonly SCRIPT_NAME="$(basename "$0")"

usage() {
  printf '%s\n' \
    'Usage:' \
    "  $SCRIPT_NAME [OPTIONS]" \
    '' \
    'Options:' \
    '  --user NAME          Target user; default: currently logged-in user' \
    '  --no-gui-apps        Skip GUI and multimedia packages and portal start hook' \
    '  --no-shell-change    Do not set Bash as login shell for user and root' \
    '  --no-ssh             Do not install or enable OpenSSH' \
    '  --non-interactive    Do not ask for confirmation during apk operations' \
    '  --dry-run            Show planned actions without making changes' \
    '  -h, --help           Show this help'
}

log() {
  printf '\n\033[1;32m==>\033[0m %s\n' "$*"
}

warn() {
  printf '\033[1;33mWARNING:\033[0m %s\n' "$*" >&2
}

die() {
  printf '\033[1;31mERROR:\033[0m %s\n' "$*" >&2
  exit 1
}

run_root() {
  if (( DRY_RUN )); then
    printf '[DRY-RUN] sudo '
    printf '%q ' "$@"
    printf '\n'
  else
    sudo "$@"
  fi
}

apk_add() {
  if (( NON_INTERACTIVE )); then
    run_root apk --no-interactive add "$@"
  else
    run_root apk add "$@"
  fi
}

while (( $# > 0 )); do
  case "$1" in
    --user)
      [[ $# -ge 2 ]] || die "Missing username for --user."
      TARGET_USER="$2"
      shift 2
      ;;
    --no-gui-apps)
      INSTALL_GUI_APPS=0
      shift
      ;;
    --no-shell-change)
      CHANGE_SHELL=0
      shift
      ;;
    --no-ssh)
      SETUP_SSH=0
      shift
      ;;
    --non-interactive)
      NON_INTERACTIVE=1
      shift
      ;;
    --dry-run)
      DRY_RUN=1
      shift
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      die "Unknown option: $1"
      ;;
  esac
done

command -v apk >/dev/null 2>&1 || die "This script expects apk."
command -v sudo >/dev/null 2>&1 || die "sudo not found."
command -v getent >/dev/null 2>&1 || die "getent not found."

TARGET_PASSWD="$(getent passwd "$TARGET_USER")" \
  || die "User '$TARGET_USER' not found."

TARGET_HOME="$(printf '%s\n' "$TARGET_PASSWD" | awk -F: '{print $6}')"
TARGET_GROUP="$(id -gn "$TARGET_USER")"

[[ -n "$TARGET_HOME" && -d "$TARGET_HOME" ]] \
  || die "Home directory for user '$TARGET_USER' not found."

[[ "$(id -u "$TARGET_USER")" != "0" ]] \
  || die "Please specify a normal user with --user, not root."

(( DRY_RUN )) || sudo -v

log "Target user: $TARGET_USER"
log "Target group: $TARGET_GROUP"
log "Home directory: $TARGET_HOME"

backup_once() {
  local file="$1"
  local backup="${file}${BACKUP_SUFFIX}"

  if [[ -e "$file" && ! -e "$backup" ]]; then
    log "Backing up $file to $backup"
    run_root cp -a "$file" "$backup"
  fi
}

ensure_user_dir() {
  local directory="$1"

  if (( DRY_RUN )); then
    printf '[DRY-RUN] Ensure directory for %s: %s\n' \
      "$TARGET_USER" "$directory"
  else
    sudo -H -u "$TARGET_USER" mkdir -p "$directory"
  fi
}

write_user_file() {
  local file="$1"
  local content="$2"

  backup_once "$file"
  ensure_user_dir "$(dirname "$file")"

  if (( DRY_RUN )); then
    printf '[DRY-RUN] Write user file: %s\n' "$file"
  else
    printf '%s\n' "$content" | sudo tee "$file" >/dev/null
    sudo chown "$TARGET_USER:$TARGET_GROUP" "$file"
    sudo chmod 0644 "$file"
  fi
}

write_root_file() {
  local file="$1"
  local content="$2"

  backup_once "$file"
  run_root mkdir -p "$(dirname "$file")"

  if (( DRY_RUN )); then
    printf '[DRY-RUN] Write root file: %s\n' "$file"
  else
    printf '%s\n' "$content" | sudo tee "$file" >/dev/null
    sudo chown root:root "$file"
    sudo chmod 0644 "$file"
  fi
}

ensure_symlink() {
  local target="$1"
  local link="$2"

  if [[ -L "$link" && "$(readlink "$link")" == "$target" ]]; then
    return 0
  fi

  if [[ -e "$link" || -L "$link" ]]; then
    warn "$link already exists and will not be overwritten."
    return 0
  fi

  log "Creating symlink: $link -> $target"
  run_root mkdir -p "$(dirname "$link")"
  run_root ln -s "$target" "$link"
}

ensure_environment_var() {
  local key="$1"
  local value="$2"
  local file="/etc/environment"
  local tmp

  backup_once "$file"

  if (( DRY_RUN )); then
    printf '[DRY-RUN] Set %s=%s in %s\n' "$key" "$value" "$file"
    return 0
  fi

  tmp="$(mktemp)"

  sudo touch "$file"
  sudo sed "/^${key}=/d" "$file" > "$tmp"
  printf '%s=%s\n' "$key" "$value" >> "$tmp"
  sudo install -m 0644 "$tmp" "$file"

  rm -f "$tmp"
}

setup_sshd() {
  if (( ! SETUP_SSH )); then
    return 0
  fi

  log "Installing and enabling OpenSSH"
  apk_add openssh

  if [[ -d /run/systemd/system ]] \
    && command -v systemctl >/dev/null 2>&1; then
    run_root systemctl enable --now sshd
  elif command -v rc-update >/dev/null 2>&1 \
    && command -v rc-service >/dev/null 2>&1; then
    run_root rc-update add sshd default
    run_root rc-service sshd start
  else
    warn "No supported init system detected. Enable sshd manually."
  fi
}

setup_base_packages() {
  log "Installing base packages"

  apk_add \
    bash \
    bash-completion \
    plocate \
    playerctl \
    cmus \
    vim \
    shadow
}

setup_shells() {
  if (( ! CHANGE_SHELL )); then
    return 0
  fi

  log "Setting Bash as login shell"

  if (( ! DRY_RUN )); then
    command -v chsh >/dev/null 2>&1 || die "chsh not found."
  fi

  run_root chsh -s /bin/bash "$TARGET_USER"
  run_root chsh -s /bin/bash root
}

setup_vim() {
  local vimrc='set mouse=
set nobackup
set noswapfile
set noundofile
set noai
set paste
set noincsearch
set nohlsearch'

  log "Configuring Vim"

  ensure_symlink /usr/bin/vim /usr/local/bin/vi
  write_user_file "${TARGET_HOME}/.vimrc" "$vimrc"
  write_root_file "/root/.vimrc" "$vimrc"
}

setup_bash() {
  local profile='if [ -f ~/.bashrc ]; then
  . ~/.bashrc
fi'

  local user_bashrc='shopt -q login_shell || . /etc/profile
shopt -s checkwinsize
export PS1='\''\[\033[1;32m\]\u@\h\[\033[0m\]:\[\033[1;34m\]\w\[\033[0m\]\$ '\''
if [[ "${TERM:-}" = "xterm" || "${TERM:-}" = "xterm-256color" ]]; then
  export PROMPT_COMMAND='\''echo -ne "\033]0;$USER@$HOSTNAME\007" '\''
fi
alias rm='\''rm -i'\'''

  local root_bashrc='shopt -q login_shell || . /etc/profile
shopt -s checkwinsize
export PS1='\''\u@\h:\w\$ '\''
if [[ "${TERM:-}" = "xterm" || "${TERM:-}" = "xterm-256color" ]]; then
  export PROMPT_COMMAND='\''echo -ne "\033]0;$USER@$HOSTNAME\007" '\''
fi
alias rm='\''rm -i'\'''

  log "Configuring Bash profiles"

  write_user_file "${TARGET_HOME}/.bash_profile" "$profile"
  write_user_file "${TARGET_HOME}/.bashrc" "$user_bashrc"
  write_root_file "/root/.bash_profile" "$profile"
  write_root_file "/root/.bashrc" "$root_bashrc"
}

setup_locate() {
  log "Setting up plocate"

  ensure_symlink /usr/bin/plocate /usr/local/bin/locate
  run_root updatedb
}

setup_sway() {
  local file="${TARGET_HOME}/.config/sxmo/sway"
  local setting='workspace_layout tabbed'
  local marker='exec_always sxmo_swayinitconf.sh'

  ensure_user_dir "$(dirname "$file")"

  if [[ -f "$file" ]] && grep -Fqx "$setting" "$file"; then
    log "Sway setting already exists."
    return 0
  fi

  backup_once "$file"

  if (( DRY_RUN )); then
    printf '[DRY-RUN] Add "%s" to %s\n' "$setting" "$file"
    return 0
  fi

  sudo touch "$file"

  if grep -Fq "$marker" "$file"; then
    sudo sed -i "\|${marker}|i ${setting}" "$file"
  else
    warn "Sway marker not found; appending setting."
    printf '\n%s\n' "$setting" | sudo tee -a "$file" >/dev/null
  fi

  sudo chown "$TARGET_USER:$TARGET_GROUP" "$file"
}

setup_gui_apps() {
  if (( ! INSTALL_GUI_APPS )); then
    return 0
  fi

  log "Installing browser, mail, multimedia, and power-monitoring apps"

  apk_add \
    firefox \
    mobile-config-firefox \
    thunderbird \
    mobile-config-thunderbird \
    kasts \
    alligator \
    vlc-qt \
    elisa \
    powersupply
}

setup_gtk3_theme() {
  local file="${TARGET_HOME}/.config/gtk-3.0/settings.ini"
  local tmp

  log "Configuring GTK3 dark theme for $TARGET_USER"

  backup_once "$file"
  ensure_user_dir "$(dirname "$file")"

  if (( DRY_RUN )); then
    printf '%s\n' \
      "[DRY-RUN] Update $file" \
      '[DRY-RUN] [Settings]' \
      '[DRY-RUN] gtk-theme-name=Adwaita-dark' \
      '[DRY-RUN] gtk-application-prefer-dark-theme=true'
    return 0
  fi

  # Preserve other settings; replace only the two theme settings.
  tmp="$(mktemp)"

  if [[ -f "$file" ]]; then
    sudo cat "$file" > "$tmp"
  fi

  awk '
    function write_theme() {
      print "gtk-theme-name=Adwaita-dark"
      print "gtk-application-prefer-dark-theme=true"
    }

    /^[[:space:]]*\[Settings\][[:space:]]*$/ {
      if (in_settings && !written) {
        write_theme()
        written = 1
      }
      seen_settings = 1
      in_settings = 1
      print
      next
    }

    /^[[:space:]]*\[/ {
      if (in_settings && !written) {
        write_theme()
        written = 1
      }
      in_settings = 0
    }

    in_settings &&
    /^[[:space:]]*gtk-theme-name[[:space:]]*=/ {
      next
    }

    in_settings &&
    /^[[:space:]]*gtk-application-prefer-dark-theme[[:space:]]*=/ {
      next
    }

    {
      print
    }

    END {
      if (!seen_settings) {
        print ""
        print "[Settings]"
        write_theme()
      } else if (in_settings && !written) {
        write_theme()
      }
    }
  ' "$tmp" | sudo tee "$file" >/dev/null

  rm -f "$tmp"

  sudo chown "$TARGET_USER:$TARGET_GROUP" "$file"
  sudo chmod 0644 "$file"
}

setup_user_dark_color_scheme() {
  if (( DRY_RUN )); then
    printf '[DRY-RUN] '
    printf '%q ' \
      sudo -H -u "$TARGET_USER" \
      env \
      -u DBUS_SESSION_BUS_ADDRESS \
      -u XDG_RUNTIME_DIR \
      -u DCONF_PROFILE \
      "HOME=$TARGET_HOME" \
      "XDG_CONFIG_HOME=${TARGET_HOME}/.config" \
      GSETTINGS_BACKEND=dconf \
      dbus-run-session -- \
      gsettings set org.gnome.desktop.interface color-scheme prefer-dark
    printf '\n'
    return 0
  fi

  if ! command -v gsettings >/dev/null 2>&1 \
    || ! command -v dbus-run-session >/dev/null 2>&1; then
    printf '%s\n' \
      "Error while activating color-scheme: 'prefer-dark'" >&2
    exit 1
  fi

  if sudo -H -u "$TARGET_USER" \
    env \
      -u DBUS_SESSION_BUS_ADDRESS \
      -u XDG_RUNTIME_DIR \
      -u DCONF_PROFILE \
      HOME="$TARGET_HOME" \
      XDG_CONFIG_HOME="${TARGET_HOME}/.config" \
      GSETTINGS_BACKEND=dconf \
    dbus-run-session -- /bin/sh -eu -c '
      schema="org.gnome.desktop.interface"

      gsettings set "$schema" color-scheme prefer-dark

      actual="$(gsettings get "$schema" color-scheme)"

      [ "$actual" = "'\''prefer-dark'\''" ]
    ' >/dev/null 2>&1; then
    printf '%s\n' \
      "Successfully saved color-scheme: 'prefer-dark'"
  else
    printf '%s\n' \
      "Error while activating color-scheme: 'prefer-dark'" >&2
    exit 1
  fi
}

setup_kde_theme() {
  local kdeglobals='[ColorEffects:Disabled]
ChangeSelectionColor=
Color=56,56,56
ColorAmount=0
ColorEffect=0
ContrastAmount=0.65
ContrastEffect=1
Enable=
IntensityAmount=0.1
IntensityEffect=2

[ColorEffects:Inactive]
ChangeSelectionColor=true
Color=112,111,110
ColorAmount=0.025
ColorEffect=2
ContrastAmount=0.1
ContrastEffect=2
Enable=false
IntensityAmount=0
IntensityEffect=0

[Colors:Button]
BackgroundAlternate=30,87,116
BackgroundNormal=49,54,59
DecorationFocus=61,174,233
DecorationHover=61,174,233
ForegroundActive=61,174,233
ForegroundInactive=161,169,177
ForegroundLink=29,153,243
ForegroundNegative=218,68,83
ForegroundNeutral=246,116,0
ForegroundNormal=252,252,252
ForegroundPositive=39,174,96
ForegroundVisited=155,89,182

[Colors:Complementary]
BackgroundAlternate=30,87,116
BackgroundNormal=42,46,50
DecorationFocus=61,174,233
DecorationHover=61,174,233
ForegroundActive=61,174,233
ForegroundInactive=161,169,177
ForegroundLink=29,153,243
ForegroundNegative=218,68,83
ForegroundNeutral=246,116,0
ForegroundNormal=252,252,252
ForegroundPositive=39,174,96
ForegroundVisited=155,89,182

[Colors:Header]
BackgroundAlternate=42,46,50
BackgroundNormal=49,54,59
DecorationFocus=61,174,233
DecorationHover=61,174,233
ForegroundActive=61,174,233
ForegroundInactive=161,169,177
ForegroundLink=29,153,243
ForegroundNegative=218,68,83
ForegroundNeutral=246,116,0
ForegroundNormal=252,252,252
ForegroundPositive=39,174,96
ForegroundVisited=155,89,182

[Colors:Header][Inactive]
BackgroundAlternate=49,54,59
BackgroundNormal=42,46,50
DecorationFocus=61,174,233
DecorationHover=61,174,233
ForegroundActive=61,174,233
ForegroundInactive=161,169,177
ForegroundLink=29,153,243
ForegroundNegative=218,68,83
ForegroundNeutral=246,116,0
ForegroundNormal=252,252,252
ForegroundPositive=39,174,96
ForegroundVisited=155,89,182

[Colors:Selection]
BackgroundAlternate=30,87,116
BackgroundNormal=61,174,233
DecorationFocus=61,174,233
DecorationHover=61,174,233
ForegroundActive=252,252,252
ForegroundInactive=161,169,177
ForegroundLink=253,188,75
ForegroundNegative=176,55,69
ForegroundNeutral=198,92,0
ForegroundNormal=252,252,252
ForegroundPositive=23,104,57
ForegroundVisited=155,89,182

[Colors:Tooltip]
BackgroundAlternate=42,46,50
BackgroundNormal=49,54,59
DecorationFocus=61,174,233
DecorationHover=61,174,233
ForegroundActive=61,174,233
ForegroundInactive=161,169,177
ForegroundLink=29,153,243
ForegroundNegative=218,68,83
ForegroundNeutral=246,116,0
ForegroundNormal=252,252,252
ForegroundPositive=39,174,96
ForegroundVisited=155,89,182

[Colors:View]
BackgroundAlternate=35,38,41
BackgroundNormal=27,30,32
DecorationFocus=61,174,233
DecorationHover=61,174,233
ForegroundActive=61,174,233
ForegroundInactive=161,169,177
ForegroundLink=29,153,243
ForegroundNegative=218,68,83
ForegroundNeutral=246,116,0
ForegroundNormal=252,252,252
ForegroundPositive=39,174,96
ForegroundVisited=155,89,182

[Colors:Window]
BackgroundAlternate=49,54,59
BackgroundNormal=42,46,50
DecorationFocus=61,174,233
DecorationHover=61,174,233
ForegroundActive=61,174,233
ForegroundInactive=161,169,177
ForegroundLink=29,153,243
ForegroundNegative=218,68,83
ForegroundNeutral=246,116,0
ForegroundNormal=252,252,252
ForegroundPositive=39,174,96
ForegroundVisited=155,89,182

[General]
ColorScheme=BreezeDark
Name=Breeze Dark
widgetStyle=Breeze

[Icons]
Theme=breeze-dark

[KDE]
ColorScheme=Breeze
LookAndFeelPackage=org.kde.breezedark.desktop
widgetStyle=Breeze'

  local foot_ini='# Space to setup configversion
# configversion: 13fb3d2d9f97f4420f7506e72b90e77d
font=monospace:size=11
dpi-aware=no

[colors-dark]
# alpha=1.0
foreground=eaeaea
background=303030
regular0=1e1e1e
regular1=d54e53
regular2=b9ca4a
regular3=e6c547
regular4=7aa6da
regular5=c397d8
regular6=70c0ba
regular7=eaeaea
bright0=666666
bright1=ff3334
bright2=9ec400
bright3=e7c547
bright4=7aa6da
bright5=b77ee0
bright6=54ced6
bright7=ffffff'

  log "Installing and configuring Qt/KDE dark theme"

  apk_add \
    plasma-integration \
    qqc2-breeze-style \
    adwaita-qt5 \
    adwaita-qt6

  log "Installing GSettings and D-Bus components"

  apk_add \
    glib \
    dconf \
    gsettings-desktop-schemas \
    dbus

  write_user_file "${TARGET_HOME}/.config/kdeglobals" "$kdeglobals"
  write_user_file "${TARGET_HOME}/.config/foot/foot.ini" "$foot_ini"

  ensure_environment_var "QT_QUICK_CONTROLS_STYLE" "org.kde.breeze"
  ensure_environment_var "QT_QPA_PLATFORMTHEME" "kde"
  ensure_environment_var "GTK_APPLICATION_PREFER_DARK_THEME" "1"

  setup_gtk3_theme
  setup_user_dark_color_scheme
}

setup_cmus() {
  local cmusrc='colorscheme jellybeans
bind -f common b player-next
bind -f common B player-next-album
bind -f common z player-prev
bind -f common Z player-prev-album'

  log "Configuring cmus"
  write_user_file "${TARGET_HOME}/.config/cmus/rc" "$cmusrc"
}

hook_add_after() {
  local file="$1"
  local anchor="$2"
  local line="$3"

  if grep -Fqx "$line" "$file"; then
    return 0
  fi

  if grep -Fq "$anchor" "$file"; then
    sudo sed -i "\|${anchor}|a ${line}" "$file"
  else
    warn "Hook anchor not found; appending: $line"
    printf '%s\n' "$line" | sudo tee -a "$file" >/dev/null
  fi
}

hook_replace() {
  local file="$1"
  local old="$2"
  local new="$3"
  local escaped

  if grep -Fqx "$new" "$file"; then
    return 0
  fi

  if grep -Fqx "$old" "$file"; then
    escaped="$(printf '%s' "$old" | sed 's/[][\/.^$*|]/\\&/g')"
    sudo sed -i "s|^${escaped}$|${new}|" "$file"
  else
    warn "Hook line not found: $old"
  fi
}

setup_sxmo_hook() {
  local source="/usr/share/sxmo/default_hooks/sxmo_hook_apps.sh"
  local target="${TARGET_HOME}/.config/sxmo/hooks/sxmo_hook_apps.sh"

  if [[ ! -f "$source" ]]; then
    warn "SXMO default hook not found: $source"
    return 0
  fi

  log "Creating personal SXMO app hook"
  ensure_user_dir "$(dirname "$target")"

  if (( DRY_RUN )); then
    if [[ ! -e "$target" ]]; then
      printf '[DRY-RUN] Copy %s to %s\n' "$source" "$target"
    else
      backup_once "$target"
    fi

    printf '[DRY-RUN] Add personal SXMO application entries\n'
    printf '[DRY-RUN] Add Powersupply immediately after Pidgin if anchor exists\n'
    return 0
  fi

  if [[ ! -e "$target" ]]; then
    sudo cp "$source" "$target"
  else
    backup_once "$target"
  fi

  hook_add_after "$target" \
    'write_line_app alacritty "$icon_trm Alacritty" "alacritty"' \
    'write_line_app alligator "$icon_glb Alligator" "alligator"'

  hook_add_after "$target" \
    'write_line_app elinks "$icon_glb ELinks" "sxmo_terminal.sh elinks"' \
    'write_line_app elisa "$icon_mus Elisa" "elisa"'

  hook_add_after "$target" \
    'write_line_app polari "$icon_msg Polari" "polari"' \
    'write_line_app polycule "$icon_msg Polycule" "polycule"'

  hook_replace "$target" \
    'write_line_app telegram-desktop "$icon_tgm Telegram" "telegram-desktop"' \
    'write_line_app Telegram "$icon_tgm Telegram" "Telegram"'

  hook_replace "$target" \
    'write_line_app vlc "$icon_vlc Vlc" "vlc"' \
    'write_line_app vlc "$icon_vlc Vlc" "QT_STYLE_OVERRIDE=Adwaita-dark vlc"'

  hook_add_after "$target" \
    'write_line_app vlc "$icon_vlc Vlc" "QT_STYLE_OVERRIDE=Adwaita-dark vlc"' \
    'write_line_app vvave "$icon_mus Vvave" "flatpak run org.kde.vvave"'

  hook_add_after "$target" \
    'write_line_app pidgin "$icon_msg Pidgin" "pidgin"' \
    'write_line_app powersupply "$icon_cfg Powersupply" "powersupply"'

  sudo chown "$TARGET_USER:$TARGET_GROUP" "$target"
  sudo chmod 0755 "$target"
}

setup_sxmo_start_hook() {
  if (( ! INSTALL_GUI_APPS )); then
    return 0
  fi

  local source="/usr/share/sxmo/default_hooks/sxmo_hook_start.sh"
  local target="${TARGET_HOME}/.config/sxmo/hooks/sxmo_hook_start.sh"
  local marker='sxmo_migrate.sh state'

  if [[ ! -f "$target" && ! -f "$source" ]]; then
    warn "SXMO default start hook not found: $source"
    return 0
  fi

  log "Configuring SXMO start hook for desktop portals"
  ensure_user_dir "$(dirname "$target")"

  if (( DRY_RUN )); then
    if [[ ! -f "$target" ]]; then
      printf '[DRY-RUN] Copy %s to %s\n' "$source" "$target"
    else
      backup_once "$target"
    fi

    printf '%s\n' \
      "[DRY-RUN] Add portal block before '$marker' if not already present:" \
      '# starting xdg-desktop-portal' \
      '/usr/libexec/xdg-desktop-portal-gtk --replace &' \
      '/usr/libexec/xdg-desktop-portal --replace &' \
      ''

    run_root chown "$TARGET_USER:$TARGET_GROUP" "$target"
    run_root chmod 0755 "$target"
    return 0
  fi

  if [[ ! -f "$target" ]]; then
    sudo cp "$source" "$target"
  else
    backup_once "$target"
  fi

  if ! grep -Fq "$marker" "$target"; then
    die "Start hook marker '$marker' not found in $target."
  fi

  if ! grep -Fqx '/usr/libexec/xdg-desktop-portal-gtk --replace &' "$target"; then
    sudo sed -i '/sxmo_migrate\.sh state/i\
# starting xdg-desktop-portal\
/usr/libexec/xdg-desktop-portal-gtk --replace &\
/usr/libexec/xdg-desktop-portal --replace &\
' "$target"
  fi

  sudo chown "$TARGET_USER:$TARGET_GROUP" "$target"
  sudo chmod 0755 "$target"
}

print_next_steps() {
  printf '%s\n' \
    '' \
    'Next steps:' \
    '' \
    '  1. Start a new login shell, or log out and back in.' \
    '' \
    '  2. Reload Sway configuration:' \
    '       sway reload' \
    '' \
    '  3. To fully apply /etc/environment, log out and back in' \
    '     or reboot the device.' \
    '' \
    '  4. Verify SSH configuration:' \
    '       sshd -t' \
    '' \
    '     On OpenRC:' \
    '       sudo rc-service sshd status' \
    '' \
    '     On systemd:' \
    '       sudo systemctl status sshd' \
    '' \
    'Backups of existing configuration files end with:' \
    "  ${BACKUP_SUFFIX}"
}

setup_sshd
setup_base_packages
setup_shells
setup_vim
setup_bash
setup_locate
setup_sway
setup_gui_apps
setup_kde_theme
setup_cmus
setup_sxmo_hook
setup_sxmo_start_hook

if (( DRY_RUN )); then
  log "Nura SXMO setup dry-run completed."
else
  log "Nura SXMO setup completed."
  print_next_steps
fi

Tags

Sxmo, Nura, linuxmobile

Es wurden noch keine Kommentare verfasst, sei der erste!