repositories / bugabinga.net
bugabinga.net
personal infrastructure for bugabinga!
owned by admin
scripts/local/go.sh
Raw#!/usr/bin/env bash
set -euo pipefail
export GOTOOLCHAIN=local
repo_root="${REPO_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)}"
repo_root="$(realpath "${repo_root}")"
cd "${repo_root}"
usage() {
echo "usage: go.sh check [read|write] [PATH...] | race [PATH...] | staticcheck [PATH...] | vuln [PATH...]" >&2
exit 2
}
path_is_excluded() {
local path="$1" relative
path="$(realpath -m -- "${path}")"
relative="${path#"${repo_root}"/}"
[[ "${path}" != "${repo_root}" && "${relative}" == "${path}" ]] && return 1
[[ "/${relative}/" =~ /(\.git|\.terraform|\.go-cache|\.go-modcache|target|generated|vendor)/ ]] && return 0
git -C "${repo_root}" check-ignore -q --no-index -- "${relative}" 2>/dev/null
}
add_module() {
local module="$1"
[[ " ${selected_modules[*]} " == *" ${module} "* ]] || selected_modules+=("${module}")
}
discover_modules() {
local mod
while IFS= read -r mod; do
mod="$(dirname "${mod}")"
path_is_excluded "${mod}" || modules+=("${mod}")
done < <(
find "${repo_root}" \
\( -type d \( -name .git -o -name .terraform -o -name .go-cache -o -name .go-modcache -o -name target -o -name generated -o -name vendor \) -prune \) -o \
\( -type f -name go.mod -print \) | sort
)
}
select_modules() {
local path absolute mod selected longest
if [[ "$#" -eq 0 ]]; then
selected_modules=("${modules[@]}")
return
fi
for path in "$@"; do
absolute="$(realpath -m -- "${path}")"
[[ "${absolute}" == "${repo_root}" || "${absolute}" == "${repo_root}/"* ]] || {
echo "path outside repository: ${path}" >&2
exit 2
}
path_is_excluded "${absolute}" && continue
case "${absolute#"${repo_root}"/}" in
scripts/local/go.sh | scripts/local/check.sh | scripts/local/check-staged.sh | scripts/local/verify.sh | scripts/local/test-go-tooling.sh | lefthook.yml | justfile)
selected_modules=("${modules[@]}")
continue
;;
.ci/*)
for mod in "${modules[@]}"; do
[[ "${mod}" == "${repo_root}/services/luci" ]] && add_module "${mod}"
done
continue
;;
esac
if [[ -d "${absolute}" ]]; then
for mod in "${modules[@]}"; do
if [[ "${absolute}" == "${mod}" || "${absolute}" == "${mod}/"* || "${mod}" == "${absolute}/"* ]]; then
add_module "${mod}"
fi
done
continue
fi
selected=""
longest=0
for mod in "${modules[@]}"; do
if [[ "${absolute}" == "${mod}/go.mod" || "${absolute}" == "${mod}/"* ]] && [[ "${#mod}" -gt "${longest}" ]]; then
selected="${mod}"
longest="${#mod}"
fi
done
[[ -z "${selected}" ]] || add_module "${selected}"
done
}
module_packages() {
local import_path dir listing
listing="$(go list -e -f '{{if .Dir}}{{.ImportPath}}{{"\t"}}{{.Dir}}{{end}}' ./...)" || return 1
while IFS=$'\t' read -r import_path dir; do
[[ -n "${import_path}" ]] || continue
path_is_excluded "${dir}" || printf '%s\n' "${import_path}"
done <<<"${listing}"
}
module_files() {
local file owner longest mod
while IFS= read -r file; do
path_is_excluded "${file}" && continue
owner=""
longest=0
for mod in "${modules[@]}"; do
if [[ "${file}" == "${mod}/"* ]] && [[ "${#mod}" -gt "${longest}" ]]; then
owner="${mod}"
longest="${#mod}"
fi
done
[[ "${owner}" == "$1" ]] && printf '%s\n' "${file}"
done < <(
find "$1" \
\( -type d \( -name .git -o -name .terraform -o -name .go-cache -o -name .go-modcache -o -name target -o -name generated -o -name vendor \) -prune \) -o \
\( -type f -name '*.go' -print \) | sort
)
}
run_module() {
local action="$1" module="$2" mode="${3:-}" format_diff package_output
local -a files packages
mapfile -t files < <(module_files "${module}")
case "${action}" in
check)
if [[ "${mode}" == "read" ]]; then
if [[ "${#files[@]}" -gt 0 ]]; then
format_diff="$(gofmt -d "${files[@]}")"
if [[ -n "${format_diff}" ]]; then
printf '%s\n' "${format_diff}"
return 1
fi
fi
else
[[ "${#files[@]}" -eq 0 ]] || gofmt -w "${files[@]}"
fi
;;
esac
[[ "${#files[@]}" -gt 0 ]] || return 0
(
cd "${module}"
package_output="$(module_packages)" || exit 1
[[ -n "${package_output}" ]] || exit 0
mapfile -t packages <<<"${package_output}"
case "${action}" in
check)
go vet "${packages[@]}"
go test "${packages[@]}"
;;
race)
go test -race "${packages[@]}"
;;
staticcheck)
go tool staticcheck "${packages[@]}"
;;
vuln)
go tool govulncheck "${packages[@]}"
;;
esac
)
}
action="${1:-}"
[[ -n "${action}" ]] || usage
shift
mode=""
case "${action}" in
check)
mode="write"
if [[ "${1:-}" == "read" || "${1:-}" == "write" ]]; then
mode="$1"
shift
fi
;;
race | staticcheck | vuln) ;;
*)
usage
;;
esac
modules=()
selected_modules=()
discover_modules
select_modules "$@"
if [[ "${#selected_modules[@]}" -eq 0 ]]; then
echo "no Go modules selected"
exit 0
fi
if [[ "${action}" == "race" ]]; then
[[ "$(go env CGO_ENABLED)" == "1" ]] || {
echo "race tests require CGO_ENABLED=1" >&2
exit 1
}
compiler="${CC:-$(go env CC)}"
command -v "${compiler%% *}" >/dev/null 2>&1 || {
echo "race tests require C compiler: ${compiler}" >&2
exit 1
}
fi
printf 'go modules:'
printf ' %s' "${selected_modules[@]#"${repo_root}"/}"
printf '\n'
for module in "${selected_modules[@]}"; do
run_module "${action}" "${module}" "${mode}"
done