Skip to content

wupdate

One of my first Gentoo related scripts to portage more easily from the command line interface in a clear and efficient way


wupdate)

wupdate.sh

#!/bin/bash

# Ensure strict error handling where applicable, though we look at individual commands in the select loop
set -f # Disable globbing globally if needed, or handle locally. Leaving standard flags safe.

DISTRO="$(awk -F= '$1=="ID"{gsub(/["'\'']/, "", $2); print tolower($2)}' /etc/os-release)"

if [[ "$DISTRO" != "gentoo" ]]; then
    echo "This is not Gentoo, please go install Gentoo to be able to run this script.."
    exit 1
fi

COLUMNS="100"

banner() {
    echo -e "\e[0;35m"
    echo -e "██╗    ██╗██╗   ██╗██████╗ ██████╗  █████╗ ████████╗███████╗"
    echo -e "██║    ██║██║   ██║██╔══██╗██╔══██╗██╔══██╗╚══██╔══╝██╔════╝"
    echo -e "██║ █╗ ██║██║   ██║██████╔╝██║  ██║███████║   ██║   █████╗     author:  wuseman"
    echo -e "██║███╗██║██║   ██║██╔═══╝ ██║  ██║██╔══██║   ██║   ██╔══╝     created: 2008-03-01"
    echo -e "╚███╔███╔╝╚██████╔╝██║     ██████╔╝██║  ██║   ██║   ███████╗"
    echo -e " ╚══╝╚══╝  ╚═════╝ ╚═╝     ╚═════╝ ╚═╝  ╚═╝   ╚═╝   ╚══════╝"
    echo -e "This tool facilitates working with Portage on Gentoo"
    echo -e "------------------------------------------------------------\e[0m"
}
banner

if [[ "$EUID" -ne 0 ]]; then
    echo -e "\n            You must run this tool as root\n"
    exit 1
fi

# Dynamically resolve portage base directory
PORTDIR="$(portageq get_repo_path / gentoo 2>/dev/null || echo "/var/db/repos/gentoo")"

PS3="
Option: "

options=(
    "Sync Portage Tree"
    "Upgrade Whole System"
    "Update Packages With New Useflags"
    "List Upgradeable Packages"
    "Add Packages That Wont Be Removed By Depclean"
    "Emerge All Packages In A Category"
    "Make Configuration File(s) Up To Date"
    "Preserved Rebuild"
    "Reverse Dynamic Library Dependency"
    "Fix Static Library"
    "Uninstall Useless Packages"
    "Remove All Distfiles"
    "List All Binarys In Portage Tree"
    "Re-emerge All Ebuilds With Missing Files"
    "List All Useflags Not In Use And In Use"
    "Calculates The Total Time I'd Compiled All Packages"
    "How Many Percents Of All Avaliable Packages In Tree Are Installed"
    "Search For Modules I Have Enabled In Kernel"
    "View Emerge Log By Date In A Human Friendly Way"
    "Compare Global Useflags With A Profile Useflag"
    "Get The Size Of All Installed Packets Sorted By Size"
    "Find Installed Packages That Are Not In The Portage Tree Anymore"
    "Find Wich Useflags A Specifik Package Use With Desc"
    "Find Wich Packages Belongs To A Package"
    "Short Information About Loaded Kernel Modules"
    "Print A List Of Installed Perl Modules"
    "Upgrade All Perl Modules Via CPAN"
    "List All Available Python Modules"
    "Figure Out If A Command Is An Alias, Function Or Shell Builtin"
    "View Emerged Packages By Time From Bottom To Top"
    "Preview All Packages That Has Been Installed From An Overlay"
    "List All Overlays One By One To Get A Good Overview"
    "Find Out How Long Time It Toke To Build A Specifik Package"
    "Find all packages with a specifk useflag"
    "Print when you ran emerge last time"
    "Print All Options Again"
    "Quit"
)

select opt in "${options[@]}"; do
    case "$opt" in
    "Sync Portage Tree")
        echo -e "\nPlease wait, syncing portage...\n"
        if command -v eix-sync &>/dev/null; then
            eix-sync
        else
            emerge --sync && eix-update
        fi
        echo -e "\nPortage has been successfully updated..\n"
        exit 0
        ;;

    "Upgrade Whole System")
        echo -e "\nPlease wait, searching for new packages to upgrade...\n"
        emerge -vuDN --with-bdeps y --keep-going @world
        echo -e "\nPortage packages were successfully upgraded...\n\n"
        exit 0
        ;;

    "Update Packages With New Useflags")
        echo -e "\nPlease wait, searching for packages which need new use flags...\n"
        emerge --exclude openssl --exclude cryptsetup --ask --changed-use --update --deep --newuse @world
        echo -e "\nPortage packages were successfully upgraded...\n\n"
        exit 0
        ;;

    "List Upgradeable Packages")
        eix --installed --upgrade | grep -o '\[U].*'
        ;;

    "Add Packages That Wont Be Removed By Depclean")
        read -r -p "Package That You Want Not To Be Replaced: " noreplacepackage
        if [[ -n "$noreplacepackage" ]]; then
            emerge --noreplace "$noreplacepackage"
        fi
        exit 0
        ;;

    "Emerge All Packages In A Category")
        read -r -p "Category (e.g. net-ftp): " categorytoinstall
        if [[ -d "$PORTDIR/$categorytoinstall" ]]; then
            for p in "$PORTDIR/$categorytoinstall"/*; do
                # Use native Bash parameter expansion instead of calling basename
                emerge --ask "$categorytoinstall/${p##*/}"
            done
        else
            echo "Category not found."
        fi
        exit 0
        ;;

    "Make Configuration File(s) Up To Date")
        etc-update
        dispatch-conf
        exit 0
        ;;

    "Preserved Rebuild")
        emerge @preserved-rebuild
        exit 0
        ;;

    "Reverse Dynamic Library Dependency")
        revdep-rebuild
        exit 0
        ;;

    "Fix Static Library")
        if command -v lafilefixer &>/dev/null; then
            lafilefixer --justfixit | grep -v skipping
        else
            echo "lafilefixer not found."
        fi
        exit 0
        ;;

    "Uninstall Useless Packages")
        emerge --ask --depclean
        ;;

    "Remove All Distfiles")
        eclean -d distfiles
        exit 0
        ;;

    "List All Binarys In Portage Tree")
        echo -e "\nPlease wait while searching for binary packages...\n"
        find "$PORTDIR/" -type d -name "*-bin" | awk -F'/' '{print $NF}' | sort
        echo ""
        read -r -p "Binary Package To Compile (Ctrl+C to quit): " compile
        if [[ -n "$compile" ]]; then
            emerge --ask "$compile"
        fi
        exit 0
        ;;

    "Re-emerge All Ebuilds With Missing Files")
        # Highly optimized pipeline to find missing files and trigger rebuilds
        emerge -av1 $(qlist --installed --nocolor | uniq | while read -r cp; do
            qlist --exact "$cp" | while read -r file; do
                if [[ ! -e "$file" ]]; then
                    echo "$cp"
                    echo "$cp: missing $file" >&2
                    break
                fi
            done
        done)
        ;;

    "List All Useflags Not In Use And In Use")
        # Rewritten logic to cleanly dump and sort current usage profiles
        emerge -epv world | grep USE | cut -d '"' -f 2 | tr ' ' '\n' | grep -v '[()]*' | sort -u > use
        grep '^-' use | sed 's/^-//' | tr '\n' ' ' > notuse
        sed -i '/^-/d' use
        tr '\n' ' ' < use > tmp_use && mv tmp_use use
        echo "Files 'use' and 'notuse' generated."
        exit 0
        ;;

    "Calculates The Total Time I'd Compiled All Packages")
        echo -e "\nPlease wait while I count...\n"
        total_compile_time="$(qlist -I | xargs qlop -t | awk '{secs += $2} END { printf("%dh:%dm:%ds\n", secs / 3600, (secs % 3600) / 60, secs % 60); }')"
        echo -e "You have compiled packages in a total time of \e[1;32m$total_compile_time\e[0m.\n"
        exit 0
        ;;

    "How Many Percents Of All Avaliable Packages In Tree Are Installed")
        # Fixed math layout to protect against division by zero
        local_installed=$(eix --only-names -I | wc -l)
        total_available=$(eix --only-names | wc -l)
        if [[ $total_available -gt 0 ]]; then
            percent_gentoo=$(( local_installed * 100 / total_available ))
            echo -e "\nYou have installed \e[1;32m$percent_gentoo%\e[0m of all available packages.\n"
        fi
        exit 0
        ;;

    "Search For Modules I Have Enabled In Kernel")
        read -r -p "Search For Module: " module_kernel
        if [[ -n "$module_kernel" ]]; then
            # Fixed single quotes preventing variable evaluation
            echo -e "\nYou built Kernel With Following Modules: \n"
            find /lib/modules/*/ -name "*${module_kernel}*" | awk -F'/' '{print $NF}'
        fi
        exit 0
        ;;

    "View Emerge Log By Date In A Human Friendly Way")
        awk -F: '{print strftime("%Y-%m-%d -> %X --> ", $1),$2}' /var/log/emerge.log
        ;;

    "Compare Global Useflags With A Profile Useflag")
        echo "Feature under construction. Check configuration manually."
        ;;

    "Get The Size Of All Installed Packets Sorted By Size")
        GREEN='\033[01;32m' WHITE='\033[0;37m'
        qsize | cut -d'/' -f2 | awk -v g="$GREEN" -v w="$WHITE" '{print w$1,g$6}' | sort -n -k 9
        exit 0
        ;;

    "Find Installed Packages That Are Not In The Portage Tree Anymore")
        for f in $(qlist -IC); do
            if [[ ! -d "$PORTDIR/$f" ]]; then
                echo "$f is no longer in the portage tree"
            fi
        done
        exit 0
        ;;

    "Find Wich Useflags A Specifik Package Use With Desc")
        read -r -p "Package For View Useflags: " useflags_equeryu
        if [[ -n "$useflags_equeryu" ]]; then
            equery u "$useflags_equeryu"
        fi
        exit 0
        ;;

    "Find Wich Packages Belongs To A Package")
        read -r -p "Package to look up file ownership for: " useflags_equeryb
        if [[ -n "$useflags_equeryb" ]]; then
            equery b "$useflags_equeryb"
        fi
        exit 0
        ;;

    "Short Information About Loaded Kernel Modules")
        # Fixed parsing to cleanly extract metadata from active modules
        modinfo $(cut -d' ' -f1 /proc/modules) 2>/dev/null | sed '/^dep/s/$/\n/; /^file\|^desc\|^dep/!d'
        exit 0
        ;;

    "Print A List Of Installed Perl Modules")
        echo -e "\nPlease wait while searching for installed Perl modules...\n"
        perl -MExtUtils::Installed -e '$inst = ExtUtils::Installed->new(); @modules = $inst->modules(); print join("\n", @modules);'
        echo ""
        exit 0
        ;;

    "Upgrade All Perl Modules Via CPAN")
        perl -MCPAN -e 'CPAN::Shell->install(CPAN::Shell->r)'
        exit 0
        ;;

    "List All Available Python Modules")
        python -c "help('modules')"
        exit 0
        ;;

    "Figure Out If A Command Is An Alias, Function Or Shell Builtin")
        read -r -p "Command To Check: " cmd_check
        if [[ -n "$cmd_check" ]]; then
            type "$cmd_check"
        fi
        exit 0
        ;;

    "View Emerged Packages By Time From Bottom To Top")
        if ! command -v genlop &>/dev/null; then
            echo -e "${0##*/}: internal error -- genlop is required, exiting..."
            exit 1
        else
            echo -e "Please wait, this might take some time..."
            genlop -l
        fi
        exit 0
        ;;

    "Preview All Packages That Has Been Installed From An Overlay")
        eix -c --installed-overlay
        exit 0
        ;;

    "List All Overlays One By One To Get A Good Overview")
        emerge --info --verbose | sed -n '/^Repo/,/^ABI/p' | head -n -1
        exit 0
        ;;

    "Find Out How Long Time It Toke To Build A Specifik Package")
        read -r -p "Package: " packagetime
        if [[ -n "$packagetime" ]]; then
            raw_seconds=$(qlist -I | xargs qlop -t | grep "$packagetime" | awk '{print $2}' | head -n 1)
            if [[ -n "$raw_seconds" ]]; then
                echo "scale=2; $raw_seconds / 60" | bc
            else
                echo "Package not found in compilation logs."
            fi
        fi
        exit 0
        ;;

    "Find all packages with a specifk useflag")
        if [[ -n "$1" ]]; then
            q use "+$1"
        else
            read -r -p "Enter useflag: " target_flag
            q use "+$target_flag"
        fi
        ;;

    "Print when you ran emerge last time")
        grep "emerge on" /var/log/emerge.log | cut -d: -f2,3,4,5,6 | tr '[:upper:]' '[:lower:]' | sed 's/ started/You ran/g' | tail -n 1
        ;;

    "Print All Options Again")
        # Kill current selection session to allow loop to re-print options dynamically
        continue
        ;;

    "Quit")
        break
        ;;

    *)
        echo -e "\n\nPlease choose a valid option from the menu.\n"
        ;;
    esac
done

Extra

Example - Search for sound-related kernel modules

find /lib/modules/*/ -name "*snd*"

The system set, also referred to as @system in Portage development, contains the software packages required for a standard Gentoo Linux installation to run properly

emerge --pretend @system

The system packages are defined by the Gentoo profiles (through the packages files)

An end-user can easily see which packages are seen as part of the system set by running the following emerge command:

firefox="$(qlist -I | xargs qlop -t | grep firefox | awk '{print $2}')"; echo $firefox / 60 | bc

Show all globally disabled USE flags

eix --print-all-useflags | grep -E '^-[-a-z0-9]+$'