优化镜像构建实时日志展示
This commit is contained in:
+99
-9
@@ -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=$!
|
||||
_ctms_spinner "$cmd_pid" "$label" "$start_ts" &
|
||||
local spin_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" &
|
||||
fi
|
||||
local display_pid=$!
|
||||
wait "$cmd_pid"
|
||||
exit_code=$?
|
||||
kill "$spin_pid" 2>/dev/null || true
|
||||
wait "$spin_pid" 2>/dev/null || true
|
||||
printf '\r\033[K'
|
||||
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
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user