mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-10 17:47:05 +01:00
Some checks failed
dependency freshness / dependencies on newest stable (push) Has been cancelled
md-naming / markdown naming convention (push) Has been cancelled
Pre-commit checks / pre-commit (push) Has been cancelled
Python tests / test (push) Has been cancelled
Shell tests / shell-tests (push) Has been cancelled
Shell tests / arch-tests (push) Has been cancelled
A push took ~13s. prettier is a pre-push hook precisely because Node's startup dominates its runtime, and pre-commit chunks a large file list into several invocations -- a 106-file push paid ten cold Node starts. ci-mirror, the hook that looks expensive, was already 0.02s once its green-tree cache hit. A file whose content, prettier version and prettier config are all unchanged since its last clean check cannot have become unformatted, so the verdict is now cached and the file never reaches Node. Only clean verdicts are recorded, so a formatting regression is always re-checked; the key includes `prettier --version` and every config file, so an upgrade or a config edit invalidates the cache wholesale. The systemd-run memory cap is unchanged. Measured on the same push range: 13.0s -> 3.3s total, of which ~0.6s is hooks and the rest is git's own network negotiation. On a 40-file list the runner itself goes 0.652s -> 0.057s, starting no prettier process at all. endurain/README.md and copilot-instructions.md are reflowed: the ~ reorganisation lengthened paths inside them, which changed prettier's markdown table alignment. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AwtowrowDXx6ccmWVPkCaF
122 lines
3.6 KiB
Bash
Executable File
122 lines
3.6 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# ============================================================================
|
|
# prettier --check, memory-capped and result-cached.
|
|
#
|
|
# Two problems this solves:
|
|
#
|
|
# 1. Memory. Prettier runs inside its own systemd-run scope so its budget is
|
|
# independent of the outer pre-push cgroup, which has already accumulated
|
|
# page cache from pytest/mypy/pylint.
|
|
#
|
|
# 2. Latency. Prettier is a pre-push hook precisely because Node's startup
|
|
# dominates its runtime, and pre-commit chunks a large file list into
|
|
# several invocations -- a 104-file push paid three cold Node starts and
|
|
# ~13s wall clock. A file whose content, prettier version and prettier
|
|
# config are all unchanged since the last clean check cannot have become
|
|
# unformatted, so its verdict is cached and it never reaches Node. The
|
|
# common push touches files that are already clean, which makes the whole
|
|
# hook a handful of hashes and no Node process at all.
|
|
#
|
|
# The cache is keyed on content, so it cannot go stale: edit a file, bump
|
|
# prettier, or change .prettierrc and the key changes with it.
|
|
# ============================================================================
|
|
|
|
set -euo pipefail
|
|
|
|
CACHE_ROOT="${PRETTIER_GATE_CACHE:-${XDG_CACHE_HOME:-$HOME/.cache}/prettier-gate}"
|
|
readonly CACHE_ROOT
|
|
# Enough entries for several branches' worth of files; pruned wholesale rather
|
|
# than per-entry, because an empty cache costs one slow run, not correctness.
|
|
readonly MAX_ENTRIES=20000
|
|
|
|
# Everything that can change prettier's verdict without changing the file.
|
|
config_fingerprint() {
|
|
local version config
|
|
version="$(prettier --version 2>/dev/null || echo unknown)"
|
|
config="$(
|
|
cat .prettierrc .prettierrc.* .prettierignore prettier.config.* 2>/dev/null
|
|
true
|
|
)"
|
|
printf '%s\n%s' "$version" "$config" | sha256sum | cut -d' ' -f1
|
|
}
|
|
|
|
# One sha256sum call for the whole list: per-file forks cost more than the
|
|
# hashing does.
|
|
cache_keys() {
|
|
local fingerprint="$1"
|
|
shift
|
|
sha256sum -- "$@" 2>/dev/null | while read -r digest _; do
|
|
printf '%s-%s\n' "$fingerprint" "$digest"
|
|
done
|
|
}
|
|
|
|
prune_if_huge() {
|
|
local count
|
|
count="$(find "$CACHE_ROOT" -maxdepth 1 -type f 2>/dev/null | wc -l)"
|
|
if ((count > MAX_ENTRIES)); then
|
|
rm -rf "${CACHE_ROOT:?}"
|
|
mkdir -p "$CACHE_ROOT"
|
|
fi
|
|
}
|
|
|
|
run_prettier() {
|
|
export NODE_OPTIONS="${NODE_OPTIONS:-} --max-old-space-size=384"
|
|
if command -v systemd-run >/dev/null 2>&1; then
|
|
systemd-run --user --scope --quiet --collect \
|
|
-p MemoryMax=512M \
|
|
-p MemorySwapMax=0 \
|
|
-- prettier --check "$@"
|
|
return
|
|
fi
|
|
prettier --check "$@"
|
|
}
|
|
|
|
main() {
|
|
if [ $# -eq 0 ]; then
|
|
exit 0
|
|
fi
|
|
|
|
mkdir -p "$CACHE_ROOT"
|
|
prune_if_huge
|
|
|
|
local fingerprint
|
|
fingerprint="$(config_fingerprint)"
|
|
|
|
# Pair each file with its key, then split into "already known clean" and
|
|
# "must be checked". readarray keeps this to two subshells regardless of
|
|
# how many files pre-commit passed.
|
|
local -a keys=() todo=() todo_keys=()
|
|
readarray -t keys < <(cache_keys "$fingerprint" "$@")
|
|
if ((${#keys[@]} != $#)); then
|
|
# A file vanished between pre-commit's listing and now: fall back to
|
|
# checking everything rather than mis-pairing files with digests.
|
|
run_prettier "$@"
|
|
exit $?
|
|
fi
|
|
|
|
local i=0 file
|
|
for file in "$@"; do
|
|
if [[ ! -f "$CACHE_ROOT/${keys[i]}" ]]; then
|
|
todo+=("$file")
|
|
todo_keys+=("${keys[i]}")
|
|
fi
|
|
i=$((i + 1))
|
|
done
|
|
|
|
if ((${#todo[@]} == 0)); then
|
|
printf 'prettier: %d file(s) unchanged since their last clean check\n' "$#"
|
|
exit 0
|
|
fi
|
|
|
|
run_prettier "${todo[@]}"
|
|
|
|
# Only a clean verdict is recorded; a failure must be re-checked next time.
|
|
local key
|
|
for key in "${todo_keys[@]}"; do
|
|
: >"$CACHE_ROOT/$key"
|
|
done
|
|
}
|
|
|
|
main "$@"
|