feat: 手动更新按钮#235
Conversation
There was a problem hiding this comment.
Hey - 我发现了 1 个问题,并留下了一些高层次的反馈:
- 构建和保存待处理更新信息的逻辑,目前分别存在于
UpdateSection中的网络下载路径和useLocalUpdatePackageImport中的本地包流程,两处出现了重复;建议抽取一个共享的辅助方法,以减少逻辑偏差并保持这两个流程的一致性。 - 支持的更新包格式分别在 TypeScript(
SUPPORTED_UPDATE_PACKAGE_EXTENSIONS)和 Rust(read_update_package_interface)中单独定义,因此建议添加说明或集中管理这部分配置,以避免两边配置不同步。
给 AI Agent 的提示
Please address the comments from this code review:
## Overall Comments
- The logic for building and saving pending update info is now duplicated between the network download path in `UpdateSection` and the local package flow in `useLocalUpdatePackageImport`; consider extracting a shared helper to reduce drift and keep the two flows consistent.
- Supported update package formats are defined separately in TypeScript (`SUPPORTED_UPDATE_PACKAGE_EXTENSIONS`) and Rust (`read_update_package_interface`), so adding a note or centralizing this configuration would help prevent the two from getting out of sync.
## Individual Comments
### Comment 1
<location path="src/services/updateService.ts" line_range="948-957" />
<code_context>
+ projectInterface: ProjectInterface | null;
+}
+
+async function readLocalPackageInterface(filePath: string): Promise<ProjectInterface> {
+ try {
+ const content = await invoke<string>('read_update_package_interface', { packagePath: filePath });
+ const pi = parseJsonc<ProjectInterface>(content, 'interface.json');
+ if (pi.interface_version !== 2 || !pi.version || !pi.name || !pi.mirrorchyan_rid) {
+ throw new Error('invalid interface.json');
+ }
+ return pi;
+ } catch (error) {
+ log.warn('读取本地更新包 interface.json 失败:', error);
+ throw new LocalUpdatePackageError('missingPackageInterface');
+ }
</code_context>
<issue_to_address>
**suggestion (bug_risk):** 不同的 interface.json 读取失败模式都被折叠为 `missingPackageInterface`,可能会误导用户和调用方。
当前在 `readLocalPackageInterface` 中,所有失败(文件缺失、解析错误、结构无效)都会暴露为 `LocalUpdatePackageError('missingPackageInterface')`,其消息会明确声称 `interface.json` 缺失。这会把“缺失”和“无效”的接口混为一谈,导致对用户的提示不准确,也使调用方无法区分并分别处理这些情况。
请引入一个单独的错误(例如 `invalidPackageInterface`)用于解析/校验失败,或者向上抛出足够的上下文信息,使调用方和 UI 能够区分“缺失”和“格式错误/不兼容”的接口,并做出相应的处理/日志记录。
建议实现:
```typescript
async function readLocalPackageInterface(filePath: string): Promise<ProjectInterface> {
try {
const content = await invoke<string>('read_update_package_interface', { packagePath: filePath });
const pi = parseJsonc<ProjectInterface>(content, 'interface.json');
if (pi.interface_version !== 2 || !pi.version || !pi.name || !pi.mirrorchyan_rid) {
log.warn('本地更新包 interface.json 无效或不兼容:', pi);
throw new LocalUpdatePackageError('invalidPackageInterface');
}
return pi;
} catch (error) {
// 解析/校验失败需要向上传递,以便调用方区分「缺失」与「无效」
if (error instanceof LocalUpdatePackageError && (error as any).code === 'invalidPackageInterface') {
throw error;
}
log.warn('读取本地更新包 interface.json 失败:', error);
throw new LocalUpdatePackageError('missingPackageInterface');
}
}
```
为了完整支持新的 `invalidPackageInterface` 失败模式,你还需要:
1. 扩展 `LocalUpdatePackageError`(在其定义处),使其接受/识别 `'invalidPackageInterface'` 作为合法的 code,并通过上面使用的 `code`(或同等属性)暴露出来。
2. 更新当前处理 `missingPackageInterface` 的 UI 文案或“错误到消息”的映射逻辑,使其也能处理 `invalidPackageInterface`,并给出合适的提示(例如:“interface.json 格式无效或不兼容”)。
3. 如果 `LocalUpdatePackageError` 不使用 `code` 字段,而是其他名称(例如 `reason`、`type`),请在 `readLocalPackageInterface` 中相应地调整 `(error as any).code` 的访问。
</issue_to_address>帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进后续评审。
Original comment in English
Hey - I've found 1 issue, and left some high level feedback:
- The logic for building and saving pending update info is now duplicated between the network download path in
UpdateSectionand the local package flow inuseLocalUpdatePackageImport; consider extracting a shared helper to reduce drift and keep the two flows consistent. - Supported update package formats are defined separately in TypeScript (
SUPPORTED_UPDATE_PACKAGE_EXTENSIONS) and Rust (read_update_package_interface), so adding a note or centralizing this configuration would help prevent the two from getting out of sync.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The logic for building and saving pending update info is now duplicated between the network download path in `UpdateSection` and the local package flow in `useLocalUpdatePackageImport`; consider extracting a shared helper to reduce drift and keep the two flows consistent.
- Supported update package formats are defined separately in TypeScript (`SUPPORTED_UPDATE_PACKAGE_EXTENSIONS`) and Rust (`read_update_package_interface`), so adding a note or centralizing this configuration would help prevent the two from getting out of sync.
## Individual Comments
### Comment 1
<location path="src/services/updateService.ts" line_range="948-957" />
<code_context>
+ projectInterface: ProjectInterface | null;
+}
+
+async function readLocalPackageInterface(filePath: string): Promise<ProjectInterface> {
+ try {
+ const content = await invoke<string>('read_update_package_interface', { packagePath: filePath });
+ const pi = parseJsonc<ProjectInterface>(content, 'interface.json');
+ if (pi.interface_version !== 2 || !pi.version || !pi.name || !pi.mirrorchyan_rid) {
+ throw new Error('invalid interface.json');
+ }
+ return pi;
+ } catch (error) {
+ log.warn('读取本地更新包 interface.json 失败:', error);
+ throw new LocalUpdatePackageError('missingPackageInterface');
+ }
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Different failure modes for reading interface.json are collapsed into `missingPackageInterface`, which can mislead users and callers.
Currently all failures in `readLocalPackageInterface` (missing file, parse error, invalid structure) are surfaced as `LocalUpdatePackageError('missingPackageInterface')`, whose message specifically claims `interface.json` is absent. This conflates missing and invalid interfaces, produces inaccurate user messaging, and prevents callers from handling these cases differently.
Please either introduce a distinct error (e.g. `invalidPackageInterface`) for parse/validation failures, or propagate enough context so callers and the UI can distinguish missing from malformed/incompatible interfaces and handle/log them appropriately.
Suggested implementation:
```typescript
async function readLocalPackageInterface(filePath: string): Promise<ProjectInterface> {
try {
const content = await invoke<string>('read_update_package_interface', { packagePath: filePath });
const pi = parseJsonc<ProjectInterface>(content, 'interface.json');
if (pi.interface_version !== 2 || !pi.version || !pi.name || !pi.mirrorchyan_rid) {
log.warn('本地更新包 interface.json 无效或不兼容:', pi);
throw new LocalUpdatePackageError('invalidPackageInterface');
}
return pi;
} catch (error) {
// 解析/校验失败需要向上传递,以便调用方区分「缺失」与「无效」
if (error instanceof LocalUpdatePackageError && (error as any).code === 'invalidPackageInterface') {
throw error;
}
log.warn('读取本地更新包 interface.json 失败:', error);
throw new LocalUpdatePackageError('missingPackageInterface');
}
}
```
To fully support the new `invalidPackageInterface` failure mode, you will also need to:
1. Extend `LocalUpdatePackageError` (wherever it is defined) so it accepts/recognises `'invalidPackageInterface'` as a valid code and exposes it via a `code` (or equivalent) property used above.
2. Update any UI strings or error-to-message mappings that currently handle `missingPackageInterface` so they also handle `invalidPackageInterface` with appropriate messaging (e.g. “interface.json 格式无效或不兼容”).
3. If `LocalUpdatePackageError` does not use a `code` field but another name (e.g. `reason`, `type`), adjust the `(error as any).code` access accordingly in `readLocalPackageInterface`.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| async function readLocalPackageInterface(filePath: string): Promise<ProjectInterface> { | ||
| try { | ||
| const content = await invoke<string>('read_update_package_interface', { packagePath: filePath }); | ||
| const pi = parseJsonc<ProjectInterface>(content, 'interface.json'); | ||
| if (pi.interface_version !== 2 || !pi.version || !pi.name || !pi.mirrorchyan_rid) { | ||
| throw new Error('invalid interface.json'); | ||
| } | ||
| return pi; | ||
| } catch (error) { | ||
| log.warn('读取本地更新包 interface.json 失败:', error); |
There was a problem hiding this comment.
suggestion (bug_risk): 不同的 interface.json 读取失败模式都被折叠为 missingPackageInterface,可能会误导用户和调用方。
当前在 readLocalPackageInterface 中,所有失败(文件缺失、解析错误、结构无效)都会暴露为 LocalUpdatePackageError('missingPackageInterface'),其消息会明确声称 interface.json 缺失。这会把“缺失”和“无效”的接口混为一谈,导致对用户的提示不准确,也使调用方无法区分并分别处理这些情况。
请引入一个单独的错误(例如 invalidPackageInterface)用于解析/校验失败,或者向上抛出足够的上下文信息,使调用方和 UI 能够区分“缺失”和“格式错误/不兼容”的接口,并做出相应的处理/日志记录。
建议实现:
async function readLocalPackageInterface(filePath: string): Promise<ProjectInterface> {
try {
const content = await invoke<string>('read_update_package_interface', { packagePath: filePath });
const pi = parseJsonc<ProjectInterface>(content, 'interface.json');
if (pi.interface_version !== 2 || !pi.version || !pi.name || !pi.mirrorchyan_rid) {
log.warn('本地更新包 interface.json 无效或不兼容:', pi);
throw new LocalUpdatePackageError('invalidPackageInterface');
}
return pi;
} catch (error) {
// 解析/校验失败需要向上传递,以便调用方区分「缺失」与「无效」
if (error instanceof LocalUpdatePackageError && (error as any).code === 'invalidPackageInterface') {
throw error;
}
log.warn('读取本地更新包 interface.json 失败:', error);
throw new LocalUpdatePackageError('missingPackageInterface');
}
}为了完整支持新的 invalidPackageInterface 失败模式,你还需要:
- 扩展
LocalUpdatePackageError(在其定义处),使其接受/识别'invalidPackageInterface'作为合法的 code,并通过上面使用的code(或同等属性)暴露出来。 - 更新当前处理
missingPackageInterface的 UI 文案或“错误到消息”的映射逻辑,使其也能处理invalidPackageInterface,并给出合适的提示(例如:“interface.json 格式无效或不兼容”)。 - 如果
LocalUpdatePackageError不使用code字段,而是其他名称(例如reason、type),请在readLocalPackageInterface中相应地调整(error as any).code的访问。
Original comment in English
suggestion (bug_risk): Different failure modes for reading interface.json are collapsed into missingPackageInterface, which can mislead users and callers.
Currently all failures in readLocalPackageInterface (missing file, parse error, invalid structure) are surfaced as LocalUpdatePackageError('missingPackageInterface'), whose message specifically claims interface.json is absent. This conflates missing and invalid interfaces, produces inaccurate user messaging, and prevents callers from handling these cases differently.
Please either introduce a distinct error (e.g. invalidPackageInterface) for parse/validation failures, or propagate enough context so callers and the UI can distinguish missing from malformed/incompatible interfaces and handle/log them appropriately.
Suggested implementation:
async function readLocalPackageInterface(filePath: string): Promise<ProjectInterface> {
try {
const content = await invoke<string>('read_update_package_interface', { packagePath: filePath });
const pi = parseJsonc<ProjectInterface>(content, 'interface.json');
if (pi.interface_version !== 2 || !pi.version || !pi.name || !pi.mirrorchyan_rid) {
log.warn('本地更新包 interface.json 无效或不兼容:', pi);
throw new LocalUpdatePackageError('invalidPackageInterface');
}
return pi;
} catch (error) {
// 解析/校验失败需要向上传递,以便调用方区分「缺失」与「无效」
if (error instanceof LocalUpdatePackageError && (error as any).code === 'invalidPackageInterface') {
throw error;
}
log.warn('读取本地更新包 interface.json 失败:', error);
throw new LocalUpdatePackageError('missingPackageInterface');
}
}To fully support the new invalidPackageInterface failure mode, you will also need to:
- Extend
LocalUpdatePackageError(wherever it is defined) so it accepts/recognises'invalidPackageInterface'as a valid code and exposes it via acode(or equivalent) property used above. - Update any UI strings or error-to-message mappings that currently handle
missingPackageInterfaceso they also handleinvalidPackageInterfacewith appropriate messaging (e.g. “interface.json 格式无效或不兼容”). - If
LocalUpdatePackageErrordoes not use acodefield but another name (e.g.reason,type), adjust the(error as any).codeaccess accordingly inreadLocalPackageInterface.
…ter clarity and maintainability
|
草,issue怎么还能挂别家repo的 |
fix #233
Summary
本 PR 在现有更新 section 中新增“选择本地更新包”入口,用于手动导入本地更新压缩包并复用现有更新安装流程。
本地更新不会请求 Mirror API,也不会进行线上版本审核或 sha256 校验;只校验压缩包内的
interface.json是否为合法 ProjectInterface V2,并确认其属于当前项目。Changes
.zip、.tar.gz、.tgz更新包。read_update_package_interface命令,用于从压缩包中读取interface.json。interface.jsoninterface_version必须为2version、name、mirrorchyan_ridname必须等于当前项目namemirrorchyan_rid必须等于当前项目mirrorchyan_ridNotes
本 PR 不包含全局拖放导入入口。此前排查发现 MXU 在提权运行时,Windows 会阻止从非提权 Explorer 向提权进程拖入文件,因此即使前端或 Tauri 监听拖放事件,也可能只能看到禁止符号,无法稳定拿到真实文件路径。为保证功能可靠,本次仅保留按钮选择文件的入口。
Summary by Sourcery
添加对从手动选择的本地安装包安装更新的支持,并复用现有的更新安装流程。
New Features:
.zip和.tar.gz更新归档中读取interface.json,以进行本地更新验证。Enhancements:
Original summary in English
Summary by Sourcery
Add support for installing updates from a manually selected local package and reuse the existing update installation flow.
New Features:
Enhancements: