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
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:
+22
-22
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user