Skip to content

Commit c47ed9a

Browse files
author
MochiOS Team
committed
fix: autostart trust, pacstrap streaming, cleanup failsafe
1 parent 2e329cb commit c47ed9a

11 files changed

Lines changed: 187 additions & 18 deletions

File tree

‎archiso-mochios/airootfs/etc/xdg/autostart/mochiinstall.desktop‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,5 @@ Icon=system-software-install
77
Terminal=false
88
Categories=System;
99
X-KDE-Authorize=true
10+
X-KDE-autostart-phase=3
11+
X-KDE-StartupNotify=false

‎archiso-mochios/airootfs/etc/xdg/autostart/nuke-discover.desktop‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ Comment=Remove discover from the taskbar after plasma loads
55
Exec=/usr/lib/mochiinstall/nuke-discover.sh
66
Terminal=false
77
X-KDE-Authorize=true
8+
X-KDE-autostart-phase=3

‎archiso-mochios/airootfs/home/mochi/.config/autostart/mochiinstall.desktop‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@ Comment=Install MochiOS to your system
55
Exec=mochiinstall
66
Terminal=false
77
Categories=System;
8-
X-KDE-autostart-phase=2
9-
X-KDE-autostart-after=panel
8+
X-KDE-autostart-phase=3
9+
X-KDE-StartupNotify=false
1010

‎archiso-mochios/airootfs/home/mochi/.config/autostart/nuke-discover.desktop‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ Name=Nuke Discover from Taskbar
44
Exec=/usr/lib/mochiinstall/nuke-discover.sh
55
Terminal=false
66
NoDisplay=true
7-
X-KDE-autostart-after=plasma-shell
7+
X-KDE-autostart-phase=3
8+
X-KDE-StartupNotify=false
Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,40 @@
11
#!/usr/bin/env bash
2-
# run before plasma starts — nuke discover
2+
# run before plasma starts — nuke discover + write clean panel config
33
sudo pacman -Rdd discover --noconfirm 2>/dev/null || true
4+
5+
# hide discover from app launcher even if package remains
6+
for f in /usr/share/applications/org.kde.discover.desktop /usr/share/applications/org.kde.discover.notifier.desktop; do
7+
if [ -f "$f" ]; then
8+
sudo sed -i 's/^NoDisplay=.*/NoDisplay=true/; /^NoDisplay=/d' "$f" 2>/dev/null
9+
echo "NoDisplay=true" | sudo tee -a "$f" >/dev/null 2>&1
10+
fi
11+
done
12+
13+
# write clean panel config so plasma doesn't pin discover
14+
mkdir -p "$HOME/.config"
15+
UUID=$(python3 -c "import uuid; print(uuid.uuid4())" 2>/dev/null || echo "85d7a3a1-2a0b-4c8e-8f1d-6b5a4c3e2f1a")
16+
cat > "$HOME/.config/plasma-org.kde.plasma.desktop-appletsrc" << EOF
17+
[Containments][${UUID}]
18+
activityId=
19+
formFactor=1
20+
location=4
21+
plugin=org.kde.plasma.panel
22+
screen=0
23+
lastScreen=0
24+
wallpaperplugin=org.kde.plasma.image
25+
26+
[Containments][${UUID}][Applets][3]
27+
plugin=org.kde.plasma.kickoff
28+
29+
[Containments][${UUID}][Applets][4]
30+
plugin=org.kde.plasma.icontasks
31+
32+
[Containments][${UUID}][Applets][5]
33+
plugin=org.kde.plasma.systemtray
34+
35+
[Containments][${UUID}][Applets][6]
36+
plugin=org.kde.plasma.digitalclock
37+
38+
[Containments][${UUID}][Applets][7]
39+
plugin=org.kde.plasma.showdesktop
40+
EOF

‎archiso-mochios/airootfs/usr/lib/mochiinstall/installer.py‎

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,40 @@
55
import re
66
import shutil
77
import time
8+
import signal
9+
import sys
10+
import atexit
811
from pathlib import Path
912

10-
CUSTOM_EXTRAS = set()
13+
CUSTOM_EXTRAS = {"steam"}
14+
15+
_CLEANUP_TARGET = [None]
16+
17+
def _unmount_all():
18+
target = _CLEANUP_TARGET[0]
19+
if not target or not os.path.ismount(target):
20+
return
21+
for mp in [f"{target}/var/cache", f"{target}/var", f"{target}/home", f"{target}/boot", target]:
22+
subprocess.run(["umount", "-l", mp], capture_output=True, check=False, timeout=10)
23+
subprocess.run(["umount", "-l", "/mnt/btrfs_tmp"], capture_output=True, check=False, timeout=10)
24+
subprocess.run(["swapoff", "-a"], capture_output=True, check=False, timeout=10)
25+
26+
# signal handlers registered at module level (main thread)
27+
# only if not in a daemon thread (TUI runs installer in thread)
28+
def _setup_signal_handlers():
29+
old = {}
30+
def handler(signum, frame):
31+
_unmount_all()
32+
sys.exit(128 + signum)
33+
for sig in (signal.SIGTERM, signal.SIGINT):
34+
try:
35+
old[sig] = signal.signal(sig, handler)
36+
except (ValueError, RuntimeError):
37+
pass
38+
return old
39+
40+
_setup_signal_handlers()
41+
atexit.register(_unmount_all)
1142

1243
_TOTAL_STEPS = 60
1344
_STEP_COUNT = [0]
@@ -35,7 +66,7 @@ def run(cmd, check=True, capture=False, timeout=None, input_data=None):
3566
return r
3667

3768

38-
def abortable_run(cmd, abort_flag, check=True, timeout=None):
69+
def abortable_run(cmd, abort_flag, check=True, timeout=None, log_fn=None):
3970
import select as _select
4071
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
4172
out_lines = []
@@ -60,6 +91,10 @@ def abortable_run(cmd, abort_flag, check=True, timeout=None):
6091
line = proc.stdout.readline()
6192
if line:
6293
out_lines.append(line)
94+
if log_fn:
95+
clean = line.rstrip()
96+
if clean:
97+
log_fn(f"[dim]{clean}[/]")
6398
if proc.poll() is not None:
6499
break
65100
for line in proc.stdout:
@@ -179,13 +214,14 @@ def setup_btrfs(root_part, target, lfn):
179214
def pacstrap_base(target, lfn, de="kde", greeter="sddm", bootloader="limine", kernels=None, extra_pkgs=None, abort_flag=None):
180215
if kernels is None:
181216
kernels = ["linux"]
182-
lfn("installing base system...")
183217

184218
kernel_pkgs = []
185219
for k in kernels:
186220
kernel_pkgs.append(k)
187221
kernel_pkgs.append(k + "-headers")
188222

223+
# step 1: base system
224+
lfn("installing base system...")
189225
base = [
190226
"base",
191227
*kernel_pkgs,
@@ -196,6 +232,9 @@ def pacstrap_base(target, lfn, de="kde", greeter="sddm", bootloader="limine", ke
196232
"sbctl",
197233
"zsh", "git", "flatpak",
198234
]
235+
abortable_run(["pacstrap", "-K", target] + base, abort_flag, timeout=900, log_fn=lfn)
236+
237+
# step 2: desktop environment
199238
de_pkgs = {
200239
"kde": ["plasma-desktop", "plasma-workspace", "kdeplasma-addons",
201240
"kwin", "konsole", "dolphin", "kate", "gwenview",
@@ -207,6 +246,11 @@ def pacstrap_base(target, lfn, de="kde", greeter="sddm", bootloader="limine", ke
207246
"wofi", "waybar", "dunst", "polkit-kde-agent",
208247
"wl-clipboard", "slurp", "grim", "hyprpaper"],
209248
}
249+
de_choice = de_pkgs.get(de, de_pkgs["kde"])
250+
lfn(f"installing {de} desktop...")
251+
abortable_run(["pacstrap", "-K", target] + de_choice, abort_flag, timeout=600, log_fn=lfn)
252+
253+
# step 3: greeter + bootloader + extras
210254
greeter_pkgs = {
211255
"sddm": ["sddm"],
212256
"gdm": ["gdm"],
@@ -219,8 +263,10 @@ def pacstrap_base(target, lfn, de="kde", greeter="sddm", bootloader="limine", ke
219263
"grub": ["grub"],
220264
"mochiboot": ["mochiboot"],
221265
}
222-
pkgs = base + de_pkgs.get(de, de_pkgs["kde"]) + greeter_pkgs.get(greeter, greeter_pkgs["sddm"]) + bl_pkgs.get(bootloader, []) + (extra_pkgs or [])
223-
abortable_run(["pacstrap", "-K", target] + pkgs, abort_flag, timeout=900)
266+
misc = greeter_pkgs.get(greeter, greeter_pkgs["sddm"]) + bl_pkgs.get(bootloader, []) + (extra_pkgs or [])
267+
if misc:
268+
lfn("installing greeter, bootloader, and extras...")
269+
abortable_run(["pacstrap", "-K", target] + misc, abort_flag, timeout=300, log_fn=lfn)
224270

225271

226272
def configure_system(target, config, lfn, efi_uuid, swap_uuid, root_uuid):
@@ -520,6 +566,7 @@ def do_install(target="/mnt/mochios", config=None, log_fn=None, abort_flag=None)
520566

521567
if abort_flag and abort_flag():
522568
raise RuntimeError("installation aborted")
569+
_CLEANUP_TARGET[0] = target
523570
setup_btrfs(root_part_p, target, log_fn)
524571

525572
efi_uuid = get_uuid(efi_part)
@@ -603,6 +650,7 @@ def do_install(target="/mnt/mochios", config=None, log_fn=None, abort_flag=None)
603650
run(["swapoff", swap_part], check=False)
604651
log_fn("installation complete!")
605652
mounts_cleanup_needed = False
653+
_CLEANUP_TARGET[0] = None
606654
return True
607655

608656
except subprocess.CalledProcessError as e:

‎archiso-mochios/airootfs/usr/lib/mochiinstall/mochiinstall_app.py‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -526,7 +526,10 @@ def on_button_pressed(self, event: Button.Pressed) -> None:
526526
self.log_widget.write("[yellow]aborting after current step...[/]")
527527

528528
def action_quit(self) -> None:
529-
pass
529+
self._abort = True
530+
self.log_widget.write("[yellow]exiting... unmounting any filesystems[/]")
531+
from installer import _unmount_all
532+
_unmount_all()
530533

531534

532535
class MochiInstallApp(App):
Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,32 @@
11
#!/usr/bin/env bash
22

3+
# wait for plasma config to appear
34
PBC="$HOME/.config/plasma-org.kde.plasma.desktop-appletsrc"
4-
for i in $(seq 1 15); do
5+
for i in $(seq 1 30); do
56
if [ -f "$PBC" ]; then
6-
sed -i '/discover/Id' "$PBC" 2>/dev/null
7-
sed -i 's/,[[:space:]]*org\.kde\.discover[^,]*//g; s/org\.kde\.discover[^,]*,[[:space:]]*//g; s/org\.kde\.discover[^,]*//g' "$PBC" 2>/dev/null
87
break
98
fi
109
sleep 1
1110
done
11+
12+
# nuke discover from the panel config in every possible way
13+
if [ -f "$PBC" ]; then
14+
sed -i '/discover/Id' "$PBC" 2>/dev/null
15+
sed -i 's/,[[:space:]]*org\.kde\.discover[^,]*//g; s/org\.kde\.discover[^,]*,[[:space:]]*//g; s/org\.kde\.discover[^,]*//g' "$PBC" 2>/dev/null
16+
fi
17+
18+
# also nuke from any plasma config
1219
for cfg in "$HOME/.config/plasma"* "$HOME/.config/kde"*; do
1320
[ -f "$cfg" ] && sed -i '/discover/Id' "$cfg" 2>/dev/null
1421
done
22+
23+
# kill discover process if running
1524
pkill -x discover 2>/dev/null || true
25+
26+
# remove discover package entirely (silently)
27+
pacman -Rdd discover --noconfirm 2>/dev/null || true
28+
29+
# hide discover .desktop files
30+
for f in /usr/share/applications/org.kde.discover*.desktop /usr/share/applications/kde4/discover*.desktop; do
31+
[ -f "$f" ] && sed -i '/^NoDisplay=/d; /^Hidden=/d' "$f" 2>/dev/null && echo -e "NoDisplay=true\nHidden=true" >> "$f" 2>/dev/null
32+
done

‎archiso-mochios/profiledef.sh‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,9 @@ bootstrap_tarball_compression=('zstd' '-c' '-T0' '--auto-threads=logical' '--lon
1616
file_permissions=(
1717
["/etc/shadow"]="0:0:400"
1818
["/usr/local/bin/mochiinstall"]="0:0:755"
19+
["/home/mochi/.config/autostart/mochiinstall.desktop"]="0:0:755"
20+
["/home/mochi/.config/autostart/nuke-discover.desktop"]="0:0:755"
21+
["/home/mochi/.config/autostart/mochi-wallpaper.desktop"]="0:0:755"
22+
["/home/mochi/.config/plasma-workspace/env/nuke-discover.sh"]="1000:1000:755"
23+
["/usr/lib/mochiinstall/nuke-discover.sh"]="0:0:755"
1924
)

‎installer.py‎

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,41 @@
55
import re
66
import shutil
77
import time
8+
import signal
9+
import sys
10+
import atexit
811
from pathlib import Path
912

1013
CUSTOM_EXTRAS = {"steam"}
1114

15+
_CLEANUP_TARGET = [None]
16+
17+
def _unmount_all():
18+
target = _CLEANUP_TARGET[0]
19+
if not target or not os.path.ismount(target):
20+
return
21+
for mp in [f"{target}/var/cache", f"{target}/var", f"{target}/home", f"{target}/boot", target]:
22+
subprocess.run(["umount", "-l", mp], capture_output=True, check=False, timeout=10)
23+
subprocess.run(["umount", "-l", "/mnt/btrfs_tmp"], capture_output=True, check=False, timeout=10)
24+
subprocess.run(["swapoff", "-a"], capture_output=True, check=False, timeout=10)
25+
26+
# signal handlers registered at module level (main thread)
27+
# only if not in a daemon thread (TUI runs installer in thread)
28+
def _setup_signal_handlers():
29+
old = {}
30+
def handler(signum, frame):
31+
_unmount_all()
32+
sys.exit(128 + signum)
33+
for sig in (signal.SIGTERM, signal.SIGINT):
34+
try:
35+
old[sig] = signal.signal(sig, handler)
36+
except (ValueError, RuntimeError):
37+
pass
38+
return old
39+
40+
_setup_signal_handlers()
41+
atexit.register(_unmount_all)
42+
1243
_TOTAL_STEPS = 60
1344
_STEP_COUNT = [0]
1445
_PROGRESS_CB = [None]
@@ -35,7 +66,7 @@ def run(cmd, check=True, capture=False, timeout=None, input_data=None):
3566
return r
3667

3768

38-
def abortable_run(cmd, abort_flag, check=True, timeout=None):
69+
def abortable_run(cmd, abort_flag, check=True, timeout=None, log_fn=None):
3970
import select as _select
4071
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
4172
out_lines = []
@@ -60,6 +91,10 @@ def abortable_run(cmd, abort_flag, check=True, timeout=None):
6091
line = proc.stdout.readline()
6192
if line:
6293
out_lines.append(line)
94+
if log_fn:
95+
clean = line.rstrip()
96+
if clean:
97+
log_fn(f"[dim]{clean}[/]")
6398
if proc.poll() is not None:
6499
break
65100
for line in proc.stdout:
@@ -179,13 +214,14 @@ def setup_btrfs(root_part, target, lfn):
179214
def pacstrap_base(target, lfn, de="kde", greeter="sddm", bootloader="limine", kernels=None, extra_pkgs=None, abort_flag=None):
180215
if kernels is None:
181216
kernels = ["linux"]
182-
lfn("installing base system...")
183217

184218
kernel_pkgs = []
185219
for k in kernels:
186220
kernel_pkgs.append(k)
187221
kernel_pkgs.append(k + "-headers")
188222

223+
# step 1: base system
224+
lfn("installing base system...")
189225
base = [
190226
"base",
191227
*kernel_pkgs,
@@ -196,6 +232,9 @@ def pacstrap_base(target, lfn, de="kde", greeter="sddm", bootloader="limine", ke
196232
"sbctl",
197233
"zsh", "git", "flatpak",
198234
]
235+
abortable_run(["pacstrap", "-K", target] + base, abort_flag, timeout=900, log_fn=lfn)
236+
237+
# step 2: desktop environment
199238
de_pkgs = {
200239
"kde": ["plasma-desktop", "plasma-workspace", "kdeplasma-addons",
201240
"kwin", "konsole", "dolphin", "kate", "gwenview",
@@ -207,6 +246,11 @@ def pacstrap_base(target, lfn, de="kde", greeter="sddm", bootloader="limine", ke
207246
"wofi", "waybar", "dunst", "polkit-kde-agent",
208247
"wl-clipboard", "slurp", "grim", "hyprpaper"],
209248
}
249+
de_choice = de_pkgs.get(de, de_pkgs["kde"])
250+
lfn(f"installing {de} desktop...")
251+
abortable_run(["pacstrap", "-K", target] + de_choice, abort_flag, timeout=600, log_fn=lfn)
252+
253+
# step 3: greeter + bootloader + extras
210254
greeter_pkgs = {
211255
"sddm": ["sddm"],
212256
"gdm": ["gdm"],
@@ -219,8 +263,10 @@ def pacstrap_base(target, lfn, de="kde", greeter="sddm", bootloader="limine", ke
219263
"grub": ["grub"],
220264
"mochiboot": ["mochiboot"],
221265
}
222-
pkgs = base + de_pkgs.get(de, de_pkgs["kde"]) + greeter_pkgs.get(greeter, greeter_pkgs["sddm"]) + bl_pkgs.get(bootloader, []) + (extra_pkgs or [])
223-
abortable_run(["pacstrap", "-K", target] + pkgs, abort_flag, timeout=900)
266+
misc = greeter_pkgs.get(greeter, greeter_pkgs["sddm"]) + bl_pkgs.get(bootloader, []) + (extra_pkgs or [])
267+
if misc:
268+
lfn("installing greeter, bootloader, and extras...")
269+
abortable_run(["pacstrap", "-K", target] + misc, abort_flag, timeout=300, log_fn=lfn)
224270

225271

226272
def configure_system(target, config, lfn, efi_uuid, swap_uuid, root_uuid):
@@ -508,6 +554,10 @@ def do_install(target="/mnt/mochios", config=None, log_fn=None, abort_flag=None)
508554
if abort_flag and abort_flag():
509555
raise RuntimeError("installation aborted")
510556
log_fn("starting mochios installation...")
557+
558+
# pre-flight: unmount any leftover mounts from failed installs
559+
_unmount_all()
560+
511561
disk = select_disk(config.get("disk"))
512562
bios_part, efi_part, swap_part, root_part_p = partition_disk(disk, log_fn)
513563
mounts_cleanup_needed = True
@@ -520,6 +570,7 @@ def do_install(target="/mnt/mochios", config=None, log_fn=None, abort_flag=None)
520570

521571
if abort_flag and abort_flag():
522572
raise RuntimeError("installation aborted")
573+
_CLEANUP_TARGET[0] = target
523574
setup_btrfs(root_part_p, target, log_fn)
524575

525576
efi_uuid = get_uuid(efi_part)
@@ -603,6 +654,7 @@ def do_install(target="/mnt/mochios", config=None, log_fn=None, abort_flag=None)
603654
run(["swapoff", swap_part], check=False)
604655
log_fn("installation complete!")
605656
mounts_cleanup_needed = False
657+
_CLEANUP_TARGET[0] = None
606658
return True
607659

608660
except subprocess.CalledProcessError as e:

0 commit comments

Comments
 (0)