net-ping 2.1.0-universal-linux
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 +7 -0
- data/CHANGES +28 -0
- data/CHANGES.out_of_date +354 -0
- data/CLAUDE.md +89 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +53 -0
- data/MANIFEST +25 -0
- data/README.md +65 -0
- data/Rakefile +183 -0
- data/doc/ping.txt +246 -0
- data/docs/superpowers/plans/2026-07-25-platform-specific-gems.md +317 -0
- data/docs/superpowers/specs/2026-07-25-platform-specific-gems-design.md +71 -0
- data/examples/example_pingexternal.rb +16 -0
- data/examples/example_pinghttp.rb +22 -0
- data/examples/example_pingtcp.rb +16 -0
- data/examples/example_pingudp.rb +12 -0
- data/lib/net/ping/external.rb +185 -0
- data/lib/net/ping/http.rb +189 -0
- data/lib/net/ping/icmp.rb +188 -0
- data/lib/net/ping/ping.rb +99 -0
- data/lib/net/ping/tcp.rb +110 -0
- data/lib/net/ping/udp.rb +117 -0
- data/lib/net/ping/version.rb +6 -0
- data/lib/net/ping/wmi.rb +118 -0
- data/lib/net/ping.rb +24 -0
- data/net-ping-universal-linux.gemspec +4 -0
- data/net-ping-universal-mingw-ucrt.gemspec +7 -0
- data/net-ping.gemspec +36 -0
- data/test/test_net_ping.rb +44 -0
- data/test/test_net_ping_external.rb +232 -0
- data/test/test_net_ping_gem_packaging.rb +333 -0
- data/test/test_net_ping_http.rb +264 -0
- data/test/test_net_ping_icmp.rb +199 -0
- data/test/test_net_ping_tcp.rb +106 -0
- data/test/test_net_ping_udp.rb +117 -0
- data/test/test_net_ping_wmi.rb +81 -0
- metadata +159 -0
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
# Platform-specific Gem Dependencies Implementation Plan
|
|
2
|
+
|
|
3
|
+
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
4
|
+
|
|
5
|
+
**Goal:** Build and validate RubyGems artifacts that install `cap2` on Linux and `win32-security` on current Windows RubyInstaller systems.
|
|
6
|
+
|
|
7
|
+
**Architecture:** Keep `net-ping.gemspec` OS-independent and create two small gemspec overlays for Linux and `mingw-ucrt`. Centralize artifact generation and metadata validation in the Rake gem namespace, then run that validation in the existing Linux/Windows CI matrix.
|
|
8
|
+
|
|
9
|
+
**Tech Stack:** Ruby, RubyGems (`Gem::Specification`, `Gem::Package`, `Gem::Platform`), Rake, test-unit, GitHub Actions.
|
|
10
|
+
|
|
11
|
+
## Global Constraints
|
|
12
|
+
|
|
13
|
+
- Produce exactly three same-version `net-ping` gems: `ruby`, `universal-linux`, and `universal-mingw-ucrt`.
|
|
14
|
+
- `universal-linux` must add `cap2 (>= 0.2.2)`; `universal-mingw-ucrt` must add `win32-security (>= 0.2.0)`.
|
|
15
|
+
- The Ruby gem must not contain either OS-specific runtime dependency.
|
|
16
|
+
- Support `mingw-ucrt` only; legacy `mingw32` is out of scope.
|
|
17
|
+
- CI builds and validates artifacts but never publishes them.
|
|
18
|
+
- Do not create git commits for this work.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## File Structure
|
|
23
|
+
|
|
24
|
+
| File | Responsibility |
|
|
25
|
+
| --- | --- |
|
|
26
|
+
| `net-ping.gemspec` | Define the OS-independent Ruby artifact and common metadata. |
|
|
27
|
+
| `net-ping-universal-linux.gemspec` | Overlay `universal-linux` and the `cap2` runtime dependency. |
|
|
28
|
+
| `net-ping-universal-mingw-ucrt.gemspec` | Overlay `universal-mingw-ucrt` and the `win32-security` runtime dependency. |
|
|
29
|
+
| `Rakefile` | Build, inspect, and locally install the platform-appropriate artifact. |
|
|
30
|
+
| `test/test_net_ping_gem_packaging.rb` | Build temporary artifacts and assert their platform/dependency metadata. |
|
|
31
|
+
| `test/test_net_ping.rb` | Load the packaging test in the aggregate suite. |
|
|
32
|
+
| `.github/workflows/test.yml` | Run gem artifact checks on Linux and Windows. |
|
|
33
|
+
| `README.md` | Explain automatic platform-specific dependency installation. |
|
|
34
|
+
| `CHANGES` | Record the metadata correction for the next release. |
|
|
35
|
+
|
|
36
|
+
### Task 1: Define and test platform gem specifications
|
|
37
|
+
|
|
38
|
+
**Files:**
|
|
39
|
+
- Create: `net-ping-universal-linux.gemspec`
|
|
40
|
+
- Create: `net-ping-universal-mingw-ucrt.gemspec`
|
|
41
|
+
- Create: `test/test_net_ping_gem_packaging.rb`
|
|
42
|
+
- Modify: `net-ping.gemspec:1-40`
|
|
43
|
+
- Modify: `test/test_net_ping.rb`
|
|
44
|
+
|
|
45
|
+
**Interfaces:**
|
|
46
|
+
- Consumes: `net-ping.gemspec`, which supplies the shared `Gem::Specification`.
|
|
47
|
+
- Produces: three loadable gemspecs whose `platform` and `runtime_dependencies` describe their target platform.
|
|
48
|
+
|
|
49
|
+
- [ ] **Step 1: Write the failing package-metadata test**
|
|
50
|
+
|
|
51
|
+
Create `test/test_net_ping_gem_packaging.rb`. Load every gemspec before building any artifact so `spec.files` cannot include an artifact created for an earlier specification. Build the loaded specifications into temporary `.gem` files, open each using `Gem::Package`, and assert the platform and runtime dependencies:
|
|
52
|
+
|
|
53
|
+
```ruby
|
|
54
|
+
require 'rubygems/package'
|
|
55
|
+
require 'test/unit'
|
|
56
|
+
|
|
57
|
+
class TestNetPingGemPackaging < Test::Unit::TestCase
|
|
58
|
+
EXPECTATIONS = {
|
|
59
|
+
'net-ping.gemspec' => ['ruby', {}],
|
|
60
|
+
'net-ping-universal-linux.gemspec' => ['universal-linux', {'cap2' => '>= 0.2.2'}],
|
|
61
|
+
'net-ping-universal-mingw-ucrt.gemspec' => [
|
|
62
|
+
'universal-mingw-ucrt',
|
|
63
|
+
{'win32-security' => '>= 0.2.0'}
|
|
64
|
+
]
|
|
65
|
+
}.freeze
|
|
66
|
+
|
|
67
|
+
def setup
|
|
68
|
+
@specifications = EXPECTATIONS.keys.map do |path|
|
|
69
|
+
[path, Gem::Specification.load(path)]
|
|
70
|
+
end
|
|
71
|
+
@gem_files = @specifications.map { |_, spec| Gem::Package.build(spec) }
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def teardown
|
|
75
|
+
@gem_files.each { |path| File.delete(path) if File.exist?(path) }
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def test_platforms_and_runtime_dependencies
|
|
79
|
+
@specifications.each do |path, spec|
|
|
80
|
+
expected_platform, expected_dependencies = EXPECTATIONS.fetch(path)
|
|
81
|
+
packaged_spec = Gem::Package.new(spec.file_name).spec
|
|
82
|
+
dependencies = packaged_spec.runtime_dependencies.to_h do |dependency|
|
|
83
|
+
[dependency.name, dependency.requirement.to_s]
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
assert_equal(expected_platform, packaged_spec.platform.to_s, path)
|
|
87
|
+
assert_equal(expected_dependencies, dependencies, path)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Add `require 'test_net_ping_gem_packaging'` to `test/test_net_ping.rb`.
|
|
94
|
+
|
|
95
|
+
- [ ] **Step 2: Run the new test to verify it fails**
|
|
96
|
+
|
|
97
|
+
Run:
|
|
98
|
+
|
|
99
|
+
```sh
|
|
100
|
+
bundle exec ruby -Itest test/test_net_ping_gem_packaging.rb
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Expected: failure because the Linux and Windows overlay gemspec files do not exist.
|
|
104
|
+
|
|
105
|
+
- [ ] **Step 3: Make the base gemspec OS-independent and add overlays**
|
|
106
|
+
|
|
107
|
+
Remove the `File::ALT_SEPARATOR`, `RbConfig`, and `RUBY_PLATFORM` conditional runtime dependency logic from `net-ping.gemspec`; leave only shared metadata and development dependencies.
|
|
108
|
+
|
|
109
|
+
Create `net-ping-universal-linux.gemspec`:
|
|
110
|
+
|
|
111
|
+
```ruby
|
|
112
|
+
spec = Gem::Specification.load('net-ping.gemspec')
|
|
113
|
+
spec.platform = Gem::Platform.new(['universal', 'linux'])
|
|
114
|
+
spec.add_dependency('cap2', '>= 0.2.2')
|
|
115
|
+
spec
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Create `net-ping-universal-mingw-ucrt.gemspec`:
|
|
119
|
+
|
|
120
|
+
```ruby
|
|
121
|
+
spec = Gem::Specification.load('net-ping.gemspec')
|
|
122
|
+
spec.platform = Gem::Platform.new(['universal', 'mingw-ucrt'])
|
|
123
|
+
spec.add_dependency('win32-security', '>= 0.2.0')
|
|
124
|
+
spec
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Use the project’s existing block-style `Gem::Specification.new` format for the base gemspec. Verify the installed RubyGems version accepts the two platform strings with `Gem::Platform.new`.
|
|
128
|
+
|
|
129
|
+
- [ ] **Step 4: Run the package-metadata test to verify it passes**
|
|
130
|
+
|
|
131
|
+
Run:
|
|
132
|
+
|
|
133
|
+
```sh
|
|
134
|
+
bundle exec ruby -Itest test/test_net_ping_gem_packaging.rb
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Expected: PASS; all three artifacts have the expected platform and exactly the expected runtime dependencies.
|
|
138
|
+
|
|
139
|
+
- [ ] **Step 5: Run the aggregate test suite**
|
|
140
|
+
|
|
141
|
+
Run:
|
|
142
|
+
|
|
143
|
+
```sh
|
|
144
|
+
bundle exec rake test
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Expected: PASS.
|
|
148
|
+
|
|
149
|
+
### Task 2: Make Rake build, validate, and install platform artifacts deterministically
|
|
150
|
+
|
|
151
|
+
**Files:**
|
|
152
|
+
- Modify: `Rakefile:6-29`
|
|
153
|
+
|
|
154
|
+
**Interfaces:**
|
|
155
|
+
- Consumes: the three gemspec paths from Task 1.
|
|
156
|
+
- Produces: `gem:create` builds all artifacts; `gem:check` aborts on invalid artifact metadata; `gem:install` installs the local platform’s specific artifact or the Ruby fallback.
|
|
157
|
+
|
|
158
|
+
- [ ] **Step 1: Add a failing artifact-validation command**
|
|
159
|
+
|
|
160
|
+
Add `gem:check` to the `gem` namespace. It must load the three expected gem files with `Gem::Package`, map each runtime dependency to `name => requirement.to_s`, and abort if the platform or dependency hash differs from:
|
|
161
|
+
|
|
162
|
+
```ruby
|
|
163
|
+
{
|
|
164
|
+
'ruby' => {},
|
|
165
|
+
'universal-linux' => {'cap2' => '>= 0.2.2'},
|
|
166
|
+
'universal-mingw-ucrt' => {'win32-security' => '>= 0.2.0'}
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Run it before changing `gem:create`:
|
|
171
|
+
|
|
172
|
+
```sh
|
|
173
|
+
bundle exec rake clean gem:create gem:check
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Expected: FAIL because `gem:create` still builds only one artifact.
|
|
177
|
+
|
|
178
|
+
- [ ] **Step 2: Implement deterministic specification loading and artifact creation**
|
|
179
|
+
|
|
180
|
+
Define the shared list once in `Rakefile`:
|
|
181
|
+
|
|
182
|
+
```ruby
|
|
183
|
+
GEMSPEC_FILES = %w[
|
|
184
|
+
net-ping.gemspec
|
|
185
|
+
net-ping-universal-linux.gemspec
|
|
186
|
+
net-ping-universal-mingw-ucrt.gemspec
|
|
187
|
+
].freeze
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Update `gem:create` to load all files before it builds any artifact:
|
|
191
|
+
|
|
192
|
+
```ruby
|
|
193
|
+
specifications = GEMSPEC_FILES.map { |path| Gem::Specification.load(path) }
|
|
194
|
+
specifications.each { |spec| Gem::Package.build(spec) }
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Retain the existing RubyGems pre-2.0 builder branch if support for it is still required. In either branch, load every specification before beginning the build loop.
|
|
198
|
+
|
|
199
|
+
Implement `gem:check` using `Gem::Package.new(file).spec`; use `abort` with the artifact filename and expected/actual values when a check fails.
|
|
200
|
+
|
|
201
|
+
Update `gem:install` to load the same specification list and select:
|
|
202
|
+
|
|
203
|
+
```ruby
|
|
204
|
+
specific = specifications.find do |spec|
|
|
205
|
+
spec.platform != Gem::Platform::RUBY && Gem::Platform.installable?(spec)
|
|
206
|
+
end
|
|
207
|
+
spec = specific || specifications.find { |item| item.platform == Gem::Platform::RUBY }
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Install `spec.file_name`, not `Dir['*.gem'].first`; abort when no Ruby fallback specification is found.
|
|
211
|
+
|
|
212
|
+
- [ ] **Step 3: Run artifact validation to verify it passes**
|
|
213
|
+
|
|
214
|
+
Run:
|
|
215
|
+
|
|
216
|
+
```sh
|
|
217
|
+
bundle exec rake gem:create gem:check
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Expected: PASS and creation of `net-ping-<version>.gem`,
|
|
221
|
+
`net-ping-<version>-universal-linux.gem`, and
|
|
222
|
+
`net-ping-<version>-universal-mingw-ucrt.gem`.
|
|
223
|
+
|
|
224
|
+
- [ ] **Step 4: Verify local artifact selection**
|
|
225
|
+
|
|
226
|
+
Run:
|
|
227
|
+
|
|
228
|
+
```sh
|
|
229
|
+
bundle exec rake gem:install
|
|
230
|
+
gem specification net-ping platform
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Expected on Linux: `universal-linux`; on Windows: `universal-mingw-ucrt`; on
|
|
234
|
+
other platforms: `ruby`.
|
|
235
|
+
|
|
236
|
+
- [ ] **Step 5: Re-run tests**
|
|
237
|
+
|
|
238
|
+
Run:
|
|
239
|
+
|
|
240
|
+
```sh
|
|
241
|
+
bundle exec rake test
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
Expected: PASS.
|
|
245
|
+
|
|
246
|
+
### Task 3: Enforce packaging in CI and document the behavior
|
|
247
|
+
|
|
248
|
+
**Files:**
|
|
249
|
+
- Modify: `.github/workflows/test.yml:19-28`
|
|
250
|
+
- Modify: `README.md:4-15`
|
|
251
|
+
- Modify: `CHANGES:1-13`
|
|
252
|
+
|
|
253
|
+
**Interfaces:**
|
|
254
|
+
- Consumes: `gem:create` and `gem:check` from Task 2.
|
|
255
|
+
- Produces: CI verification on both matrix operating systems and accurate end-user dependency documentation.
|
|
256
|
+
|
|
257
|
+
- [ ] **Step 1: Add the CI packaging verification step**
|
|
258
|
+
|
|
259
|
+
After the existing `bundle exec rake test` step, add:
|
|
260
|
+
|
|
261
|
+
```yaml
|
|
262
|
+
- run: bundle exec rake gem:create gem:check
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
Do not add RubyGems credentials, publishing actions, or tag triggers.
|
|
266
|
+
|
|
267
|
+
- [ ] **Step 2: Document platform-specific dependency resolution**
|
|
268
|
+
|
|
269
|
+
Replace the prerequisite list’s unconditional `win32-security (MS Windows
|
|
270
|
+
only)` wording with text that states RubyGems installs `win32-security` from
|
|
271
|
+
the Windows artifact and `cap2` from the Linux artifact when installing
|
|
272
|
+
`net-ping`. Keep the installation command `gem install net-ping`.
|
|
273
|
+
|
|
274
|
+
At the beginning of `CHANGES`, add:
|
|
275
|
+
|
|
276
|
+
```text
|
|
277
|
+
== Next Release
|
|
278
|
+
* Publish platform-specific gem metadata so Linux installs cap2 and current
|
|
279
|
+
Windows RubyInstaller installs win32-security for ICMP support.
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
- [ ] **Step 3: Run targeted packaging and full test verification**
|
|
283
|
+
|
|
284
|
+
Run:
|
|
285
|
+
|
|
286
|
+
```sh
|
|
287
|
+
bundle exec rake gem:create gem:check
|
|
288
|
+
bundle exec rake test
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
Expected: both commands PASS.
|
|
292
|
+
|
|
293
|
+
- [ ] **Step 4: Inspect the final diff without committing**
|
|
294
|
+
|
|
295
|
+
Run:
|
|
296
|
+
|
|
297
|
+
```sh
|
|
298
|
+
git diff --check
|
|
299
|
+
git diff -- net-ping.gemspec net-ping-universal-linux.gemspec \
|
|
300
|
+
net-ping-universal-mingw-ucrt.gemspec Rakefile \
|
|
301
|
+
test/test_net_ping_gem_packaging.rb test/test_net_ping.rb \
|
|
302
|
+
.github/workflows/test.yml README.md CHANGES
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
Expected: only the planned packaging, CI, test, and documentation changes;
|
|
306
|
+
no whitespace errors and no git commit.
|
|
307
|
+
|
|
308
|
+
## Plan Self-Review
|
|
309
|
+
|
|
310
|
+
- **Spec coverage:** Task 1 creates the three required artifacts and assigns
|
|
311
|
+
their dependencies; Task 2 validates metadata and selects a local artifact;
|
|
312
|
+
Task 3 runs validation in CI and documents the behavior. CI publishing,
|
|
313
|
+
legacy `mingw32`, and runtime protocol changes are excluded.
|
|
314
|
+
- **Placeholder scan:** No unresolved item, unspecified test, or ambiguous
|
|
315
|
+
implementation step remains.
|
|
316
|
+
- **Consistency:** The gemspec filenames, platform names, dependency
|
|
317
|
+
versions, and Rake task names are identical across all tasks.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Platform-specific gem dependencies
|
|
2
|
+
|
|
3
|
+
## Goal
|
|
4
|
+
|
|
5
|
+
Resolve issue #31 by publishing platform-specific `net-ping` gems whose
|
|
6
|
+
runtime dependencies accurately describe the requirements for ICMP support.
|
|
7
|
+
The solution also corrects the equivalent Linux `cap2` metadata omission.
|
|
8
|
+
|
|
9
|
+
## Scope
|
|
10
|
+
|
|
11
|
+
The release produces three gems with the same name and version:
|
|
12
|
+
|
|
13
|
+
| Gem platform | Additional runtime dependency |
|
|
14
|
+
| --- | --- |
|
|
15
|
+
| `ruby` | None |
|
|
16
|
+
| `universal-linux` | `cap2 (>= 0.2.2)` |
|
|
17
|
+
| `universal-mingw-ucrt` | `win32-security (>= 0.2.0)` |
|
|
18
|
+
|
|
19
|
+
Only the current RubyInstaller `mingw-ucrt` platform is supported for Windows.
|
|
20
|
+
Legacy `mingw32` is out of scope.
|
|
21
|
+
|
|
22
|
+
The CI workflow builds and validates these gems, but does not publish them.
|
|
23
|
+
The existing release process remains responsible for pushing all three files
|
|
24
|
+
to RubyGems.
|
|
25
|
+
|
|
26
|
+
## Design
|
|
27
|
+
|
|
28
|
+
`net-ping.gemspec` becomes the OS-independent Ruby gemspec. It must not
|
|
29
|
+
inspect the host OS or add OS-specific runtime dependencies.
|
|
30
|
+
|
|
31
|
+
`net-ping-universal-linux.gemspec` loads the base specification, changes its
|
|
32
|
+
platform to `universal-linux`, and adds `cap2`. The platform is intentionally
|
|
33
|
+
CPU-independent so RubyGems can select it for supported Linux CPU variants.
|
|
34
|
+
|
|
35
|
+
`net-ping-universal-mingw-ucrt.gemspec` loads the same base specification,
|
|
36
|
+
changes its platform to `universal-mingw-ucrt`, and adds `win32-security`.
|
|
37
|
+
|
|
38
|
+
The Rake gem namespace explicitly enumerates the three gemspecs. `gem:create`
|
|
39
|
+
cleans old gem artifacts and builds all three. `gem:install` selects the
|
|
40
|
+
specific generated specification compatible with the local platform, falling
|
|
41
|
+
back to the Ruby specification when no platform-specific specification
|
|
42
|
+
matches, then installs its artifact.
|
|
43
|
+
|
|
44
|
+
## Verification
|
|
45
|
+
|
|
46
|
+
Add `gem:check`, which reads each generated gem through RubyGems and fails
|
|
47
|
+
when its platform or runtime dependencies differ from this specification:
|
|
48
|
+
|
|
49
|
+
- Ruby gem: platform `ruby`; neither `cap2` nor `win32-security`.
|
|
50
|
+
- Linux gem: platform `universal-linux`; includes `cap2`.
|
|
51
|
+
- Windows gem: platform `universal-mingw-ucrt`; includes `win32-security`.
|
|
52
|
+
|
|
53
|
+
The existing GitHub Actions matrix continues to run the test suite. It also
|
|
54
|
+
runs `gem:create` and `gem:check` on both Ubuntu and Windows. A missing,
|
|
55
|
+
malformed, or incorrectly attributed dependency causes the job to fail.
|
|
56
|
+
|
|
57
|
+
## Documentation
|
|
58
|
+
|
|
59
|
+
Update the prerequisite/install documentation to state that RubyGems chooses
|
|
60
|
+
the platform-specific package and installs the Linux or Windows ICMP
|
|
61
|
+
dependency automatically.
|
|
62
|
+
|
|
63
|
+
Add a `CHANGES` entry describing the corrected platform-specific dependency
|
|
64
|
+
metadata.
|
|
65
|
+
|
|
66
|
+
## Non-goals
|
|
67
|
+
|
|
68
|
+
- Publishing gems from CI.
|
|
69
|
+
- Supporting legacy `mingw32`.
|
|
70
|
+
- Changing ICMP runtime behavior.
|
|
71
|
+
- Altering non-ICMP protocol implementations or tests.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
########################################################################
|
|
2
|
+
# example_pingexternal.rb
|
|
3
|
+
#
|
|
4
|
+
# A short sample program demonstrating an external ping. You can run
|
|
5
|
+
# this program via the example:external task. Modify as you see fit.
|
|
6
|
+
########################################################################
|
|
7
|
+
require 'net/ping'
|
|
8
|
+
|
|
9
|
+
good = 'www.rubyforge.org'
|
|
10
|
+
bad = 'foo.bar.baz'
|
|
11
|
+
|
|
12
|
+
p1 = Net::Ping::External.new(good)
|
|
13
|
+
p p1.ping?
|
|
14
|
+
|
|
15
|
+
p2 = Net::Ping::External.new(bad)
|
|
16
|
+
p p2.ping?
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
########################################################################
|
|
2
|
+
# example_pinghttp.rb
|
|
3
|
+
#
|
|
4
|
+
# A short sample program demonstrating an http ping. You can run
|
|
5
|
+
# this program via the example:http task. Modify as you see fit.
|
|
6
|
+
########################################################################
|
|
7
|
+
require 'net/ping'
|
|
8
|
+
|
|
9
|
+
good = 'http://www.google.com/index.html'
|
|
10
|
+
bad = 'http://www.ruby-lang.org/index.html'
|
|
11
|
+
|
|
12
|
+
puts "== Good ping, no redirect"
|
|
13
|
+
|
|
14
|
+
p1 = Net::Ping::HTTP.new(good)
|
|
15
|
+
p p1.ping?
|
|
16
|
+
|
|
17
|
+
puts "== Bad ping"
|
|
18
|
+
|
|
19
|
+
p2 = Net::Ping::HTTP.new(bad)
|
|
20
|
+
p p2.ping?
|
|
21
|
+
p p2.warning
|
|
22
|
+
p p2.exception
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
########################################################################
|
|
2
|
+
# example_pingtcp.rb
|
|
3
|
+
#
|
|
4
|
+
# A short sample program demonstrating a tcp ping. You can run
|
|
5
|
+
# this program via the example:tcp task. Modify as you see fit.
|
|
6
|
+
########################################################################
|
|
7
|
+
require 'net/ping'
|
|
8
|
+
|
|
9
|
+
good = 'www.google.com'
|
|
10
|
+
bad = 'foo.bar.baz'
|
|
11
|
+
|
|
12
|
+
p1 = Net::Ping::TCP.new(good, 'http')
|
|
13
|
+
p p1.ping?
|
|
14
|
+
|
|
15
|
+
p2 = Net::Ping::TCP.new(bad)
|
|
16
|
+
p p2.ping?
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
########################################################################
|
|
2
|
+
# example_pingudp.rb
|
|
3
|
+
#
|
|
4
|
+
# A short sample program demonstrating a UDP ping. You can run
|
|
5
|
+
# this program via the example:udp task. Modify as you see fit.
|
|
6
|
+
########################################################################
|
|
7
|
+
require 'net/ping'
|
|
8
|
+
|
|
9
|
+
host = 'www.google.com'
|
|
10
|
+
|
|
11
|
+
u = Net::Ping::UDP.new(host)
|
|
12
|
+
p u.ping?
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
require 'open3'
|
|
2
|
+
require 'rbconfig'
|
|
3
|
+
|
|
4
|
+
require File.join(File.dirname(__FILE__), 'ping')
|
|
5
|
+
|
|
6
|
+
# The Net module serves as a namespace only.
|
|
7
|
+
module Net
|
|
8
|
+
|
|
9
|
+
# The Ping::External class encapsulates methods for external (system) pings.
|
|
10
|
+
class Ping::External < Ping
|
|
11
|
+
# Pings the host using your system's ping utility and checks for any
|
|
12
|
+
# errors or warnings. Returns true if successful, or false if not.
|
|
13
|
+
#
|
|
14
|
+
# If the ping failed then the Ping::External#exception method should
|
|
15
|
+
# contain a string indicating what went wrong. If the ping succeeded then
|
|
16
|
+
# the Ping::External#warning method may or may not contain a value.
|
|
17
|
+
#
|
|
18
|
+
def ping(host = @host, count = 1, interval = 1, timeout = @timeout)
|
|
19
|
+
|
|
20
|
+
raise "Count must be an integer" unless count.is_a? Integer
|
|
21
|
+
raise "Timeout must be a number" unless timeout.is_a? Numeric
|
|
22
|
+
|
|
23
|
+
unless interval.is_a?(Numeric) && interval >= 0.2
|
|
24
|
+
raise "Interval must be a decimal greater than or equal to 0.2"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
super(host)
|
|
28
|
+
|
|
29
|
+
pcmd = ['ping']
|
|
30
|
+
bool = false
|
|
31
|
+
|
|
32
|
+
case RbConfig::CONFIG['host_os']
|
|
33
|
+
when /linux/i
|
|
34
|
+
pcmd += ['-c', count.to_s, '-W', timeout.to_s, host]
|
|
35
|
+
pcmd += ['-i', interval.to_s] unless RbConfig::CONFIG['busybox']
|
|
36
|
+
when /aix/i
|
|
37
|
+
pcmd += ['-c', count.to_s, '-w', timeout.to_s, host]
|
|
38
|
+
when /bsd|osx|mach|darwin/i
|
|
39
|
+
pcmd += ['-c', count.to_s, '-t', timeout.to_s, host]
|
|
40
|
+
when /solaris|sunos/i
|
|
41
|
+
pcmd += [host, timeout.to_s]
|
|
42
|
+
when /hpux/i
|
|
43
|
+
pcmd += [host, "-n#{count.to_s}", '-m', timeout.to_s]
|
|
44
|
+
when /win32|windows|msdos|mswin|cygwin|mingw/i
|
|
45
|
+
pcmd += ['-n', count.to_s, '-w', (timeout * 1000).to_s, host]
|
|
46
|
+
else
|
|
47
|
+
pcmd += [host]
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
start_time = Time.now
|
|
51
|
+
|
|
52
|
+
begin
|
|
53
|
+
err = nil
|
|
54
|
+
|
|
55
|
+
Open3.popen3(*pcmd) do |stdin, stdout, stderr, thread|
|
|
56
|
+
stdin.close
|
|
57
|
+
err = stderr.gets # Can't chomp yet, might be nil
|
|
58
|
+
|
|
59
|
+
case thread.value.exitstatus
|
|
60
|
+
when 0
|
|
61
|
+
info = stdout.read
|
|
62
|
+
if info =~ /unreachable/ix # Windows
|
|
63
|
+
bool = false
|
|
64
|
+
@exception = "host unreachable"
|
|
65
|
+
else
|
|
66
|
+
bool = true # Success, at least one response.
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
if err && (err =~ /warning/i)
|
|
70
|
+
@warning = err.chomp
|
|
71
|
+
end
|
|
72
|
+
when 2
|
|
73
|
+
bool = false # Transmission successful, no response.
|
|
74
|
+
@exception = err.chomp if err
|
|
75
|
+
else
|
|
76
|
+
bool = false # An error occurred
|
|
77
|
+
if err
|
|
78
|
+
@exception = err.chomp
|
|
79
|
+
else
|
|
80
|
+
stdout.each_line do |line|
|
|
81
|
+
if line =~ /(timed out|could not find host|packet loss)/i
|
|
82
|
+
@exception = line.chomp
|
|
83
|
+
break
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
rescue Exception => error
|
|
90
|
+
@exception = error.message
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# There is no duration if the ping failed
|
|
94
|
+
@duration = Time.now - start_time if bool
|
|
95
|
+
|
|
96
|
+
bool
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def ping6(host = @host, count = 1, interval = 1, timeout = @timeout)
|
|
100
|
+
|
|
101
|
+
raise "Count must be an integer" unless count.is_a? Integer
|
|
102
|
+
raise "Timeout must be a number" unless timeout.is_a? Numeric
|
|
103
|
+
|
|
104
|
+
unless interval.is_a?(Numeric) && interval >= 0.2
|
|
105
|
+
raise "Interval must be a decimal greater than or equal to 0.2"
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
super(host)
|
|
109
|
+
|
|
110
|
+
pcmd = ['ping6']
|
|
111
|
+
bool = false
|
|
112
|
+
|
|
113
|
+
case RbConfig::CONFIG['host_os']
|
|
114
|
+
when /linux/i
|
|
115
|
+
pcmd += ['-c', count.to_s, '-W', timeout.to_s, host]
|
|
116
|
+
pcmd += ['-i', interval.to_s] unless RbConfig::CONFIG['busybox']
|
|
117
|
+
when /aix/i
|
|
118
|
+
pcmd += ['-c', count.to_s, '-w', timeout.to_s, host]
|
|
119
|
+
when /freebsd/i
|
|
120
|
+
pcmd += ['-c', count.to_s, '-x', timeout.to_s, host]
|
|
121
|
+
when /bsd|osx|mach|darwin/i
|
|
122
|
+
pcmd += ['-c', count.to_s, '-i', interval.to_s, host]
|
|
123
|
+
when /solaris|sunos/i
|
|
124
|
+
pcmd += [host, timeout.to_s]
|
|
125
|
+
when /hpux/i
|
|
126
|
+
pcmd += [host, "-n#{count.to_s}", '-m', timeout.to_s]
|
|
127
|
+
when /win32|windows|msdos|mswin|cygwin|mingw/i
|
|
128
|
+
pcmd += ['-n', count.to_s, '-w', (timeout * 1000).to_s, host]
|
|
129
|
+
else
|
|
130
|
+
pcmd += [host]
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
start_time = Time.now
|
|
134
|
+
|
|
135
|
+
begin
|
|
136
|
+
err = nil
|
|
137
|
+
|
|
138
|
+
Open3.popen3(*pcmd) do |stdin, stdout, stderr, thread|
|
|
139
|
+
stdin.close
|
|
140
|
+
err = stderr.gets # Can't chomp yet, might be nil
|
|
141
|
+
|
|
142
|
+
case thread.value.exitstatus
|
|
143
|
+
when 0
|
|
144
|
+
info = stdout.read
|
|
145
|
+
if info =~ /unreachable/ix # Windows
|
|
146
|
+
bool = false
|
|
147
|
+
@exception = "host unreachable"
|
|
148
|
+
else
|
|
149
|
+
bool = true # Success, at least one response.
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
if err && (err =~ /warning/i)
|
|
153
|
+
@warning = err.chomp
|
|
154
|
+
end
|
|
155
|
+
when 2
|
|
156
|
+
bool = false # Transmission successful, no response.
|
|
157
|
+
@exception = err.chomp if err
|
|
158
|
+
else
|
|
159
|
+
bool = false # An error occurred
|
|
160
|
+
if err
|
|
161
|
+
@exception = err.chomp
|
|
162
|
+
else
|
|
163
|
+
stdout.each_line do |line|
|
|
164
|
+
if line =~ /(timed out|could not find host|packet loss)/i
|
|
165
|
+
@exception = line.chomp
|
|
166
|
+
break
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
rescue Exception => error
|
|
173
|
+
@exception = error.message
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# There is no duration if the ping failed
|
|
177
|
+
@duration = Time.now - start_time if bool
|
|
178
|
+
|
|
179
|
+
bool
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
alias ping? ping
|
|
183
|
+
alias pingecho ping
|
|
184
|
+
end
|
|
185
|
+
end
|