From 60e62585eb03dbe915d913f52e65d5431770342b Mon Sep 17 00:00:00 2001 From: "Doncho N. Gunchev" Date: Sun, 30 Nov 2025 16:58:57 +0200 Subject: [PATCH] Format the code, add fmt and check targets --- AGENTS.md | 6 +- Makefile | 17 +- build.sh | 24 ++- changelog.sh | 2 +- etc/profile.d/ssh_controlmasters.sh | 2 + etc/profile.d/z-aliases.sh | 2 +- etc/profile.d/z-ps-twtty-7.sh | 292 ++++++++++++++-------------- gwebu-profile.spec.in | 5 +- 8 files changed, 188 insertions(+), 162 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 201ce83..d3b6413 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -6,6 +6,8 @@ - `make rpm` - Build RPM package - `make podman_rpm` - Build RPM using podman (for MacOS) - `make changelog` - Add changelog entry via ./changelog.sh +- `make check` - Run shellcheck on all shell scripts +- `make fmt` - Format all shell scripts with shfmt - `make clean` - Clean generated files - Pre-commit hooks run automatically on commit (see .pre-commit-config.yaml) @@ -14,7 +16,7 @@ - **File Permissions**: profile.d scripts must be 0644 (install -m 0644) - they are sourced, not executed - **Line Endings**: LF only (enforced by pre-commit, see .editorconfig) - **No trailing whitespace** (enforced by pre-commit, see .editorconfig) -- **Error Handling**: Use `command -v` instead of `which` for portability +- **Error Handling**: Use `command -v` instead of `which` for portability, `set -euo pipefail` - **OS Compatibility**: Support both Linux and MacOS with conditional logic - **Naming**: Profile.d files use `z-.sh` pattern for alphabetical loading - **Licensing**: The Unlicense unless explicitly stated otherwise @@ -23,8 +25,8 @@ ## Testing - No specific testing framework currently used +- Use `make check` to lint shell scripts with shellcheck - Shell scripts should be tested with basic manual verification -- Use `set -euo pipefail` for robust error handling ## Cursor/Copilot Rules - No specific .cursorrules or .github/copilot-instructions.md found diff --git a/Makefile b/Makefile index 8da1508..ea433d4 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ SHELL:=/bin/bash # Use bash syntax, mitigates dash's printf on Debian ver:=$(shell git describe --dirty --long --match='v[0-9]*.[0-9]*' | cut -c 2- | cut -d - -f 1,2,4) rpm_ver:=$(firstword $(subst -, ,$(ver))) -rpm_rev:=$(subst $(rpm_ver)-,,$(ver)) -rpm_rev:=$(subst -,_,$(rpm_rev)) +name_rev:=$(subst $(rpm_ver)-,,$(ver)) +rpm_rev:=$(subst -,_,$(name_rev)) help: @@ -15,6 +15,8 @@ help: @echo " rpm: Create an RPM package." @echo " podman_rpm Create an RPM package using podman on MacOS." @echo " changelog: Add a changelog entry to gwebu-profile.spec.in." + @echo " check: Run shellcheck on all shell scripts." + @echo " fmt: Format all shell scripts with shfmt." @echo @echo " clean: Clean all generated files." @echo @@ -45,6 +47,17 @@ changelog: ./changelog.sh +.PHONY: check +check: + shellcheck --shell=bash --external-sources --source-path=etc/profile.d *.sh etc/profile.d/*.sh + rpmlint *.spec.in + + +.PHONY: fmt +fmt: + shfmt -w -i 4 -ci *.sh etc/profile.d/*.sh + + .PHONY: clean clean: rm -rf dist diff --git a/build.sh b/build.sh index b0d3b56..dd98621 100755 --- a/build.sh +++ b/build.sh @@ -3,13 +3,16 @@ set -euo pipefail shopt -s nullglob dotglob -if [ "$(uname -s)" != "Linux" ]; then echo "This script only works on Linux!" >&2; exit 254; fi +if [ "$(uname -s)" != "Linux" ]; then + echo "This script only works on Linux!" >&2 + exit 254 +fi set -x # debug . /etc/os-release -ARCH="${ARCH:-$(uname -m)}" # -VER="${VER:-${VERSION_ID%%\.*}}" # 8 -DIST_PRE="${PLATFORM_ID##*:}" # el8 +ARCH="${ARCH:-$(uname -m)}" # +VER="${VER:-${VERSION_ID%%\.*}}" # 9 +DIST_PRE="${PLATFORM_ID##*:}" # el9 DIST="${DIST:-${DIST_PRE%%[0-9]*}}" # el OUT_DIR="/tmp/RPMS" @@ -24,17 +27,20 @@ export LC_TIME="${LANG}" rm -rf "$OUT_DIR" mkdir "$OUT_DIR" +# Download all sources and patches. #spectool -g ./*.spec # +# Install all build dependencies. #if [ "$UID" == "0" ]; then -# dnf builddep -y --refresh ./*.spec +# dnf builddep -y --refresh ./*.spec #fi -# make rpmsrc +# make dist + rpmbuild -ta ./dist/*.tar.xz \ - --define "_sourcedir $PWD/dist" \ - --define "_srcrpmdir $OUT_DIR" \ - --define "_rpmdir $OUT_DIR" \ + --define "_sourcedir $PWD/dist" \ + --define "_srcrpmdir $OUT_DIR" \ + --define "_rpmdir $OUT_DIR" mv "$OUT_DIR"/*/*.rpm "$OUT_DIR/" rmdir "$OUT_DIR"/* 2>/dev/null || true diff --git a/changelog.sh b/changelog.sh index 2021c28..7bc771e 100755 --- a/changelog.sh +++ b/changelog.sh @@ -12,7 +12,7 @@ change1="* $(date +'%a %b %d %Y') $(git log -1 --format='%aN <%aE>') - ${rpm_ver change2="- $(git log -1 --format=%s)" awk -v change1="${change1}" -v change2="${change2}" '/^%changelog/ {print; print change1; print change2; print ""; next} 1' gwebu-profile.spec.in \ - > gwebu-profile.spec.tmp && mv gwebu-profile.spec.tmp gwebu-profile.spec.in + >gwebu-profile.spec.tmp && mv gwebu-profile.spec.tmp gwebu-profile.spec.in sed -i.bak "s/Version: .*/Version: ${rpm_ver}/" gwebu-profile.spec.in sed -i.bak "s/Release: .*/Release: ${rpm_numeric_rev}/" gwebu-profile.spec.in diff --git a/etc/profile.d/ssh_controlmasters.sh b/etc/profile.d/ssh_controlmasters.sh index 8913c35..a4b8043 100644 --- a/etc/profile.d/ssh_controlmasters.sh +++ b/etc/profile.d/ssh_controlmasters.sh @@ -5,5 +5,7 @@ fi # SSH Control Masters tools (setup controlmasters to be in ~/.ssh/c). alias ssh_controlmasters_ls='(cd ~/.ssh/c; ls -A 2>/dev/null || echo "-- No control masters --")' +# shellcheck disable=SC2154 alias ssh_controlmasters_check='(cd ~/.ssh/c; [ "$(ls -A)" ] && for i in *; do echo -n "$i: "; ssh -O check "${i%:*}" -p "${i##*:}"; done)' +# shellcheck disable=SC2154 alias ssh_controlmasters_stop='(cd ~/.ssh/c; [ "$(ls -A)" ] && for i in *; do echo -n "$i: "; ssh -O stop "${i%:*}" -p "${i##*:}"; done)' diff --git a/etc/profile.d/z-aliases.sh b/etc/profile.d/z-aliases.sh index 9c91d7b..1dbc5e4 100644 --- a/etc/profile.d/z-aliases.sh +++ b/etc/profile.d/z-aliases.sh @@ -18,7 +18,7 @@ if [[ "$OSTYPE" != darwin* ]]; then alias lll='ls --color=auto -Al "--time-style=+%Y-%m-%d %H:%M:%S GMT%z"' # if there is iproute installed - if command -v ip > /dev/null; then + if command -v ip >/dev/null; then # color ip route if ip -V | grep '^ip utility, iproute2-.*, libbpf' &>/dev/null; then # EL 8+ - "ip utility, iproute2-6.2.0, libbpf 0.5.0" diff --git a/etc/profile.d/z-ps-twtty-7.sh b/etc/profile.d/z-ps-twtty-7.sh index 4abae88..980def4 100644 --- a/etc/profile.d/z-ps-twtty-7.sh +++ b/etc/profile.d/z-ps-twtty-7.sh @@ -51,140 +51,139 @@ if [ "${BASH_SOURCE-}" = "$0" ]; then exit 33 fi -if [ "$PS1" ] ; then # interactive shell detection +if [ "$PS1" ]; then # interactive shell detection -# Log the logout event. -function prompt_command_exit() { - trap - EXIT - local now - now=$(date --rfc-3339=ns 2> /dev/null || date -Iseconds) - local HistFile - HistFile="$HOME/bash_history/$(date '+%Y-%m/%Y-%m-%d')" - mkdir -p "${HistFile%/*}" - echo -e "# Logout,$USER@${HOSTNAME}:$PWD,$(tty),${SSH_CLIENT:-local},login=${my_LoginTime:-$now},now=$now\nlogout" >> "$HistFile" -} + # Log the logout event. + function prompt_command_exit() { + trap - EXIT + local now + now=$(date --rfc-3339=ns 2>/dev/null || date -Iseconds) + local HistFile + HistFile="$HOME/bash_history/$(date '+%Y-%m/%Y-%m-%d')" + mkdir -p "${HistFile%/*}" + echo -e "# Logout,$USER@${HOSTNAME}:$PWD,$(tty),${SSH_CLIENT:-local},login=${my_LoginTime:-$now},now=$now\nlogout" >>"$HistFile" + } -# Executed before each prompt. Fill the variables needed by PS1 here. -function prompt_command() { - local now - now=$(date --rfc-3339=ns 2> /dev/null || date -Iseconds) + # Executed before each prompt. Fill the variables needed by PS1 here. + function prompt_command() { + local now + now=$(date --rfc-3339=ns 2>/dev/null || date -Iseconds) - # Manage the history - local HistFile - HistFile="$HOME/bash_history/$(date '+%Y-%m/%Y-%m-%d')" - mkdir -p "${HistFile%/*}" + # Manage the history + local HistFile + HistFile="$HOME/bash_history/$(date '+%Y-%m/%Y-%m-%d')" + mkdir -p "${HistFile%/*}" - if [ -z "$my_LoginTime" ]; then - my_LoginTime="$now" - fi - - # Calculate the width of the prompt: - my_TTY="$(tty)" - my_TTY="${my_TTY:5}" # cut the '/dev' part -> tty/1, pts/2... - my_PWD="${PWD}" - # Add all the accessories below ... - my_D="$(date '+%Y-%m-%d %H:%M:%S')" - # This is for string size calculations only. The variable my_P is set, see PROMPT_COMMAND below. - if [ -z "$my_P" ]; then my_P="ERROR"; fi # make shellcheck happy. - local prompt="--($my_D, Err ${my_P[*]}, $my_TTY)---($PWD)--" - - if [ -n "${VIRTUAL_ENV:-}" ] && [ -n "$_OLD_VIRTUAL_PS1" ]; then - if [ -n "$VIRTUAL_ENV_PROMPT" ]; then - my_VENV="${VIRTUAL_ENV_PROMPT%\ }" - my_VENV="${my_VENV%\)}" - my_VENV="${my_VENV#\(}" - else - # Best guess - export my_VENV="${VIRTUAL_ENV##*/}" + if [ -z "$my_LoginTime" ]; then + my_LoginTime="$now" fi - prompt="--($my_D, Err ${my_P[*]}, $my_TTY, Venv $my_VENV)---($PWD)--" - # local ps1_prefix - ps1_prefix="${_OLD_VIRTUAL_PS1%\$\{my_TTY\}*}\${my_TTY}" - ps1_suffix="${_OLD_VIRTUAL_PS1#"$ps1_prefix"}" - # The magic with numbers copies the comma with the colors around it. - export PS1="${ps1_prefix}${ps1_prefix:${#ps1_prefix}-39:30}\ + + # Calculate the width of the prompt: + my_TTY="$(tty)" + my_TTY="${my_TTY:5}" # cut the '/dev' part -> tty/1, pts/2... + my_PWD="${PWD}" + # Add all the accessories below ... + my_D="$(date '+%Y-%m-%d %H:%M:%S')" + # This is for string size calculations only. The variable my_P is set, see PROMPT_COMMAND below. + if [ -z "$my_P" ]; then my_P="ERROR"; fi # make shellcheck happy. + local prompt="--($my_D, Err ${my_P[*]}, $my_TTY)---($PWD)--" + + if [ -n "${VIRTUAL_ENV:-}" ] && [ -n "$_OLD_VIRTUAL_PS1" ]; then + if [ -n "$VIRTUAL_ENV_PROMPT" ]; then + my_VENV="${VIRTUAL_ENV_PROMPT%\ }" + my_VENV="${my_VENV%\)}" + my_VENV="${my_VENV#\(}" + else + # Best guess + export my_VENV="${VIRTUAL_ENV##*/}" + fi + prompt="--($my_D, Err ${my_P[*]}, $my_TTY, Venv $my_VENV)---($PWD)--" + # local ps1_prefix + ps1_prefix="${_OLD_VIRTUAL_PS1%\$\{my_TTY\}*}\${my_TTY}" + ps1_suffix="${_OLD_VIRTUAL_PS1#"$ps1_prefix"}" + # The magic with numbers copies the comma with the colors around it. + export PS1="${ps1_prefix}${ps1_prefix:${#ps1_prefix}-39:30}\ ${ps1_prefix:${#ps1_prefix}-81:14}Venv${ps1_prefix:${#ps1_prefix}-63:14} ${my_VENV}${ps1_suffix}" - fi + fi - local fill_size=0 - [ -z "${COLUMNS}" ] && COLUMNS=$(tput cols) - ((fill_size=COLUMNS-${#prompt})) - my_FILL="" - if [ "$fill_size" -gt 0 ]; then - my_FILL="────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────" - while [ "$fill_size" -gt ${#my_FILL} ]; do - my_FILL="${my_FILL}${my_FILL}${my_FILL}${my_FILL}" - done - my_FILL="${my_FILL::$fill_size}" - fi + local fill_size=0 + [ -z "${COLUMNS}" ] && COLUMNS=$(tput cols) + ((fill_size = COLUMNS - ${#prompt})) + my_FILL="" + if [ "$fill_size" -gt 0 ]; then + my_FILL="────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────" + while [ "$fill_size" -gt ${#my_FILL} ]; do + my_FILL="${my_FILL}${my_FILL}${my_FILL}${my_FILL}" + done + my_FILL="${my_FILL::$fill_size}" + fi - if [ "$fill_size" -lt 0 ]; then - my_PWD="…${my_PWD:1-$fill_size}" - fi + if [ "$fill_size" -lt 0 ]; then + my_PWD="…${my_PWD:1-$fill_size}" + fi - local OldCmdNo="$CmdNo" # See if we got new command later. - local Cmd - Cmd="$(history 1)" - CmdNo="${Cmd:0:7}" - if [[ -z "$OldCmdNo" ]]; then - Cmd="login" - else - Cmd="${Cmd:7}" - fi - if [ "$OldCmdNo" != "$CmdNo" ]; then # Only save new commands, not empty lines or Ctrl+C. - echo -e "# PIPESTATUS=${my_P[*]},$USER@${HOSTNAME}:$PWD,$(tty),${SSH_CLIENT:-local},login=$my_LoginTime,now=$now\n$Cmd" >> "$HistFile" - fi -} + local OldCmdNo="$CmdNo" # See if we got new command later. + local Cmd + Cmd="$(history 1)" + CmdNo="${Cmd:0:7}" + if [[ -z "$OldCmdNo" ]]; then + Cmd="login" + else + Cmd="${Cmd:7}" + fi + if [ "$OldCmdNo" != "$CmdNo" ]; then # Only save new commands, not empty lines or Ctrl+C. + echo -e "# PIPESTATUS=${my_P[*]},$USER@${HOSTNAME}:$PWD,$(tty),${SSH_CLIENT:-local},login=$my_LoginTime,now=$now\n$Cmd" >>"$HistFile" + fi + } -function twtty { - # The special "\[" and "\]" are telling bash that the text enclosed will not move the caret. - # shellcheck disable=SC2034 - local GRAY='\[\033[1;30m\]' - # shellcheck disable=SC2034 - local LIGHT_GRAY='\[\033[0;37m\]' - # shellcheck disable=SC2034 - local WHITE='\[\033[1;37m\]' - # shellcheck disable=SC2034 - local NO_COLOUR='\[\033[0m\]' + function twtty { + # The special "\[" and "\]" are telling bash that the text enclosed will not move the caret. + # shellcheck disable=SC2034 + local GRAY='\[\033[1;30m\]' + # shellcheck disable=SC2034 + local LIGHT_GRAY='\[\033[0;37m\]' + # shellcheck disable=SC2034 + local WHITE='\[\033[1;37m\]' + # shellcheck disable=SC2034 + local NO_COLOUR='\[\033[0m\]' - # shellcheck disable=SC2034 - local LIGHT_BLUE='\[\033[1;34m\]' - # shellcheck disable=SC2034 - local YELLOW='\[\033[1;33m\]' + # shellcheck disable=SC2034 + local LIGHT_BLUE='\[\033[1;34m\]' + # shellcheck disable=SC2034 + local YELLOW='\[\033[1;33m\]' - # shellcheck disable=SC2034 - local RED='\[\033[0;31m\]' - # shellcheck disable=SC2034 - local LIGHT_RED='\[\033[1;31m\]' + # shellcheck disable=SC2034 + local RED='\[\033[0;31m\]' + # shellcheck disable=SC2034 + local LIGHT_RED='\[\033[1;31m\]' - # shellcheck disable=SC2034 - local GREEN='\[\033[0;32m\]' - # shellcheck disable=SC2034 - local LIGHT_GREEN='\[\033[1;32m\]' + # shellcheck disable=SC2034 + local GREEN='\[\033[0;32m\]' + # shellcheck disable=SC2034 + local LIGHT_GREEN='\[\033[1;32m\]' - if [ "${UID}" -ne '0' ]; then - # Normal user colors - local C1="${GREEN}" - local C2="${LIGHT_GREEN}" - local C3="${WHITE}" - else - # root user colors - local C1="${LIGHT_RED}" - local C2="${YELLOW}" - local C3="${WHITE}" - fi + if [ "${UID}" -ne '0' ]; then + # Normal user colors + local C1="${GREEN}" + local C2="${LIGHT_GREEN}" + local C3="${WHITE}" + else + # root user colors + local C1="${LIGHT_RED}" + local C2="${YELLOW}" + local C3="${WHITE}" + fi - case "$TERM" in - xterm*) - TITLEBAR='\[\033]0;\u@\h:\w\007\]' - ;; - *) - TITLEBAR='' - ;; - esac + case "$TERM" in + xterm*) + TITLEBAR='\[\033]0;\u@\h:\w\007\]' + ;; + *) + TITLEBAR='' + ;; + esac - export PS1="$TITLEBAR\ -${C1}┌${C2}─(\ + export PS1="$TITLEBAR${C1}┌${C2}─(\ ${C1}\${my_D}${C2}, ${C1}Err ${C3}\${my_P[*]}${C2}, ${C3}\${my_TTY}\ ${C2})─${C1}─\${my_FILL}${C2}─(\ ${C1}\${my_PWD}\ @@ -194,37 +193,38 @@ ${C1}└${C2}─(\ ${C1}\${USER}${C2}@${C1}\${HOSTNAME%%.*}\ ${C2})${C3}\$${NO_COLOUR} " - export PS2="${C2}─${C1}─${C1}─${NO_COLOUR} \[\033[K\]" - # Set my_P to the exit codes of the last command pipe. - # shellcheck disable=SC2016 - local P='my_P=("${PIPESTATUS[@]}");prompt_command' - if declare -p PROMPT_COMMAND &>/dev/null; then - local re='^declare -a ' - if [[ "$(declare -p PROMPT_COMMAND)" =~ $re ]]; then # Array, supported since bash 5.1 - PROMPT_COMMAND=("$P" "${PROMPT_COMMAND[@]}") - else # String + export PS2="${C2}─${C1}─${C1}─${NO_COLOUR} \[\033[K\]" + # Set my_P to the exit codes of the last command pipe. + # shellcheck disable=SC2016 + local P='my_P=("${PIPESTATUS[@]}");prompt_command' + if declare -p PROMPT_COMMAND &>/dev/null; then + local re='^declare -a ' + if [[ "$(declare -p PROMPT_COMMAND)" =~ $re ]]; then # Array, supported since bash 5.1 + PROMPT_COMMAND=("$P" "${PROMPT_COMMAND[@]}") + else # String + # shellcheck disable=SC2178 + # shellcheck disable=SC2128 + PROMPT_COMMAND="$P;${PROMPT_COMMAND}" + fi + else # shellcheck disable=SC2178 - # shellcheck disable=SC2128 - PROMPT_COMMAND="$P;${PROMPT_COMMAND}" + PROMPT_COMMAND="$P" fi - else - # shellcheck disable=SC2178 - PROMPT_COMMAND="$P" + unset P + + trap prompt_command_exit EXIT + shopt -s cmdhist histappend + export HISTCONTROL='ignorespace' # ':erasedups' would prevent logging duplicate commands. + export HISTIGNORE='history:history *' + } + + # Secure bash history + if [ ! -d "$HOME/bash_history" ]; then + mkdir -m 0700 "$HOME/bash_history" fi - unset P - trap prompt_command_exit EXIT - shopt -s cmdhist histappend - export HISTCONTROL='ignorespace' # ':erasedups' would prevent logging duplicate commands. - export HISTIGNORE='history:history *' -} - -# Secure bash history -if [ ! -d "$HOME/bash_history" ]; then - mkdir -m 0700 "$HOME/bash_history" -fi - -# call and unset -twtty; unset twtty + # call and unset + twtty + unset twtty fi diff --git a/gwebu-profile.spec.in b/gwebu-profile.spec.in index f33e58b..f238f4f 100644 --- a/gwebu-profile.spec.in +++ b/gwebu-profile.spec.in @@ -1,6 +1,6 @@ Summary: Gwebu profile.d - cool date, prompt with history, aliases Name: gwebu-profile -Version: 1.0.8 +Version: 1.0.9 Release: 0 BuildArch: noarch License: GPLv2 @@ -41,6 +41,9 @@ install -m 0644 etc/profile.d/*.sh %{buildroot}%{_sysconfdir}/profile.d/ %changelog +* Sun Nov 30 2025 Doncho N. Gunchev - 1.0.9-0 +- Format the code, add fmt and check targets + * Sun Nov 02 2025 Doncho N. Gunchev - 1.0.8-0 - Fixing VENV again...