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
