#!/bin/sh # SPDX-License-Identifier: AGPL-3.0-only # Copyright 2022 Sxmo Contributors # A pretty generic status content generator # It aggregates all file content present in a folder # It sorts file elements numerically by zero-padded priority prefix # It watches file events to stdout new content ROOT="${XDG_RUNTIME_DIR:-/run/user/10000}/sxmo_status/${SXMO_STATUS_NAME:-default}" mkdir -p "$ROOT" lock_ex() { : } lock_sh() { : } free() { : } usage() { printf "Usage: %s [ACTIONS]\n" "${0##*/}" >&2 printf "ACTIONS:\n" >&2 printf " -s: the status content (default action)\n" >&2 printf " -w: file events and stdout status content\n" >&2 printf " -a : add a bar component\n" >&2 printf " -d : remove a bar component\n" >&2 printf " -r: remove all bar components\n" >&2 printf " -D: the status content explained\n" >&2 printf " -h: this message\n" >&2 } add() { id= priority= value= while [ "$#" -gt 0 ]; do arg="$1" shift case "$arg" in "-f"|"-b"|"-t"|"-e"|"-o") [ "$#" -gt 0 ] && shift ;; *) if [ -z "$id" ]; then id="$arg" elif [ -z "$priority" ]; then priority="$arg" elif [ -z "$value" ]; then value="$arg" fi ;; esac done if [ -z "$id" ] || [ -z "$priority" ]; then printf "usage: %s -a \n" "${0##*/}" >&2 exit 1 fi mkdir -p "$ROOT" padded_prio="$(printf '%03d' "$priority" 2>/dev/null || printf '%s' "$priority")" target="$ROOT/$padded_prio-$id" lock_ex # Remove any old file for this id with a different priority prefix for f in "$ROOT"/*-"$id"; do [ -e "$f" ] || continue if [ "$f" != "$target" ]; then rm -f "$f" fi done if [ -z "$value" ]; then rm -f "$target" free return fi if [ -r "$target" ]; then old_val="" read -r old_val < "$target" 2>/dev/null || true if [ "$old_val" = "$value" ]; then free return fi fi printf "%s\n" "$value" > "${XDG_RUNTIME_DIR:-/run/user/10000}/sxmo_status/.tmp.$$" mv -f "${XDG_RUNTIME_DIR:-/run/user/10000}/sxmo_status/.tmp.$$" "$target" free } del() { id="$1" if [ -z "$id" ]; then printf "usage: %s -d \n" "${0##*/}" >&2 exit 1 fi lock_ex for f in "$ROOT"/*-"$id"; do [ -e "$f" ] || continue rm -f "$f" done free } show() { lock_sh out="" for f in "$ROOT"/*; do [ -f "$f" ] || continue val="" read -r val < "$f" 2>/dev/null || true [ -n "$val" ] || continue if [ -z "$out" ]; then out="$val" else out="$out $val" fi done printf "%s\n" "$out" free } debug() { lock_sh for f in "$ROOT"/*; do [ -f "$f" ] || continue val="" read -r val < "$f" 2>/dev/null || true printf "%s\n>%s<\n" "${f##*/}" "$val" done free } watch() { FIFO="$(mktemp -u)" mkfifo "$FIFO" NOTIFYPID= # shellcheck disable=SC2317 finish() { [ -n "$NOTIFYPID" ] && kill "$NOTIFYPID" 2>/dev/null || true rm -f "$FIFO" exit 0 } trap 'finish' TERM INT while true; do mkdir -p "$ROOT" inotifywait -mq -e "close_write,move,delete,delete_self,move_self" "$ROOT" >> "$FIFO" & NOTIFYPID=$! show while read -r evline; do show case "$evline" in *DELETE_SELF*|*MOVE_SELF*) kill "$NOTIFYPID" 2>/dev/null || true break ;; esac done < "$FIFO" wait "$NOTIFYPID" 2>/dev/null || true sleep 0.1 done } reset() { lock_ex mkdir -p "$ROOT" rm -f "$ROOT"/* free } action="" while [ "$#" -gt 0 ]; do case "$1" in "-o") shift 2 2>/dev/null || shift ;; "-s"|"-w"|"-r"|"-a"|"-d"|"-D"|"-h") action="$1" shift break ;; *) action="$1" shift break ;; esac done case "$action" in ""|"-s") show ;; "-w") watch "$@" ;; "-r") reset "$@" ;; "-a") add "$@" ;; "-d") del "$@" ;; "-D") debug "$@" ;; "-h") usage ;; esac