mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-15 19:57:07 +08:00
* fix: repair develop scheduler locks and runtime recovery * test: wait for child reaping after verified termination * fix: abort cron mutations when scheduler deletion fails
129 lines
4.3 KiB
Bash
129 lines
4.3 KiB
Bash
#!/usr/bin/env bash
|
|
|
|
# Cache discovery only, never the installed packages. Ordinary installs at the
|
|
# same root are visible immediately. TTL bounds changes outside known inputs.
|
|
ql_node_path_cache_key() {
|
|
local pnpm_bin node_bin name directory file
|
|
pnpm_bin=$(type -P pnpm) || return 1
|
|
node_bin=$(type -P node) || return 1
|
|
{
|
|
printf '%s\n' 'v1' "$EUID" "$PWD" "$PATH" "${HOME:-}" \
|
|
"${PNPM_HOME:-}" "${XDG_CONFIG_HOME:-}" "${XDG_DATA_HOME:-}" \
|
|
"$pnpm_bin" "$node_bin"
|
|
for name in ${!npm_config_@} ${!NPM_CONFIG_@}; do
|
|
printf '%s=%s\n' "$name" "${!name}"
|
|
done
|
|
# Follow executable symlinks, detecting upgrades at the same command path.
|
|
stat -Lc '%n:%i:%s:%Y:%Z' "$pnpm_bin" "$node_bin" 2>/dev/null || \
|
|
stat -Lf '%N:%i:%z:%m:%c' "$pnpm_bin" "$node_bin" 2>/dev/null
|
|
directory=$PWD
|
|
while :; do
|
|
for file in "$directory/.npmrc" "$directory/pnpm-workspace.yaml"; do
|
|
if [[ -f "$file" ]]; then
|
|
printf '%s\n' "$file"
|
|
cat -- "$file"
|
|
printf '\n'
|
|
fi
|
|
done
|
|
[[ "$directory" == / ]] && break
|
|
directory=${directory%/*}
|
|
[[ -n "$directory" ]] || directory=/
|
|
done
|
|
for file in "${HOME:-}/.npmrc" \
|
|
"${XDG_CONFIG_HOME:-${HOME:-}/.config}/pnpm/rc" \
|
|
"${npm_config_userconfig:-${NPM_CONFIG_USERCONFIG:-/dev/null}}" \
|
|
"${npm_config_globalconfig:-${NPM_CONFIG_GLOBALCONFIG:-/dev/null}}"; do
|
|
if [[ -f "$file" ]]; then
|
|
printf '%s\n' "$file"
|
|
cat -- "$file"
|
|
printf '\n'
|
|
fi
|
|
done
|
|
} | cksum
|
|
}
|
|
|
|
ql_read_node_path_cache() {
|
|
local cache="$1" key="$2" now
|
|
local stored_key="" stored_at="" stored_path=""
|
|
now=${EPOCHSECONDS:-$(date +%s)}
|
|
if [[ -f "$cache" && ! -L "$cache" && -O "$cache" ]]; then
|
|
if ! {
|
|
IFS= read -r stored_key && IFS= read -r stored_at && IFS= read -r stored_path
|
|
} < "$cache"; then
|
|
return 1
|
|
fi
|
|
if [[ "$stored_key" == "$key" && "$stored_at" =~ ^(0|[1-9][0-9]{0,10})$ && "$stored_path" == /* ]] && \
|
|
(( now >= stored_at && now - stored_at < 60 )); then
|
|
printf '%s\n' "$stored_path"
|
|
return 0
|
|
fi
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
# Keep the lock descriptor in a subshell so sourcing this helper never changes
|
|
# the caller's descriptors. A crashed refresher releases the kernel lock.
|
|
ql_refresh_node_global_path() (
|
|
local cache="$1" key="$2" now result previous_umask
|
|
local lock="${cache}.lock"
|
|
previous_umask=$(umask)
|
|
umask 077
|
|
if type -P flock &>/dev/null && mkdir -p -- "$dir_tmp" 2>/dev/null; then
|
|
if [[ ! -L "$lock" && ( ! -e "$lock" || ( -f "$lock" && -O "$lock" ) ) ]] && \
|
|
{ exec 9>> "$lock"; } 2>/dev/null; then
|
|
# BusyBox flock (Alpine) has no -w. Both implementations support -n;
|
|
# bound contention retries and fall back immediately on other failures.
|
|
# Never remove the lock file while waiters exist.
|
|
local lock_attempt=0 lock_status
|
|
while :; do
|
|
if flock -n 9 2>/dev/null; then
|
|
if ql_read_node_path_cache "$cache" "$key"; then
|
|
return 0
|
|
fi
|
|
break
|
|
else
|
|
lock_status=$?
|
|
fi
|
|
[[ "$lock_status" == 1 && "$lock_attempt" -lt 20 ]] || break
|
|
lock_attempt=$((lock_attempt + 1))
|
|
sleep 0.1
|
|
done
|
|
fi
|
|
fi
|
|
|
|
# Private lock creation must not change pnpm's inherited creation mask.
|
|
umask "$previous_umask"
|
|
now=${EPOCHSECONDS:-$(date +%s)}
|
|
result=$(pnpm root -g 9>&- 2>/dev/null) || return $?
|
|
# Never cache failed, empty, multiline or non-absolute answers.
|
|
if [[ "$result" == /* && "$result" != *$'\n'* && "$result" != *$'\r'* ]]; then
|
|
(
|
|
umask 077
|
|
mkdir -p -- "$dir_tmp" || exit 0
|
|
local temporary
|
|
temporary=$(mktemp "${cache}.XXXXXX") || exit 0
|
|
if printf '%s\n%s\n%s\n' "$key" "$now" "$result" > "$temporary"; then
|
|
mv -f -- "$temporary" "$cache" || rm -f -- "$temporary"
|
|
else
|
|
rm -f -- "$temporary"
|
|
fi
|
|
) 2>/dev/null
|
|
fi
|
|
printf '%s\n' "$result"
|
|
)
|
|
|
|
ql_get_node_global_path() {
|
|
if [[ "${QL_NODE_PATH_CACHE:-1}" == 0 ]]; then
|
|
pnpm root -g 2>/dev/null
|
|
return $?
|
|
fi
|
|
|
|
local key cache
|
|
cache="${dir_tmp}/pnpm-root-${EUID}.cache"
|
|
key=$(ql_node_path_cache_key) || { pnpm root -g 2>/dev/null; return $?; }
|
|
if ql_read_node_path_cache "$cache" "$key"; then
|
|
return 0
|
|
fi
|
|
ql_refresh_node_global_path "$cache" "$key"
|
|
}
|