random-port 0.7.6 → 0.8.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/Gemfile +5 -2
- data/Gemfile.lock +40 -22
- data/LICENSE.txt +1 -1
- data/LICENSES/MIT.txt +1 -1
- data/README.md +10 -1
- data/Rakefile +2 -1
- data/lib/random-port/module.rb +11 -3
- data/lib/random-port/pool.rb +44 -31
- data/lib/random-port.rb +1 -1
- data/random-port.gemspec +2 -2
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: dd90fdffc75dd2489cab29b75ddadb118d7399fc51acf86d0c7588cff3656bef
|
|
4
|
+
data.tar.gz: f8f40a67dd0fd7daf6fd7ad67e9272035a587b96dbaf581777f659a3d1779bd3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9b076ebfe2d5b5ec19a2252783e2e1d01050feebb698d5ef1066aefbb230708617fabba95f9a363b3c6dc03204ce8eb7de92d1d902c572374f69d7d1c979e9d5
|
|
7
|
+
data.tar.gz: c6f56a56d9b510904a982a78ed9e2cab315cdd8d5e21a0587ac3aae10c9da9e1435ebbf1bd888d92a0f34930b3032f99febcaae593268988685ea060ba2db70c
|
data/Gemfile
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2018-
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2018-2026 Yegor Bugayenko
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
|
5
5
|
|
|
6
6
|
source 'https://rubygems.org'
|
|
7
7
|
gemspec
|
|
8
8
|
|
|
9
|
-
gem 'minitest', '~>
|
|
9
|
+
gem 'minitest', '~>6.0', require: false
|
|
10
|
+
gem 'minitest-mock', '~>5.27', require: false
|
|
11
|
+
gem 'minitest-reporters', '~>1.7', require: false
|
|
10
12
|
gem 'qbash', '~>0.2', require: false
|
|
11
13
|
gem 'rake', '~>13.2', require: false
|
|
12
14
|
gem 'rubocop', '~>1.75', require: false
|
|
@@ -15,5 +17,6 @@ gem 'rubocop-performance', '~>1.25', require: false
|
|
|
15
17
|
gem 'rubocop-rake', '~>0.7', require: false
|
|
16
18
|
gem 'rubocop-rspec', '~> 3.7', require: false
|
|
17
19
|
gem 'simplecov', '~>0.22', require: false
|
|
20
|
+
gem 'simplecov-cobertura', '~>3.0', require: false
|
|
18
21
|
gem 'threads', '~>0.4', require: false
|
|
19
22
|
gem 'yard', '~>0.9', require: false
|
data/Gemfile.lock
CHANGED
|
@@ -7,35 +7,47 @@ PATH
|
|
|
7
7
|
GEM
|
|
8
8
|
remote: https://rubygems.org/
|
|
9
9
|
specs:
|
|
10
|
+
ansi (1.5.0)
|
|
10
11
|
ast (2.4.3)
|
|
11
12
|
backtrace (0.4.1)
|
|
12
|
-
|
|
13
|
+
builder (3.3.0)
|
|
14
|
+
concurrent-ruby (1.3.6)
|
|
13
15
|
docile (1.4.1)
|
|
14
|
-
elapsed (0.2.
|
|
16
|
+
elapsed (0.2.2)
|
|
15
17
|
loog (~> 0.6)
|
|
16
18
|
tago (~> 0.1)
|
|
17
|
-
|
|
19
|
+
ellipsized (0.3.0)
|
|
20
|
+
json (2.18.0)
|
|
18
21
|
language_server-protocol (3.17.0.5)
|
|
19
22
|
lint_roller (1.1.0)
|
|
20
23
|
logger (1.7.0)
|
|
21
|
-
loog (0.
|
|
24
|
+
loog (0.7.2)
|
|
25
|
+
ellipsized
|
|
22
26
|
logger (~> 1.0)
|
|
23
|
-
minitest (
|
|
27
|
+
minitest (6.0.1)
|
|
28
|
+
prism (~> 1.5)
|
|
29
|
+
minitest-mock (5.27.0)
|
|
30
|
+
minitest-reporters (1.7.1)
|
|
31
|
+
ansi
|
|
32
|
+
builder
|
|
33
|
+
minitest (>= 5.0)
|
|
34
|
+
ruby-progressbar
|
|
24
35
|
parallel (1.27.0)
|
|
25
|
-
parser (3.3.
|
|
36
|
+
parser (3.3.10.1)
|
|
26
37
|
ast (~> 2.4.1)
|
|
27
38
|
racc
|
|
28
|
-
prism (1.
|
|
29
|
-
qbash (0.
|
|
39
|
+
prism (1.8.0)
|
|
40
|
+
qbash (0.7.2)
|
|
30
41
|
backtrace (> 0)
|
|
31
42
|
elapsed (> 0)
|
|
32
43
|
loog (> 0)
|
|
33
44
|
tago (> 0)
|
|
34
45
|
racc (1.8.1)
|
|
35
46
|
rainbow (3.1.1)
|
|
36
|
-
rake (13.3.
|
|
47
|
+
rake (13.3.1)
|
|
37
48
|
regexp_parser (2.11.3)
|
|
38
|
-
|
|
49
|
+
rexml (3.4.4)
|
|
50
|
+
rubocop (1.84.1)
|
|
39
51
|
json (~> 2.3)
|
|
40
52
|
language_server-protocol (~> 3.17.0.2)
|
|
41
53
|
lint_roller (~> 1.1.0)
|
|
@@ -43,41 +55,44 @@ GEM
|
|
|
43
55
|
parser (>= 3.3.0.2)
|
|
44
56
|
rainbow (>= 2.2.2, < 4.0)
|
|
45
57
|
regexp_parser (>= 2.9.3, < 3.0)
|
|
46
|
-
rubocop-ast (>= 1.
|
|
58
|
+
rubocop-ast (>= 1.49.0, < 2.0)
|
|
47
59
|
ruby-progressbar (~> 1.7)
|
|
48
60
|
unicode-display_width (>= 2.4.0, < 4.0)
|
|
49
|
-
rubocop-ast (1.
|
|
61
|
+
rubocop-ast (1.49.0)
|
|
50
62
|
parser (>= 3.3.7.2)
|
|
51
|
-
prism (~> 1.
|
|
63
|
+
prism (~> 1.7)
|
|
52
64
|
rubocop-minitest (0.38.2)
|
|
53
65
|
lint_roller (~> 1.1)
|
|
54
66
|
rubocop (>= 1.75.0, < 2.0)
|
|
55
67
|
rubocop-ast (>= 1.38.0, < 2.0)
|
|
56
|
-
rubocop-performance (1.26.
|
|
68
|
+
rubocop-performance (1.26.1)
|
|
57
69
|
lint_roller (~> 1.1)
|
|
58
70
|
rubocop (>= 1.75.0, < 2.0)
|
|
59
|
-
rubocop-ast (>= 1.
|
|
71
|
+
rubocop-ast (>= 1.47.1, < 2.0)
|
|
60
72
|
rubocop-rake (0.7.1)
|
|
61
73
|
lint_roller (~> 1.1)
|
|
62
74
|
rubocop (>= 1.72.1)
|
|
63
|
-
rubocop-rspec (3.
|
|
75
|
+
rubocop-rspec (3.9.0)
|
|
64
76
|
lint_roller (~> 1.1)
|
|
65
|
-
rubocop (~> 1.
|
|
77
|
+
rubocop (~> 1.81)
|
|
66
78
|
ruby-progressbar (1.13.0)
|
|
67
79
|
simplecov (0.22.0)
|
|
68
80
|
docile (~> 1.1)
|
|
69
81
|
simplecov-html (~> 0.11)
|
|
70
82
|
simplecov_json_formatter (~> 0.1)
|
|
83
|
+
simplecov-cobertura (3.1.0)
|
|
84
|
+
rexml
|
|
85
|
+
simplecov (~> 0.19)
|
|
71
86
|
simplecov-html (0.13.2)
|
|
72
87
|
simplecov_json_formatter (0.1.4)
|
|
73
|
-
tago (0.
|
|
74
|
-
threads (0.
|
|
88
|
+
tago (0.7.0)
|
|
89
|
+
threads (0.5.0)
|
|
75
90
|
backtrace (~> 0)
|
|
76
91
|
concurrent-ruby (~> 1.0)
|
|
77
92
|
unicode-display_width (3.2.0)
|
|
78
93
|
unicode-emoji (~> 4.1)
|
|
79
|
-
unicode-emoji (4.
|
|
80
|
-
yard (0.9.
|
|
94
|
+
unicode-emoji (4.2.0)
|
|
95
|
+
yard (0.9.38)
|
|
81
96
|
|
|
82
97
|
PLATFORMS
|
|
83
98
|
arm64-darwin-22
|
|
@@ -87,7 +102,9 @@ PLATFORMS
|
|
|
87
102
|
x86_64-linux
|
|
88
103
|
|
|
89
104
|
DEPENDENCIES
|
|
90
|
-
minitest (~>
|
|
105
|
+
minitest (~> 6.0)
|
|
106
|
+
minitest-mock (~> 5.27)
|
|
107
|
+
minitest-reporters (~> 1.7)
|
|
91
108
|
qbash (~> 0.2)
|
|
92
109
|
rake (~> 13.2)
|
|
93
110
|
random-port!
|
|
@@ -97,6 +114,7 @@ DEPENDENCIES
|
|
|
97
114
|
rubocop-rake (~> 0.7)
|
|
98
115
|
rubocop-rspec (~> 3.7)
|
|
99
116
|
simplecov (~> 0.22)
|
|
117
|
+
simplecov-cobertura (~> 3.0)
|
|
100
118
|
threads (~> 0.4)
|
|
101
119
|
yard (~> 0.9)
|
|
102
120
|
|
data/LICENSE.txt
CHANGED
data/LICENSES/MIT.txt
CHANGED
data/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
[](https://rubydoc.info/github/yegor256/random-port/master/frames)
|
|
10
10
|
[](https://github.com/yegor256/random-port/blob/master/LICENSE.txt)
|
|
11
11
|
[](https://codecov.io/github/yegor256/random-port?branch=master)
|
|
12
|
-
[](https://hitsofcode.com/view/github/random-port
|
|
12
|
+
[](https://hitsofcode.com/view/github/yegor256/random-port)
|
|
13
13
|
|
|
14
14
|
It's a simple Ruby gem to get a random TCP port.
|
|
15
15
|
|
|
@@ -52,6 +52,15 @@ RandomPort::Pool::SINGLETON.acquire do |port|
|
|
|
52
52
|
end
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
+
Or use shortened version, all methods called in `RandomPort`
|
|
56
|
+
will be delegated to `Pool::SINGLETON`:
|
|
57
|
+
|
|
58
|
+
```ruby
|
|
59
|
+
RandomPort.acquire do |port|
|
|
60
|
+
# Use it here...
|
|
61
|
+
end
|
|
62
|
+
```
|
|
63
|
+
|
|
55
64
|
The pool is thread-safe by default.
|
|
56
65
|
You can configure it to be
|
|
57
66
|
not-thread-safe, using optional `sync` argument of the constructor.
|
data/Rakefile
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2018-
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2018-2026 Yegor Bugayenko
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
|
5
5
|
|
|
6
6
|
require 'rubygems'
|
|
@@ -37,4 +37,5 @@ require 'yard'
|
|
|
37
37
|
desc 'Build Yard documentation'
|
|
38
38
|
YARD::Rake::YardocTask.new do |t|
|
|
39
39
|
t.files = ['lib/**/*.rb']
|
|
40
|
+
t.options = ['--fail-on-warning']
|
|
40
41
|
end
|
data/lib/random-port/module.rb
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2018-
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2018-2026 Yegor Bugayenko
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
|
5
5
|
|
|
6
|
-
#
|
|
6
|
+
# Main module that contains all RandomPort classes and utilities.
|
|
7
|
+
#
|
|
8
|
+
# This module provides a simple way to acquire random TCP ports
|
|
9
|
+
# that are guaranteed to be available for use. It includes a Pool
|
|
10
|
+
# class that manages port allocation and ensures thread safety.
|
|
7
11
|
#
|
|
8
12
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
9
|
-
# Copyright:: Copyright (c) 2018-
|
|
13
|
+
# Copyright:: Copyright (c) 2018-2026 Yegor Bugayenko
|
|
10
14
|
# License:: MIT
|
|
11
15
|
module RandomPort
|
|
16
|
+
extend Forwardable
|
|
17
|
+
|
|
18
|
+
def_delegators :'RandomPort::Pool::SINGLETON', :acquire, :release, :count, :size, :empty?
|
|
19
|
+
module_function :acquire, :release, :count, :size, :empty?
|
|
12
20
|
end
|
data/lib/random-port/pool.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2018-
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2018-2026 Yegor Bugayenko
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
|
5
5
|
|
|
6
6
|
require 'monitor'
|
|
@@ -8,7 +8,7 @@ require 'socket'
|
|
|
8
8
|
require 'tago'
|
|
9
9
|
require_relative 'module'
|
|
10
10
|
|
|
11
|
-
# Pool of
|
|
11
|
+
# Pool of TCP ports.
|
|
12
12
|
#
|
|
13
13
|
# Use it like this:
|
|
14
14
|
#
|
|
@@ -17,26 +17,27 @@ require_relative 'module'
|
|
|
17
17
|
# # to the pool afterwards.
|
|
18
18
|
# end
|
|
19
19
|
#
|
|
20
|
-
# You can specify the maximum
|
|
21
|
-
# If more
|
|
20
|
+
# You can specify the maximum number of ports to acquire using +limit+.
|
|
21
|
+
# If more acquisition requests arrive, an exception will be raised.
|
|
22
22
|
#
|
|
23
|
-
# The class is thread-safe
|
|
24
|
-
#
|
|
23
|
+
# The class is thread-safe by default. You can configure it to be
|
|
24
|
+
# non-thread-safe using the optional +sync+ argument of the constructor,
|
|
25
25
|
# passing <tt>FALSE</tt>.
|
|
26
26
|
#
|
|
27
27
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
28
|
-
# Copyright:: Copyright (c) 2018-
|
|
28
|
+
# Copyright:: Copyright (c) 2018-2026 Yegor Bugayenko
|
|
29
29
|
# License:: MIT
|
|
30
30
|
class RandomPort::Pool
|
|
31
|
-
#
|
|
31
|
+
# Raised when a port cannot be acquired within the timeout period.
|
|
32
32
|
class Timeout < StandardError; end
|
|
33
33
|
|
|
34
|
+
# @return [Integer] The maximum number of ports that can be acquired from this pool
|
|
34
35
|
attr_reader :limit
|
|
35
36
|
|
|
36
|
-
#
|
|
37
|
-
# @param [Boolean] sync Set
|
|
38
|
-
# @param [Integer] limit
|
|
39
|
-
# @param [Integer] start The
|
|
37
|
+
# Constructor.
|
|
38
|
+
# @param [Boolean] sync Set to FALSE if you want this pool to be non-thread-safe
|
|
39
|
+
# @param [Integer] limit The maximum number of ports that can be acquired from the pool
|
|
40
|
+
# @param [Integer] start The first port number to try when acquiring
|
|
40
41
|
def initialize(sync: true, limit: 65_536, start: 1025)
|
|
41
42
|
@ports = []
|
|
42
43
|
@sync = sync
|
|
@@ -45,27 +46,33 @@ class RandomPort::Pool
|
|
|
45
46
|
@next = start
|
|
46
47
|
end
|
|
47
48
|
|
|
48
|
-
# Application
|
|
49
|
+
# Application-wide singleton pool of ports.
|
|
49
50
|
SINGLETON = RandomPort::Pool.new
|
|
50
51
|
|
|
51
|
-
#
|
|
52
|
+
# Returns the number of ports currently acquired from the pool.
|
|
53
|
+
# @return [Integer] The count of acquired ports
|
|
52
54
|
def count
|
|
53
55
|
@ports.count
|
|
54
56
|
end
|
|
55
57
|
alias size count
|
|
56
58
|
|
|
57
|
-
#
|
|
59
|
+
# Checks if the pool is empty (no ports are currently acquired).
|
|
60
|
+
# @return [Boolean] TRUE if no ports are acquired, FALSE otherwise
|
|
58
61
|
def empty?
|
|
59
62
|
@ports.empty?
|
|
60
63
|
end
|
|
61
64
|
|
|
62
|
-
#
|
|
65
|
+
# Acquires one or more available TCP ports from the pool.
|
|
63
66
|
#
|
|
64
67
|
# You can specify the number of ports to acquire. If it's more than one,
|
|
65
|
-
# an array will be returned.
|
|
68
|
+
# an array will be returned. If a block is given, the port(s) will be
|
|
69
|
+
# automatically released after the block execution.
|
|
66
70
|
#
|
|
67
|
-
#
|
|
68
|
-
#
|
|
71
|
+
# @param [Integer] total The number of ports to acquire (default: 1)
|
|
72
|
+
# @param [Integer] timeout The maximum seconds to wait for port availability
|
|
73
|
+
# @yield [Integer|Array<Integer>] The acquired port(s)
|
|
74
|
+
# @return [Integer|Array<Integer>] The acquired port(s) if no block given
|
|
75
|
+
# @raise [Timeout] If ports cannot be acquired within the timeout period
|
|
69
76
|
def acquire(total = 1, timeout: 4)
|
|
70
77
|
start = Time.now
|
|
71
78
|
attempt = 0
|
|
@@ -77,7 +84,7 @@ class RandomPort::Pool
|
|
|
77
84
|
"(#{@ports.size} already occupied) " \
|
|
78
85
|
"for #{total} port(s), after #{attempt} attempts in #{start.ago}"
|
|
79
86
|
end
|
|
80
|
-
attempt +=
|
|
87
|
+
attempt += 1
|
|
81
88
|
opts = safe { group(total) }
|
|
82
89
|
if opts.nil?
|
|
83
90
|
@next += 1
|
|
@@ -96,9 +103,9 @@ class RandomPort::Pool
|
|
|
96
103
|
end
|
|
97
104
|
end
|
|
98
105
|
|
|
99
|
-
#
|
|
100
|
-
# @param [Integer] port TCP port number to release
|
|
101
|
-
# @return nil
|
|
106
|
+
# Releases one or more ports back to the pool.
|
|
107
|
+
# @param [Integer|Array<Integer>] port The TCP port number(s) to release
|
|
108
|
+
# @return [nil]
|
|
102
109
|
def release(port)
|
|
103
110
|
safe do
|
|
104
111
|
if port.is_a?(Array)
|
|
@@ -111,12 +118,12 @@ class RandomPort::Pool
|
|
|
111
118
|
|
|
112
119
|
private
|
|
113
120
|
|
|
114
|
-
#
|
|
115
|
-
# @param [Integer] total
|
|
116
|
-
# @return [Array<Integer>|nil]
|
|
121
|
+
# Attempts to acquire a contiguous group of ports.
|
|
122
|
+
# @param [Integer] total The number of ports to acquire
|
|
123
|
+
# @return [Array<Integer>|nil] An array of port numbers if successful, nil otherwise
|
|
117
124
|
def group(total)
|
|
118
125
|
return nil if @ports.count + total > @limit
|
|
119
|
-
opts = Array.new(
|
|
126
|
+
opts = Array.new(total, 0)
|
|
120
127
|
begin
|
|
121
128
|
(0..(total - 1)).each do |i|
|
|
122
129
|
port = i.zero? ? @next : opts[i - 1] + 1
|
|
@@ -132,12 +139,15 @@ class RandomPort::Pool
|
|
|
132
139
|
opts
|
|
133
140
|
end
|
|
134
141
|
|
|
135
|
-
#
|
|
142
|
+
# Verifies that a specific TCP port is available for use.
|
|
136
143
|
#
|
|
137
|
-
#
|
|
144
|
+
# Attempts to bind to the port on various interfaces to ensure availability.
|
|
145
|
+
# If the port is occupied, this method raises an error (+Errno::EADDRINUSE+).
|
|
138
146
|
#
|
|
139
|
-
# @param [Integer] port
|
|
140
|
-
# @return [Integer] The same port number
|
|
147
|
+
# @param [Integer] port The port number to verify
|
|
148
|
+
# @return [Integer] The same port number if available
|
|
149
|
+
# @raise [Errno::EADDRINUSE] If the port is already in use
|
|
150
|
+
# @raise [SocketError] If there's a socket-related error
|
|
141
151
|
def take(port)
|
|
142
152
|
['127.0.0.1', '::1', '0.0.0.0', 'localhost'].each do |host|
|
|
143
153
|
begin
|
|
@@ -149,6 +159,9 @@ class RandomPort::Pool
|
|
|
149
159
|
port
|
|
150
160
|
end
|
|
151
161
|
|
|
162
|
+
# Executes a block of code with or without thread synchronization.
|
|
163
|
+
# @param block The block of code to execute
|
|
164
|
+
# @return The result of the block execution
|
|
152
165
|
def safe(&block)
|
|
153
166
|
if @sync
|
|
154
167
|
@monitor.synchronize(&block)
|
data/lib/random-port.rb
CHANGED
data/random-port.gemspec
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2018-
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2018-2026 Yegor Bugayenko
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
|
5
5
|
|
|
6
6
|
require 'English'
|
|
@@ -8,7 +8,7 @@ Gem::Specification.new do |s|
|
|
|
8
8
|
s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version=
|
|
9
9
|
s.required_ruby_version = '>=2.3'
|
|
10
10
|
s.name = 'random-port'
|
|
11
|
-
s.version = '0.
|
|
11
|
+
s.version = '0.8.0'
|
|
12
12
|
s.license = 'MIT'
|
|
13
13
|
s.summary = 'Random TCP port'
|
|
14
14
|
s.description = 'Reserves a random TCP port'
|