优化镜像构建实时日志展示
Storage Persistence Guard / storage-persistence-audit (pull_request) Has been cancelled
Storage Persistence Guard / storage-persistence-audit (push) Has been cancelled

This commit is contained in:
Cheng Zhou
2026-06-30 11:26:40 +08:00
parent 18daea7f2c
commit b283cf1e5c
2 changed files with 101 additions and 11 deletions
+97 -7
View File
@@ -328,9 +328,10 @@ ctms_require_dependencies() {
fi
}
# ── 长命令执行(折叠输出 + spinner ──────────
# ── 长命令执行(默认 spinner,可选实时日志窗口) ──
# 用法: ctms_run_quiet <提示语> -- <命令...>
# VERBOSE=1 时展开实时输出;否则折叠为 spinner,失败时回放完整日志
# CTMS_LIVE_OUTPUT=1 时显示最近几行;VERBOSE=1 时展开全部实时输出。
# 其他情况仅显示 spinner,失败时回放完整日志。
ctms_run_quiet() {
local label="$1"; shift
[[ "${1:-}" == "--" ]] && shift
@@ -351,13 +352,21 @@ ctms_run_quiet() {
if [[ -t 1 ]]; then
"$@" >"$log_file" 2>&1 &
local cmd_pid=$!
if [[ "${CTMS_LIVE_OUTPUT:-0}" -eq 1 ]]; then
_ctms_live_log "$cmd_pid" "$label" "$start_ts" "$log_file" &
else
_ctms_spinner "$cmd_pid" "$label" "$start_ts" &
local spin_pid=$!
fi
local display_pid=$!
wait "$cmd_pid"
exit_code=$?
kill "$spin_pid" 2>/dev/null || true
wait "$spin_pid" 2>/dev/null || true
kill "$display_pid" 2>/dev/null || true
wait "$display_pid" 2>/dev/null || true
if [[ "${CTMS_LIVE_OUTPUT:-0}" -eq 1 ]]; then
_ctms_clear_live_log
else
printf '\r\033[K'
fi
else
printf ' %s%s%s %s …\n' "${CC_MUTED}" "$ICON_INFO" "${C_RESET}" "$label"
"$@" >"$log_file" 2>&1
@@ -379,12 +388,17 @@ ctms_run_quiet() {
ctms_fail "命令执行失败,详细日志保留于:${log_file#"$CTMS_ROOT_DIR"/}(追加 --verbose 可看实时输出)"
}
# 固定占用 9 行:上边框 + 6 行日志 + 下边框 + 状态行。
# 日志行会截断,避免终端自动换行破坏 ANSI 光标定位。
_CTMS_LIVE_LOG_ROWS=6
_CTMS_LIVE_LOG_HEIGHT=9
_ctms_spinner() {
local cmd_pid="$1" label="$2" start_ts="$3"
local frames=('⠋' '⠙' '⠹' '⠸' '⠼' '⠴' '⠦' '⠧' '⠇' '⠏')
local i=0
local i=0 elapsed
while kill -0 "$cmd_pid" 2>/dev/null; do
local elapsed=$(( $(date +%s) - start_ts ))
elapsed=$(( $(date +%s) - start_ts ))
printf '\r\033[K %s%s%s %s %s(%ss)%s' \
"${CC_INFO}${C_BOLD}" "${frames[i]}" "${C_RESET}" \
"$label" "${CC_MUTED}" "$elapsed" "${C_RESET}"
@@ -393,6 +407,82 @@ _ctms_spinner() {
done
}
_ctms_live_log() {
local cmd_pid="$1" label="$2" start_ts="$3" log_file="$4"
local frames=('⠋' '⠙' '⠹' '⠸' '⠼' '⠴' '⠦' '⠧' '⠇' '⠏')
local i=0 first=1
local columns box_width content_width elapsed line row
local -a lines=()
columns="$(tput cols 2>/dev/null || printf 80)"
[[ "$columns" =~ ^[0-9]+$ ]] || columns=80
box_width=$(( columns - 4 ))
[[ "$box_width" -gt 160 ]] && box_width=160
[[ "$box_width" -lt 50 ]] && box_width=50
content_width=$(( box_width - 4 ))
while kill -0 "$cmd_pid" 2>/dev/null; do
lines=()
while IFS= read -r line; do
lines+=("$line")
done < <(_ctms_recent_log_lines "$log_file" "$_CTMS_LIVE_LOG_ROWS" "$content_width")
if [[ "$first" -eq 0 ]]; then
printf '\r\033[%dA' "$(( _CTMS_LIVE_LOG_HEIGHT - 1 ))"
fi
printf '\033[2K %s╭─ 实时输出 %s╮%s\n' \
"${CC_PRIMARY}${C_BOLD}" "$(ctms_repeat_char '─' "$(( box_width - 13 ))")" "${C_RESET}"
for ((row=0; row<_CTMS_LIVE_LOG_ROWS; row++)); do
line="${lines[$row]:-}"
printf '\033[2K %s│%s %-*s %s│%s\n' \
"${CC_PRIMARY}" "${C_RESET}${CC_MUTED}" "$content_width" "$line" "${CC_PRIMARY}" "${C_RESET}"
done
printf '\033[2K %s╰%s╯%s\n' \
"${CC_PRIMARY}" "$(ctms_repeat_char '─' "$(( box_width - 2 ))")" "${C_RESET}"
elapsed=$(( $(date +%s) - start_ts ))
printf '\033[2K %s%s%s %s %s(%ss)%s' \
"${CC_INFO}${C_BOLD}" "${frames[i]}" "${C_RESET}" \
"$label" "${CC_MUTED}" "$elapsed" "${C_RESET}"
first=0
i=$(( (i + 1) % ${#frames[@]} ))
sleep 0.2
done
}
_ctms_recent_log_lines() {
local log_file="$1" rows="$2" width="$3"
[[ -s "$log_file" ]] || return 0
if [[ "$_CTMS_HAS_PERL" -eq 1 ]]; then
# 只读取文件尾部,清除颜色/光标控制符,并把 Docker 的 CR 进度输出拆成独立行。
tail -n 80 "$log_file" | perl -CSDA -pe '
s/\e\[[0-9;?]*[ -\/]*[@-~]//g;
s/\e[()][0-9A-Za-z]//g;
s/\r/\n/g;
' | tail -n "$rows" | perl -CSDA -Mutf8 -pe \
'BEGIN { $width = shift @ARGV } chomp; $_ = substr($_, 0, $width) . "\n";' "$width"
else
local esc
esc="$(printf '\033')"
tail -n 80 "$log_file" \
| tr '\r' '\n' \
| sed -e "s/${esc}\\[[0-9;?]*[A-Za-z]//g" -e "s/${esc}[()][0-9A-Za-z]//g" \
| tail -n "$rows" \
| cut -c "1-${width}"
fi
}
_ctms_clear_live_log() {
printf '\r\033[%dA' "$(( _CTMS_LIVE_LOG_HEIGHT - 1 ))"
local row
for ((row=0; row<_CTMS_LIVE_LOG_HEIGHT-1; row++)); do
printf '\033[2K\n'
done
printf '\033[2K\033[%dA\r' "$(( _CTMS_LIVE_LOG_HEIGHT - 1 ))"
}
# ── .env 读写 ─────────────────────────────────
ctms_read_env_value() {
local key="$1"
+2 -2
View File
@@ -339,9 +339,9 @@ run_build_and_start() {
else
step "构建镜像并启动服务"
if [[ "$TARGET_ENV" == "dev" ]]; then
ctms_run_quiet "构建并刷新开发容器(首次较慢)" -- compose_cmd up -d --build --force-recreate backend nginx frontend-dev
CTMS_LIVE_OUTPUT=1 ctms_run_quiet "构建并刷新开发容器(首次较慢)" -- compose_cmd up -d --build --force-recreate backend nginx frontend-dev
else
ctms_run_quiet "构建镜像并启动容器(首次较慢)" -- compose_cmd up -d --build
CTMS_LIVE_OUTPUT=1 ctms_run_quiet "构建镜像并启动容器(首次较慢)" -- compose_cmd up -d --build
fi
fi
}