mirror of
https://github.com/Yuyi-Oak/BlueArchiveToolkit.git
synced 2026-07-22 05:25:14 +08:00
Emit runtime download progress and validation summaries for official sync. Add repeatable real-network full pull smoke runbook and script. Fixes #4 Fixes #6
185 lines
5.8 KiB
Bash
Executable File
185 lines
5.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -Eeuo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
|
cd "${REPO_ROOT}"
|
|
|
|
timestamp="$(date -u +%Y%m%dT%H%M%SZ)"
|
|
SMOKE_ROOT="${BAT_SMOKE_ROOT:-/tmp/bat-official-smoke-${timestamp}}"
|
|
OUTPUT_DIR="${BAT_SMOKE_OUTPUT:-${SMOKE_ROOT}/resources}"
|
|
STATE_DIR="${BAT_SMOKE_STATE_DIR:-${SMOKE_ROOT}/state}"
|
|
REPORT_DIR="${BAT_SMOKE_REPORT_DIR:-${SMOKE_ROOT}/report}"
|
|
BAT_BIN="${BAT_BIN:-${REPO_ROOT}/target/release/bat}"
|
|
|
|
fail() {
|
|
printf 'error: %s\n' "$*" >&2
|
|
exit 1
|
|
}
|
|
|
|
real_output="$(realpath -m "${OUTPUT_DIR}")"
|
|
case "${real_output}" in
|
|
/tmp/*) ;;
|
|
*)
|
|
if [[ "${BAT_SMOKE_ALLOW_NON_TMP:-}" != "1" ]]; then
|
|
fail "BAT_SMOKE_OUTPUT must be under /tmp by default; set BAT_SMOKE_ALLOW_NON_TMP=1 only for an isolated test path"
|
|
fi
|
|
;;
|
|
esac
|
|
|
|
if [[ -e "${OUTPUT_DIR}" ]] && [[ -n "$(find "${OUTPUT_DIR}" -mindepth 1 -maxdepth 1 -print -quit 2>/dev/null)" ]]; then
|
|
fail "output directory is not empty: ${OUTPUT_DIR}"
|
|
fi
|
|
|
|
mkdir -p "${OUTPUT_DIR}" "${STATE_DIR}" "${REPORT_DIR}"
|
|
|
|
if [[ "${BAT_SMOKE_SKIP_BUILD:-}" != "1" ]]; then
|
|
cargo build --release -p bat-infrastructure --bin bat
|
|
fi
|
|
|
|
[[ -x "${BAT_BIN}" ]] || fail "bat binary is not executable: ${BAT_BIN}"
|
|
|
|
write_command_file() {
|
|
local name="$1"
|
|
shift
|
|
local command_file="${REPORT_DIR}/${name}.command.txt"
|
|
: >"${command_file}"
|
|
printf '$' >>"${command_file}"
|
|
printf ' %q' "$@" >>"${command_file}"
|
|
printf '\n' >>"${command_file}"
|
|
}
|
|
|
|
run_step() {
|
|
local name="$1"
|
|
shift
|
|
printf '==> %s\n' "${name}"
|
|
write_command_file "${name}" "$@"
|
|
"$@" >"${REPORT_DIR}/${name}.stdout.json" 2>"${REPORT_DIR}/${name}.stderr.log"
|
|
}
|
|
|
|
require_contains() {
|
|
local path="$1"
|
|
local needle="$2"
|
|
local description="$3"
|
|
if ! grep -Fq "${needle}" "${path}"; then
|
|
fail "${description}; expected '${needle}' in ${path}"
|
|
fi
|
|
}
|
|
|
|
run_step "01-dry-run-plan" \
|
|
"${BAT_BIN}" \
|
|
--auto-discover \
|
|
--output "${OUTPUT_DIR}" \
|
|
--state-dir "${STATE_DIR}" \
|
|
--dry-run \
|
|
--plan \
|
|
--json \
|
|
--no-progress
|
|
|
|
run_step "02-first-full-pull" \
|
|
"${BAT_BIN}" \
|
|
--auto-discover \
|
|
--output "${OUTPUT_DIR}" \
|
|
--state-dir "${STATE_DIR}" \
|
|
--json \
|
|
--progress \
|
|
--no-banner
|
|
|
|
require_contains "${REPORT_DIR}/02-first-full-pull.stderr.log" "下载进度:总体" "first pull did not emit total download progress"
|
|
require_contains "${REPORT_DIR}/02-first-full-pull.stderr.log" "单文件" "first pull did not emit single-file download progress"
|
|
require_contains "${REPORT_DIR}/02-first-full-pull.stderr.log" "校验结果:" "first pull did not emit verification summary"
|
|
|
|
run_step "03-second-up-to-date" \
|
|
"${BAT_BIN}" \
|
|
--auto-discover \
|
|
--output "${OUTPUT_DIR}" \
|
|
--state-dir "${STATE_DIR}" \
|
|
--json \
|
|
--no-progress
|
|
|
|
require_contains "${REPORT_DIR}/03-second-up-to-date.stdout.json" '"update_status": "up_to_date"' "second run did not report up_to_date"
|
|
|
|
current_link="${OUTPUT_DIR}/current"
|
|
[[ -e "${current_link}" ]] || fail "current release symlink/path was not created: ${current_link}"
|
|
current_dir="$(realpath "${current_link}")"
|
|
|
|
damage_file="$(find "${current_dir}" -type f \
|
|
! -name 'official-sync-snapshot.json' \
|
|
! -name 'official-download-manifest.json' \
|
|
-print -quit)"
|
|
[[ -n "${damage_file}" ]] || fail "no resource file found to damage under ${current_dir}"
|
|
|
|
printf '%s\n' "${damage_file}" >"${REPORT_DIR}/damaged-file.txt"
|
|
{
|
|
printf 'path: %s\n' "${damage_file}"
|
|
printf 'bytes: %s\n' "$(wc -c <"${damage_file}" | tr -d ' ')"
|
|
printf 'sha256: %s\n' "$(sha256sum "${damage_file}" | awk '{print $1}')"
|
|
} >"${REPORT_DIR}/damaged-file.before.txt"
|
|
printf 'BAT official smoke intentional corruption\n' >"${damage_file}"
|
|
|
|
run_step "04-repair-after-damage" \
|
|
"${BAT_BIN}" \
|
|
repair \
|
|
--auto-discover \
|
|
--output "${OUTPUT_DIR}" \
|
|
--state-dir "${STATE_DIR}" \
|
|
--json \
|
|
--progress \
|
|
--no-banner
|
|
|
|
require_contains "${REPORT_DIR}/04-repair-after-damage.stdout.json" '"command": "repair"' "repair command report missing"
|
|
require_contains "${REPORT_DIR}/04-repair-after-damage.stdout.json" '"status": "completed"' "repair command did not complete"
|
|
require_contains "${REPORT_DIR}/04-repair-after-damage.stderr.log" "下载进度:总体" "repair did not emit total download progress"
|
|
require_contains "${REPORT_DIR}/04-repair-after-damage.stderr.log" "单文件" "repair did not emit single-file download progress"
|
|
require_contains "${REPORT_DIR}/04-repair-after-damage.stderr.log" "校验结果:" "repair did not emit verification summary"
|
|
|
|
run_step "05-verify-after-repair" \
|
|
"${BAT_BIN}" \
|
|
verify \
|
|
--auto-discover \
|
|
--output "${OUTPUT_DIR}" \
|
|
--state-dir "${STATE_DIR}" \
|
|
--json \
|
|
--no-progress
|
|
|
|
require_contains "${REPORT_DIR}/05-verify-after-repair.stdout.json" '"healthy": true' "verify after repair did not report healthy=true"
|
|
|
|
file_count="$(find "${current_dir}" -type f | wc -l | tr -d ' ')"
|
|
current_size="$(du -sh "${current_dir}" | awk '{print $1}')"
|
|
report_file="${REPORT_DIR}/SMOKE_REPORT.md"
|
|
|
|
cat >"${report_file}" <<EOF
|
|
# Official Full Pull Smoke Report
|
|
|
|
- generated_at_utc: ${timestamp}
|
|
- repo: ${REPO_ROOT}
|
|
- bat: ${BAT_BIN}
|
|
- output: ${OUTPUT_DIR}
|
|
- state_dir: ${STATE_DIR}
|
|
- current_release: ${current_dir}
|
|
- current_release_size: ${current_size}
|
|
- current_release_file_count: ${file_count}
|
|
- damaged_file: ${damage_file}
|
|
|
|
## Steps
|
|
|
|
1. dry-run with full URL plan: 01-dry-run-plan
|
|
2. first full pull: 02-first-full-pull
|
|
3. second up-to-date check: 03-second-up-to-date
|
|
4. intentional local file damage and repair: 04-repair-after-damage
|
|
5. verify after repair: 05-verify-after-repair
|
|
|
|
Each step has:
|
|
|
|
- <step>.command.txt
|
|
- <step>.stdout.json
|
|
- <step>.stderr.log
|
|
|
|
The large resource output is intentionally outside Git and remains under:
|
|
|
|
\`${OUTPUT_DIR}\`
|
|
EOF
|
|
|
|
printf '\nSmoke report: %s\n' "${report_file}"
|
|
printf 'Resource output: %s\n' "${OUTPUT_DIR}"
|