forked from Jean28518/linux-assistant
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinstall.sh
More file actions
executable file
·293 lines (257 loc) · 11.5 KB
/
Copy pathinstall.sh
File metadata and controls
executable file
·293 lines (257 loc) · 11.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
#!/usr/bin/env bash
# Installs Linux Assistant from a .deb and clears out an older installation
# first — including the parts no package manager knows about.
#
# bash install.sh # use the .deb next to this script
# bash install.sh path/to/package.deb # use a specific one
# bash install.sh --purge # also wipe settings, cache and shortcuts
# bash install.sh --yes # never ask, assume yes
#
# Run it as your normal user. It calls sudo where it needs to, so that the
# session-bound parts (gsettings shortcuts, ~/.config) act on your account and
# not on root's.
set -euo pipefail
ASSUME_YES=0
PURGE=0
DEB=""
for arg in "$@"; do
case "$arg" in
--yes|-y) ASSUME_YES=1 ;;
--purge) PURGE=1 ;;
# Prints the comment header above, up to the first non-comment line.
-h|--help) sed -n '2,${/^#/!q;s/^# \?//;p;}' "$0"; exit 0 ;;
*) DEB="$arg" ;;
esac
done
SCRIPT_DIR="$( cd -- "$( dirname -- "$( readlink -f "${BASH_SOURCE[0]}" )" )" && pwd )"
APP_ID_FLATPAK="io.github.jean28518.Linux-Assistant"
info() { printf '\033[1;34m::\033[0m %s\n' "$1"; }
warn() { printf '\033[1;33m!!\033[0m %s\n' "$1"; }
step() { printf '\n\033[1m%s\033[0m\n' "$1"; }
# Returns 0 on yes. Under --yes it answers itself.
confirm() {
if [ "$ASSUME_YES" = "1" ]; then
return 0
fi
local reply
read -r -p " $1 [j/N] " reply
[[ "$reply" =~ ^([jJyY])$ ]]
}
if [ "$(id -u)" = "0" ]; then
warn "Bitte als normaler Benutzer starten, nicht mit sudo."
warn "Das Skript ruft sudo selbst auf, wo es nötig ist — sonst landen"
warn "Einstellungen und Tastenkürzel im Home-Verzeichnis von root."
exit 1
fi
# --- The package -------------------------------------------------------------
if [ -z "$DEB" ]; then
# Newest match wins, so a rebuilt package is picked up without an argument.
DEB="$(ls -t "$SCRIPT_DIR"/linux-assistant_*_*.deb "$SCRIPT_DIR"/linux-assistant.deb 2>/dev/null | head -n1 || true)"
fi
if [ -z "$DEB" ] || [ ! -f "$DEB" ]; then
warn "Kein .deb gefunden."
echo " Entweder eins mitgeben: bash install.sh /pfad/zum/paket.deb"
echo " oder selbst bauen: bash build-deb.sh"
exit 1
fi
DEB="$(readlink -f "$DEB")"
NEW_VERSION="$(dpkg-deb --field "$DEB" Version 2>/dev/null || echo "?")"
info "Paket: $DEB"
info "Version: $NEW_VERSION"
# --- What is already installed ----------------------------------------------
step "1. Bestandsaufnahme"
OLD_DEB_VERSION="$(dpkg-query -W -f='${Version}' linux-assistant 2>/dev/null || true)"
OLD_FLATPAK=""
if command -v flatpak >/dev/null 2>&1; then
OLD_FLATPAK="$(flatpak list --app --columns=application 2>/dev/null | grep -ix "$APP_ID_FLATPAK" || true)"
fi
# Anything on PATH that dpkg does not claim was put there by hand.
MANUAL_BIN=""
if BIN_PATH="$(command -v linux-assistant 2>/dev/null)"; then
if ! dpkg-query -S "$(readlink -f "$BIN_PATH")" >/dev/null 2>&1; then
MANUAL_BIN="$BIN_PATH"
fi
fi
# An array, not a space-joined string: a path containing a space used to be
# split into two, and the loop below then tried to delete both halves.
MANUAL_DESKTOP_FILES=()
for d in /usr/share/applications ~/.local/share/applications; do
[ -d "$d" ] || continue
while IFS= read -r f; do
dpkg-query -S "$f" >/dev/null 2>&1 || MANUAL_DESKTOP_FILES+=("$f")
done < <(find "$d" -maxdepth 1 -iname '*linux*assistant*.desktop' 2>/dev/null)
done
MANUAL_DESKTOP="${MANUAL_DESKTOP_FILES[*]:-}"
[ -n "$OLD_DEB_VERSION" ] && info "deb-Installation gefunden: $OLD_DEB_VERSION"
[ -n "$OLD_FLATPAK" ] && info "Flatpak gefunden: $APP_ID_FLATPAK"
[ -n "$MANUAL_BIN" ] && info "Manuell abgelegt: $MANUAL_BIN"
[ -n "$MANUAL_DESKTOP" ] && info "Verwaiste Starter:$MANUAL_DESKTOP"
if [ -z "$OLD_DEB_VERSION$OLD_FLATPAK$MANUAL_BIN$MANUAL_DESKTOP" ]; then
info "Keine Altinstallation gefunden — es wird frisch installiert."
fi
# --- Remove what apt cannot replace -----------------------------------------
step "2. Altinstallation entfernen"
if [ -n "$OLD_DEB_VERSION" ]; then
# Same package name and the same paths since 0.5.3, so apt replaces this
# one during the install below. Nothing to do here.
info "deb $OLD_DEB_VERSION wird beim Installieren ersetzt."
fi
if [ -n "$OLD_FLATPAK" ]; then
# A Flatpak lives beside the deb rather than replacing it, so it has to go
# explicitly or you end up with two assistants in the menu.
warn "Das Flatpak läuft sonst parallel zur neuen Installation weiter."
if confirm "Flatpak $APP_ID_FLATPAK entfernen?"; then
flatpak uninstall -y "$APP_ID_FLATPAK"
fi
fi
if [ -n "$MANUAL_BIN" ]; then
warn "$MANUAL_BIN gehört zu keinem Paket."
if confirm "Datei löschen?"; then
sudo rm -f "$MANUAL_BIN"
fi
fi
# Quoted through an array: an unquoted expansion word-splits a path that
# contains a space and then deletes the wrong thing.
for f in "${MANUAL_DESKTOP_FILES[@]}"; do
warn "$f gehört zu keinem Paket."
if confirm "Starter löschen?"; then
if [ -w "$(dirname "$f")" ]; then rm -f "$f"; else sudo rm -f "$f"; fi
fi
done
# --- Install -----------------------------------------------------------------
step "3. Installieren"
# apt, not `dpkg -i`: it pulls the declared dependencies. dpkg would leave the
# package half configured when one of them is missing.
sudo apt-get update -qq || warn "apt update fehlgeschlagen — versuche es trotzdem."
APT_ARGS=(install -y)
if [ "$OLD_DEB_VERSION" = "$NEW_VERSION" ]; then
# Without this apt reports "already the newest version" and does nothing,
# which is the wrong answer when you re-run the script to repair an
# installation whose files were removed by hand.
info "Gleiche Version bereits installiert — erzwinge Neuinstallation."
APT_ARGS+=(--reinstall)
fi
sudo apt-get "${APT_ARGS[@]}" "$DEB"
# --- Leftovers no package manager tracks -------------------------------------
step "4. Reste"
if [ "$PURGE" = "1" ]; then
rm -rf ~/.config/linux-assistant ~/.cache/linux-assistant
# Written by the command-queue with underscores, unlike everything else.
rm -f ~/.cache/linux_assistant_commands
info "Einstellungen und Cache gelöscht."
else
for d in ~/.config/linux-assistant ~/.cache/linux-assistant; do
if [ -d "$d" ]; then
info "Behalten: $d (mit --purge löschen für einen frischen Start)"
fi
done
fi
# The app looks for an entry it already owns before adding one, but the
# duplicates earlier versions left behind are still in the desktop's settings —
# a package removal never takes them away, because they do not belong to the
# package.
if command -v gsettings >/dev/null 2>&1 && [ -n "${DBUS_SESSION_BUS_ADDRESS:-}" ]; then
SCHEMA="org.gnome.settings-daemon.plugins.media-keys"
BASE="/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings"
if gsettings list-schemas 2>/dev/null | grep -qx "$SCHEMA"; then
KEEP=()
DROP=()
while IFS= read -r path; do
[ -n "$path" ] || continue
cmd="$(gsettings get "$SCHEMA.custom-keybinding:$path" command 2>/dev/null || echo "")"
if [[ "$cmd" == *linux-assistant* ]]; then DROP+=("$path"); else KEEP+=("$path"); fi
done < <(gsettings get "$SCHEMA" custom-keybindings 2>/dev/null \
| tr -d "[]' " | tr ',' '\n')
if [ "${#DROP[@]}" -gt 0 ]; then
info "Gefundene Tastenkürzel für linux-assistant: ${#DROP[@]}"
if [ "$PURGE" = "1" ] || [ "${#DROP[@]}" -gt 1 ]; then
if [ "$PURGE" = "1" ]; then
prompt="Alle entfernen? Die App legt beim nächsten Start ein neues an."
else
prompt="Mehrfach vorhanden — Duplikate entfernen?"
fi
if confirm "$prompt"; then
if [ "$PURGE" = "1" ]; then
remaining=("${KEEP[@]:-}")
else
remaining=("${KEEP[@]:-}" "${DROP[0]}") # eins behalten
fi
list="["
for p in "${remaining[@]}"; do
[ -n "$p" ] || continue
[ "$list" != "[" ] && list="$list, "
list="$list'$p'"
done
gsettings set "$SCHEMA" custom-keybindings "$list]"
# Dropping a path from the list leaves its keys in dconf,
# so the next `custom0` inherits an old name, command and
# binding. Reset the subtree of everything we dropped.
if command -v dconf >/dev/null 2>&1; then
for p in "${DROP[@]}"; do
case " ${remaining[*]} " in
*" $p "*) continue ;;
esac
dconf reset -f "$p" 2>/dev/null || true
done
fi
info "Bereinigt."
fi
fi
fi
fi
fi
# Cinnamon: same dconf structure as GNOME under a different schema. XFCE is
# one targeted property per modifier. KDE writes ini blocks in khotkeysrc
# whose safe removal needs the python helpers the package removal just
# deleted, so KDE gets an explicit hint instead of a fragile sed.
if [ "$PURGE" = "1" ] && command -v gsettings >/dev/null 2>&1 \
&& [ -n "${DBUS_SESSION_BUS_ADDRESS:-}" ]; then
CIN_SCHEMA="org.cinnamon.desktop.keybindings"
if gsettings list-schemas 2>/dev/null | grep -qx "$CIN_SCHEMA"; then
KEEP=()
DROP=()
while IFS= read -r path; do
[ -n "$path" ] || continue
cmd="$(gsettings get "$CIN_SCHEMA.custom-keybinding:$path" command 2>/dev/null || echo "")"
if [[ "$cmd" == *linux-assistant* ]]; then DROP+=("$path"); else KEEP+=("$path"); fi
done < <(gsettings get "$CIN_SCHEMA" custom-keybindings 2>/dev/null \
| tr -d "[]' " | tr ',' '\n')
if [ "${#DROP[@]}" -gt 0 ]; then
list="["
for p in "${KEEP[@]:-}"; do
[ -n "$p" ] || continue
[ "$list" != "[" ] && list="$list, "
list="$list'$p'"
done
gsettings set "$CIN_SCHEMA" custom-keybindings "$list]"
if command -v dconf >/dev/null 2>&1; then
for p in "${DROP[@]}"; do
dconf reset -f "$p" 2>/dev/null || true
done
fi
info "Cinnamon-Tastenkürzel entfernt."
fi
fi
fi
if [ "$PURGE" = "1" ] && command -v xfconf-query >/dev/null 2>&1 \
&& xfconf-query -c xfce4-keyboard-shortcuts -l >/dev/null 2>&1; then
for mod in "<Super>q" "<Alt>q"; do
if xfconf-query -c xfce4-keyboard-shortcuts -p "/commands/custom/$mod" -r 2>/dev/null; then
info "XFCE-Tastenkürzel $mod entfernt."
fi
done
fi
if [ "$PURGE" = "1" ] && grep -q "linux-assistant" ~/.config/khotkeysrc 2>/dev/null; then
info "Hinweis: in ~/.config/khotkeysrc liegt noch ein KDE-Kürzel — bitte im KDE-Kurzbefehl-Editor entfernen."
fi
step "Fertig"
linux-assistant --version || true
echo
echo "Starten: linux-assistant (oder über das Anwendungsmenü)"
# Alt+Q on Zorin, Ubuntu and Pop!_OS, where the desktop already owns Super+Q;
# Super+Q elsewhere. Same rule as Linux.getHotkeyModifier().
case "$(. /etc/os-release 2>/dev/null; echo "${ID:-} ${ID_LIKE:-}")" in
*zorin*|*ubuntu*|*pop*) SHORTCUT="Alt+Q" ;;
*) SHORTCUT="Super+Q" ;;
esac
echo "Kürzel: $SHORTCUT, sobald es die App beim ersten Start eingerichtet hat"