diff --git a/.github/workflows/shell-tests.yml b/.github/workflows/shell-tests.yml index ea5eccc..a949d38 100644 --- a/.github/workflows/shell-tests.yml +++ b/.github/workflows/shell-tests.yml @@ -55,7 +55,14 @@ jobs: run: find . -type f -name '*.sh' -print0 | xargs -0 -n1 bash -n - name: Run ShellCheck - run: git ls-files -z -- '*.sh' | xargs -0 -r shellcheck -x --severity=error -- + shell: bash + run: | + # All tracked Bash scripts outside tests are production by default. + # Check both groups even when production lint fails. + status=0 + git ls-files -z -- "*.sh" ":!:tests/**" | xargs -0 -r shellcheck -x --severity=warning -- || status=1 + git ls-files -z -- "tests/*.sh" | xargs -0 -r shellcheck -x --severity=error -- || status=1 + exit "$status" - name: Run tests env: diff --git a/README.md b/README.md index 1b38090..369f6e7 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,9 @@ 生产宿主机(包括 Netcup)仅执行差异检查及改动脚本的 `bash -n`,不运行全量 ShellCheck 或完整测试集; 分析和测试交由 CI:PR 按完整差异及依赖映射选择套件,README/许可证修改无需业务测试; 公共设施或未知依赖改动回退全量,main 推送仍执行全量。两个必需 Job 始终运行,输出选择和跳过记录。 -ShellCheck 与语法检查仍覆盖全部脚本;文档修改无需本地全套测试,但仍须通过必需 CI。 +Ubuntu 使用固定 ShellCheck v0.10.0:所有受 Git 跟踪、位于 tests/ 之外的 .sh 文件执行 warning 门槛,tests/ 内的 .sh 文件执行 error 门槛;新目录中的生产 .sh 文件自动纳入,不维护生产文件白名单。Zsh 配置 p10k-config.zsh 不交给 Bash ShellCheck。两组 lint 都会执行并累计失败,Debian 不重复 lint。 +例外仅允许局部明确的 SC 规则编号和邻近理由;禁止文件级或全局 warning 抑制。测试 warning 不阻断不等于被 disable,禁止用抑制隐藏行为缺陷。CI 工作流改动继续触发全量测试回退;warning 门槛失败时后续 Ubuntu 行为套件不会执行,不能以 Debian 通过代替双环境验收。 +语法检查仍覆盖全部 .sh 脚本;文档修改无需本地全套测试,但仍须通过必需 CI。 本机重测试必须使用原生资源限制及权限隔离;无法隔离或超限时停止,不自动提高额度或转宿主机执行。 ## 快速开始 diff --git a/linux_setup.sh b/linux_setup.sh index 6ca3c06..8a9e35b 100755 --- a/linux_setup.sh +++ b/linux_setup.sh @@ -208,7 +208,7 @@ pre_check() { local version_id local major_version - # shellcheck disable=SC1091 + # shellcheck disable=SC1091 # /etc/os-release is provided by the target OS, not this repository. . /etc/os-release os_id="${ID:-}" version_id="${VERSION_ID:-}" diff --git a/modules/docker-setup.sh b/modules/docker-setup.sh index cd06c52..f0703f8 100644 --- a/modules/docker-setup.sh +++ b/modules/docker-setup.sh @@ -121,7 +121,7 @@ detect_supported_distribution() { local version_id local major_version - # shellcheck disable=SC1091 + # shellcheck disable=SC1091 # /etc/os-release is provided by the target OS, not this repository. . /etc/os-release os_id="${ID:-}" version_id="${VERSION_ID:-}" diff --git a/modules/system-customize.sh b/modules/system-customize.sh index c290ed6..ac8d972 100644 --- a/modules/system-customize.sh +++ b/modules/system-customize.sh @@ -1913,7 +1913,6 @@ XANMOD_STAGED_SOURCE="" XANMOD_CANDIDATE_SOURCE="" XANMOD_ARMORED_KEY_TEMP="" XANMOD_ACTIVE_APT_LISTS_DIR="" -XANMOD_ACTIVE_APT_LISTS_BUILDING=false XANMOD_ALLOCATION_CANDIDATE="" XANMOD_ALLOCATION_KIND="" XANMOD_ALLOCATION_OWNER_TOKEN="" @@ -1951,7 +1950,6 @@ XANMOD_BACKUP_SNAPSHOT_BUILDING=false XANMOD_BACKUP_SNAPSHOT_REMOVED=false XANMOD_BACKUP_GROUP_SNAPSHOT_DIR="" XANMOD_BACKUP_STAGE_DIR="" -XANMOD_BACKUP_STAGE_BUILDING=false XANMOD_BACKUP_TRANSACTION_ID="" XANMOD_CONFIGURATION_PREVIOUSLY_MANAGED=false XANMOD_BACKUP_SNAPSHOT_PATHS=() @@ -2167,7 +2165,7 @@ get_locale_config_file() { local major_version="" if [[ -r /etc/os-release ]]; then - # shellcheck disable=SC1091 + # shellcheck disable=SC1091 # /etc/os-release is provided by the target OS, not this repository. . /etc/os-release os_id="${ID:-}" version_id="${VERSION_ID:-}" @@ -2282,7 +2280,7 @@ authorize_xanmod_install() { } get_os_codename() { if [[ -r "$XANMOD_OS_RELEASE" ]]; then - # shellcheck disable=SC1090 + # shellcheck disable=SC1090 # Runtime OS-release path; test mode substitutes an isolated fixture. . "$XANMOD_OS_RELEASE" if [[ -n "${VERSION_CODENAME:-}" ]]; then echo "$VERSION_CODENAME" @@ -3000,8 +2998,11 @@ xanmod_allocate_temp_directory() { [[ -d "$parent" && ! -L "$parent" ]] || return 1 [[ -z "$XANMOD_ALLOCATION_CANDIDATE" && -z "$XANMOD_ALLOCATION_STATE" ]] || return 1 printf -v "$path_variable" '%s' "" - printf -v "$building_variable" '%s' false - for attempt in {1..64}; do + # Callers without a building-state consumer omit this optional output. + if [[ -n "$building_variable" ]]; then + printf -v "$building_variable" "%s" false + fi + for (( attempt=1; attempt<=64; attempt++ )); do token=$(xanmod_random_token) || return 1 owner_token=$(xanmod_random_token) || return 1 candidate="$parent/$prefix.$token" @@ -3069,7 +3070,7 @@ xanmod_allocate_temp_file() { [[ -d "$parent" && ! -L "$parent" ]] || return 1 [[ -z "$XANMOD_ALLOCATION_CANDIDATE" && -z "$XANMOD_ALLOCATION_STATE" ]] || return 1 printf -v "$path_variable" '%s' "" - for attempt in {1..64}; do + for (( attempt=1; attempt<=64; attempt++ )); do token=$(xanmod_random_token) || return 1 owner_token=$(xanmod_random_token) || return 1 candidate="$parent/$prefix.$token$suffix" @@ -3123,13 +3124,11 @@ xanmod_allocate_temp_file() { cleanup_xanmod_active_apt_lists() { if [[ -z "$XANMOD_ACTIVE_APT_LISTS_DIR" ]]; then - XANMOD_ACTIVE_APT_LISTS_BUILDING=false return 0 fi if [[ ! -e "$XANMOD_ACTIVE_APT_LISTS_DIR" && ! -L "$XANMOD_ACTIVE_APT_LISTS_DIR" ]] || remove_xanmod_temp_directory "$XANMOD_ACTIVE_APT_LISTS_DIR" "临时 APT lists"; then XANMOD_ACTIVE_APT_LISTS_DIR="" - XANMOD_ACTIVE_APT_LISTS_BUILDING=false return 0 fi return 1 @@ -3141,8 +3140,7 @@ xanmod_source_is_usable() { local temp_parent="${TMPDIR:-/tmp}" xanmod_allocate_temp_directory XANMOD_ACTIVE_APT_LISTS_DIR \ - XANMOD_ACTIVE_APT_LISTS_BUILDING "$temp_parent" xanmod-apt-lists 0755 || return 1 - XANMOD_ACTIVE_APT_LISTS_BUILDING=false + "" "$temp_parent" xanmod-apt-lists 0755 || return 1 if ! install -d -m 0755 "$XANMOD_ACTIVE_APT_LISTS_DIR/partial"; then cleanup_xanmod_active_apt_lists || true return 1 @@ -3958,14 +3956,12 @@ commit_xanmod_backup_group() { cleanup_xanmod_backup_stage() { if [[ -z "$XANMOD_BACKUP_STAGE_DIR" ]]; then - XANMOD_BACKUP_STAGE_BUILDING=false return 0 fi if ! remove_xanmod_temp_directory "$XANMOD_BACKUP_STAGE_DIR" "XanMod backup stage"; then return 1 fi XANMOD_BACKUP_STAGE_DIR="" - XANMOD_BACKUP_STAGE_BUILDING=false } restore_xanmod_backup_group_snapshot() { @@ -4062,11 +4058,10 @@ prepare_persistent_xanmod_backups() { create_xanmod_backup_group_snapshot || return 1 XANMOD_BACKUP_TRANSACTION_ID=$(basename "$XANMOD_BACKUP_GROUP_SNAPSHOT_DIR") if ! xanmod_allocate_temp_directory XANMOD_BACKUP_STAGE_DIR \ - XANMOD_BACKUP_STAGE_BUILDING "$XANMOD_BACKUP_STATE_DIR" .xanmod-backup-stage 0700; then + "" "$XANMOD_BACKUP_STATE_DIR" .xanmod-backup-stage 0700; then restore_xanmod_backup_group_snapshot || true return 1 fi - XANMOD_BACKUP_STAGE_BUILDING=false if xanmod_configuration_looks_previously_managed; then XANMOD_CONFIGURATION_PREVIOUSLY_MANAGED=true @@ -4296,7 +4291,7 @@ restore_xanmod_saved_trap() { trap - "$signal_name" if [[ -n "$trap_definition" ]]; then - # shellcheck disable=SC2294 + # shellcheck disable=SC2294 # Restore shell-quoted code captured by trap -p; eval is intentional. eval "$trap_definition" fi } diff --git a/modules/system-optimize.sh b/modules/system-optimize.sh index ee4b15a..1ad5b76 100644 --- a/modules/system-optimize.sh +++ b/modules/system-optimize.sh @@ -333,7 +333,7 @@ get_ubuntu_kernel_meta_package() { kernel_version=$(uname -r) if [[ -r /etc/os-release ]]; then - # shellcheck disable=SC1091 + # shellcheck disable=SC1091 # /etc/os-release is provided by the target OS, not this repository. . /etc/os-release version_id="${VERSION_ID:-}" fi @@ -400,7 +400,7 @@ ensure_zram_kernel_module() { kernel_version=$(uname -r) if [[ -r /etc/os-release ]]; then - # shellcheck disable=SC1091 + # shellcheck disable=SC1091 # /etc/os-release is provided by the target OS, not this repository. . /etc/os-release os_id="${ID:-}" fi diff --git a/tests/test-lint-coverage.sh b/tests/test-lint-coverage.sh new file mode 100644 index 0000000..bb14d00 --- /dev/null +++ b/tests/test-lint-coverage.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash +set -euo pipefail +# Execute only the workflow lint block against inert files and a ShellCheck spy. +ROOT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) +unset GH_TOKEN GITHUB_TOKEN SSH_PRIVATE_KEY_B64 +export GIT_CONFIG_NOSYSTEM=1 GIT_CONFIG_GLOBAL=/dev/null +unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE GIT_CONFIG_COUNT +root=$(mktemp -d) +cleanup() { rm -rf -- "$root"; } +trap cleanup EXIT +# Fail closed if the named step or its literal block changes shape. +awk ' + /^ - name: Run ShellCheck$/ { found++; step=1; next } + step && /^ run: \|$/ { block=1; next } + block && /^ / { print substr($0, 11); lines++; next } + block { step=0; block=0 } + END { if (found != 1 || lines == 0) exit 1 } +' "$ROOT_DIR/.github/workflows/shell-tests.yml" > "$root/lint.sh" +mkdir -p "$root/bin" "$root/repo" +cat > "$root/bin/shellcheck" <<'STUB' +#!/usr/bin/env bash +set -euo pipefail +[[ $1 == -x && $3 == -- && $# -gt 3 ]] || exit 90 +level=$2 +shift 3 +for path; do printf "%s\t%s\n" "$level" "$path" >> "$CAPTURE"; done +case $level in + --severity=warning) exit "$PRODUCTION_STATUS" ;; + --severity=error) exit "$TEST_STATUS" ;; + *) exit 91 ;; +esac +STUB +chmod +x "$root/bin/shellcheck" +export PATH="$root/bin:$PATH" CAPTURE="$root/capture" +cd "$root/repo" +git init -q +mkdir -p new/deep tests/nested +touch entry.sh new/deep/production.sh "new/space name.sh" tests/direct.sh tests/nested/deep.sh ignored.zsh +git add . +touch untracked.sh +printf "%s\n" \ + $'--severity=warning\tentry.sh' \ + $'--severity=warning\tnew/deep/production.sh' \ + $'--severity=warning\tnew/space name.sh' \ + $'--severity=error\ttests/direct.sh' \ + $'--severity=error\ttests/nested/deep.sh' > "$root/expected" +for PRODUCTION_STATUS in 0 1; do + for TEST_STATUS in 0 1; do + export PRODUCTION_STATUS TEST_STATUS + : > "$CAPTURE" + status=0 + bash --noprofile --norc -e -o pipefail "$root/lint.sh" || status=$? + expected=0 + if (( PRODUCTION_STATUS != 0 || TEST_STATUS != 0 )); then expected=1; fi + [[ $status == "$expected" ]] + diff -u "$root/expected" "$CAPTURE" + printf "PASS: workflow lint production=%s tests=%s exit=%s\n" "$PRODUCTION_STATUS" "$TEST_STATUS" "$status" + done +done diff --git a/tests/test-push-worker-registration.sh b/tests/test-push-worker-registration.sh index c19aaec..3ef0fcf 100755 --- a/tests/test-push-worker-registration.sh +++ b/tests/test-push-worker-registration.sh @@ -126,12 +126,9 @@ setup_fixture() { CURRENT_FIXTURE_ROOT=$root mkdir -m 0700 "$root" "$root/runtime" "$root/capture" TMPDIR="$root/runtime"; initialize_runtime - # shellcheck disable=SC2034 MAX_PARALLEL=2 - # shellcheck disable=SC2034 MAX_RETRIES=1 BATCH_WORKER_FAILED=false - # shellcheck disable=SC2034 BATCH_WORKER_ERROR=false } assert_no_registration_residue() { @@ -219,7 +216,6 @@ CHILD leader_start=$(wait_test_process_start "$leader"); read_process_record "$leader" WORKER_TRANSFER_PID=$leader; WORKER_TRANSFER_START=$leader_start; WORKER_TRANSFER_PGID=$PROC_PGID; WORKER_TRANSFER_SID=$PROC_SID publish_worker_session_state active; state_file=$WORKER_SESSION_STATE_FILE - # shellcheck disable=SC2034 # Consumed by sourced push cleanup state machine. MANAGED_SESSION_CLEANUP_TICKS=300 rc=0; terminate_worker_transfer || rc=$? (( rc != 0 )) || fail "deadline failure unexpectedly succeeded" @@ -295,7 +291,6 @@ run_with_watchdog root-cause 20 root_cause_regression_case run_ready_failure_case() ( kind="$1"; root="$TEST_DIR/ready-$kind"; setup_fixture "$root" - # shellcheck disable=SC2034 WORKER_REGISTRATION_TIMEOUT_TICKS=10 push_to_server() { : > "$root/capture/transfer"; return 0; } case "$kind" in @@ -385,9 +380,7 @@ prune_identity_failure_case repeated root="$TEST_DIR/prune-cleanup-failure"; setup_fixture "$root" sleep 300 & worker=$!; read_process_record "$worker"; start=$PROC_START ACTIVE_WORKERS[$worker]=$start - # shellcheck disable=SC2034 ACTIVE_WORKER_STATE_FILES[$worker]="$TEMP_DIR/worker-session.$worker.state" - # shellcheck disable=SC2034 ACTIVE_WORKER_STATE_STARTS[$worker]=$start eval "$(declare -f process_identity_matches | sed '1s/process_identity_matches/original_process_identity_matches/')" eval "$(declare -f read_process_record_for_session_scan | sed '1s/read_process_record_for_session_scan/original_read_process_record_for_session_scan/')" @@ -410,9 +403,7 @@ prune_identity_failure_case repeated root="$TEST_DIR/prune-exited"; setup_fixture "$root" sleep 0.1 & worker=$!; read_process_record "$worker"; start=$PROC_START ACTIVE_WORKERS[$worker]=$start - # shellcheck disable=SC2034 ACTIVE_WORKER_STATE_FILES[$worker]="$TEMP_DIR/worker-session.$worker.state" - # shellcheck disable=SC2034 ACTIVE_WORKER_STATE_STARTS[$worker]=$start sleep 0.2; prune_active_workers assert_eq 0 "${#ACTIVE_WORKERS[@]}" "exited worker is normally reaped" @@ -578,7 +569,6 @@ pass "failed managed-session reap remains bounded for 20 deterministic runs" TEMP_DIR=$(dirname "$state_file") ACTIVE_WORKERS=(); ACTIVE_WORKER_STATE_FILES=(); ACTIVE_WORKER_STATE_STARTS=() BATCH_WORKER_FAILED=false - # shellcheck disable=SC2034 # Consumed by sourced worker accounting. BATCH_WORKER_ERROR=false MAX_PARALLEL=1 ACTIVE_WORKERS[$worker]=$worker_start @@ -614,7 +604,6 @@ pass "failed managed-session reap remains bounded for 20 deterministic runs" ( trap - EXIT HUP INT TERM leader=424242; leader_start=777777; wait_called=false; after_wait=false - # shellcheck disable=SC2034 # Test double fills caller arrays through namerefs. collect_owned_session_records() { local -n pids_ref="$2" starts_ref="$3" ppids_ref="$4" pgids_ref="$5" states_ref="$6" pids_ref=(); starts_ref=(); ppids_ref=(); pgids_ref=(); states_ref=() @@ -717,13 +706,11 @@ run_preserved_cleanup_retry_case() ( local run="$1" root runtime runtime_dev runtime_inode credential leader leader_start leader_pgid leader_sid state_file local owner watchdog rc=0 metadata="" state_status=0 local -a session_pids=() - # shellcheck disable=SC2034 # Filled through collect_owned_session_records namerefs. local -A session_starts=() session_ppids=() session_pgids=() session_states=() root="$TEST_DIR/runtime-evidence-retry-$run"; setup_fixture "$root" runtime=$TEMP_DIR; runtime_dev=$TEMP_DIR_DEV; runtime_inode=$TEMP_DIR_INODE credential="$runtime/private-key" printf 'fixture-credential-do-not-print\n' > "$credential"; chmod 0600 "$credential" - # shellcheck disable=SC2034 # Consumed by sourced runtime cleanup. RUNTIME_KEY_FILE=$credential setsid bash -c 'trap "" HUP INT TERM; kill -STOP "$BASHPID"; while :; do :; done' & leader=$! @@ -949,7 +936,6 @@ run_runtime_retention_signal_case() ( local signal_name="$1" expected="$2" root leader="" leader_start="" leader_pgid="" leader_sid="" target="" target_pid="" target_start="" local runtime runtime_dev runtime_inode state_file credential watchdog="" rc=0 line key value state_status=0 reap_status=0 local -a session_pids=() - # shellcheck disable=SC2034 # Filled through collect_owned_session_records namerefs. local -A session_starts=() session_ppids=() session_pgids=() session_states=() cleanup_runtime_retention_signal_fixture() { if [[ -n "$target" ]]; then kill -KILL "$target" 2>/dev/null || true; wait "$target" 2>/dev/null || true; fi @@ -1172,7 +1158,6 @@ done run_parallel_fallback_iteration() ( run="$1"; root="$TEST_DIR/session-parallel-$run"; setup_fixture "$root" - # shellcheck disable=SC2034 # consumed by sourced run_server_batch MAX_PARALLEL=2 push_to_server() { local server="$1" lock_fd @@ -1180,13 +1165,9 @@ run_parallel_fallback_iteration() ( printf '%s\n' "$server" >> "$root/capture/calls"; : > "$root/capture/ready.$server" flock -u "$lock_fd"; exec {lock_fd}>&- while [[ ! -e "$root/capture/release" ]]; do sleep 0.01; done - # shellcheck disable=SC2034 # consumed by sourced state publisher WORKER_TRANSFER_PID=$BASHPID - # shellcheck disable=SC2034 # consumed by sourced state publisher WORKER_TRANSFER_START=11 - # shellcheck disable=SC2034 # consumed by sourced state publisher WORKER_TRANSFER_PGID=$BASHPID - # shellcheck disable=SC2034 # consumed by sourced state publisher WORKER_TRANSFER_SID=$BASHPID publish_worker_session_state cleanup_failed return "$MANAGED_CLEANUP_FAILURE_STATUS" @@ -1373,7 +1354,6 @@ run_live_cleanup_failure_signal_case() ( } trap cleanup_live_failure_fixture EXIT local -a session_pids=() - # shellcheck disable=SC2034 # Filled by collect_owned_session_records namerefs. local -A session_starts=() session_ppids=() session_pgids=() session_states=() root="$TEST_DIR/live-cleanup-failure-$signal_name"; CURRENT_FIXTURE_ROOT=$root write_active_grace_fixture "$root" @@ -1459,7 +1439,6 @@ run_state_publication_signal_case() ( local state="$1" phase="$2" signal_name="$3" expected="$4" mode root main_pid="" main_start="" worker_pid="" worker_start="" leader_pid="" leader_start="" managed_sid="" local watchdog="" watchdog_start="" unrelated="" unrelated_start="" rc=0 line key value marker state_file hook_stage local -a session_pids=() - # shellcheck disable=SC2034 # Filled by collect_owned_session_records namerefs. local -A session_starts=() session_ppids=() session_pgids=() session_states=() cleanup_publication_fixture() { [[ -z "$worker_pid" || -z "$worker_start" ]] || { test_process_identity_exists "$worker_pid" "$worker_start" && kill -KILL "$worker_pid" 2>/dev/null || true; } diff --git a/tests/test-push.sh b/tests/test-push.sh index fbc675b..768b922 100644 --- a/tests/test-push.sh +++ b/tests/test-push.sh @@ -1,5 +1,4 @@ #!/usr/bin/env bash -# shellcheck disable=SC2034 # Test globals are consumed by sourced tools/push.sh functions. set -euo pipefail ROOT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) diff --git a/tools/xanmod-install.sh b/tools/xanmod-install.sh index a7fa655..98179ec 100755 --- a/tools/xanmod-install.sh +++ b/tools/xanmod-install.sh @@ -66,7 +66,6 @@ XANMOD_STAGED_SOURCE="" XANMOD_CANDIDATE_SOURCE="" XANMOD_ARMORED_KEY_TEMP="" XANMOD_ACTIVE_APT_LISTS_DIR="" -XANMOD_ACTIVE_APT_LISTS_BUILDING=false XANMOD_ALLOCATION_CANDIDATE="" XANMOD_ALLOCATION_KIND="" XANMOD_ALLOCATION_OWNER_TOKEN="" @@ -185,7 +184,7 @@ ensure_package() { } get_os_codename() { if [[ -r "$XANMOD_OS_RELEASE" ]]; then - # shellcheck disable=SC1090 + # shellcheck disable=SC1090 # Runtime OS-release path; test mode substitutes an isolated fixture. . "$XANMOD_OS_RELEASE" if [[ -n "${VERSION_CODENAME:-}" ]]; then echo "$VERSION_CODENAME" @@ -899,8 +898,11 @@ xanmod_allocate_temp_directory() { [[ -d "$parent" && ! -L "$parent" ]] || return 1 [[ -z "$XANMOD_ALLOCATION_CANDIDATE" && -z "$XANMOD_ALLOCATION_STATE" ]] || return 1 printf -v "$path_variable" '%s' "" - printf -v "$building_variable" '%s' false - for attempt in {1..64}; do + # Callers without a building-state consumer omit this optional output. + if [[ -n "$building_variable" ]]; then + printf -v "$building_variable" "%s" false + fi + for (( attempt=1; attempt<=64; attempt++ )); do token=$(xanmod_random_token) || return 1 owner_token=$(xanmod_random_token) || return 1 candidate="$parent/$prefix.$token" @@ -968,7 +970,7 @@ xanmod_allocate_temp_file() { [[ -d "$parent" && ! -L "$parent" ]] || return 1 [[ -z "$XANMOD_ALLOCATION_CANDIDATE" && -z "$XANMOD_ALLOCATION_STATE" ]] || return 1 printf -v "$path_variable" '%s' "" - for attempt in {1..64}; do + for (( attempt=1; attempt<=64; attempt++ )); do token=$(xanmod_random_token) || return 1 owner_token=$(xanmod_random_token) || return 1 candidate="$parent/$prefix.$token$suffix" @@ -1022,13 +1024,11 @@ xanmod_allocate_temp_file() { cleanup_xanmod_active_apt_lists() { if [[ -z "$XANMOD_ACTIVE_APT_LISTS_DIR" ]]; then - XANMOD_ACTIVE_APT_LISTS_BUILDING=false return 0 fi if [[ ! -e "$XANMOD_ACTIVE_APT_LISTS_DIR" && ! -L "$XANMOD_ACTIVE_APT_LISTS_DIR" ]] || remove_xanmod_temp_directory "$XANMOD_ACTIVE_APT_LISTS_DIR" "临时 APT lists"; then XANMOD_ACTIVE_APT_LISTS_DIR="" - XANMOD_ACTIVE_APT_LISTS_BUILDING=false return 0 fi return 1 @@ -1040,8 +1040,7 @@ xanmod_source_is_usable() { local temp_parent="${TMPDIR:-/tmp}" xanmod_allocate_temp_directory XANMOD_ACTIVE_APT_LISTS_DIR \ - XANMOD_ACTIVE_APT_LISTS_BUILDING "$temp_parent" xanmod-apt-lists 0755 || return 1 - XANMOD_ACTIVE_APT_LISTS_BUILDING=false + "" "$temp_parent" xanmod-apt-lists 0755 || return 1 if ! install -d -m 0755 "$XANMOD_ACTIVE_APT_LISTS_DIR/partial"; then cleanup_xanmod_active_apt_lists || true return 1 @@ -1227,7 +1226,7 @@ restore_xanmod_saved_trap() { trap - "$signal_name" if [[ -n "$trap_definition" ]]; then - # shellcheck disable=SC2294 + # shellcheck disable=SC2294 # Restore shell-quoted code captured by trap -p; eval is intentional. eval "$trap_definition" fi }