From cbb519644d6cceba39d718f21c1d290992f0e8cd Mon Sep 17 00:00:00 2001 From: boypt <1033514+boypt@users.noreply.github.com> Date: Sun, 16 Aug 2026 11:21:01 +0800 Subject: [PATCH] lint: add shellcheck/shfmt rules to AGENTS.md, format compile.sh and pullsrc.sh --- AGENTS.md | 19 ++++ compile.sh | 304 +++++++++++++++++++++++++++-------------------------- pullsrc.sh | 60 ++++++----- 3 files changed, 205 insertions(+), 178 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index f5f7676..4dc8b07 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -51,6 +51,25 @@ docker run --rm -v .:/data elssh:el8 - `.github/workflows/build-images.yml` — manually triggered (`workflow_dispatch`), builds Docker images for each EL version and pushes to `ghcr.io`. - `.github/workflows/build-rpm.yml` — runs on `v*` tags, builds RPMs inside Docker containers and creates a GitHub release. +## Linting & formatting + +All shell scripts (`*.sh`) must pass `shellcheck` and `shfmt` before committing: + +```bash +# Lint (warnings are errors) +shellcheck -S warning compile.sh pullsrc.sh + +# Format check (must produce no diff) +shfmt -d -i 0 -bn -ci compile.sh pullsrc.sh + +# Auto-fix formatting in-place +shfmt -w -i 0 -bn -ci compile.sh pullsrc.sh +``` + +- **shellcheck** `-S warning`: treat warnings as failures; informational/style notes may be suppressed inline with `# shellcheck disable=SCxxxx`. +- **shfmt** `-i 0 -bn -ci`: tabs for indentation (no extra indent), binary operators (`&&`, `||`, `|`) at start of next line, case body indented. +- Both tools must exit 0 before any commit touching `*.sh` files. + ## Gitignore `*-local*` is gitignored — version-local.env, editor swap files, etc. `*.tar.gz` is gitignored everywhere, including `downloads/`. Generated RPMs go to `output/` (also gitignored). diff --git a/compile.sh b/compile.sh index ff0f2d6..8c60926 100755 --- a/compile.sh +++ b/compile.sh @@ -11,7 +11,7 @@ trap 'echo -e "Aborted, error $? in command: $BASH_COMMAND"; trap ERR; exit 1' E # Set magic variables for current file & dir __dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" __file="${__dir}/$(basename "${BASH_SOURCE[0]}")" -__base="$(basename ${__file} .sh)" +__base="$(basename "${__file}" .sh)" __root="$(cd "$(dirname "${__dir}")" && pwd)" # <-- change this as it depends on your app arg1="${1:-}" @@ -24,200 +24,204 @@ rpmtopdir= # 2: build openssl statically CHECKEXISTS() { - if [[ ! -f $__dir/downloads/$1 ]];then - echo "$1 not found, run 'pullsrc.sh', or manually put it in the downloads dir." - exit 1 - fi + if [[ ! -f $__dir/downloads/$1 ]]; then + echo "$1 not found, run 'pullsrc.sh', or manually put it in the downloads dir." + exit 1 + fi } - GUESS_DIST() { - # will not work if rpm cmd not exists - if ! type -p rpm > /dev/null;then - echo 'unknown' && return 0 - fi + # will not work if rpm cmd not exists + if ! type -p rpm >/dev/null; then + echo 'unknown' && return 0 + fi - local dist=$(rpm --eval '%{?dist}' | tr -d '.') + local dist + dist=$(rpm --eval '%{?dist}' | tr -d '.') - # fallback to el7 - [[ $dist == "el9" ]] && dist="el7" - [[ $dist == "el8" ]] && dist="el7" - [[ $dist == "an8" ]] && dist="el7" # Anolis 8 - [[ $dist == "an7" ]] && dist="el7" # Anolis 7 - [[ $dist == uel* ]] && dist="el7" # UOS20+ + # fallback to el7 + [[ $dist == "el9" ]] && dist="el7" + [[ $dist == "el8" ]] && dist="el7" + [[ $dist == "an8" ]] && dist="el7" # Anolis 8 + [[ $dist == "an7" ]] && dist="el7" # Anolis 7 + [[ $dist == uel* ]] && dist="el7" # UOS20+ - [[ -n $dist ]] && echo $dist && return 0 + [[ -n $dist ]] && echo $dist && return 0 - local glibcver=$(ldd --version | head -n1 | grep -Eo '[0-9]+' | tr -d '\n') + local glibcver + glibcver=$(ldd --version | head -n1 | grep -Eo '[0-9]+' | tr -d '\n') - # centos 5 uses glibc 2.5 - [[ $glibcver -eq 25 ]] && echo 'el5' && return 0 + # centos 5 uses glibc 2.5 + [[ $glibcver -eq 25 ]] && echo 'el5' && return 0 - # centos 6 uses glibc 2.12 - [[ $glibcver -eq 212 ]] && echo 'el6' && return 0 + # centos 6 uses glibc 2.12 + [[ $glibcver -eq 212 ]] && echo 'el6' && return 0 - # centos 7 uses glibc 2.17 - [[ $glibcver -eq 217 ]] && echo 'el7' && return 0 + # centos 7 uses glibc 2.17 + [[ $glibcver -eq 217 ]] && echo 'el7' && return 0 - # centos 8 uses glibc 2.28, also map to el7 - [[ $glibcver -eq 228 ]] && echo 'el7' && return 0 + # centos 8 uses glibc 2.28, also map to el7 + [[ $glibcver -eq 228 ]] && echo 'el7' && return 0 - # some centos-like dists ships higher version of glibc, fallback to el7 - [[ $glibcver -gt 217 ]] && echo 'el7' && return 0 + # some centos-like dists ships higher version of glibc, fallback to el7 + [[ $glibcver -gt 217 ]] && echo 'el7' && return 0 } TOPDIR_SELECT() { - local DISTVER=$(GUESS_DIST) - case $DISTVER in - el7) - rpmtopdir=el7 - if [[ -z ${WITH_OPENSSL+x} ]]; then - local opensslver=$(rpm -q openssl --qf "%{VERSION}" 2>/dev/null | cut -d. -f1) - [[ $opensslver -ge 3 ]] && WITH_OPENSSL=1 || WITH_OPENSSL=2 - fi - ;; - el6) - rpmtopdir=el6 - WITH_OPENSSL=${WITH_OPENSSL:-2} - ;; - el5) - rpmtopdir=el5 - WITH_OPENSSL=${WITH_OPENSSL:-2} - ;; - *) - echo "Distro undefined, please specify manually: el5 el6 el7" - echo -e "\nCurrent OS:" - [[ -f /etc/os-release ]] && cat /etc/os-release - [[ -f /etc/redhat-release ]] && cat /etc/redhat-release - [[ -f /etc/system-release ]] && cat /etc/system-release - echo -e "Current OS vendor: $(rpm --eval '%{?_vendor}') \n" - return 1 - ;; - esac + local DISTVER + DISTVER=$(GUESS_DIST) + case $DISTVER in + el7) + rpmtopdir=el7 + if [[ -z ${WITH_OPENSSL+x} ]]; then + local opensslver + opensslver=$(rpm -q openssl --qf "%{VERSION}" 2>/dev/null | cut -d. -f1) + [[ $opensslver -ge 3 ]] && WITH_OPENSSL=1 || WITH_OPENSSL=2 + fi + ;; + el6) + rpmtopdir=el6 + WITH_OPENSSL=${WITH_OPENSSL:-2} + ;; + el5) + rpmtopdir=el5 + WITH_OPENSSL=${WITH_OPENSSL:-2} + ;; + *) + echo "Distro undefined, please specify manually: el5 el6 el7" + echo -e "\nCurrent OS:" + [[ -f /etc/os-release ]] && cat /etc/os-release + [[ -f /etc/redhat-release ]] && cat /etc/redhat-release + [[ -f /etc/system-release ]] && cat /etc/system-release + echo -e "Current OS vendor: $(rpm --eval '%{?_vendor}') \n" + return 1 + ;; + esac } BUILD_RPM() { - source version.env - [[ -f version-local.env ]] && source version-local.env + # shellcheck disable=SC1091 + source version.env + # shellcheck disable=SC1091 + [[ -f version-local.env ]] && source version-local.env - local SOURCES=( $OPENSSHSRC \ - $OPENSSLSRC \ - $ASKPASSSRC \ - ) - # UOS20 build: prefix PKGREL with "uos20." so the resulting RPMs are - # distinguishable from the standard build (e.g. PKGREL `1` becomes - # `uos20.1`, not `uos201`), and pass `uos20 1` to the spec to enable - # the kernel-panic patch. - # NOTE: RPM does not allow '-' in the Release field (it is the - # Version/Release delimiter), so '.' is used as the separator. - local _pkgrel="${PKGREL:-1}" - if [[ ${UOS20:-0} == 1 ]]; then - _pkgrel="uos20.${_pkgrel}" - fi - local RPMBUILDOPTS=( \ - --define "with_openssl ${WITH_OPENSSL:-2}" \ - --define "opensslver ${OPENSSLVER}" \ - --define "opensshver ${OPENSSHVER}" \ - --define "opensshpkgrel ${_pkgrel}" \ - --define 'debug_package %{nil}' \ - --define 'no_gtk2 1' \ - --define 'skip_gnome_askpass 1' \ - --define 'skip_x11_askpass 1' \ - ) - [[ ${UOS20:-0} == 1 ]] && RPMBUILDOPTS+=('--define' 'uos20 1') + local SOURCES=("$OPENSSHSRC" + "$OPENSSLSRC" + "$ASKPASSSRC" + ) + # UOS20 build: prefix PKGREL with "uos20." so the resulting RPMs are + # distinguishable from the standard build (e.g. PKGREL `1` becomes + # `uos20.1`, not `uos201`), and pass `uos20 1` to the spec to enable + # the kernel-panic patch. + # NOTE: RPM does not allow '-' in the Release field (it is the + # Version/Release delimiter), so '.' is used as the separator. + local _pkgrel="${PKGREL:-1}" + if [[ ${UOS20:-0} == 1 ]]; then + _pkgrel="uos20.${_pkgrel}" + fi + local RPMBUILDOPTS=( + --define "with_openssl ${WITH_OPENSSL:-2}" + --define "opensslver ${OPENSSLVER}" + --define "opensshver ${OPENSSHVER}" + --define "opensshpkgrel ${_pkgrel}" + --define 'debug_package %{nil}' + --define 'no_gtk2 1' + --define 'skip_gnome_askpass 1' + --define 'skip_x11_askpass 1' + ) + [[ ${UOS20:-0} == 1 ]] && RPMBUILDOPTS+=('--define' 'uos20 1') - # EL5 dist fixes - if [[ $rpmtopdir == *el5 ]]; then - SOURCES+=($PERLSRC) + # EL5 dist fixes + if [[ $rpmtopdir == *el5 ]]; then + SOURCES+=("$PERLSRC") - # Hack: fake the perl src when perl is ready already(docker images) - [[ $(perl -e 'print $] >= 5.010 ? 1 : 0') -eq 1 ]] && \ - touch ./downloads/$PERLSRC - - RPMBUILDOPTS+=('--define' "perlver ${PERLVER}" '--define' 'dist .el5') - export CC=gcc44 - fi + # Hack: fake the perl src when perl is ready already(docker images) + [[ $(perl -e 'print $] >= 5.010 ? 1 : 0') -eq 1 ]] \ + && touch ./downloads/"$PERLSRC" - # add dist variable if not defined - [[ $rpmtopdir == *el7 ]] && [[ -z $(rpm --eval '%{?dist}') ]] && \ - RPMBUILDOPTS+=('--define' "dist .$(rpm -q glibc | rev | cut -d. -f2 | rev)") + RPMBUILDOPTS+=('--define' "perlver ${PERLVER}" '--define' 'dist .el5') + export CC=gcc44 + fi - pushd $rpmtopdir - RPMBUILDOPTS+=('--define' "_topdir $PWD") - for fn in ${SOURCES[@]}; do - CHECKEXISTS $fn && \ - install -v -m666 $__dir/downloads/$fn ./SOURCES/ - done + # add dist variable if not defined + [[ $rpmtopdir == *el7 ]] && [[ -z $(rpm --eval '%{?dist}') ]] \ + && RPMBUILDOPTS+=('--define' "dist .$(rpm -q glibc | rev | cut -d. -f2 | rev)") - if [[ ${M32:-0} != 0 ]]; then - local SETARCH="setarch i386" - RPMBUILDOPTS+=('--target' i686) - export CFLAGS="${CFLAGS:-} -m32" LDFLAGS="${LDFLAGS:-} -m32" - fi + pushd $rpmtopdir + RPMBUILDOPTS+=('--define' "_topdir $PWD") + for fn in "${SOURCES[@]}"; do + CHECKEXISTS "$fn" \ + && install -v -m666 "$__dir"/downloads/"$fn" ./SOURCES/ + done - ${SETARCH:-} \ - rpmbuild -bb ./SPECS/${SPECFILE:-openssh.spec} "${RPMBUILDOPTS[@]}" - - if [[ $? -ne 0 ]]; then - echo "Error: rpmbuild failed with exit code $?" - exit 1 - fi + if [[ ${M32:-0} != 0 ]]; then + local SETARCH="setarch i386" + RPMBUILDOPTS+=('--target' i686) + export CFLAGS="${CFLAGS:-} -m32" LDFLAGS="${LDFLAGS:-} -m32" + fi - mkdir -p $__dir/output - find ./RPMS -type f -name '*.rpm' -exec install -v -m644 {} $__dir/output/ \; - popd + if ! ${SETARCH:-} rpmbuild -bb ./SPECS/"${SPECFILE:-openssh.spec}" "${RPMBUILDOPTS[@]}"; then + echo "Error: rpmbuild failed with exit code $?" + exit 1 + fi + + mkdir -p "$__dir"/output + find ./RPMS -type f -name '*.rpm' -exec install -v -m644 {} "$__dir"/output/ \; + popd } -LIST_RPMDIR(){ - local RPMDIR=$__dir/${rpmtopdir}/RPMS/$(rpm --eval '%{_arch}') - [[ -d $RPMDIR ]] && echo $RPMDIR +LIST_RPMDIR() { + local RPMDIR + RPMDIR=$__dir/${rpmtopdir}/RPMS/$(rpm --eval '%{_arch}') + [[ -d $RPMDIR ]] && echo "$RPMDIR" } LIST_RPMS() { - local RPMDIR=$(LIST_RPMDIR) - [[ -d $RPMDIR ]] && find $RPMDIR -type f -name '*.rpm' + local RPMDIR + RPMDIR=$(LIST_RPMDIR) + [[ -d $RPMDIR ]] && find "$RPMDIR" -type f -name '*.rpm' } # sub cmds case $arg1 in - GETEL) - GUESS_DIST - exit 0 - ;; - GETRPM) - TOPDIR_SELECT - LIST_RPMS - exit 0 - ;; - RPMDIR) - TOPDIR_SELECT - LIST_RPMDIR - exit 0 - ;; - *) - if [[ -n $arg1 && ! -d $arg1 ]]; then - echo -e "Subcmd: $arg1 not found.\n GETEL, GETRPM, RPMDIR" - exit 1 - fi - ;; + GETEL) + GUESS_DIST + exit 0 + ;; + GETRPM) + TOPDIR_SELECT + LIST_RPMS + exit 0 + ;; + RPMDIR) + TOPDIR_SELECT + LIST_RPMDIR + exit 0 + ;; + *) + if [[ -n $arg1 && ! -d $arg1 ]]; then + echo -e "Subcmd: $arg1 not found.\n GETEL, GETRPM, RPMDIR" + exit 1 + fi + ;; esac # manual specified dist if [[ -n $arg1 && -d $arg1 ]]; then - rpmtopdir=$arg1 - BUILD_RPM - exit 0 + rpmtopdir=$arg1 + BUILD_RPM + exit 0 fi # auto select dist TOPDIR_SELECT -if [[ ! -d $rpmtopdir ]]; then - echo "This script works only in el5/el6/el7" - echo "eg: ${0} el7" - exit 1 +if [[ ! -d $rpmtopdir ]]; then + echo "This script works only in el5/el6/el7" + echo "eg: ${0} el7" + exit 1 fi if [[ -d $rpmtopdir ]]; then - BUILD_RPM + BUILD_RPM fi diff --git a/pullsrc.sh b/pullsrc.sh index e623c51..7565f28 100755 --- a/pullsrc.sh +++ b/pullsrc.sh @@ -11,7 +11,7 @@ trap 'echo -e "Aborted, error $? in command: $BASH_COMMAND"; trap ERR; exit 1' E # Set magic variables for current file & dir __dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" __file="${__dir}/$(basename "${BASH_SOURCE[0]}")" -__base="$(basename ${__file} .sh)" +__base="$(basename "${__file}" .sh)" __root="$(cd "$(dirname "${__dir}")" && pwd)" # <-- change this as it depends on your app arg1="${1:-}" @@ -20,57 +20,61 @@ arg1="${1:-}" # allow command fail: # fail_command || true +# shellcheck disable=SC1091 source version.env +# shellcheck disable=SC1091 [[ -f version-local.env ]] && source version-local.env OPENSSHMIR=https://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable OPENSSLMIR=https://www.openssl.org/source/ +# shellcheck disable=SC2153 OPENSSLMIR=${GH_PROXY:-}https://github.com/openssl/openssl/releases/download/openssl-${OPENSSLVER}/ ASKPASSMIR=https://src.fedoraproject.org/repo/pkgs/openssh/x11-ssh-askpass-1.2.4.1.tar.gz/8f2e41f3f7eaa8543a2440454637f3c3 PERLMIR=https://www.cpan.org/src/5.0 LATEST_OPENSSH() { - curl -s "$OPENSSHMIR/" 2>/dev/null | \ - grep -o 'openssh-[0-9.]*p[0-9]*\.tar\.gz' | \ - sed 's/openssh-//; s/\.tar\.gz//' | \ - sort -Vu | tail -1 || true + curl -s "$OPENSSHMIR/" 2>/dev/null \ + | grep -o 'openssh-[0-9.]*p[0-9]*\.tar\.gz' \ + | sed 's/openssh-//; s/\.tar\.gz//' \ + | sort -Vu | tail -1 || true } if [[ $arg1 == "--latest" ]]; then - latest=$(LATEST_OPENSSH) - current="${OPENSSHVER}" - echo "Current version: $current" - echo "Latest version: $latest" - if [[ "$latest" == "$current" ]]; then - echo "Already up to date." - else - echo "NEW VERSION AVAILABLE: $latest" - fi - exit 0 + latest=$(LATEST_OPENSSH) + # shellcheck disable=SC2153 + current="${OPENSSHVER}" + echo "Current version: $current" + echo "Latest version: $latest" + if [[ "$latest" == "$current" ]]; then + echo "Already up to date." + else + echo "NEW VERSION AVAILABLE: $latest" + fi + exit 0 fi mkdir -p downloads pushd downloads if [[ ! -f $OPENSSLSRC && ${DOCKERBUILD:-0} == 0 ]]; then - echo "Get:" $OPENSSLMIR/$OPENSSLSRC - wget --no-check-certificate $OPENSSLMIR/$OPENSSLSRC || \ - echo "!!! Please download $OPENSSLSRC in $PWD by yourself." + echo "Get:" "$OPENSSLMIR"/"$OPENSSLSRC" + wget --no-check-certificate "$OPENSSLMIR"/"$OPENSSLSRC" \ + || echo "!!! Please download $OPENSSLSRC in $PWD by yourself." fi if [[ ! -f $OPENSSHSRC && ${DOCKERBUILD:-0} == 0 ]]; then - echo Get: $OPENSSHMIR/$OPENSSHSRC - wget --no-check-certificate $OPENSSHMIR/$OPENSSHSRC || \ - echo "!!! Please download $OPENSSHSRC in $PWD by yourself." + echo Get: "$OPENSSHMIR"/"$OPENSSHSRC" + wget --no-check-certificate "$OPENSSHMIR"/"$OPENSSHSRC" \ + || echo "!!! Please download $OPENSSHSRC in $PWD by yourself." fi if [[ ! -f $ASKPASSSRC && ${DOCKERBUILD:-0} == 0 ]]; then - echo Get: $ASKPASSMIR/$ASKPASSSRC - wget --no-check-certificate $ASKPASSMIR/$ASKPASSSRC || \ - echo "!!! Please download $ASKPASSSRC in $PWD by yourself." + echo Get: "$ASKPASSMIR"/"$ASKPASSSRC" + wget --no-check-certificate "$ASKPASSMIR"/"$ASKPASSSRC" \ + || echo "!!! Please download $ASKPASSSRC in $PWD by yourself." fi -if [[ $($__dir/compile.sh GETEL) == "el5" && ${DOCKERBUILD:-0} == 1 && ! -f $PERLSRC ]]; then - echo Get: $PERLMIR/$PERLSRC - wget --no-check-certificate $PERLMIR/$PERLSRC || \ - echo "!!! Please download $PERLSRC in $PWD by yourself." +if [[ $("$__dir"/compile.sh GETEL) == "el5" && ${DOCKERBUILD:-0} == 1 && ! -f $PERLSRC ]]; then + echo Get: "$PERLMIR"/"$PERLSRC" + wget --no-check-certificate "$PERLMIR"/"$PERLSRC" \ + || echo "!!! Please download $PERLSRC in $PWD by yourself." fi