diff --git a/docs/issues/2026-04-11-issue-backlog-tracking.md b/docs/issues/2026-04-11-issue-backlog-tracking.md index 6c87b66..2c5d544 100644 --- a/docs/issues/2026-04-11-issue-backlog-tracking.md +++ b/docs/issues/2026-04-11-issue-backlog-tracking.md @@ -31,6 +31,7 @@ | #330 | 建议在查询结果表格中增加自适应内容列宽的功能 | Fixed | `632e57e` | | #331 | 重复连接 DB,一分钟重试了 60 多次 | Fixed | `ca76440` | | #333 | AI 功能添加供应商测试正常,但问答显示失败 | Fixed | Pending | +| #337 | 自动更新无效 | Fixed | Pending | | #351 | 为什么没有截断和清空表的功能呀? | Fixed | Pending | ## Notes @@ -95,6 +96,12 @@ - 处理:为 `AnthropicProvider.Chat / ChatStream` 补充 400 降级回退。首次带 `tools` 请求若返回 400/422/404,则自动去掉 `tools` 重试一次,允许不支持 function calling 的兼容端点继续完成普通问答。 - 验证:补充 `internal/ai/provider/anthropic_test.go` 回归测试,覆盖非流式与流式两条链路下“首请求因 tools 返回 400,回退后成功”的场景,并执行 `go test ./internal/ai/provider -count=1`。 +### #337 + +- 根因:Linux 自动更新链路有两个断点。其一,更新资产名只按 `linux/amd64` 固定选择 `GoNavi--Linux-Amd64.tar.gz`,没有根据当前运行的是 `WebKit41` 变体去选 `-WebKit41` 包;其二,Linux 安装脚本解压后优先查找固定文件名 `GoNavi`,而 release tar.gz 实际打包的是构建产物名,导致替换阶段经常找不到新二进制。 +- 处理:为更新资产解析新增“基于当前可执行文件路径推断 Linux 变体”的后缀选择逻辑;同时调整 Linux 更新脚本,解压后优先搜索与当前运行二进制同名的文件,再回退查找 `GoNavi`。 +- 验证:补充 `internal/app/methods_update_test.go` 回归测试,覆盖 Linux `WebKit41` 资产名选择与更新脚本目标名解析,并执行 `go test ./internal/app -run 'Test(ExpectedAssetNameForExecutableUsesLinuxWebKit41Suffix|BuildLinuxScriptPrefersTargetExecutableBasename|TestFetchLatestUpdateInfo|TestCheckForUpdates|TestBuildWindowsScript)' -count=1`。 + ### #330 - 根因:查询结果表格已经支持拖拽调整列宽,但 resize handle 没有提供双击自适应逻辑,导致用户只能靠手工拖拽慢慢试宽度。 diff --git a/internal/app/methods_update.go b/internal/app/methods_update.go index 9ec71e3..4dfd27c 100644 --- a/internal/app/methods_update.go +++ b/internal/app/methods_update.go @@ -493,6 +493,19 @@ func fetchLatestRelease() (*githubRelease, error) { } func expectedAssetName(goos, goarch, version string) (string, error) { + executablePath := "" + if goos == "linux" { + if path, err := os.Executable(); err == nil { + if resolved, resolveErr := filepath.EvalSymlinks(path); resolveErr == nil && strings.TrimSpace(resolved) != "" { + path = resolved + } + executablePath = path + } + } + return expectedAssetNameForExecutable(goos, goarch, version, executablePath) +} + +func expectedAssetNameForExecutable(goos, goarch, version, executablePath string) (string, error) { version = strings.TrimSpace(version) version = strings.TrimPrefix(version, "v") version = strings.TrimPrefix(version, "V") @@ -517,12 +530,26 @@ func expectedAssetName(goos, goarch, version string) (string, error) { } case "linux": if goarch == "amd64" { - return fmt.Sprintf("GoNavi-%s-Linux-Amd64.tar.gz", version), nil + return fmt.Sprintf("GoNavi-%s-Linux-Amd64%s.tar.gz", version, resolveLinuxReleaseArtifactSuffix(executablePath)), nil } } return "", fmt.Errorf("当前平台暂不支持在线更新:%s/%s", goos, goarch) } +func resolveLinuxReleaseArtifactSuffix(executablePath string) string { + normalizedPath := strings.ToLower(strings.TrimSpace(executablePath)) + if normalizedPath == "" { + return "" + } + normalizedPath = strings.ReplaceAll(normalizedPath, "\\", "/") + compactPath := strings.ReplaceAll(normalizedPath, "_", "") + compactPath = strings.ReplaceAll(compactPath, "-", "") + if strings.Contains(normalizedPath, "webkit41") || strings.Contains(compactPath, "webkit241") || strings.Contains(compactPath, "webkit41") { + return "-WebKit41" + } + return "" +} + func findReleaseAsset(assets []githubAsset, name string) (*githubAsset, error) { for _, asset := range assets { if asset.Name == name { @@ -1195,8 +1222,12 @@ while kill -0 $PID 2>/dev/null; do done TMPDIR=$(mktemp -d) tar -xzf "$ARCHIVE" -C "$TMPDIR" -NEWBIN="$TMPDIR/GoNavi" +TARGET_NAME="$(basename "$TARGET")" +NEWBIN="$TMPDIR/$TARGET_NAME" if [ ! -f "$NEWBIN" ]; then + NEWBIN=$(find "$TMPDIR" -type f -name "$TARGET_NAME" | head -n 1) +fi +if [ -z "$NEWBIN" ] || [ ! -f "$NEWBIN" ]; then NEWBIN=$(find "$TMPDIR" -type f -name "GoNavi" | head -n 1) fi if [ -z "$NEWBIN" ] || [ ! -f "$NEWBIN" ]; then diff --git a/internal/app/methods_update_test.go b/internal/app/methods_update_test.go index ed1beaf..da7704b 100644 --- a/internal/app/methods_update_test.go +++ b/internal/app/methods_update_test.go @@ -3,6 +3,7 @@ package app import ( "errors" stdRuntime "runtime" + "strings" "testing" ) @@ -158,3 +159,41 @@ func TestCheckForUpdatesSilentlySkipsFailureLogs(t *testing.T) { t.Fatalf("expected silent check to skip error logging, got %d", logged) } } + +func TestExpectedAssetNameForExecutableUsesLinuxWebKit41Suffix(t *testing.T) { + assetName, err := expectedAssetNameForExecutable( + "linux", + "amd64", + "v0.6.5", + "/opt/GoNavi/gonavi-build-linux-amd64-webkit41", + ) + if err != nil { + t.Fatalf("expectedAssetNameForExecutable returned error: %v", err) + } + + want := "GoNavi-0.6.5-Linux-Amd64-WebKit41.tar.gz" + if assetName != want { + t.Fatalf("unexpected linux webkit41 asset name: got %q want %q", assetName, want) + } +} + +func TestBuildLinuxScriptPrefersTargetExecutableBasename(t *testing.T) { + script := buildLinuxScript( + "/tmp/GoNavi-0.6.5-Linux-Amd64-WebKit41.tar.gz", + "/opt/GoNavi/gonavi-build-linux-amd64-webkit41", + "/tmp/.gonavi-update-linux-0.6.5", + 12345, + ) + + mustContain := []string{ + `TARGET_NAME="$(basename "$TARGET")"`, + `NEWBIN="$TMPDIR/$TARGET_NAME"`, + `NEWBIN=$(find "$TMPDIR" -type f -name "$TARGET_NAME" | head -n 1)`, + `NEWBIN=$(find "$TMPDIR" -type f -name "GoNavi" | head -n 1)`, + } + for _, want := range mustContain { + if !strings.Contains(script, want) { + t.Fatalf("linux update script missing required token: %s\nscript:\n%s", want, script) + } + } +}