-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathuninstall.sh
More file actions
executable file
·1175 lines (1042 loc) · 45.7 KB
/
uninstall.sh
File metadata and controls
executable file
·1175 lines (1042 loc) · 45.7 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
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/bin/bash
#
# ██████╗ ██████╗ █████╗ ██████╗ ██╗ ██╗██╗ ██╗ ██████╗ ███████╗
# ██╔══██╗██╔══██╗██╔══██╗██╔══██╗██║ ██║╚██╗ ██╔╝██╔═══██╗██╔════╝
# ██║ ██║██████╔╝███████║██████╔╝███████║ ╚████╔╝ ██║ ██║███████╗
# ██║ ██║██╔══██╗██╔══██║██╔═══╝ ██╔══██║ ╚██╔╝ ██║ ██║╚════██║
# ██████╔╝██║ ██║██║ ██║██║ ██║ ██║ ██║ ╚██████╔╝███████║
# ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝
#
# draphyOS Uninstaller
# https://github.com/draphy/draphyOS
#
# Exit on undefined variable
set -u
# Colors (with fallback for non-color terminals)
if [[ -t 1 ]] && [[ "${TERM:-dumb}" != "dumb" ]]; then
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
MINT='\033[38;2;154;184;124m' # Mint-Y green #9ab87c
NC='\033[0m'
else
RED=''
GREEN=''
YELLOW=''
BLUE=''
MINT=''
NC=''
fi
# Validate HOME directory
if [ -z "${HOME:-}" ] || [ ! -d "$HOME" ]; then
echo "ERROR: HOME directory not set or does not exist"
exit 1
fi
INSTALL_DIR="$HOME/.draphyOS"
MARKER_FILE="$HOME/.draphyOS-installed"
# Discover all config files from repo (if repo still exists)
# Returns relative paths (e.g., "i3/config", "fish/config.fish")
get_all_config_files() {
local configs_dir="$INSTALL_DIR/configs"
if [ ! -d "$configs_dir" ]; then
return
fi
find "$configs_dir" -type f -printf '%P\n' 2>/dev/null | sort
}
# Map a config name (relative path) to the user's file path
get_user_config_path() {
local config_name="$1"
case "$config_name" in
xprofile)
echo "$HOME/.xprofile"
;;
*)
echo "$HOME/.config/$config_name"
;;
esac
}
print_header() {
echo ""
echo -e "${RED}"
echo " ██████╗ ██████╗ █████╗ ██████╗ ██╗ ██╗██╗ ██╗ ██████╗ ███████╗"
echo " ██╔══██╗██╔══██╗██╔══██╗██╔══██╗██║ ██║╚██╗ ██╔╝██╔═══██╗██╔════╝"
echo " ██║ ██║██████╔╝███████║██████╔╝███████║ ╚████╔╝ ██║ ██║███████╗"
echo " ██║ ██║██╔══██╗██╔══██║██╔═══╝ ██╔══██║ ╚██╔╝ ██║ ██║╚════██║"
echo " ██████╔╝██║ ██║██║ ██║██║ ██║ ██║ ██║ ╚██████╔╝███████║"
echo " ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝"
echo -e "${NC}"
echo -e " Uninstaller"
echo ""
}
print_step() {
echo -e "${GREEN}[*]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[!]${NC} $1"
}
print_error() {
echo -e "${RED}[✗]${NC} $1"
}
print_success() {
echo -e "${GREEN}[✓]${NC} $1"
}
# Check if installed
check_installed() {
if [ ! -f "$MARKER_FILE" ] && [ ! -d "$INSTALL_DIR" ]; then
print_error "draphyOS is not installed."
exit 1
fi
}
# Remove config symlinks (ONLY symlinks pointing to draphyOS, not restored files!)
remove_configs() {
print_step "Removing draphyOS config symlinks..."
# Auto-discover symlinks from repo if available, otherwise scan ~/.config for draphyOS symlinks
local SYMLINKS=()
if [ -d "$INSTALL_DIR/configs" ]; then
local config_name
while IFS= read -r config_name; do
[ -z "$config_name" ] && continue
# Skip cheatsheet .txt files (they are copies, not symlinks)
[[ "$config_name" == i3/scripts/cheatsheets/*.txt ]] && continue
SYMLINKS+=("$(get_user_config_path "$config_name")")
done < <(get_all_config_files)
else
# Fallback: scan ~/.config for any symlinks pointing to draphyOS
print_warning "Repo not found, scanning for draphyOS symlinks..."
while IFS= read -r -d '' link; do
SYMLINKS+=("$link")
done < <(find "$HOME/.config" "$HOME/.xprofile" -maxdepth 6 -type l 2>/dev/null | while read -r l; do
local t; t=$(readlink "$l" 2>/dev/null)
if [[ "$t" == *"draphyOS"* ]] || [[ "$t" == *".draphyOS"* ]]; then
printf '%s\0' "$l"
fi
done)
fi
for link in "${SYMLINKS[@]}"; do
# ONLY remove symlinks - regular files might be restored backups!
if [ -L "$link" ]; then
# Verify it points to draphyOS before removing
# Use readlink without -f first to avoid hanging on circular symlinks
local target
target=$(readlink "$link" 2>/dev/null)
if [ -z "$target" ]; then
# Broken symlink - remove if it was likely created by draphyOS
# (the target path contains draphyOS even if target doesn't exist)
local raw_target
raw_target=$(readlink "$link" 2>/dev/null || true)
if [[ "$raw_target" == *"draphyOS"* ]] || [[ "$raw_target" == *".draphyOS"* ]]; then
rm -f "$link"
fi
continue
fi
# Check both the direct target and resolved path
if [[ "$target" == *"draphyOS"* ]] || [[ "$target" == *".draphyOS"* ]]; then
rm -f "$link"
else
# Try resolving full path with timeout to prevent hang
local full_target
if command -v timeout &>/dev/null; then
full_target=$(timeout 2 readlink -f "$link" 2>/dev/null)
else
full_target=$(readlink -f "$link" 2>/dev/null)
fi
if [[ "$full_target" == *"draphyOS"* ]] || [[ "$full_target" == *".draphyOS"* ]]; then
rm -f "$link"
fi
fi
fi
done
# Remove cheatsheets directory (copied by draphyOS)
# Only remove if it exists and contains only expected cheatsheet files
local cheatsheets_dir="$HOME/.config/i3/scripts/cheatsheets"
if [ -d "$cheatsheets_dir" ]; then
# Check for any non-.txt files that might be user-created
local has_user_files=false
while IFS= read -r -d '' file; do
has_user_files=true
break
done < <(find "$cheatsheets_dir" -type f ! -name "*.txt" -print0 2>/dev/null)
if [ "$has_user_files" = true ]; then
print_warning "Found custom files in cheatsheets directory, preserving it"
else
rm -rf "$cheatsheets_dir" 2>/dev/null || true
fi
fi
# Remove draphyOS wallpaper only (not user's wallpaper)
# Check if it's the draphyOS wallpaper before removing
if [ -f "$HOME/.config/wallpaper.png" ]; then
# Only remove if no backup exists (meaning it's draphyOS wallpaper)
local has_backup=false
for backup_wp in "$HOME"/.config-backup-*/wallpaper.png; do
if [ -f "$backup_wp" ]; then
has_backup=true
break
fi
done
if [ "$has_backup" = false ]; then
rm -f "$HOME/.config/wallpaper.png" 2>/dev/null || true
fi
fi
# Remove xdg-terminals.list (created by draphyOS, not a symlink)
rm -f "$HOME/.config/xdg-terminals.list" 2>/dev/null || true
# Handle configs that were converted from symlinks to real files
# (polybar/picom/gammastep are modified during hardware/VM/location configuration)
# Only remove if no backup exists (meaning draphyOS created them)
local CONVERTED_CONFIGS=(
"$HOME/.config/polybar/config.ini"
"$HOME/.config/picom/picom.conf"
"$HOME/.config/gammastep/config.ini"
)
for config in "${CONVERTED_CONFIGS[@]}"; do
# Skip if it's a symlink (already handled above) or doesn't exist
if [ -L "$config" ] || [ ! -f "$config" ]; then
continue
fi
# Check if backup exists for this config
local config_name
config_name=$(basename "$(dirname "$config")")
local has_backup=false
for backup_dir in "$HOME"/.config-backup-*/; do
if [ -d "$backup_dir$config_name" ] || [ -f "$backup_dir$config_name" ]; then
has_backup=true
break
fi
done
# If no backup, this was created by draphyOS - safe to remove
if [ "$has_backup" = false ]; then
rm -f "$config" 2>/dev/null || true
fi
done
# Remove empty directories created by draphyOS (auto-discovered from repo)
# Uses rmdir which ONLY removes truly empty directories — safe by design
if [ -d "$INSTALL_DIR/configs" ]; then
# Discover all directories from repo structure and remove deepest-first
local config_name
while IFS= read -r config_name; do
[ -z "$config_name" ] && continue
local user_file
user_file=$(get_user_config_path "$config_name")
local user_dir
user_dir=$(dirname "$user_file")
# Try removing this dir and parents up to ~/.config (deepest first)
while [ "$user_dir" != "$HOME/.config" ] && [ "$user_dir" != "$HOME" ]; do
rmdir "$user_dir" 2>/dev/null || true
user_dir=$(dirname "$user_dir")
done
done < <(get_all_config_files)
else
# Fallback: try known directories (deepest first)
local CLEANUP_DIRS=(
"$HOME/.config/i3/scripts/cheatsheets"
"$HOME/.config/i3/scripts"
"$HOME/.config/polybar"
"$HOME/.config/picom"
"$HOME/.config/gammastep"
"$HOME/.config/yazi"
"$HOME/.config/btop"
"$HOME/.config/environment.d"
"$HOME/.config/rofi"
"$HOME/.config/dunst"
"$HOME/.config/xdg-desktop-portal"
"$HOME/.config/xfce4/xfconf/xfce-perchannel-xml"
"$HOME/.config/xfce4/xfconf"
"$HOME/.config/xfce4"
"$HOME/.config/alacritty"
"$HOME/.config/fish/functions"
"$HOME/.config/fish/conf.d"
)
for dir in "${CLEANUP_DIRS[@]}"; do
rmdir "$dir" 2>/dev/null || true
done
fi
# Don't remove main config dirs (i3, fish, alacritty, gtk-3.0) - they might have restored configs!
print_success "draphyOS symlinks removed"
}
# Remove v10 third-party repos (optional)
remove_v10_repos() {
print_step "Cleaning up v10 third-party repositories..."
# Remove third-party repo files
sudo rm -f /etc/yum.repos.d/brave-browser.repo 2>/dev/null || true
sudo rm -f /etc/yum.repos.d/google-chrome.repo 2>/dev/null || true
sudo rm -f /etc/yum.repos.d/vscode.repo 2>/dev/null || true
sudo rm -f /etc/yum.repos.d/docker-ce.repo 2>/dev/null || true
# Remove both naming variants (colon vs underscore) for compatibility
sudo rm -f /etc/yum.repos.d/home:justkidding.repo 2>/dev/null || true
sudo rm -f /etc/yum.repos.d/home_justkidding.repo 2>/dev/null || true
# Remove COPR
sudo dnf copr remove lihaohong/yazi -y 2>/dev/null || true
# Remove ProtonVPN repo package
sudo dnf remove protonvpn-stable-release -y 2>/dev/null || true
print_success "Third-party repos removed"
}
# Cleanup Docker configuration (optional)
cleanup_docker() {
# Check if Docker was configured by draphyOS
if groups "$USER" 2>/dev/null | grep -q docker; then
echo ""
echo -e "You are in the ${YELLOW}docker${NC} group (added by draphyOS)."
echo -e "Do you want to remove yourself from the docker group? (y/n)"
read -r response </dev/tty || response="n"
if [[ "$response" =~ ^[Yy](es)?$ ]]; then
print_step "Removing $USER from docker group..."
sudo gpasswd -d "$USER" docker 2>/dev/null || true
print_success "Removed from docker group"
fi
fi
# Disable Docker service if running
if systemctl is-enabled docker &>/dev/null; then
echo -e "Docker service is enabled. Disable it? (y/n)"
read -r response </dev/tty || response="n"
if [[ "$response" =~ ^[Yy](es)?$ ]]; then
print_step "Disabling Docker service..."
sudo systemctl disable docker 2>/dev/null || true
sudo systemctl stop docker 2>/dev/null || true
print_success "Docker service disabled"
fi
fi
}
# Cleanup PostgreSQL configuration (optional)
cleanup_postgresql() {
# Check if PostgreSQL service is enabled
if systemctl is-enabled postgresql &>/dev/null; then
echo ""
echo -e "PostgreSQL service is ${YELLOW}enabled${NC}."
echo -e "Do you want to disable PostgreSQL service? (y/n)"
echo -e "${YELLOW}(Your databases in /var/lib/pgsql/data will be preserved)${NC}"
read -r response </dev/tty || response="n"
if [[ "$response" =~ ^[Yy](es)?$ ]]; then
print_step "Disabling PostgreSQL service..."
sudo systemctl disable postgresql 2>/dev/null || true
sudo systemctl stop postgresql 2>/dev/null || true
print_success "PostgreSQL service disabled"
fi
fi
}
# Remove fnm and Node.js (optional)
cleanup_fnm() {
local fnm_dir="$HOME/.local/share/fnm"
local fnm_legacy="$HOME/.fnm"
if [ -d "$fnm_dir" ] || [ -d "$fnm_legacy" ] || command -v fnm &>/dev/null; then
echo ""
echo -e "fnm (Node.js manager) is installed."
echo -e "Do you want to ${RED}remove fnm and all Node.js versions${NC}? (y/n)"
read -r response </dev/tty || response="n"
if [[ "$response" =~ ^[Yy](es)?$ ]]; then
print_step "Removing fnm and Node.js..."
rm -rf "$fnm_dir" 2>/dev/null || true
rm -rf "$fnm_legacy" 2>/dev/null || true
rm -rf "$HOME/.cache/fnm" 2>/dev/null || true
print_success "fnm and Node.js removed"
else
print_step "Keeping fnm installation"
fi
fi
}
# Remove Claude Code CLI (optional)
cleanup_claude_code() {
if command -v claude &>/dev/null || [ -d "$HOME/.claude" ]; then
echo ""
echo -e "Claude Code CLI is installed."
echo -e "Do you want to ${RED}uninstall Claude Code${NC}? (y/n)"
read -r response </dev/tty || response="n"
if [[ "$response" =~ ^[Yy](es)?$ ]]; then
print_step "Uninstalling Claude Code..."
# Try npm uninstall first (if installed via npm)
if npm list -g @anthropic-ai/claude-code &>/dev/null 2>&1; then
npm uninstall -g @anthropic-ai/claude-code 2>/dev/null || true
fi
# Complete cleanup for native installation
rm -rf "$HOME/.claude" 2>/dev/null || true
rm -f "$HOME/.local/bin/claude" 2>/dev/null || true
rm -rf "$HOME/.local/share/claude" 2>/dev/null || true
rm -rf "$HOME/.local/state/claude" 2>/dev/null || true
rm -rf "$HOME/.config/claude" 2>/dev/null || true
rm -rf /tmp/*claude* 2>/dev/null || true
# Remove PATH entries from shell configs
sed -i '/\.claude\/bin/d' "$HOME/.bashrc" 2>/dev/null || true
sed -i '/\.claude\/bin/d' "$HOME/.zshrc" 2>/dev/null || true
# Verify removal
if ! command -v claude &>/dev/null; then
print_success "Claude Code uninstalled"
else
print_warning "Claude Code may still be in PATH. Restart your shell."
fi
else
print_step "Keeping Claude Code installation"
fi
fi
}
# Remove cgroup delegation config (created for Docker rootless)
cleanup_cgroup_delegation() {
local delegate_conf="/etc/systemd/system/user@.service.d/delegate.conf"
if [ -f "$delegate_conf" ]; then
# Check if it was created by draphyOS
if grep -q "cpu cpuset io memory pids" "$delegate_conf" 2>/dev/null; then
print_step "Removing cgroup delegation config..."
sudo rm -f "$delegate_conf" 2>/dev/null || true
sudo rmdir /etc/systemd/system/user@.service.d 2>/dev/null || true
sudo systemctl daemon-reload 2>/dev/null || true
print_success "cgroup delegation config removed"
fi
fi
}
# Disable switcheroo-control (if enabled for hybrid graphics)
cleanup_switcheroo() {
if systemctl is-enabled switcheroo-control &>/dev/null 2>&1; then
echo ""
echo -e "switcheroo-control (GPU switching) is enabled."
echo -e "Do you want to ${YELLOW}disable${NC} it? (y/n)"
read -r response </dev/tty || response="n"
if [[ "$response" =~ ^[Yy](es)?$ ]]; then
print_step "Disabling switcheroo-control..."
sudo systemctl disable switcheroo-control 2>/dev/null || true
sudo systemctl stop switcheroo-control 2>/dev/null || true
print_success "switcheroo-control disabled"
fi
fi
}
# Disable power-profiles-daemon (if enabled by draphyOS for TLP conflict resolution)
cleanup_power_profiles() {
# Only offer to disable if it was potentially enabled by draphyOS
# (when TLP was disabled in favor of power-profiles-daemon)
if systemctl is-enabled power-profiles-daemon &>/dev/null 2>&1; then
# Check if TLP is installed but masked (indicates draphyOS made the choice)
if rpm -q tlp &>/dev/null && systemctl is-enabled tlp &>/dev/null 2>&1; then
# TLP is enabled, power-profiles-daemon shouldn't be - skip
return
fi
echo ""
echo -e "power-profiles-daemon is ${YELLOW}enabled${NC}."
echo -e "Do you want to disable it? (y/n)"
echo -e "${YELLOW}(Only disable if you plan to use TLP or another power manager)${NC}"
read -r response </dev/tty || response="n"
if [[ "$response" =~ ^[Yy](es)?$ ]]; then
print_step "Disabling power-profiles-daemon..."
sudo systemctl disable power-profiles-daemon 2>/dev/null || true
sudo systemctl stop power-profiles-daemon 2>/dev/null || true
print_success "power-profiles-daemon disabled"
fi
fi
}
# Revert gsettings (dark mode preferences)
revert_gsettings() {
if command -v gsettings &>/dev/null; then
print_step "Reverting GNOME/GTK settings to defaults..."
# Reset to default (empty/system default)
gsettings reset org.gnome.desktop.interface color-scheme 2>/dev/null || true
gsettings reset org.gnome.desktop.interface gtk-theme 2>/dev/null || true
gsettings reset org.gnome.desktop.interface icon-theme 2>/dev/null || true
gsettings reset org.gnome.desktop.interface cursor-theme 2>/dev/null || true
print_success "GNOME/GTK settings reset to defaults"
fi
}
# Remove NVIDIA drivers (optional)
cleanup_nvidia() {
if rpm -q akmod-nvidia &>/dev/null; then
echo ""
echo -e "NVIDIA drivers are installed."
echo -e "${YELLOW}WARNING: Removing NVIDIA drivers may affect your display!${NC}"
echo -e "Do you want to ${RED}remove NVIDIA drivers${NC}? (y/n)"
read -r response </dev/tty || response="n"
if [[ "$response" =~ ^[Yy](es)?$ ]]; then
print_step "Removing NVIDIA drivers..."
sudo dnf remove -y akmod-nvidia xorg-x11-drv-nvidia* nvidia-settings 2>/dev/null || true
# Regenerate initramfs
sudo dracut --force 2>/dev/null || true
print_success "NVIDIA drivers removed"
print_warning "REBOOT REQUIRED - system will use nouveau driver"
else
print_step "Keeping NVIDIA drivers"
fi
fi
}
# Show warnings for remaining manual cleanup
show_v10_cleanup_warnings() {
echo ""
print_warning "The following may need manual cleanup:"
echo ""
echo " Docker (if you have containers/images):"
echo " docker system prune -a"
echo ""
echo " PostgreSQL data (preserves your databases):"
echo " Location: /var/lib/pgsql/data"
echo " To remove: sudo rm -rf /var/lib/pgsql/data"
echo ""
}
# Revert fish shell to bash (optional)
revert_shell() {
local current_shell
current_shell=$(basename "$SHELL")
if [ "$current_shell" = "fish" ]; then
echo -e "Your default shell is currently ${YELLOW}fish${NC}."
echo -e "Do you want to revert to ${GREEN}bash${NC}? (y/n)"
read -r response </dev/tty || response="n"
if [[ "$response" =~ ^[Yy](es)?$ ]]; then
local bash_path
bash_path=$(command -v bash)
local fish_path
fish_path=$(command -v fish)
if [ -n "$bash_path" ]; then
print_step "Reverting shell to bash..."
if sudo chsh -s "$bash_path" "$USER" 2>/dev/null || chsh -s "$bash_path" 2>/dev/null; then
print_success "Shell reverted to bash"
# Remove fish from /etc/shells if it was added by draphyOS
if [ -n "$fish_path" ] && grep -qxF "$fish_path" /etc/shells 2>/dev/null; then
# Use grep -v for safe removal (no regex interpretation)
grep -vxF "$fish_path" /etc/shells | sudo tee /etc/shells.tmp >/dev/null 2>&1 && \
sudo mv /etc/shells.tmp /etc/shells 2>/dev/null || true
fi
else
print_warning "Could not change shell. Run manually: chsh -s $bash_path"
fi
fi
else
print_step "Keeping fish as default shell"
fi
fi
}
# Remove installed packages (dynamic - only removes what draphyOS added)
remove_packages() {
local pkg_state_file="$HOME/.draphyOS-packages-before"
local base_system=""
local base_variant=""
if [ -f "$MARKER_FILE" ]; then
base_system=$(grep "^BASE_SYSTEM=" "$MARKER_FILE" 2>/dev/null | cut -d= -f2)
base_variant=$(grep "^BASE_VARIANT=" "$MARKER_FILE" 2>/dev/null | cut -d= -f2)
fi
# Check if we have saved package state for dynamic removal
if [ -f "$pkg_state_file" ]; then
echo -e "${GREEN}Found package state from before installation${NC}"
echo -e "This allows precise removal of only packages added by draphyOS."
echo ""
echo -e "Do you want to ${RED}remove packages added by draphyOS${NC}? (y/n)"
read -r response </dev/tty || response="n"
if [[ "$response" =~ ^[Yy](es)?$ ]]; then
print_step "Calculating packages to remove..."
# Get current installed packages (using rpm for consistency with install)
local current_pkgs
current_pkgs=$(mktemp)
rpm -qa --qf '%{NAME}\n' 2>/dev/null | sort -u > "$current_pkgs"
# Find packages that were added (in current but not in before)
local pkgs_to_remove
pkgs_to_remove=$(comm -23 "$current_pkgs" "$pkg_state_file")
rm -f "$current_pkgs"
if [ -z "$pkgs_to_remove" ]; then
print_step "No packages to remove (system already at original state)"
return
fi
# Count and show what will be removed
local count
count=$(echo "$pkgs_to_remove" | wc -l)
echo -e "Found ${YELLOW}$count${NC} packages added by draphyOS"
echo ""
echo -e "Packages to remove:"
echo "$pkgs_to_remove" | head -20 | while read -r pkg; do
echo -e " ${RED}-${NC} $pkg"
done
if [ "$count" -gt 20 ]; then
echo -e " ... and $((count - 20)) more"
fi
echo ""
echo -e "Proceed with removal? (y/n)"
read -r confirm </dev/tty || confirm="n"
if [[ "$confirm" =~ ^[Yy](es)?$ ]]; then
print_step "Removing $count packages..."
# Convert to array and remove
# Use --noautoremove here since we're being precise about what to remove
# Validate package list is not empty before passing to dnf
if [ -n "$pkgs_to_remove" ]; then
# Use array to safely handle package names with special chars
local -a pkg_array
mapfile -t pkg_array <<< "$pkgs_to_remove"
if [ ${#pkg_array[@]} -gt 0 ]; then
sudo dnf remove -y --noautoremove "${pkg_array[@]}" 2>/dev/null || true
fi
fi
print_success "Packages removed - system restored to pre-install state"
# Clean up the state file
rm -f "$pkg_state_file"
else
print_step "Package removal cancelled"
fi
else
print_step "Skipping package removal"
fi
else
# Fallback: No saved state - use legacy method
print_warning "No saved package state found (older installation)"
echo -e "Will use predefined package list instead."
echo ""
remove_packages_legacy "$base_system" "$base_variant"
fi
}
# Legacy package removal (fallback when no state file exists)
remove_packages_legacy() {
local base_system="$1"
local base_variant="$2"
# Critical system packages that must NEVER be auto-removed
local PROTECTED_PACKAGES=(
xorg-x11-server-Xorg xorg-x11-xinit xorg-x11-drv-libinput
mesa-dri-drivers mesa-vulkan-drivers mesa-libGL
lightdm lightdm-gtk-greeter lightdm-gtk
i3 i3status i3lock dunst rofi
NetworkManager dbus-x11 polkit
gtk3 gtk2 adwaita-gtk2-theme adwaita-icon-theme
)
# draphyOS-specific packages
local DRAPHYOS_PACKAGES=(
polybar picom fish alacritty
feh flameshot playerctl xss-lock
xdotool xclip ImageMagick
redshift geoclue2 yad qt5ct
mint-y-icons
fontawesome-6-free-fonts fontawesome-6-brands-fonts
)
# Core i3 packages (for full removal option)
local CORE_I3_PACKAGES=(
i3 i3lock dunst rofi
lightdm lightdm-gtk-greeter
arandr lxappearance tmux powertop
xfce-polkit gnome-keyring xfce4-settings
blueman adwaita-cursor-theme
)
if [ "$base_system" = "fedora-i3" ]; then
echo -e "${GREEN}Detected: Fedora i3 Spin${NC}"
echo -e "Only draphyOS-specific packages will be removed."
echo ""
echo -e "Do you want to ${RED}remove draphyOS packages${NC}? (y/n)"
echo -e "${YELLOW}(polybar, picom, fish, redshift, etc.)${NC}"
read -r response </dev/tty || response="n"
if [[ "$response" =~ ^[Yy](es)?$ ]]; then
print_step "Protecting critical system packages..."
sudo dnf mark install "${PROTECTED_PACKAGES[@]}" &>/dev/null || true
print_step "Removing draphyOS-specific packages..."
sudo dnf remove -y --noautoremove "${DRAPHYOS_PACKAGES[@]}" 2>/dev/null || true
print_success "draphyOS packages removed (core i3 packages kept)"
else
print_step "Skipping package removal"
fi
else
echo -e "${GREEN}Detected: Fedora ${base_variant:-other}${NC}"
echo ""
echo -e "Choose package removal option:"
echo -e " ${YELLOW}1)${NC} Remove only draphyOS additions"
echo -e " ${YELLOW}2)${NC} Remove ALL i3-related packages"
echo -e " ${YELLOW}3)${NC} Skip package removal"
echo ""
echo -n "Enter choice [1-3]: "
read -r choice </dev/tty || choice="3"
case "$choice" in
1)
print_step "Protecting critical system packages..."
sudo dnf mark install "${PROTECTED_PACKAGES[@]}" &>/dev/null || true
print_step "Removing draphyOS-specific packages..."
sudo dnf remove -y --noautoremove "${DRAPHYOS_PACKAGES[@]}" 2>/dev/null || true
print_success "draphyOS packages removed"
;;
2)
echo -e "${RED}WARNING: This will remove i3 and all related packages!${NC}"
echo -n "Are you sure? (yes/no): "
read -r confirm </dev/tty || confirm="no"
if [ "$confirm" = "yes" ]; then
local BASE_PROTECTED=(
xorg-x11-server-Xorg xorg-x11-xinit xorg-x11-drv-libinput
mesa-dri-drivers mesa-vulkan-drivers mesa-libGL
NetworkManager dbus-x11 polkit
gtk3 gtk2 adwaita-gtk2-theme adwaita-icon-theme
)
sudo dnf mark install "${BASE_PROTECTED[@]}" &>/dev/null || true
print_step "Removing ALL i3-related packages..."
sudo dnf remove -y --noautoremove "${DRAPHYOS_PACKAGES[@]}" "${CORE_I3_PACKAGES[@]}" 2>/dev/null || true
print_success "All i3 packages removed"
fi
;;
*)
print_step "Skipping package removal"
;;
esac
fi
}
# Remove battery limit service/udev/scripts
remove_battery_limit() {
local removed=false
# Remove systemd service
if [ -f /etc/systemd/system/battery-charge-limit.service ]; then
print_step "Removing battery limit service..."
sudo systemctl disable battery-charge-limit.service 2>/dev/null || true
sudo systemctl stop battery-charge-limit.service 2>/dev/null || true
sudo rm -f /etc/systemd/system/battery-charge-limit.service
sudo systemctl daemon-reload
removed=true
fi
# Remove ASUS udev rule
if [ -f /etc/udev/rules.d/99-battery-charge-limit.rules ]; then
print_step "Removing battery limit udev rule..."
sudo rm -f /etc/udev/rules.d/99-battery-charge-limit.rules
sudo udevadm control --reload-rules 2>/dev/null || true
removed=true
fi
# Remove ASUS battery script
if [ -f /usr/local/bin/asus-battery-limit.sh ]; then
print_step "Removing ASUS battery limit script..."
sudo rm -f /usr/local/bin/asus-battery-limit.sh
removed=true
fi
if [ "$removed" = true ]; then
print_success "Battery limit configuration removed"
echo " Note: Battery will charge to 100% after reboot"
fi
}
# Remove LightDM customization (careful not to break graphical login)
remove_lightdm() {
# Detect base system
local base_system=""
if [ -f "$MARKER_FILE" ]; then
base_system=$(grep "^BASE_SYSTEM=" "$MARKER_FILE" 2>/dev/null | cut -d= -f2)
fi
# Only touch LightDM if we have a backup to restore
if [ -f /etc/lightdm/lightdm-gtk-greeter.conf.backup ]; then
print_step "Restoring original LightDM config..."
sudo mv /etc/lightdm/lightdm-gtk-greeter.conf.backup /etc/lightdm/lightdm-gtk-greeter.conf 2>/dev/null || true
print_success "LightDM restored from backup"
else
# For Fedora i3 Spin, DON'T reset LightDM - it needs to work!
if [ "$base_system" = "fedora-i3" ]; then
print_step "Keeping current LightDM config (required for i3 Spin)"
else
# For other systems, only remove draphyOS customization if it exists
if grep -q "draphyOS" /etc/lightdm/lightdm-gtk-greeter.conf 2>/dev/null; then
print_step "Removing draphyOS LightDM customization..."
# Keep a working config, just remove draphyOS-specific parts
sudo sed -i '/draphyOS/d' /etc/lightdm/lightdm-gtk-greeter.conf 2>/dev/null || true
print_success "LightDM customization removed"
fi
fi
fi
# Remove draphyOS wallpaper from system
sudo rm -rf /usr/share/backgrounds/draphyOS 2>/dev/null || true
}
# Restore backup
restore_backup() {
# Detect base system for smart restore handling
local base_system=""
if [ -f "$MARKER_FILE" ]; then
base_system=$(grep "^BASE_SYSTEM=" "$MARKER_FILE" 2>/dev/null | cut -d= -f2)
fi
# Find latest backup
LATEST_BACKUP=$(ls -td "$HOME"/.config-backup-* 2>/dev/null | head -1)
if [ -n "$LATEST_BACKUP" ] && [ -d "$LATEST_BACKUP" ]; then
echo -e "Found backup: ${YELLOW}$LATEST_BACKUP${NC}"
echo ""
# List what's in the backup
echo -e "Backup contains:"
for item in "$LATEST_BACKUP"/*; do
if [ -e "$item" ]; then
echo -e " - $(basename "$item")"
fi
done
echo ""
# For Fedora i3 Spin, auto-restore with option to skip
if [ "$base_system" = "fedora-i3" ]; then
echo -e "${YELLOW}IMPORTANT: You're on Fedora i3 Spin.${NC}"
echo -e "Restoring backup will give you back your original Fedora i3 configs."
echo -e "${RED}Without restore, i3 will NOT have working configs!${NC}"
echo ""
echo -e "Restore backup? [${GREEN}Y${NC}/n] (${GREEN}Y is default${NC})"
read -r response </dev/tty || response="y"
# Default to yes for i3 spin
if [[ -z "$response" ]] || [[ "$response" =~ ^[Yy](es)?$ ]]; then
response="y"
fi
else
echo -e "Do you want to ${GREEN}restore${NC} this backup? (y/n)"
read -r response </dev/tty || response="n"
fi
if [[ "$response" =~ ^[Yy](es)?$ ]]; then
print_step "Restoring backup..."
# Ensure target directories exist
mkdir -p "$HOME/.config"
# Restore each config
for item in "$LATEST_BACKUP"/*; do
if [ -e "$item" ]; then
BASENAME=$(basename "$item")
case "$BASENAME" in
xprofile)
cp -r "$item" "$HOME/.xprofile"
print_step " Restored: .xprofile"
;;
Xresources)
# Legacy backup support
cp -r "$item" "$HOME/.Xresources"
print_step " Restored: .Xresources"
;;
alacritty)
mkdir -p "$HOME/.config/alacritty"
cp -r "$item"/* "$HOME/.config/alacritty/" 2>/dev/null || cp -r "$item" "$HOME/.config/"
print_step " Restored: alacritty"
;;
wallpaper.png)
cp -r "$item" "$HOME/.config/wallpaper.png"
print_step " Restored: wallpaper.png"
;;
*)
# For directories, ensure parent exists
if [ -d "$item" ]; then
cp -r "$item" "$HOME/.config/"
else
cp "$item" "$HOME/.config/"
fi
print_step " Restored: $BASENAME"
;;
esac
fi
done
print_success "Backup restored successfully"
# Reload Xresources if restored (legacy backup support)
if [ -f "$HOME/.Xresources" ] && command -v xrdb &>/dev/null; then
# Only attempt if DISPLAY is set (X is running)
if [ -n "${DISPLAY:-}" ]; then
if command -v timeout &>/dev/null; then
timeout 5 xrdb -merge "$HOME/.Xresources" 2>/dev/null || true
else
xrdb -merge "$HOME/.Xresources" 2>/dev/null || true
fi
fi
fi
else
# User declined restore
if [ "$base_system" = "fedora-i3" ]; then
print_warning "Backup not restored."
echo ""
# Offer to copy default configs from /etc/skel
copy_default_i3_configs
fi
fi
else
print_warning "No backup found to restore"
# For i3 spin, offer to copy default configs
if [ "$base_system" = "fedora-i3" ]; then
echo ""
copy_default_i3_configs
fi
fi
}
# Copy default i3 configs from /etc/skel (Fedora i3 Spin only)
copy_default_i3_configs() {
echo -e "${YELLOW}Your i3 needs config files to function.${NC}"
echo ""
# Check what default configs are available
local has_skel_i3=false
local has_skel_i3status=false
if [ -d /etc/skel/.config/i3 ]; then
has_skel_i3=true
fi
if [ -d /etc/skel/.config/i3status ] || [ -f /etc/skel/.config/i3status/config ]; then
has_skel_i3status=true
fi
if [ "$has_skel_i3" = true ]; then
echo -e "Default Fedora i3 configs found in /etc/skel/"
echo -e "Do you want to copy default i3 configs? (y/n)"
read -r response </dev/tty || response="n"
if [[ "$response" =~ ^[Yy](es)?$ ]]; then
print_step "Copying default i3 configs..."
# Copy i3 config
mkdir -p "$HOME/.config/i3"
if [ -d /etc/skel/.config/i3 ]; then
cp -r /etc/skel/.config/i3/* "$HOME/.config/i3/" 2>/dev/null || true
print_step " Copied: i3 config"
fi
# Copy i3status config if exists
if [ -d /etc/skel/.config/i3status ]; then
mkdir -p "$HOME/.config/i3status"
cp -r /etc/skel/.config/i3status/* "$HOME/.config/i3status/" 2>/dev/null || true
print_step " Copied: i3status config"
fi
# Copy other common configs if they exist in skel
for dir in dunst rofi; do
if [ -d "/etc/skel/.config/$dir" ]; then
mkdir -p "$HOME/.config/$dir"
cp -r "/etc/skel/.config/$dir/"* "$HOME/.config/$dir/" 2>/dev/null || true
print_step " Copied: $dir config"
fi
done
print_success "Default configs copied"
echo -e "${GREEN}Your i3 should work with default Fedora i3 Spin settings.${NC}"
else
print_warning "No configs restored. i3 may not work properly."
echo -e "You can manually copy configs with:"
echo -e " ${YELLOW}cp -r /etc/skel/.config/i3 ~/.config/${NC}"
fi
else
print_warning "Default i3 configs not found in /etc/skel/"
echo -e "You may need to create a basic i3 config manually."
echo -e "Generate one with: ${YELLOW}i3-config-wizard${NC}"
fi
}
# Remove system update script
remove_update_script() {
local update_script="/usr/local/bin/update-draphyOS"
if [ -f "$update_script" ]; then
print_step "Removing system update script..."
if sudo rm -f "$update_script"; then
print_success "Update script removed"
else
print_warning "Could not remove update script"
fi
fi