expect-pty 0.3.3 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +36 -14
- data/Gemfile +1 -0
- data/README.md +191 -83
- data/benchmark/matching.rb +26 -0
- data/benchmark/scaling.rb +70 -0
- data/benchmark/support.rb +23 -3
- data/docs/COMPATIBILITY.md +68 -57
- data/docs/INTERNAL_CONTRACTS.md +89 -39
- data/docs/PERFORMANCE.md +65 -19
- data/docs/VERIFICATION.md +206 -90
- data/lib/expect/configuration.rb +3 -1
- data/lib/expect/interaction.rb +15 -0
- data/lib/expect/logging.rb +111 -7
- data/lib/expect/matcher.rb +61 -8
- data/lib/expect/pattern.rb +5 -2
- data/lib/expect/pattern_list.rb +3 -0
- data/lib/expect/redactor.rb +81 -0
- data/lib/expect/relay.rb +12 -0
- data/lib/expect/relay_writer.rb +9 -0
- data/lib/expect/result.rb +2 -0
- data/lib/expect/session_resources.rb +4 -0
- data/lib/expect/terminal.rb +2 -1
- data/lib/expect/version.rb +1 -1
- data/lib/expect.rb +50 -24
- data/script/ci +30 -3
- data/test/buffer_accounting_test.rb +83 -0
- data/test/deadline_test.rb +237 -0
- data/test/diagnostics_test.rb +353 -0
- data/test/lifecycle_contract_test.rb +71 -0
- data/test/literal_scan_test.rb +97 -0
- metadata +8 -1
data/docs/VERIFICATION.md
CHANGED
|
@@ -1,64 +1,122 @@
|
|
|
1
1
|
# 验证记录
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## 0.4.0 发布前复核(2026-09-27)
|
|
4
|
+
|
|
5
|
+
发布前新增七项回归:总期限在文本回调后到达时,已知 EOF 先于剩余活跃来源的超时派发;覆盖日志路径前交付旧尾部,冲刷失败不能提前截断新文件;嵌套诊断等待保留外层匹配结果;日志回调轮换目标时正确交接所有权;诊断回调新建或再次写入另一方向时,尾部仍交给旧目标。各项均先复现失败,再验证修复,纯相对超时行为保持不变。
|
|
6
|
+
|
|
7
|
+
从 `b5e9159` 建立独立检出,只带入本轮 30 个功能、测试、文档和版本文件,排除主工作区的其他格式化改动。macOS arm64、Ruby 4.0.6、Bundler 4.0.17 下执行 `ruby script/release.rb --dry-run`,319 项测试、1,820 条断言全部通过,RuboCop 检查 58 个文件无违规;四组基准 smoke、Gem 构建、两种隔离安装和新增接口检查均通过。
|
|
8
|
+
|
|
9
|
+
此处记录本地发布预演,远端矩阵、标签和发布产物以 0.4.0 对应提交的 GitHub Actions 与 Release 为准;下节保留改进阶段的双平台验证结果。
|
|
10
|
+
|
|
11
|
+
## 底层引擎补齐与模块注释(2026-09-27)
|
|
4
12
|
|
|
5
|
-
|
|
13
|
+
基线为已发布的 `b5e9159`(0.3.3),本节记录 0.4.0 发布准备前的底层改进验证。范围限于底层 Expect:裁剪计数、生命周期及错误契约、等待总期限、诊断目标、按字节流脱敏、增量字面扫描及多来源基准。未引入厂商实现、SSH 编排或新的 Reactor。
|
|
6
14
|
|
|
7
|
-
|
|
15
|
+
新增 43 项回归,覆盖外部回收、借用 IO、关闭重试、缓冲裁剪与正常消费、绝对期限限制各类重置、已知 EOF、EINTR、分片与重叠秘密、二进制诊断、流尾部交付,以及字面缓存与全量扫描的操作序列对照。
|
|
8
16
|
|
|
9
|
-
|
|
|
17
|
+
| 当前环境 | 完整 `bash script/ci` |
|
|
10
18
|
| --- | --- |
|
|
11
|
-
| macOS arm64,Ruby 4.0.6,Bundler 4.0.17
|
|
12
|
-
|
|
|
13
|
-
| Linux aarch64,Ruby 3.2.11,Bundler 4.0.17,独立容器副本 | 同上;冻结开发锁文件,容器独立安装依赖 |
|
|
19
|
+
| macOS arm64,Ruby 4.0.6,Bundler 4.0.17 | 312 项 / 1,784 条断言,0 失败、错误、跳过;RuboCop 58 文件无违规 |
|
|
20
|
+
| Linux aarch64,Ruby 3.2.11,Bundler 4.0.17,当前源码独立容器副本 | 同上;容器使用冻结锁文件及独立 Linux 依赖 |
|
|
14
21
|
|
|
15
|
-
|
|
22
|
+
两套检查均通过对话示例、四组基准 smoke、Gem 构建、普通 RubyGems 和最小 Bundler 应用的隔离安装。安装后检查新增总期限、裁剪计数、内部过滤器和结构化诊断实际工作,并确认 Logger 等开发依赖没有泄漏到运行时。macOS 构建存在宿主 RDoc 7/8 重复常量警告,命令退出状态为 0。
|
|
16
23
|
|
|
17
|
-
|
|
24
|
+
审阅 `lib/expect` 全部 14 个模块,补齐其中 12 个模块的中文职责、方法及复杂流程注释;加载入口和版本文件保留现有充分说明。以注释编辑开始时的源码快照对照,15 个库文件的 Ripper 语法树(忽略位置)完全相同,逐行差异也仅为注释或空白。工作区其他 Ruby 格式化修正同样核对语法树等价。
|
|
25
|
+
|
|
26
|
+
另通过 14 个文档 Ruby 片段语法解析、工作流 actionlint(未启用 shellcheck)和 `git diff --check`。两轮同机匹配性能对照、真实管道来源容量与阻塞目标检查见 [性能基准](PERFORMANCE.md#持续字面扫描验证2026-09-27);1,000 管道来源只证明该受控场景,不代表真实设备吞吐或长期运行。
|
|
27
|
+
|
|
28
|
+
本轮未运行远端 CI、Ruby 3.3/3.4 或真实 SSH/设备测试,未提交、推送或发布。以下历史记录不作为本轮验收结果。
|
|
29
|
+
|
|
30
|
+
## 模块审查、资源清理与正则输入复用(2026-09-27)
|
|
31
|
+
|
|
32
|
+
基线为 `b9fc077`,以下为 0.3.3
|
|
33
|
+
发布准备前的源码审查记录。覆盖会话、配置、模式声明与定位、匹配结果及期限、资源所有权、日志、终端、人工接管、转接恢复、示例、发布和打包模块。修复工厂/构造失败后的子进程回收、部分句柄清理、原始异常保留、EOF
|
|
34
|
+
继续期限和发布包提交来源验证;新行为均有先失败后通过的回归。EOF 补充多源同时结束和重置期限用例,保留已知 EOF 的派发顺序。
|
|
35
|
+
|
|
36
|
+
日志与终端方法拆入独立能力文件,公共入口保持 `expect/pty`;打包检查确认两文件随 Gem
|
|
37
|
+
分发。正则输入复用通过冻结输入、编码分片、二进制、字节偏移及匹配/转接回归,实测数据见 [性能基准](PERFORMANCE.md#正则输入复用验证2026-09-27)。
|
|
38
|
+
|
|
39
|
+
| 当前运行环境 | 完整 `bash script/ci` |
|
|
40
|
+
|----------------------------------------------------------|----------------------------------------------------------------|
|
|
41
|
+
| macOS arm64,Ruby 4.0.6,Bundler 4.0.17,原工作区 | 269 项 / 1,356 断言,0 失败、错误、跳过;RuboCop 51 文件无违规 |
|
|
42
|
+
| macOS arm64,同一运行时,隔离 worktree | 同上;从基线加本轮补丁及新增文件重建 |
|
|
43
|
+
| Linux aarch64,Ruby 3.2.11,Bundler 4.0.17,独立容器副本 | 同上;冻结开发锁文件,容器独立安装依赖 |
|
|
44
|
+
|
|
45
|
+
三次均完成对话示例、三组基准 smoke、Gem 构建、普通 RubyGems 与最小 Bundler 应用的隔离安装及真实 PTY 对话。另检查包内 69
|
|
46
|
+
个文件及新增模块,无构建目录或日志;工作流 actionlint 通过(未启用 shellcheck),发布与示例 `--help` 正常。macOS 构建仍有宿主
|
|
47
|
+
RDoc 7/8 重复常量警告,退出状态为 0。
|
|
48
|
+
|
|
49
|
+
发布测试使用临时 Git 仓库,验证合法包通过,忽略文件、`assume-unchanged` 隐藏内容、忽略执行权限变化及主页元数据不一致均被拒绝,未连接发布服务。审查时版本仍为
|
|
50
|
+
0.3.2,改动位于 `Unreleased`,这些本地检查不代替发布验证;当时未运行真实 SSH、远端 CI 或 Ruby 3.3/3.4,也未提交、推送或发布。0.3.3
|
|
51
|
+
的远端平台结果以发布提交对应的 GitHub Actions 为准,以下历史结果不作为本轮验证证据。
|
|
18
52
|
|
|
19
53
|
## 配置并发与模块审查改进(2026-09-26)
|
|
20
54
|
|
|
21
|
-
当前工作树在既有未提交的匹配、转接和清理改动上,增加 `configure` 的串行读改写与回归测试:旧实现的并发用例先失败,修复后通过;嵌套调用显式抛出
|
|
55
|
+
当前工作树在既有未提交的匹配、转接和清理改动上,增加 `configure` 的串行读改写与回归测试:旧实现的并发用例先失败,修复后通过;嵌套调用显式抛出
|
|
56
|
+
`ThreadError`,不会陷入死锁或发布部分配置。`read_available` 的裁剪选择改为显式参数,转接调用明确禁止裁剪其待处理缓冲。RuboCop
|
|
57
|
+
对生产代码启用分支复杂度检查,既有状态机只在对应方法局部豁免;补充内部调用契约、贡献指南、issue/PR 模板与安全说明。
|
|
22
58
|
|
|
23
|
-
macOS arm64、Ruby 4.0.6、Bundler 4.0.17 下执行 `bash script/ci`:249 项测试、1,242 条断言,0 失败、错误或跳过;RuboCop 检查 49
|
|
59
|
+
macOS arm64、Ruby 4.0.6、Bundler 4.0.17 下执行 `bash script/ci`:249 项测试、1,242 条断言,0 失败、错误或跳过;RuboCop 检查 49
|
|
60
|
+
个文件无违规。对话示例、三组基准 smoke、Gem 构建、普通 RubyGems 与 Bundler 隔离安装及真实 PTY 对话均通过。构建时本机 RDoc 7/8
|
|
61
|
+
重复常量警告仍存在,但命令成功完成。
|
|
24
62
|
|
|
25
63
|
本轮未运行 Linux/Ruby 3.2、远端 CI 或真实 SSH;未提交、推送或发布。下文历史结果不作为本轮检查证据。
|
|
26
64
|
|
|
27
65
|
## 0.3.0 发布前复核(2026-09-26)
|
|
28
66
|
|
|
29
|
-
以 0.2.0 为基线导入源码更新,发布前增加 8 项回归,覆盖退出正则切换、同规则跨次匹配、待发送恢复、跨次
|
|
67
|
+
以 0.2.0 为基线导入源码更新,发布前增加 8 项回归,覆盖退出正则切换、同规则跨次匹配、待发送恢复、跨次
|
|
68
|
+
CRLF、转义回调内匹配与异常尾部恢复、嵌套写入超时进度。新用例先在修复前失败,再验证修复;仅内部转义处理器的两项测试随职责调整更新调用方式。
|
|
30
69
|
|
|
31
|
-
macOS arm64、Ruby 4.0.6、Bundler 4.0.17 下执行 `BUNDLER_VERSION=4.0.17 bash script/ci`:225 项测试、903 条断言,0
|
|
70
|
+
macOS arm64、Ruby 4.0.6、Bundler 4.0.17 下执行 `BUNDLER_VERSION=4.0.17 bash script/ci`:225 项测试、903 条断言,0
|
|
71
|
+
失败、错误或跳过;RuboCop 检查 42 个文件无违规,对话示例、Gem 构建、隔离安装及 PTY 对话全部通过。连续 1,000 次使用同一输入调用
|
|
72
|
+
`interact`,仅保留一个输入包装器,关闭会话不关闭借用 IO。
|
|
32
73
|
|
|
33
|
-
真实 IO 的已有 Ruby 写缓冲可能让 `write_nonblock` 先阻塞刷新,已在 README 明确首次写入前设置 `sync`
|
|
74
|
+
真实 IO 的已有 Ruby 写缓冲可能让 `write_nonblock` 先阻塞刷新,已在 README 明确首次写入前设置 `sync`
|
|
75
|
+
或交接前排空缓冲的要求;未通过绕过缓冲改变字节顺序。真实 SSH 与完整上游差分不在本次验证范围。远端平台矩阵以发布提交对应的
|
|
76
|
+
GitHub Actions 结果为准,以下记录属于各自历史时点。
|
|
34
77
|
|
|
35
78
|
## 转接期限、交付恢复与输入接续(2026-09-26)
|
|
36
79
|
|
|
37
|
-
继续引用审查中的 R1–R5,在原有未提交改动上修复;基线为 194 项测试 / 737 条断言全部通过。新增 `test/relay_recovery_test.rb`
|
|
80
|
+
继续引用审查中的 R1–R5,在原有未提交改动上修复;基线为 194 项测试 / 737 条断言全部通过。新增 `test/relay_recovery_test.rb`
|
|
81
|
+
的前 8 个用例先在未修复实现运行,得到 5 个失败、3 个错误,分别确认阻塞超时、部分发送重放、监听器失败重放、短写入丢后缀、原始输入
|
|
82
|
+
IO 接续、背压读取 EINTR、写超时进度和 EOF 截断编码问题。修复后这 8 项通过,再扩展到 23 项恢复与边界用例。
|
|
38
83
|
|
|
39
84
|
根因与修复:
|
|
40
85
|
|
|
41
|
-
- `interconnect` 的期限原先只约束读取循环,同步 `target.write` 可以无限阻塞;`Relay` 现统一 select
|
|
42
|
-
|
|
43
|
-
- `
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
86
|
+
- `interconnect` 的期限原先只约束读取循环,同步 `target.write` 可以无限阻塞;`Relay` 现统一 select
|
|
87
|
+
读写并保留总期限,超时后的前缀刷新也只尝试非阻塞写入。
|
|
88
|
+
- 原先只有单次 `write` 的局部偏移,转发失败后重新发送整个源缓冲;`RelayWriter` 现按目标保留游标,成功目标不重放,短写入继续后缀,flush
|
|
89
|
+
异常只重试 flush。转义回调等待前缀交付,剩余输入与待发送数据分别保留。
|
|
90
|
+
- `interact` 原先每次新建输入包装器;现由连接持有并按原始 IO 身份复用,关闭连接时不等键盘 EOF、不关闭借用
|
|
91
|
+
IO。关闭路径也先通过有界测试复现等待,再修复并复验。
|
|
92
|
+
- 背压读取的 `EINTR` 纳入原写期限重试;直接写超时异常提供 `bytes_written`。编码检查感知 EOF,固定 UTF-8 正则对截断字符抛出
|
|
93
|
+
`EncodingError`,匹配缓冲保留原字节。
|
|
94
|
+
|
|
95
|
+
同类路径复核覆盖直接写入、转接的常规/转义/EOF/超时发送、日志及普通监听器的 `emit`、匹配和转义两处正则定位。共同 `emit`
|
|
96
|
+
同样补齐短写入检查;匹配和转义都传入 EOF 状态。日志、回调、普通匹配的监听器以及自定义写入对象仍同步运行,文档明确这些操作不受
|
|
97
|
+
IO 等待期限强制中断;自定义对象必须准确返回已接受的字节数。R6 使用 Ruby 已有的正则实例
|
|
98
|
+
timeout,新增测试验证异常透传、缓冲保留及全局配置不变,未增加进程全局设置。
|
|
99
|
+
|
|
100
|
+
| 环境 | 完整 `script/ci` | 打包及运行 |
|
|
101
|
+
|----------------------------|--------------------------------------------------------------|-------------------------------------------------|
|
|
102
|
+
| macOS arm64,Ruby 4.0.7 | 217 项 / 857 断言,0 失败、错误、跳过;RuboCop 42 文件无违规 | 对话示例、Gem 构建、隔离安装及真实 PTY 对话通过 |
|
|
51
103
|
| Linux aarch64,Ruby 3.2.11 | 217 项 / 857 断言,0 失败、错误、跳过;RuboCop 42 文件无违规 | 对话示例、Gem 构建、隔离安装及真实 PTY 对话通过 |
|
|
52
104
|
|
|
53
|
-
Linux 从 gemspec 文件白名单及锁文件构造独立源码快照,只读挂载后复制到容器,使用 Bundler 4.0.20、锁定依赖及
|
|
105
|
+
Linux 从 gemspec 文件白名单及锁文件构造独立源码快照,只读挂载后复制到容器,使用 Bundler 4.0.20、锁定依赖及
|
|
106
|
+
`BUNDLE_FROZEN=true`;未读取或分发工作区设备日志。检查构建包包含 `relay.rb`、转接写入器(现名 `relay_writer.rb`
|
|
107
|
+
)、原有重命名模块和新增回归测试,不含 `tmp/` 或 `.git/`。macOS 构建时存在本机 RDoc 多版本重复常量警告,命令成功退出,隔离安装与
|
|
108
|
+
PTY 验证通过。工作区原有 16 处样式问题只作相应格式修正。
|
|
54
109
|
|
|
55
|
-
Linux 首轮新增用例误把 0.1 秒转接超时当作发送完成:`pending_output? == false` 时,`buffer`
|
|
110
|
+
Linux 首轮新增用例误把 0.1 秒转接超时当作发送完成:`pending_output? == false` 时,`buffer`
|
|
111
|
+
仍可能含尚未排入队列的输入。探针证实该状态存在;用例改为关闭源写端并等待转接返回该 EOF 来源,明确验证缓冲已空后再断言回复,避免依赖机器吞吐量。
|
|
56
112
|
|
|
57
|
-
`git diff --check` 通过。未运行 Ruby 3.3/3.4、远端 CI 或真实
|
|
113
|
+
`git diff --check` 通过。未运行 Ruby 3.3/3.4、远端 CI 或真实
|
|
114
|
+
SSH;未提交、推送或发布。新增源码仍需随现有重构文件一起纳入后续提交。性能窗口、完整输出存储等建议已补充使用说明,未改变默认缓冲上限或任意正则的匹配语义。
|
|
58
115
|
|
|
59
116
|
## Tcl 对照与全项目复核(2026-09-26)
|
|
60
117
|
|
|
61
|
-
基于 `e6fc883` 及当前全部未提交改动,复核库源码、测试、示例、打包和发布脚本。保留既有 `Matcher`、`SessionResources` 和
|
|
118
|
+
基于 `e6fc883` 及当前全部未提交改动,复核库源码、测试、示例、打包和发布脚本。保留既有 `Matcher`、`SessionResources` 和
|
|
119
|
+
`interaction.rb` 职责命名,不新增兼容别名。本轮补充四项回归测试,修复三处问题:
|
|
62
120
|
|
|
63
121
|
- Ruby 编码转换器识别非法 UTF-8 前缀,避免将过长编码、代理区或越界码点误判为等待更多字节;合法分片继续等待,原字节保留。
|
|
64
122
|
- 转接读取先存入转接缓冲,再调用日志;日志异常后输入归还会话,可继续匹配。
|
|
@@ -66,51 +124,71 @@ Linux 首轮新增用例误把 0.1 秒转接超时当作发送完成:`pending_
|
|
|
66
124
|
|
|
67
125
|
三项缺陷均先运行回归测试确认旧实现失败,再修改实现并复验。合法分片用例覆盖二、三、四字节字符的每个截断位置。
|
|
68
126
|
|
|
69
|
-
| 环境
|
|
70
|
-
|
|
71
|
-
| macOS arm64,Ruby 4.0.7
|
|
127
|
+
| 环境 | 完整 `script/ci` | 打包验证 |
|
|
128
|
+
|----------------------------|--------------------------------------------------------------|---------------------------------------------|
|
|
129
|
+
| macOS arm64,Ruby 4.0.7 | 191 项 / 728 断言,0 失败、错误、跳过;RuboCop 39 文件无违规 | 对话示例、构建、隔离安装与真实 PTY 对话通过 |
|
|
72
130
|
| Linux aarch64,Ruby 3.2.11 | 191 项 / 728 断言,0 失败、错误、跳过;RuboCop 39 文件无违规 | 对话示例、构建、隔离安装与真实 PTY 对话通过 |
|
|
73
131
|
|
|
74
|
-
macOS 验证目录从 `git archive HEAD`、全部工作区补丁及未跟踪源码重建,包含本地开发锁文件;隔离的 GEM_HOME 安装 Bundler
|
|
132
|
+
macOS 验证目录从 `git archive HEAD`、全部工作区补丁及未跟踪源码重建,包含本地开发锁文件;隔离的 GEM_HOME 安装 Bundler
|
|
133
|
+
4.0.17,并以 `BUNDLE_FROZEN=true bash script/ci` 验证,未依赖本机损坏的 Bundler 启动器。Linux 使用 `ruby:3.2-bookworm`
|
|
134
|
+
,源码只读挂载并复制到容器临时目录,同样安装锁定依赖;完整测试包含 `release_test.rb`。
|
|
75
135
|
|
|
76
|
-
核对 Tcl 官方 `expect.c` 的匹配、缓冲消费和继续计时流程,以及 `exp_inter.c` 的部分模式匹配和终端恢复;另在 Tcl Expect
|
|
136
|
+
核对 Tcl 官方 `expect.c` 的匹配、缓冲消费和继续计时流程,以及 `exp_inter.c` 的部分模式匹配和终端恢复;另在 Tcl Expect
|
|
137
|
+
5.45.4 与本库中分别实跑缓冲消费、保留、EOF 和 wait
|
|
138
|
+
场景,均通过。功能差异和未实现能力见 [接口说明](COMPATIBILITY.md#tcl-expect-语义边界),不代表完整 Tcl 差分验收。
|
|
77
139
|
|
|
78
140
|
本轮未重跑真实 SSH、Ruby 3.3/3.4 或远端 CI,也未提交、推送或发布。以下记录保留各自验证时点,不作为本轮执行证据。
|
|
79
141
|
|
|
80
142
|
## 当前工作区:交互、匹配与 IO 修复(2026-09-24)
|
|
81
143
|
|
|
82
|
-
本轮检查并修复固定 UTF-8 正则在末尾字符未收齐时提前匹配、正则转义历史窗口截断到 UTF-8 续字节,以及就绪查询、写入和转接中的
|
|
144
|
+
本轮检查并修复固定 UTF-8 正则在末尾字符未收齐时提前匹配、正则转义历史窗口截断到 UTF-8 续字节,以及就绪查询、写入和转接中的
|
|
145
|
+
`EINTR`。新增回归覆盖分片字符、历史窗口和 select/read/write 中断。
|
|
83
146
|
|
|
84
|
-
| 环境
|
|
85
|
-
|
|
86
|
-
| macOS arm64,Ruby 4.0.7
|
|
147
|
+
| 环境 | 测试结果 | 其他检查 |
|
|
148
|
+
|---------------------------|---------------------------------------|--------------------------------------------------------|
|
|
149
|
+
| macOS arm64,Ruby 4.0.7 | 187 项 / 692 断言,无失败、错误、跳过 | RuboCop 39 个文件无违规;对话示例通过 |
|
|
87
150
|
| Linux aarch64,Ruby 4.0.6 | 176 项 / 658 断言,无失败、错误、跳过 | 只读挂载源码;排除依赖本机打包环境的 `release_test.rb` |
|
|
88
151
|
|
|
89
|
-
`git diff --check` 通过。本轮未在 Ruby 3.2 重新运行完整测试,也未运行远端 CI;下节的 Ruby 3.2 结果属于 2026-09-12
|
|
152
|
+
`git diff --check` 通过。本轮未在 Ruby 3.2 重新运行完整测试,也未运行远端 CI;下节的 Ruby 3.2 结果属于 2026-09-12
|
|
153
|
+
的历史验证,不能代表当前工作区。
|
|
90
154
|
|
|
91
155
|
## Ruby 原生接口与关闭策略(2026-09-12)
|
|
92
156
|
|
|
93
|
-
此次重构以 144 项测试 / 526 个断言为基线。原有交互场景全部迁移到新接口,新增 18 项回归,三个环境均通过 `bundle exec rake
|
|
157
|
+
此次重构以 144 项测试 / 526 个断言为基线。原有交互场景全部迁移到新接口,新增 18 项回归,三个环境均通过 `bundle exec rake`
|
|
158
|
+
(RuboCop 和完整测试)及 `ruby examples/dialogue.rb`:
|
|
94
159
|
|
|
95
|
-
| 环境
|
|
96
|
-
|
|
97
|
-
| macOS arm64,Ruby 4.0.6
|
|
160
|
+
| 环境 | 测试结果 | RuboCop |
|
|
161
|
+
|----------------------------|---------------------------------------|-------------------|
|
|
162
|
+
| macOS arm64,Ruby 4.0.6 | 162 项 / 618 断言,无失败、错误、跳过 | 37 个文件,无违规 |
|
|
98
163
|
| Linux aarch64,Ruby 3.2.11 | 162 项 / 618 断言,无失败、错误、跳过 | 37 个文件,无违规 |
|
|
99
|
-
| Linux aarch64,Ruby 4.0.6
|
|
164
|
+
| Linux aarch64,Ruby 4.0.6 | 162 项 / 618 断言,无失败、错误、跳过 | 37 个文件,无违规 |
|
|
100
165
|
|
|
101
|
-
新增检查覆盖配置发布的原子性、冻结与会话隔离、子类覆盖、无效赋值保留状态、Ruby
|
|
166
|
+
新增检查覆盖配置发布的原子性、冻结与会话隔离、子类覆盖、无效赋值保留状态、Ruby
|
|
167
|
+
真值、字面模式标志、全部活跃会话的超时回调、重复超时注册、日志所有权。真实子进程验证软关闭收集尾部、响应 TERM、绝不发送
|
|
168
|
+
KILL、保留存活 PID、后续硬关闭和重复回收,以及自动清理、日志异常和无效关闭期限。模拟 EINTR 检查重复 select 中断不能延长期限、读取中断不丢输入。
|
|
102
169
|
|
|
103
|
-
最终会话输出接口统一为 `puts`、`write` 和 `send_slow(..., delay:)`,移除会话 `print` 和 `write_slow`。`lib/expect/` 的 9
|
|
170
|
+
最终会话输出接口统一为 `puts`、`write` 和 `send_slow(..., delay:)`,移除会话 `print` 和 `write_slow`。`lib/expect/` 的 9
|
|
171
|
+
个模块文件及主入口均补充中文注释,说明方法用途、匹配状态机、编码分片、转接缓冲、日志所有权和进程关闭;词法检查确认注释增补没有改变可执行代码。
|
|
104
172
|
|
|
105
|
-
原有 PTY、控制终端、信号、中文/二进制、背压、捕获组、匹配优先级、多会话、日志、interact 和 GC
|
|
173
|
+
原有 PTY、控制终端、信号、中文/二进制、背压、捕获组、匹配优先级、多会话、日志、interact 和 GC
|
|
174
|
+
测试继续全量运行。模块设置已收敛到配置对象;旧方法、位置超时、数组回调和 Perl 正则模式解析已移除,测试使用新 API。10 个文档
|
|
175
|
+
Ruby 示例块均通过语法检查。
|
|
106
176
|
|
|
107
|
-
macOS 的独立 `bundle exec rake test:kibitz` 也通过全部 6 个场景,报告位于
|
|
177
|
+
macOS 的独立 `bundle exec rake test:kibitz` 也通过全部 6 个场景,报告位于
|
|
178
|
+
`tmp/kibitz/20260911T232907Z-20260912-9935-te8xfa/report.json`。本轮在 Linux Ruby 3.2 容器中重新运行
|
|
179
|
+
`test/compare_upstream.rb`, **11 组共同交互行为对照通过**;适配脚本使用新 Ruby API,显式转换错误标记及可读会话索引,原版
|
|
180
|
+
Perl fixture 未修改。
|
|
108
181
|
|
|
109
|
-
关闭策略另核对上游 `lib/Expect.pm` 的 `soft_close`、`hard_close` 和 `DESTROY`:软关闭最多 TERM,硬关闭可 KILL,销毁可先软后硬。Ruby
|
|
182
|
+
关闭策略另核对上游 `lib/Expect.pm` 的 `soft_close`、`hard_close` 和 `DESTROY`:软关闭最多 TERM,硬关闭可 KILL,销毁可先软后硬。Ruby
|
|
183
|
+
以 `graceful_close` / `close(graceful:)` 表达默认策略,以关键字配置等待期限;显式关闭返回 `Process::Status`,通用 `close`
|
|
184
|
+
返回 `nil`。
|
|
110
185
|
|
|
111
|
-
Linux 源码以只读方式挂载,使用 `BUNDLE_FROZEN=true` 和独立容器依赖目录;镜像摘要仍为下文记录的 `ruby:3.2` 与 `ruby:4.0
|
|
186
|
+
Linux 源码以只读方式挂载,使用 `BUNDLE_FROZEN=true` 和独立容器依赖目录;镜像摘要仍为下文记录的 `ruby:3.2` 与 `ruby:4.0`
|
|
187
|
+
。Gemfile 和锁文件未改动,锁文件 SHA-256 为 `b1186a77057fba44bb79c440ffb6921042c16c1b88d213fabaa6548befb38d57`。macOS 复用了
|
|
188
|
+
`/tmp/expect-pty-gems` 的隔离依赖环境。
|
|
112
189
|
|
|
113
|
-
本轮没有重新连接真实 SSH 或运行远端 CI。`pkg/` 的 0.1.0 / 0.1.1 构建与记录仍代表历史版本;当前源码的接口见 README 和
|
|
190
|
+
本轮没有重新连接真实 SSH 或运行远端 CI。`pkg/` 的 0.1.0 / 0.1.1 构建与记录仍代表历史版本;当前源码的接口见 README 和
|
|
191
|
+
COMPATIBILITY。以下各节保留其原验证时间、接口和范围,不作为当前接口的使用说明。
|
|
114
192
|
|
|
115
193
|
## 历史验证记录
|
|
116
194
|
|
|
@@ -120,20 +198,23 @@ Linux 源码以只读方式挂载,使用 `BUNDLE_FROZEN=true` 和独立容器
|
|
|
120
198
|
|
|
121
199
|
完整测试集包含 76 项测试,全部通过,无跳过:
|
|
122
200
|
|
|
123
|
-
| 环境
|
|
124
|
-
|
|
125
|
-
| macOS arm64,Ruby 4.0.6
|
|
201
|
+
| 环境 | 结果 |
|
|
202
|
+
|----------------------------|-----------|
|
|
203
|
+
| macOS arm64,Ruby 4.0.6 | 76 项通过 |
|
|
126
204
|
| Linux aarch64,Ruby 3.2.11 | 76 项通过 |
|
|
127
|
-
| Linux aarch64,Ruby 4.0.6
|
|
205
|
+
| Linux aarch64,Ruby 4.0.6 | 76 项通过 |
|
|
128
206
|
|
|
129
207
|
Linux 使用官方 Docker 镜像:
|
|
130
208
|
|
|
131
209
|
- `ruby:3.2`:`sha256:d3bcbd845d26ae1efafcc987f641aa9ac796267b9b857e0f196a2b05070c8330`
|
|
132
210
|
- `ruby:4.0`:`sha256:8dc3950712ad2078bdd275b890419ba2fd3aab5a0653b291a7325f0d8a24ca05`
|
|
133
211
|
|
|
134
|
-
测试范围包含真实 PTY 的控制终端、stdin/stdout/stderr、raw/noecho、终端尺寸、Ctrl-C 前台信号、退出码、TERM/KILL 回收、GC
|
|
212
|
+
测试范围包含真实 PTY 的控制终端、stdin/stdout/stderr、raw/noecho、终端尺寸、Ctrl-C 前台信号、退出码、TERM/KILL 回收、GC
|
|
213
|
+
兜底;模式优先级、捕获组、中文分片、二进制、缓冲上限;回调、事件、绝对/接收重置超时;多会话、日志、管道和 socket、大块双向
|
|
214
|
+
IO、写入背压;人工交互、跨读取转义序列、异常和超时后终端恢复;与 Ruby 标准库 IO#expect 共存。
|
|
135
215
|
|
|
136
|
-
macOS 改变终端设置后内核可能设置 PENDIN 临时状态位。终端恢复测试屏蔽这一状态位,比较其余完整配置;没有忽略真实的
|
|
216
|
+
macOS 改变终端设置后内核可能设置 PENDIN 临时状态位。终端恢复测试屏蔽这一状态位,比较其余完整配置;没有忽略真实的
|
|
217
|
+
echo、canonical、输入/输出、信号或控制字符设置变化。
|
|
137
218
|
|
|
138
219
|
复现:
|
|
139
220
|
|
|
@@ -142,13 +223,16 @@ bundle install
|
|
|
142
223
|
bundle exec rake test
|
|
143
224
|
```
|
|
144
225
|
|
|
145
|
-
本机全局 RubyGems/Bundler 安装存在版本混用,验证使用了临时 GEM_HOME 中的独立 Bundler 4.0.16、Rake 和 Minitest;未修改项目对
|
|
226
|
+
本机全局 RubyGems/Bundler 安装存在版本混用,验证使用了临时 GEM_HOME 中的独立 Bundler 4.0.16、Rake 和 Minitest;未修改项目对
|
|
227
|
+
Bundler 的通常用法或用户的全局 gem。
|
|
146
228
|
|
|
147
229
|
## 上游差分验证
|
|
148
230
|
|
|
149
|
-
`test/compare_upstream.rb` 对同一输入分别运行原始 Perl 模块与本 Ruby
|
|
231
|
+
`test/compare_upstream.rb` 对同一输入分别运行原始 Perl 模块与本 Ruby
|
|
232
|
+
实现:字面模式、数组正则、跨行锚点、模式优先级、notransfer、缓冲上限、超时保留缓冲、连续回调、真实 PTY 对话。 **9 组对照通过**。
|
|
150
233
|
|
|
151
|
-
对照在 Linux Ruby 3.2 容器内执行,Perl 依赖 IO::Pty / IO::Stty 仅安装到该临时容器。正则捕获及错误访问的 Perl
|
|
234
|
+
对照在 Linux Ruby 3.2 容器内执行,Perl 依赖 IO::Pty / IO::Stty 仅安装到该临时容器。正则捕获及错误访问的 Perl
|
|
235
|
+
对象模型差异见兼容性说明;没有将它们伪装为一致行为。
|
|
152
236
|
|
|
153
237
|
```sh
|
|
154
238
|
# 此项是可选验证,需要 Perl 及 IO::Pty / IO::Stty。
|
|
@@ -159,9 +243,11 @@ ruby test/compare_upstream.rb /path/to/expect.pm
|
|
|
159
243
|
|
|
160
244
|
## 真实 SSH
|
|
161
245
|
|
|
162
|
-
使用用户授权的 `crate@127.0.0.1` 完成真实 OpenSSH 密码认证,进入远端交互 shell 和 PTY。校验随机输出标记、`id -un` 返回
|
|
246
|
+
使用用户授权的 `crate@127.0.0.1` 完成真实 OpenSSH 密码认证,进入远端交互 shell 和 PTY。校验随机输出标记、`id -un` 返回
|
|
247
|
+
`crate`、`tty` 返回 `/dev/...`,随后 `exit`,SSH 退出码为 0。
|
|
163
248
|
|
|
164
|
-
测试随机标记由远端拼接,排除了仅匹配命令回显的误判。密码由隐藏输入读取或从进程环境取出,只保留在验证进程内,未写入源码、测试、文档和日志。临时
|
|
249
|
+
测试随机标记由远端拼接,排除了仅匹配命令回显的误判。密码由隐藏输入读取或从进程环境取出,只保留在验证进程内,未写入源码、测试、文档和日志。临时
|
|
250
|
+
known_hosts 在退出后删除。
|
|
165
251
|
|
|
166
252
|
```sh
|
|
167
253
|
SSH_USER=crate SSH_HOST=127.0.0.1 ruby examples/ssh_login.rb
|
|
@@ -169,66 +255,96 @@ SSH_USER=crate SSH_HOST=127.0.0.1 ruby examples/ssh_login.rb
|
|
|
169
255
|
|
|
170
256
|
## 打包和范围
|
|
171
257
|
|
|
172
|
-
提供 `expect-pty.gemspec`、MIT LICENSE、中文 README、API 兼容性表、对话和 SSH 示例,以及 macOS/Linux 的 Ruby 3.2/3.3/3.4/4.0
|
|
258
|
+
提供 `expect-pty.gemspec`、MIT LICENSE、中文 README、API 兼容性表、对话和 SSH 示例,以及 macOS/Linux 的 Ruby 3.2/3.3/3.4/4.0
|
|
259
|
+
CI 配置。CI 文件已进行 YAML 解析检查,远端 GitHub Actions 尚未运行。
|
|
173
260
|
|
|
174
|
-
初始构建物为 `expect-pty-0.1.0.gem`,补充后的交付版本为 `expect-pty-0.1.1.gem`,包含可运行的测试和 fixtures。安装验证在独立
|
|
261
|
+
初始构建物为 `expect-pty-0.1.0.gem`,补充后的交付版本为 `expect-pty-0.1.1.gem`,包含可运行的测试和 fixtures。安装验证在独立
|
|
262
|
+
GEM_HOME 中、从项目目录外运行 `require "expect/pty"` 和真实 PTY 对话,避免依赖源码目录的加载路径。
|
|
175
263
|
|
|
176
264
|
原生 Windows、其他 Unix、真实外部设备/外部 SSH 服务未实测。没有发布 gem、推送仓库或创建远端 Release;本次交付为本地源码和安装包。
|
|
177
265
|
|
|
178
266
|
## 补充验证:登录后多脚本与日志(2026-09-11)
|
|
179
267
|
|
|
180
|
-
新增 `test/script_logging_test.rb` 的 8 项真实 PTY 测试,及可单独运行的 `test/integration/ssh_scripts.rb`。自动测试总计从
|
|
268
|
+
新增 `test/script_logging_test.rb` 的 8 项真实 PTY 测试,及可单独运行的 `test/integration/ssh_scripts.rb`。自动测试总计从
|
|
269
|
+
76 项增至 84 项。新增测试共享 5 个 `.sh` fixture,覆盖多脚本日志文件、回调和借用 File、日志出错、异常退出码、输出不符、引号和中文传输,以及超时后的日志连续性。
|
|
181
270
|
|
|
182
|
-
最终全量回归:macOS Ruby 4.0.6 为 84 项 / 283 断言,Linux Ruby 3.2.11 为 84 项 / 283 断言,Linux Ruby 4.0.6 为 84 项 / 289
|
|
271
|
+
最终全量回归:macOS Ruby 4.0.6 为 84 项 / 283 断言,Linux Ruby 3.2.11 为 84 项 / 283 断言,Linux Ruby 4.0.6 为 84 项 / 289
|
|
272
|
+
断言,均无失败、错误或跳过。Rake 的 `test:ssh` 入口已注册,Ruby 脚本和 5 个 shell fixture 的语法检查通过。
|
|
183
273
|
|
|
184
|
-
真实 SSH `crate@127.0.0.1` 已通过同一会话内的 7 项执行(5 个文件脚本,加日志关闭/恢复用例)及 11 项日志检查。第 4 个 fixture
|
|
274
|
+
真实 SSH `crate@127.0.0.1` 已通过同一会话内的 7 项执行(5 个文件脚本,加日志关闭/恢复用例)及 11 项日志检查。第 4 个 fixture
|
|
275
|
+
故意返回 7,第 5 个仍执行成功;最终 SSH 退出码为 0。日志读取验证包含执行期间即时 flush、逐条顺序、无重复、覆盖/暂停/追加,以及
|
|
276
|
+
`soft_close` 收集最终延迟输出。
|
|
185
277
|
|
|
186
|
-
实际通过的日志和 JSON 报告保存在 `tmp/ssh-logs/20260911T124918Z-20260911-97383-lka948/`。目录被 Git
|
|
278
|
+
实际通过的日志和 JSON 报告保存在 `tmp/ssh-logs/20260911T124918Z-20260911-97383-lka948/`。目录被 Git
|
|
279
|
+
忽略,每次重跑生成新目录,失败时保留失败报告。
|
|
187
280
|
|
|
188
|
-
该成功会话日志共 1633 字节,SHA-256 为 `6b8abf4df93e1c40dec21a2b89c359bf4e2a9f9636791a83713150af5796672c`,与 JSON
|
|
281
|
+
该成功会话日志共 1633 字节,SHA-256 为 `6b8abf4df93e1c40dec21a2b89c359bf4e2a9f9636791a83713150af5796672c`,与 JSON
|
|
282
|
+
报告的摘要一致;日志和报告均为 0600 权限。`pkg/` 中保留 0.1.0 作为初始构建记录,后续修正和测试脚本随 0.1.1 打包。
|
|
189
283
|
|
|
190
284
|
## 完整性复核与 0.1.1
|
|
191
285
|
|
|
192
|
-
复核上游实际代码后,补充 `test_handles(timeout, *sessions)` 等待语义,以及 `set_seq` 正则序列和跨读取回调,差分用例从 9
|
|
286
|
+
复核上游实际代码后,补充 `test_handles(timeout, *sessions)` 等待语义,以及 `set_seq` 正则序列和跨读取回调,差分用例从 9
|
|
287
|
+
组扩展到 11 组。新增回归也覆盖从 `expect` 切换到 `interconnect` 再返回时的日志唯一性、转义后的原始日志,以及日志目标抛 IO
|
|
288
|
+
错误时保留输入并正确报告错误。
|
|
193
289
|
|
|
194
|
-
0.1.1 包含库源码、中文文档、完整测试与 5 个 `.sh` fixtures、Gemfile、gemspec 和 Rakefile。具体构建摘要和安装后的验证结果记录在构建物旁的
|
|
290
|
+
0.1.1 包含库源码、中文文档、完整测试与 5 个 `.sh` fixtures、Gemfile、gemspec 和 Rakefile。具体构建摘要和安装后的验证结果记录在构建物旁的
|
|
291
|
+
`pkg/VERIFICATION-0.1.1.txt`,避免文档与包自身摘要循环依赖。
|
|
195
292
|
|
|
196
|
-
SSH 首轮测试曾准确报告中文脚本退出 127;根据日志定位到测试 helper 的逐字节转义与远端 shell 行编辑相互影响。已改为完整脚本单引号传输,并禁用交互
|
|
293
|
+
SSH 首轮测试曾准确报告中文脚本退出 127;根据日志定位到测试 helper 的逐字节转义与远端 shell 行编辑相互影响。已改为完整脚本单引号传输,并禁用交互
|
|
294
|
+
shell 的 emacs/vi 编辑;重跑后中文、标准输出和错误输出逐字节匹配通过。
|
|
197
295
|
|
|
198
296
|
## 补充验证:interact 与本地 Kibitz(2026-09-11)
|
|
199
297
|
|
|
200
|
-
当前源码全量测试为 **109 项**,无失败、错误或跳过:macOS arm64 Ruby 4.0.6 为 380 断言,Linux aarch64 Ruby 3.2.11 为 380
|
|
298
|
+
当前源码全量测试为 **109 项**,无失败、错误或跳过:macOS arm64 Ruby 4.0.6 为 380 断言,Linux aarch64 Ruby 3.2.11 为 380
|
|
299
|
+
断言,Linux aarch64 Ruby 4.0.6 为 386 断言。Linux 仍使用上文记录的两个镜像。这些新增内容记在 Unreleased,已有 0.1.1
|
|
300
|
+
构建记录保持为该包的历史验证结果。
|
|
201
301
|
|
|
202
|
-
新增 7 项 `test/interact_test.rb` 测试覆盖真实 PTY 接管、输入即时回显、远端 Ctrl-C、两次 Ctrl-]
|
|
302
|
+
新增 7 项 `test/interact_test.rb` 测试覆盖真实 PTY 接管、输入即时回显、远端 Ctrl-C、两次 Ctrl-]
|
|
303
|
+
返回、恢复自动化、超时/EOF/回调和输出异常后的终端恢复。另补 1 项 CRLF 输出分帧回归,检查空输出、无末尾换行和多个末尾换行。人工交互启用远端
|
|
304
|
+
echo,回到自动化时关闭 echo;自动脚本的无回显设置保留。TTY 身份探测的换行匹配不参与输出截取,不存在同一分帧问题。
|
|
203
305
|
|
|
204
306
|
实际 SSH `crate@127.0.0.1` 通过的三条路径,均记录 SSH 退出码 0,日志与报告权限 0600:
|
|
205
307
|
|
|
206
|
-
| 路径
|
|
207
|
-
|
|
208
|
-
| 自动 PTY 交互
|
|
209
|
-
| 人工输入后 Ctrl-] | 回车前可见 `printf` 输入,执行结果正确,返回后自动命令成功 | `tmp/ssh-interact/20260911T131343Z-20260911-423-7pgq5m/`
|
|
210
|
-
| 人工直接 exit
|
|
308
|
+
| 路径 | 结果 | 报告所在目录 |
|
|
309
|
+
|-------------------|------------------------------------------------------------|-----------------------------------------------------------|
|
|
310
|
+
| 自动 PTY 交互 | 4 项命令、13 项交互/日志检查 | `tmp/ssh-interact/20260911T131311Z-20260911-367-hkxq5z/` |
|
|
311
|
+
| 人工输入后 Ctrl-] | 回车前可见 `printf` 输入,执行结果正确,返回后自动命令成功 | `tmp/ssh-interact/20260911T131343Z-20260911-423-7pgq5m/` |
|
|
312
|
+
| 人工直接 exit | 远端 EOF、终端恢复、正常退出,不执行自动化恢复命令 | `tmp/ssh-interact/20260911T132040Z-20260911-1777-qi6yry/` |
|
|
211
313
|
|
|
212
|
-
参考上游 `examples/kibitz` 源码的连接图,新增 `examples/kibitz/kibitz.rb` 和 `test_kibitz.rb`。本地示例通过 Unix socket
|
|
314
|
+
参考上游 `examples/kibitz` 源码的连接图,新增 `examples/kibitz/kibitz.rb` 和 `test_kibitz.rb`。本地示例通过 Unix socket
|
|
315
|
+
连接两份 CLI,各自运行于独立真实 PTY;共享模式启动真实 shell。`test/kibitz_test.rb` 新增 7
|
|
316
|
+
项测试,覆盖共享状态、输入回显、双向广播、中文/stderr、Ctrl-C、无子进程互传、自定义分片转义、禁用转义、非零退出、连接与转接超时、日志唯一性以及终端恢复和
|
|
317
|
+
socket 清理。
|
|
213
318
|
|
|
214
319
|
测试捕获并修正了就绪提示先于本地 raw/noecho 设置的启动时序问题;现在两端的就绪提示均在终端设置完成后发送。分片转义检查先确认普通前缀已到达对端,再发送转义的剩余部分,确保确实覆盖跨读取路径。
|
|
215
320
|
|
|
216
|
-
`bundle exec rake test:kibitz` 独立执行 6 个场景并全部通过,报告保存于
|
|
321
|
+
`bundle exec rake test:kibitz` 独立执行 6 个场景并全部通过,报告保存于
|
|
322
|
+
`tmp/kibitz/20260911T132223Z-20260911-2081-1poaup/report.json`,每个场景有独立 `session.log`
|
|
323
|
+
。此验证参考并重现上游的本地交互行为,不代表移植或运行了上游的用户邀请、跨主机 rlogin 和转义菜单。
|
|
217
324
|
|
|
218
325
|
## Ruby API 与编码规范重构(2026-09-12)
|
|
219
326
|
|
|
220
|
-
本轮基线为 109 项测试 / 380 断言。新增 `test/ruby_api_test.rb` 的 35 项测试 / 146 断言,最终三种环境均通过完整的
|
|
327
|
+
本轮基线为 109 项测试 / 380 断言。新增 `test/ruby_api_test.rb` 的 35 项测试 / 146 断言,最终三种环境均通过完整的
|
|
328
|
+
`bundle exec rake` 和 `ruby examples/dialogue.rb`:
|
|
221
329
|
|
|
222
|
-
| 环境
|
|
223
|
-
|
|
224
|
-
| macOS arm64,Ruby 4.0.6
|
|
330
|
+
| 环境 | 完整测试 | RuboCop |
|
|
331
|
+
|----------------------------|---------------------------------------|-------------------|
|
|
332
|
+
| macOS arm64,Ruby 4.0.6 | 144 项 / 526 断言,无失败、错误、跳过 | 35 个文件,无违规 |
|
|
225
333
|
| Linux aarch64,Ruby 3.2.11 | 144 项 / 526 断言,无失败、错误、跳过 | 35 个文件,无违规 |
|
|
226
|
-
| Linux aarch64,Ruby 4.0.6
|
|
334
|
+
| Linux aarch64,Ruby 4.0.6 | 144 项 / 526 断言,无失败、错误、跳过 | 35 个文件,无违规 |
|
|
227
335
|
|
|
228
|
-
新增验证覆盖简洁 `expect(10) { on(...) ... }`、显式块参数保留调用方 `self`、闭包、可选块参数、注册时异常和 `break`
|
|
336
|
+
新增验证覆盖简洁 `expect(10) { on(...) ... }`、显式块参数保留调用方 `self`、闭包、可选块参数、注册时异常和 `break`
|
|
337
|
+
不消费输入、关键字与位置超时校验、EOF / 超时 / 多会话回调、继续等待及原期限;也覆盖借用和接管 IO 的块清理、初始化失败、缓冲和监听列表副本、日志块、原生
|
|
338
|
+
`puts` 的空参数/嵌套/递归数组、对象写入与链式追加。
|
|
229
339
|
|
|
230
|
-
`Result` 转换验证直接对照七个 Struct 字段,包括 `to_a`、`Array(result)`、`to_h`、位置/键模式解构及显式多重赋值;确认不再响应
|
|
340
|
+
`Result` 转换验证直接对照七个 Struct 字段,包括 `to_a`、`Array(result)`、`to_h`、位置/键模式解构及显式多重赋值;确认不再响应
|
|
341
|
+
`to_ary`。另验证 `session.send(:buffer)` 等 Ruby 反射调用和实际字节写入分离。原有 PTY、二进制、超时、进程回收、日志、interact、Kibitz
|
|
342
|
+
测试继续全量运行。
|
|
231
343
|
|
|
232
|
-
开发依赖固定在 Ruby 3.2 可运行的范围:RuboCop 1.89.0、parallel 1.28.0、Minitest 5.27.0、Rake 13.4.2,锁文件已补齐校验和。Linux
|
|
344
|
+
开发依赖固定在 Ruby 3.2 可运行的范围:RuboCop 1.89.0、parallel 1.28.0、Minitest 5.27.0、Rake 13.4.2,锁文件已补齐校验和。Linux
|
|
345
|
+
验证以只读方式挂载源码,使用 `BUNDLE_FROZEN=true` 安装同一锁文件;镜像仍为本文记录的 `ruby:3.2` 和 `ruby:4.0`。macOS 使用
|
|
346
|
+
`/tmp/expect-pty-gems` 中的独立 Bundler 4.0.16。
|
|
233
347
|
|
|
234
|
-
调用与迁移说明已同步至 README、兼容性表和示例;`send(data)` 需改为 `write(data)`,多重赋值需显式使用 `result.to_a`,`puts`
|
|
348
|
+
调用与迁移说明已同步至 README、兼容性表和示例;`send(data)` 需改为 `write(data)`,多重赋值需显式使用 `result.to_a`,`puts`
|
|
349
|
+
返回 `nil`。不冲突的 Expect.pm 入口继续作为兼容入口保留。本轮未重新连接真实 SSH、运行 Perl 上游差分或触发远端
|
|
350
|
+
CI;历史验证记录不作为这些路径本轮实测的证明。
|
data/lib/expect/configuration.rb
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
class Expect
|
|
4
4
|
# 集中校验会话配置。类级默认值以冻结快照发布,每个会话再构造独立副本。
|
|
5
|
+
# 这里只保存策略值,不持有 IO、缓冲或日志对象;修改默认配置不会追溯影响已创建的会话。
|
|
5
6
|
class Configuration
|
|
6
7
|
# 会话通过 Forwardable 委托这些属性;to_h 使用同一清单生成配置副本。
|
|
7
8
|
ATTRIBUTES = %i[
|
|
@@ -91,7 +92,7 @@ class Expect
|
|
|
91
92
|
|
|
92
93
|
alias log_listeners? log_listeners
|
|
93
94
|
|
|
94
|
-
#
|
|
95
|
+
# 控制 interact 是否临时设置并恢复本地输入终端;通用 interconnect 不修改终端模式。
|
|
95
96
|
def raw_terminal=(value)
|
|
96
97
|
@raw_terminal = !!value
|
|
97
98
|
end
|
|
@@ -99,6 +100,7 @@ class Expect
|
|
|
99
100
|
alias raw_terminal? raw_terminal
|
|
100
101
|
|
|
101
102
|
# 控制收到任何新数据时是否刷新匹配期限,适用于按静默时长判断超时。
|
|
103
|
+
# 只刷新相对 timeout;单次等待显式指定的绝对 deadline 仍是不可延长的上限。
|
|
102
104
|
def reset_timeout_on_read=(value)
|
|
103
105
|
@reset_timeout_on_read = !!value
|
|
104
106
|
end
|
data/lib/expect/interaction.rb
CHANGED
|
@@ -5,11 +5,13 @@ require_relative "relay"
|
|
|
5
5
|
|
|
6
6
|
# 为会话补充人工接管和多路 IO 转接;核心会话定义位于 lib/expect.rb。
|
|
7
7
|
class Expect
|
|
8
|
+
# 正则没有“潜在部分匹配”接口,只保留有限历史;已转发的历史字节不能撤回。
|
|
8
9
|
REGEXP_ESCAPE_HISTORY_LIMIT = 65_536
|
|
9
10
|
private_constant :REGEXP_ESCAPE_HISTORY_LIMIT
|
|
10
11
|
|
|
11
12
|
# 在 raw 本地终端显示远端文本,补齐 LF 所需的 CR,同时保留已有 CRLF。
|
|
12
13
|
class InteractOutput
|
|
14
|
+
# 包装器借用目标,不复制或关闭其描述符;换行状态属于这个目标的连续显示流。
|
|
13
15
|
def initialize(target)
|
|
14
16
|
@target = target
|
|
15
17
|
@previous_carriage_return = false
|
|
@@ -17,6 +19,7 @@ class Expect
|
|
|
17
19
|
|
|
18
20
|
attr_reader :target
|
|
19
21
|
|
|
22
|
+
# 只改变显示字节,不改写匹配输入;记住上一块的 CR,避免分块的 CRLF 被扩成 CRCRLF。
|
|
20
23
|
def render(data)
|
|
21
24
|
bytes = data.to_s.b
|
|
22
25
|
rendered = bytes.gsub(/(?<!\r)\n/n, "\r\n")
|
|
@@ -25,6 +28,7 @@ class Expect
|
|
|
25
28
|
rendered
|
|
26
29
|
end
|
|
27
30
|
|
|
31
|
+
# 提供普通可写对象接口;Relay 会先 render,再按转换后字节数维护独立发送游标。
|
|
28
32
|
def write(data)
|
|
29
33
|
@target.write(render(data))
|
|
30
34
|
end
|
|
@@ -169,10 +173,12 @@ class Expect
|
|
|
169
173
|
return block_given? && count.positive? ? :pending : true
|
|
170
174
|
end
|
|
171
175
|
end
|
|
176
|
+
|
|
172
177
|
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
173
178
|
|
|
174
179
|
private_class_method :relay_buffer
|
|
175
180
|
|
|
181
|
+
# 同一输入 IO 重用一个借用会话,以保留上次接管预读的尾部并避免不断积累包装器。
|
|
176
182
|
def interact_source(input)
|
|
177
183
|
return input if input.is_a?(Expect)
|
|
178
184
|
|
|
@@ -181,6 +187,8 @@ class Expect
|
|
|
181
187
|
@interact_inputs[input] ||= Expect.open(input)
|
|
182
188
|
end
|
|
183
189
|
|
|
190
|
+
# 为当前数据块冻结目标选择并各建一个发送游标;此后修改 listeners 只影响后续数据。
|
|
191
|
+
# 调用方须先排空旧游标;显示转换也只做一次,短写重试时不能重复转换 CRLF。
|
|
184
192
|
def queue_output(data)
|
|
185
193
|
targets = []
|
|
186
194
|
targets << $stdout if log_stdout?
|
|
@@ -209,6 +217,7 @@ class Expect
|
|
|
209
217
|
raise
|
|
210
218
|
end
|
|
211
219
|
|
|
220
|
+
# 还原 prepare 保存的完整终端模式;没有切换过或句柄已关闭时无需恢复。
|
|
212
221
|
def restore_interact_terminal(state)
|
|
213
222
|
return unless state
|
|
214
223
|
|
|
@@ -216,6 +225,7 @@ class Expect
|
|
|
216
225
|
io.console_mode = mode unless io.closed?
|
|
217
226
|
end
|
|
218
227
|
|
|
228
|
+
# 仅为已切为 raw 的同一个本地终端补齐换行,文件、管道和其他终端保留原字节。
|
|
219
229
|
def interact_display(source, output, terminal_state)
|
|
220
230
|
@interact_output = nil unless terminal_state && @interact_output&.target.equal?(output)
|
|
221
231
|
return output unless terminal_state
|
|
@@ -238,7 +248,11 @@ class Expect
|
|
|
238
248
|
attr_accessor :sequences
|
|
239
249
|
# 让同步写入的背压读取遵守当前转接的数据所有权,退出后恢复普通匹配缓冲。
|
|
240
250
|
attr_accessor :interaction_buffer
|
|
251
|
+
# 只有裁剪、替换和消费才改变代次;同一代次只会追加,供字面扫描复用已排除的前缀。
|
|
252
|
+
attr_reader :buffer_generation
|
|
253
|
+
# 待交付游标随源会话保存,Relay 的超时或异常退出不会丢失各目标已经写出的进度。
|
|
241
254
|
attr_reader :relay_outputs
|
|
255
|
+
# 数组包装区分“没有待执行回调”与“已识别无处理器的停止转义”,前缀交付后只派发一次。
|
|
242
256
|
attr_accessor :relay_callback
|
|
243
257
|
|
|
244
258
|
# 历史属于产生它的转义规则;同规则重入继续匹配,换规则不能重放已转发输入。
|
|
@@ -252,5 +266,6 @@ class Expect
|
|
|
252
266
|
# 转接尚未处理的输入不能被匹配窗口上限裁掉;下次 expect 会重新应用该上限。
|
|
253
267
|
def restore_relay_buffer(buffer)
|
|
254
268
|
@buffer = buffer + @buffer
|
|
269
|
+
@buffer_generation += 1
|
|
255
270
|
end
|
|
256
271
|
end
|