Note, it is a work in progress, but it should work in most scenarios.
Once you have selected the module to act upon, press '?' key to get a help screen.
Please, give your feedback.
Code: Select all
#!/usr/bin/env bash
# ---------------------------------------------------------------
# Nemaster v.20230620
# https://forum.porteus.org/viewtopic.php?p=94310#p94310
# dependencies: fzf, pactree, paccheck
# Credits to ncmprhnsbl and Will Conner, author of yayfzf (https://github.com/ConnerWill/yayfzf),
# from whom I borrowed many of the ideas included in this script.
# ===============================================================
#set -x
[[ $EUID -eq 0 ]] || su -c "$0"
. /usr/share/porteus/porteus-functions
warn() { tput bold; for i in {1,0,1,0,1}; do tput setaf $i; tput sc; printf "$*"; tput el; tput rc; sleep 0.1; done; tput sgr0; echo; } >&2
notify() { tput bold; for i in {2,0,2,0,2}; do tput setaf $i; tput sc; printf "$*"; tput el; tput rc; sleep 0.1; done; tput sgr0; echo; } >&2
confirm() { echo; tput setaf 6; read -n1 -rsp "$1"; tput sgr0; echo -e "\n"; [[ ${REPLY,} == y ]]; } >&2
YLW=$(tput setaf 3;tput bold); rst=$(tput sgr0)
printf "\e[8;240;800t"
trap "$(printf "\e[8;24;80t")" SIGHUP SIGINT SIGTERM
for reqcmd in {fzf,pactree,paccheck}; do command -v $cmd 2>&1 || { echo >&2 "Please install $reqcmd and run again"; exit 1; }; done
[ -f /etc/pacman.d/mirrorlist.bak ] && mirrorlist-toggle >/dev/null 2>&1 ### Allow rolling repos
_Help=$(mktemp)
cat <<EOH >$_Help
${YLW}NEMASTER:${rst}: Remaster your Nemesis modules interactively
${YLW}KEYBINDINGS:${rst}
${YLW}Ctrl-a ${rst}Select all
${YLW}Ctrl-t ${rst}Toggle Selection
${YLW}Tab ${rst}Select individual package/s
${YLW}Shift-Tab ${rst}Unselect individual package/s
${YLW}Ctrl-p ${rst}(un)Hide preview-window
${YLW}Enter ${rst}Execute command
${YLW}Esc ${rst}Skip/Quit
${YLW}? ${rst}Help (this page)
${YLW}ASSUMPTIONS${rst}
By using this program, YOU ASSUME FULL RESPONSIBILITY for
what happens to your system.
Nemesis is a system derived from Artix, which in turn is derived
from ArchLinux. Therefore, an average knowledge of pacman usage
is assumed.
It is strongly recommended that you READ THE INSTRUCTIONS BELOW
and MAKE A BACKUP of your modules before proceeding.
${YLW}HOW IT WORKS${rst}
The program involves 7 steps:
1. Select a module to remaster from your ${PORTDIR}
and subdirs. You can search by typing part of his name.
2. REMOVE orphan packages found (if any).
If in doubt, press <Ctrl+a> then <Enter>
3. REMOVE packages from module.
This option has been included to complete the set of possible actions.
Can be useful when full remastering or when removing obsolete packages.
Use only in case you know what you're doing, otherwise, press <Esc>.
4. ADD missing dependencies reported by LIVE SYSTEM.
A target module for every missing dependency is suggested, but
you decide which ones and where they will be placed.
Of course, you can press <Esc> to skip this step.
(No fonts/cursors are mandatory dependencies...)
5. UPDATE packages in module.
Press <Ctrl-a> to select all, then <Enter> to update them.
6. ADD any arbitrary package(s) into the module.
You can search by typing part of his name and select them with
<Tab>. Press <Enter> when done.
7. Finally, you can add AUR packages previously built.
They *must* be placed anywhere *under your ${YLW}/home${rst}* folder.
${YLW}TIPS${rst}
To create your own bundle, create an empty folder, then right click
and build a new (empty) module. You can use it later to inject packages
into it.
A logfile will be created allowing to review what has been updated.
Hopefully, the progressive use of this script will help you
to keep your Nemesis in an optimal state.
Happy Nemastering!
EOH
_Prepare() {
clear
rm "/var/cache/pacman/pkg/*" >/dev/null 2>&1 # clear package cache
if [ ! -f /var/lib/pacman/local/ALPM_DB_VERSION ]; then
#setup-pman ||
( pacman-db-upgrade; haveged; pacman-key --init; pacman-key --populate archlinux artix; pkill haveged; pacman -Syy; )
fi
}
_Nemaster() {
XPATH="$(find "$PORTDIR" -iname '*.xzm' | fzf --header 'Select module to Nemaster (type something to filter)')"
X="${XPATH##*/}"; X="${X%-*}"; test "${#X}" -le 5 && X="${XPATH##*/}" && X="${X%.xzm}" ### Ensure module name is not ### X="${X::-4}" XDIR="${XPATH%/*}"
[ -z "$XMODS" ] && XMODS=$(mktemp -d)
cd $XMODS || exit
unsquashfs -f -d "${X}" "${XPATH}"
dB="$(pacman-conf DBPath)"
cp -as --parents "$dB"{sync,local/ALPM_DB_VERSION} "$X"
XPKGS="$(pacman -Qqr $X)"
### SUGGESTED DEPS
paccheck | awk '/unsatisfied/ {print $1 $4}' | tr -d "'" > /tmp/MISSING
for pkg in $(awk -F: '{print $1}' /tmp/MISSING); do wmod $pkg \
| sed -r 's/([a-z])-[0-9]+\.[0-9].+/\1/g'; done > /tmp/PARENTMOD
paste <(awk -F: '{print $1}' /tmp/PARENTMOD) <(awk -F: '{print $2}' /tmp/MISSING) | sort -u > /tmp/SUGGESTED
### REINSTALL ALL NATIVE PACKAGES
### pacman -Qqnr "$X" | xargs -ro pacman --logfile "$X"-pacman.log -Sddr "$X" --asdeps --noconfirm --overwrite "*"
FZF_DEFAULT_OPTS="--ansi --border --border-label-pos=3 --color=label:bold:#FFB900,spinner:#98BC99,prompt:#98BEDE --exit-0 --info=inline --keep-right --layout=reverse-list --marker + --pointer ➤ --prompt search> --multi --preview-window=right,60%:wrap --print-query --reverse --bind ctrl-a:select-all,ctrl-d:deselect-all,ctrl-t:toggle-all,ctrl-p:toggle-preview,enter:clear-query+accept --scrollbar "
pacman -Qqdt \
| fzf $FZF_DEFAULT_OPTS \
--bind "?:preview:(cat $_Help)" --preview "pacman -Si {1}" \
--bind "change:reload:sleep 0.1 {q} {}" \
--border-label="[ REMOVE ORPHANS packages in module $X ]" \
--header "<Enter> to EJECT <Esc> to skip or <?> for help" \
| xargs -ro pacman --logfile "$X"-pacman.log -Rddr "$X" --noconfirm
echo "$XPKGS" \
| fzf $FZF_DEFAULT_OPTS \
--bind "?:preview:(cat $_Help)" --preview "pacman -Si {1}" \
--border-label="[ REMOVE EXISTING packages in module $X ]" \
--header "<Enter> to EJECT <Esc> to skip or <?> for help" \
| xargs -ro pacman --logfile "$X"-pacman.log -Rddr "$X" --noconfirm
awk -F: '{print $2}' /tmp/MISSING \
| fzf $FZF_DEFAULT_OPTS \
--bind "?:preview:(cat $_Help)" --preview "grep $X /tmp/SUGGESTED" \
--border-label="[ ADD MISSING DEPS to module $X ]" \
--preview-label=" SUGGESTED PACKAGES TO ADD: " \
--header "<Enter> to ADD <Esc> to skip or <?> for help" \
| xargs -ro pacman --logfile "$X"-pacman.log -Sddr "$X" --asdeps --noconfirm --overwrite "*"
pacman -Qqur "$X" \
| fzf $FZF_DEFAULT_OPTS \
--bind "?:preview:(cat $_Help)" --preview "pacman -Si {1}" \
--border-label="[ UPDATE EXISTING packages in module $X ]" \
--header "<Enter> to UPDATE <Esc> to skip or <?> for help" \
| xargs -ro pacman --logfile "$X"-pacman.log -Sddr "$X" --asdeps --noconfirm --overwrite "*"
pacman -Slq \
| fzf $FZF_DEFAULT_OPTS \
--bind "?:preview:(cat $_Help)" --preview "pacman -Si {1}" \
--border-label "[ ADD NEW packages to $X module ]" \
--header "<Enter> to INJECT <Esc> to skip or <?> for help" \
--sync \
| xargs -ro pacman --logfile "$X"-pacman.log -Sddr "$X" --asdeps --noconfirm --overwrite "*"
find /home -type f '(' -name *.zst -o -name *.xz ')' -print \
| fzf $FZF_DEFAULT_OPTS \
--bind "?:preview:(cat $_Help)" --preview "pacman -Si {1}" \
--border-label="[ ADD AUR local built packages in $X ]" \
--header "<Enter> to INJECT <Esc> to skip or <?> for help" \
| xargs -ro pacman --logfile "$X"-pacman.log -Uddr "$X" --asdeps --noconfirm --overwrite "*"
}
_SanitizeDB() {
# Because of partial upgrades (i.e. pacman -Sddr or -Uddr ...), every package in module will be marked as explicit sooner or later.
# Trying to revert the situation in order to track down new/obsolete dependencies
printf "\nPrevious explicit packages count: "; notify $(wc -l <<<"$(pacman -Qqer $X)")
pacman -Dr "$X" - <<<"$XPKGS" --asdeps >/dev/null 2>&1 ### Mark every package as a dependency by default. Then...
for pkg in $XPKGS; do [[ $(pactree -r $pkg | wc -l ) -eq 1 ]] && XPLCT+=( "$pkg" ); done
pacman -Dr "$X" ${XPLCT[@]} --asexplicit >/dev/null 2>&1
printf "Explicit packages count after database sanitize: "; notify ${#XPLCT[@]}
printf "Dependencies count after database sanitize: "; notify $(wc -l <<<"$(pacman -Qqdr $X)")
printf "Total packages in module: "; notify $(wc -l <<<"$XPKGS")
}
_FixPerms() {
[ -z "$X" ] && return
warn "Resetting permissions in: $X" && confirm "Press 'y' when ready "
chmod -f 711 "$X"/var/db/sudo/ >/dev/null 2>&1
chmod -f 700 "$X"/etc/polkit-1/rules.d "$X"/var/db/sudo/lectured/ "$X"/var/lib/NetworkManager/ "$X"/etc/NetworkManager/system-connections/ >/dev/null 2>&1
chmod -f 750 "$X"/root "$X"/etc/sudoers.d/ "$X"/etc/openvpn/{client,server}/ "$X"/{usr/share,etc}/polkit-1/rules.d/ >/dev/null 2>&1
chmod -f 755 "$X"/etc "$X"/etc/local.d "$X"/usr "$X"/usr/local "$1"/usr/local/bin >/dev/null 2>&1
chmod -f 555 "$X"/{proc,sys}/ "$X"/srv/ftp >/dev/null 2>&1
chmod -f 775 "$X"/var/games >/dev/null 2>&1
chmod -f 1777 "$X"/var/{spool/mail,tmp} >/dev/null 2>&1
find "$X"/usr/share/{applications,backgrounds,fonts,icons,themes} -type d -exec chmod 755 {} \; >/dev/null 2>&1
find "$X"/usr/share/{applications,backgrounds,fonts,icons,themes} -type f -exec chmod 644 {} \; >/dev/null 2>&1
find "$X"/usr/share/{applications,backgrounds,fonts,icons,themes} \( -type d -o -type f \) ! -user root -exec chown 0: {} \; >/dev/null 2>&1
find "$X"/usr/share/{applications,backgrounds,fonts,icons,themes} -type l ! -user root -exec chown -h 0: {} \; >/dev/null 2>&1
find "$X"/home/guest \( -type d -o -type f \) ! -user guest -exec chown guest: {} \; >/dev/null 2>&1
find "$X"/home/guest -type l ! -user guest -exec chown -h guest: {} \; >/dev/null 2>&1
chown 0: /home >/dev/null 2>&1
chown 0:43 "$X"/etc/shadow
chown polkitd:polkitd "$X"/etc/polkit-1/rules.d
sed -i 's/wheel/root/' "$X"/{etc,usr/share}/polkit-1/rules.d/50-default.rules >/dev/null 2>&1 ### FIX root password issue
## Fix cups admin address
sed -i usr/share/applications/cups.desktop -e 's^:631/^:631/admin^g' 2>/dev/null
}
_Strip() {
printf "Size before strip: "; notify "$(du -sh "$X" | awk '{print$1}')"
### TODO Export headers & pkgconfigs instead of strip them, as they are to be included later in 05-devel
#EXP=/tmp/EXPORT
#mkdir -p $EXP/{headers,input,language,man} >/dev/null 2>&1
[ "$X" = "05-devel" ] || {
[ -z "$X" ] || rm -r usr/lib/{libgdruntime.*,libgphobos.*,libgo.*,libasan.*,libtsan.*,libgfortran.*,libitm.*,liblsan.*,libobjc.*,libquadmath.*,libubsan.*,libatomic_ops*} >/dev/null 2>&1
[ -z "$X" ] || rm -r usr/{src,include} usr/share/{aclocal,cmake,devhelp,gir-1.0,info,licenses,man,pkgconfig} lib/pkgconfig usr/lib/pkgconfig usr/include/* >/dev/null 2>&1 #libgomp, is needed by ffmpeg
[ -z "$X" ] || find "$X" -type f \( -name "*.c" -o -name "*.cmake" -o -name "*.deps" -o -name "*.gir" -o -name "*.h" -o -name "*.a" -o -name "*.la" -o -name "*.m4" -o -name "*.o" -o -name "*.pc" -o -name "*.prl" -o -name "*.vapi" \) -delete
}
[ -z "$X" ] || rm -rf "$X"/usr/{doc,info,man} usr/lib/systemd/* "$X"/tmp >/dev/null 2>&1
[ -z "$X" ] || rm -rf "$X"/usr/share/{doc,gtk-doc,help,locale,sounds/alsa,*/translations,vala} usr/share/i18n/charmaps/*.gz tmp/* >/dev/null 2>&1
[ -z "$X" ] || find "$X" -type f \( -iname "AUTHORS*" -o -iname "COPYING*" -o -iname "README*" -o -iname "LICENSE*" \) -delete
[ -z "$X" ] || find "$X"/usr/share/mime/ -mindepth 1 -maxdepth 1 -not -name packages -exec rm -rf "{}" \; 2>&1
[ -z "$X" ] || rm -r "$X$dB"{sync,local/ALPM_DB_VERSION} 2>&1
printf "Size after strip: "; notify "$(du -sh "$X" | awk '{print$1}')"
if confirm "Do you prefer zstd faster compression (10% bigger size)? [y/*] "; then
mksquashfs "$X" "$X"-$(date '+%Y%m%d').xzm -comp zstd -b 256K
else
dir2xzm "$X" "$X"-$(date '+%Y%m%d').xzm
fi
rm -r "$X"
unset X
}
_Bye() {
printf "\e[8;24;80t"
rm /tmp/{MISSING,PARENTMOD,SUGGESTED} $_Help >/dev/null 2>&1
[ -d "$XMODS" ] && ( xdg-open $XMODS & disown )
}
trap _Bye SIGHUP SIGINT SIGTERM EXIT
TheRightThing() {
_Prepare
_Nemaster
_SanitizeDB
_FixPerms
_Strip
}
while confirm "Ready to Nemaster? [y/*] "; do TheRightThing || _Bye; done
exit 0
# M"""""""`YM dP
# M mmmm. M 88
# M MMMMM M .d8888b. 88d8b.d8b. .d8888b. .d8888b. d8888P .d8888b. 88d888b.
# M MMMMM M 88ooood8 88'`88'`88 88' `88 Y8ooooo. 88 88ooood8 88' `88
# M MMMMM M 88. ... 88 88 88 88. .88 88 88 88. ... 88
# M MMMMM M `88888P' dP dP dP `88888P8 `88888P' dP `88888P' dP
# MMMMMMMMMMM
NEW Demo. Remastering original 002-gui-20230603.xzm module:
Demo: Full remastering 003-shared. (Or how to use 003-shared module to build your own toolkit module)
Last part shows the new packages working together after module has been activated.
Thanks_
EDIT: There's a bug: 05-devel shouldn't be stripped
EDIT #2:
* Changes in user interface and Documentation.
* Strip routine still needs finetuning for 05-devel
EDIT #3:
* Added new demo (get a FULL-HD .gif (57.02MB) version here)
* Corrected _Strip routine
* Still a work in progress but can be considered a working version. (Unless anyone reports bugs)
EDIT #4:
* Adapted to suit the wmod function after the last change in 001-CORE
* More finetuning in user interface and documentation.
* Maybe include a REMOVE pkgs routine to allow a full module remaster.
* Strip function still needs some rework.
EDIT #5:
* Still more finetuning in user interface and documentation.
* REMOVE pkgs routine included to allow a full remastering.
* Mirrors automatically toggled if necessary.
* Strip function will be fixed next.
EDIT #6:
* Added a check to prevent the module filename from being squeezed too much
* Added the option to save the module with zstd compression
* Some minor corrections
* Strip function is 400 lines long. Still undecided if including it in the script or as a file apart to be sourced