Localize user-facing UI, agent output, and backend messages to Simplified Chinese
ci / go (push) Waiting to run
ci / go-db (agent) (push) Waiting to run
ci / go-db (config) (push) Waiting to run
ci / go-db (db) (push) Waiting to run
ci / go-db (evidence) (push) Waiting to run
ci / go-db (llmrec) (push) Waiting to run
ci / go-db (server) (push) Waiting to run
detections / detections (push) Waiting to run
docs / links (push) Waiting to run
web / web (push) Waiting to run

This commit is contained in:
dela
2026-10-09 14:08:31 +08:00
parent 8af63417c8
commit 97668dab7e
148 changed files with 1671 additions and 1672 deletions
+22 -22
View File
@@ -80,14 +80,14 @@ func applyStaged(p Paths) (Action, State) {
log.Printf("[update] 暂存的新版本未通过校验,已丢弃,继续运行当前版本:%v", err)
cleanStaged(p)
_ = os.Remove(p.Marker)
return Continue, State{FailedStage: true, Detail: "새 버전 검증에 실패해 폐기했습니다: " + err.Error()}
return Continue, State{FailedStage: true, Detail: "新版本校验失败,已丢弃: " + err.Error()}
}
if err := swap(p); err != nil {
log.Printf("[update] 换装失败,继续运行当前版本:%v", err)
cleanStaged(p)
_ = os.Remove(p.Marker)
return Continue, State{FailedStage: true, Detail: "버전 교체에 실패했습니다: " + err.Error()}
return Continue, State{FailedStage: true, Detail: "版本替换失败: " + err.Error()}
}
// 换装成功。保留标记,交给下一次启动(跑的就是新版)确认是否稳定。
@@ -115,12 +115,12 @@ func confirmOrRollback(p Paths, m marker) (Action, State) {
// 让进程按当前状态起——起不来的话用户至少能在日志里看到原因。
log.Printf("[update] 新版本连续 %d 次启动失败,且回滚失败:%v", maxAttempts, err)
_ = os.Remove(p.Marker)
return Continue, State{Detail: "새 버전 시작에 실패하고 롤백도 실패했습니다: " + err.Error()}
return Continue, State{Detail: "新版本启动失败,回滚也失败: " + err.Error()}
}
log.Printf("[update] 新版本连续 %d 次启动失败,已回滚到 %s,退出以重启(exit %d)",
maxAttempts, orUnknown(m.From), ExitRestart)
_ = os.Remove(p.Marker)
return Restart, State{RolledBack: true, Detail: fmt.Sprintf("새 버전 시작에 실패해 이전 버전으로 롤백했습니다(%s)", orUnknown(m.From))}
return Restart, State{RolledBack: true, Detail: fmt.Sprintf("新版本启动失败,已回滚到上一版本(%s)", orUnknown(m.From))}
}
if err := writeMarker(p.Marker, m); err != nil {
log.Printf("[update] 更新升级标记失败:%v", err)
@@ -160,14 +160,14 @@ const SettleDelay = 30 * time.Second
func verifyStaged(p Paths) error {
want, err := os.ReadFile(p.Sum)
if err != nil {
return fmt.Errorf("체크섬 읽기 실패: %w", err)
return fmt.Errorf("校验和读取失败: %w", err)
}
got, err := fileSHA256(p.New)
if err != nil {
return fmt.Errorf("체크섬 계산 실패: %w", err)
return fmt.Errorf("校验和计算失败: %w", err)
}
if !strings.EqualFold(strings.TrimSpace(string(want)), got) {
return errors.New("SHA256 이 일치하지 않습니다(다운로드가 손상됐거나 변조됨)")
return errors.New("SHA256 不匹配(下载已损坏或被篡改)")
}
return smokeTest(p.New)
}
@@ -176,7 +176,7 @@ func verifyStaged(p Paths) error {
// 这能挡掉下载截断、架构选错(exec format error)、缺依赖等一大类问题。
func smokeTest(bin string) error {
if err := os.Chmod(bin, 0o755); err != nil {
return fmt.Errorf("실행 권한 부여 실패: %w", err)
return fmt.Errorf("授予执行权限失败: %w", err)
}
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
@@ -185,14 +185,14 @@ func smokeTest(bin string) error {
cmd.Env = append(os.Environ(), smokeEnv+"=1")
out, err := cmd.CombinedOutput()
if ctx.Err() != nil {
return errors.New("스모크 테스트 시간 초과(새 바이너리가 응답하지 않음)")
return errors.New("冒烟测试超时(新二进制文件无响应)")
}
if err != nil {
snippet := strings.TrimSpace(string(out))
if len(snippet) > 300 {
snippet = snippet[:300] + "…"
}
return fmt.Errorf("스모크 테스트 실패: %v: %s", err, snippet)
return fmt.Errorf("冒烟测试失败: %v: %s", err, snippet)
}
return nil
}
@@ -204,17 +204,17 @@ func smokeTest(bin string) error {
func swap(p Paths) error {
// Windows 的 rename 不会覆盖已存在的目标,上一轮升级留下的 .old 必须先清掉。
if err := os.Remove(p.Old); err != nil && !errors.Is(err, os.ErrNotExist) {
return fmt.Errorf("이전 백업 %s 정리 실패: %w", p.Old, err)
return fmt.Errorf("清理旧备份 %s 失败: %w", p.Old, err)
}
if err := os.Rename(p.Current, p.Old); err != nil {
return fmt.Errorf("현재 버전 백업 실패: %w", err)
return fmt.Errorf("当前版本备份失败: %w", err)
}
if err := os.Rename(p.New, p.Current); err != nil {
// 换装失败但当前版本已经被挪走了,必须原样放回去,否则下次启动没有可执行文件。
if rerr := os.Rename(p.Old, p.Current); rerr != nil {
return fmt.Errorf("새 버전 설치 실패(%v), 현재 버전 복구도 실패: %w", err, rerr)
return fmt.Errorf("新版本安装失败(%v),当前版本恢复也失败: %w", err, rerr)
}
return fmt.Errorf("새 버전 설치 실패: %w", err)
return fmt.Errorf("新版本安装失败: %w", err)
}
_ = os.Remove(p.Sum)
return nil
@@ -223,16 +223,16 @@ func swap(p Paths) error {
// rollback 把 swap 备份的旧版本换回来。
func rollback(p Paths) error {
if _, err := os.Stat(p.Old); err != nil {
return fmt.Errorf("롤백할 백업이 없습니다(%s): %w", p.Old, err)
return fmt.Errorf("没有可回滚的备份(%s): %w", p.Old, err)
}
// 把起不来的新版挪到 .failed 留作排查,而不是直接删掉。
failed := p.Current + ".failed"
_ = os.Remove(failed)
if err := os.Rename(p.Current, failed); err != nil {
return fmt.Errorf("실패한 버전 이동 실패: %w", err)
return fmt.Errorf("移动失败版本失败: %w", err)
}
if err := os.Rename(p.Old, p.Current); err != nil {
return fmt.Errorf("이전 버전 복구 실패: %w", err)
return fmt.Errorf("上一版本恢复失败: %w", err)
}
return nil
}
@@ -245,21 +245,21 @@ func Rollback() error {
return err
}
if _, err := os.Stat(p.Old); err != nil {
return errors.New("롤백할 이전 버전이 없습니다(" + p.Old + " 없음)")
return errors.New("没有可回滚的上一版本(不存在 " + p.Old + ")")
}
cleanStaged(p)
if err := smokeTest(p.Old); err != nil {
return fmt.Errorf("이전 버전을 실행할 수 없어 롤백을 거부합니다: %w", err)
return fmt.Errorf("无法运行上一版本,拒绝回滚: %w", err)
}
// 交换当前与备份:回滚之后还能再滚回来。
tmp := p.Current + ".swap"
_ = os.Remove(tmp)
if err := os.Rename(p.Current, tmp); err != nil {
return fmt.Errorf("현재 버전 이동 실패: %w", err)
return fmt.Errorf("当前版本移动失败: %w", err)
}
if err := os.Rename(p.Old, p.Current); err != nil {
_ = os.Rename(tmp, p.Current)
return fmt.Errorf("이전 버전 설치 실패: %w", err)
return fmt.Errorf("上一版本安装失败: %w", err)
}
if err := os.Rename(tmp, p.Old); err != nil {
log.Printf("[update] 回滚后整理备份失败(不影响运行):%v", err)
@@ -293,7 +293,7 @@ func fileSHA256(path string) (string, error) {
func orUnknown(s string) string {
if strings.TrimSpace(s) == "" {
return "알 수 없는 버전"
return "未知版本"
}
return s
}