From bcf2db0413a596cad1c0e4d6892210a7b16a64e8 Mon Sep 17 00:00:00 2001 From: Xuz Date: Thu, 1 Oct 2026 20:12:03 +0800 Subject: [PATCH] =?UTF-8?q?Windows=20CI=20=E5=8F=AA=E5=9C=A8=E6=8E=A8?= =?UTF-8?q?=E9=80=81=E6=94=B9=E5=88=B0=E5=B9=B3=E5=8F=B0=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E3=80=81=E6=9E=84=E5=BB=BA=E8=84=9A=E6=9C=AC?= =?UTF-8?q?=E6=88=96=E4=BE=9D=E8=B5=96=E6=97=B6=E8=BF=90=E8=A1=8C=EF=BC=8C?= =?UTF-8?q?tag=20=E4=B8=8D=E5=86=8D=E8=A7=A6=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/windows.yml | 22 ++++++++++++++++++++++ CLAUDE.md | 2 +- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 8f647f6..cc8f6f0 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -1,10 +1,32 @@ # The Windows build, which the Macs this is developed on cannot compile: # the whole crate through clippy, the external CLI's tests, including the # named pipe between two processes, and the updater's. +# +# A push runs it only when it touches code that differs on Windows (the +# files with `cfg(windows)` and friends), the build script or the +# dependencies. Windows code added to another file goes in this list too; +# until then, run it by hand (Actions › windows › Run workflow). Tags never +# run it: the release workflow builds Windows itself. name: windows on: push: + branches: ["**"] + paths: + - "src/cli/**" + - "src/update/**" + - "src/app/paths.rs" + - "src/main.rs" + - "src/bin/**" + - "src/ssh/connection.rs" + - "src/sftp/download.rs" + - "src/credential/credential_dialog.rs" + - "src/settings/settings_panel.rs" + - "tests/cli_bin.rs" + - "build.rs" + - "Cargo.toml" + - "Cargo.lock" + - "rust-toolchain.toml" workflow_dispatch: jobs: diff --git a/CLAUDE.md b/CLAUDE.md index 64122af..a6e63ec 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -132,7 +132,7 @@ cargo test -- --ignored # 会读写真实钥匙串的测试 - 用同步的 Win32 管道,不用 tokio 的:请求线程要阻塞的 `File`,而 tokio 的管道是 overlapped 句柄,拿去做同步 IO 时 std 会中止进程。 - 监听线程先建好下一个实例再把已连接的交给请求线程,否则那一刻来的客户端会看到「没运行」。请求线程结束时直接关句柄,**不要** `DisconnectNamedPipe`(会丢掉客户端还没读的数据)也不要 `FlushFileBuffers`(客户端挂住时会一直阻塞)。停止时置标志、反复以客户端身份连一下唤醒 `ConnectNamedPipe`,直到线程结束。 - **Windows 的 PATH 是副本加用户 PATH。** `IntegrationPaths::system()` 在 Windows 上:`exe` 是 `shellrs.exe` 旁边的 `shellrs-cli.exe`,`bin_link` 是 `%LOCALAPPDATA%\ShellRS\bin\shellrs.exe`(副本,不是链接),`user_path` 是 `UserPath::Registry`(`HKCU\Environment\Path`,写回 `REG_EXPAND_SZ` 后广播 `WM_SETTINGCHANGE`;只有之后启动的程序看得到)。副本按长度加修改时间判断是否本版(安装时用 `set_modified` 把时间设成源文件的)。正在运行的副本不能覆盖但能改名,所以安装、移除都先把旧的改名成 `shellrs.exe..old` 再尽量删掉。生产环境启动时 `CliIntegration::update_outdated` 在后台更新旧副本,否则 Agent 会一直碰到 `version_mismatch`。测试一律 `user_path: None` 或 `UserPath::File`,绝不碰注册表。开发时 `cargo run` 只构建 `shellrs`,要 `cargo build` 才有 `shellrs-cli.exe`,否则设置页显示找不到。 - - **Windows 只在 CI 上编译和测试**(`.github/workflows/windows.yml`:clippy 全 crate、`cargo test --lib cli::`、`cargo test --test cli_bin`),本机没有 Windows 工具链;改 `pipe_windows.rs`、`install_windows.rs` 的 Windows 部分和 `cfg(windows)` 代码后要看 CI。 + - **Windows 只在 CI 上编译和测试**(`.github/workflows/windows.yml`:clippy 全 crate、`cargo test --lib cli::`、`cargo test --lib update::`、`cargo test --test cli_bin`),本机没有 Windows 工具链;改 `pipe_windows.rs`、`install_windows.rs` 的 Windows 部分和 `cfg(windows)` 代码后要看 CI。它不是每次推送都跑:只在推送改到 `paths` 里列的文件(含 `cfg(windows)` 等平台代码的文件、`build.rs`、`Cargo.toml` / `Cargo.lock`)时才跑,tag 不触发;在别的文件里新加 Windows 代码时把文件加进这个列表,或者在 Actions 里手动运行。 - **每个请求一个线程**,后端方法都是阻塞的;SSH 句柄绑在创建它的 runtime 上,所以 `ssh::run_command` 和 SFTP 工作线程各自建 current-thread runtime。 - **exec 不许挂住**:`SshPrompts` 非交互;陌生主机在 events 回调里直接返回 `false`(`ask` 没人回答会永远等下去,因为超时不计提示时间),缺凭据由 `MissingCredential` 失败。`exec(true)` 后立刻 `eof()`,远程没有 stdin;读循环读到 `Close` / `None` 为止,退出码可能在 EOF 之后才到。输出回调写失败(Agent 断开)就放弃命令、断开连接。 - **传输无人值守**:`SshCliBackend::transfer` 先等 `Connected` 再发请求;连接前的 `Prompt` 一律回 `Cancel` 并按提示种类给出错误码;`Question` 按固定策略回答(冲突覆盖并勾选全部、续传一律重新开始、出错跳过并记为失败);以 `Idle` 为结束。请求用 `UploadRequest::scp` / `DownloadRequest::scp`:worker 连上后按 scp 规则解析目标(`scp_remote_target` / `scp_local_target`,目标目录必须存在,远程还要 `stat` 确认,因为有的服务器 realpath 不存在的路径也成功),并让新建文件保留源文件的权限位(上传整套 `0o777`,下载只补可执行位);SFTP 标签的请求不受影响。批次准备失败时 worker 也发 `Idle`。