User:Flexibeast/guides/Desktop notifications of emerge progress

From Gentoo Wiki
Jump to:navigation Jump to:search

Here's how i've set up my box to give me desktop notfications about the progress of a multi-package emerge.

i use OpenRC, but i try to follow the XDG specs. In particular, i've moved my personal config to use the XDG/Base Directories specification. So my XDG_STATE_HOME is ~/.local/state. In the following, i'll use <XDG_STATE_HOME> as a placeholder to refer to the full resolved path (i.e. with ~ expanded to the desktop user's HOME directory), for reasons that will be explained below.

We need to know the DBUS_SESSION_BUS_ADDRESS of the user who will be receiving the desktop notifications; otherwise, notifications will be provided, but won't necessarily follow the user's notifications configuration. On my system, i start a D-Bus session bus when i log in on the console, via ~/.zlogin, which my preferred shell, zsh, runs when starting a login shell; in doing so, i save the session bus address to ~/.local/state/session-bus-address:

CODE ~/.zlogin
dbus-daemon --session --fork --print-address 4 --print-pid 5 4>|"${XDG_STATE_HOME}/session-bus-address" 5>|"${XDG_STATE_HOME}/session-bus-pid"

i'm currently running Wayfire as my WM, which i start from the console. In the shell script i use to set up my Wayfire environment, i have the lines:

CODE Wayfire env
echo -n ${DISPLAY} >|"${XDG_STATE_HOME}/display"
echo -n ${WAYLAND_DISPLAY} >|"${XDG_STATE_HOME}/wayland-display"

This saves the values of those variables for later use in an environment in which their values aren't available. The use of the >| redirection operator clobbers any existing file.

i have an executable shell script in my PATH - which for the purposes of this article i'll call my-notify - with the contents:

FILE ~/.local/bin/my-notify
#!/bin/dash
 
STATE_DIR='<XDG_STATE_HOME>'
export DBUS_SESSION_BUS_ADDRESS=$(cat "${STATE_DIR}/session-bus-address" | tr -d '\n')
export DISPLAY=$(cat "${STATE_DIR}/display" | tr -d '\n')
export WAYLAND_DISPLAY=$(cat "${STATE_DIR}/wayland-display" | tr -d '\n')
 
/usr/bin/notify-send --expire-time=10000 "${1}"

The full path of the desktop user's XDG_STATE_HOME needs to be manually provided here, as this script will be running in an environment in which that variable isn't set appropriately.

notify-send(1) is a simple command-line program to create desktop notifications via D-Bus, provided as part of the x11-libs/libnotify package. It has its limitations, but it's sufficient for this purpose; more complex use-cases might need something like gdbus(1). The expire-time is in milliseconds, expressing how long to display the notification for before closing it.

Next, i've created a Portage bashrc file, with the contents:

FILE /etc/portage/bashrc
if [ "${EBUILD_PHASE}" == "configure" ]
then
        echo $(genlop -c | sed -ne 's/^ Currently merging \(.*\)$/\1/p' | tr -d '\n') >| /var/tmp/emergestatus
fi

if [ "${EBUILD_PHASE}" == "postinst" ]
then
        STATUS=$(cat /var/tmp/emergestatus)
        doas -u <desktop user> <full path to my-notify> \
                "postinst: ${PF}"$'\n'"(${STATUS})"
fi

The merge-analysing genlop program is provided by the app-portage/genlop package. Here it's used to get information about where we are in the merge process (e.g. "2 of 5" packages).

doas(1) is used here because my-notify needs to be run as the desktop user in order for the notification to appear on that user's desktop. And in order for the notify-send command in my-notify to work, it needs to know appropriate values for DISPLAY / WAYLAND_DISPLAY, since those variables aren't set in the environment in which the script will be called (i.e. the environment Portage is running in).

Thus, because i'm running emerge as root, in my /etc/doas.conf i have:

FILE /etc/doas.conf
permit nopass root as <desktop user> cmd <full path to my-notify>

Finally, in order to be able to read and write to the state file /var/tmp/emergestatus, the Portage sandbox needs to be configured accordingly. So i've created a file /etc/sandbox.d/90emergestatus, with the contents:

FILE /etc/sandbox.d/90emergestatus
SANDBOX_READ="/var/tmp/emergestatus"
SANDBOX_WRITE="/var/tmp/emergestatus

With all the above in place, and assuming a notification daemon is running, each time that the postinst stage is completed for a package, the user will be provided with a desktop notification, e.g.:

postinst: gnome-base/librsvg-2.57.3
(2 of 5)