scmd 3.0.3 → 3.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -7
- data/Gemfile +5 -2
- data/README.md +1 -1
- data/bench/results.txt +32 -32
- data/bench/runner.rb +12 -10
- data/lib/scmd.rb +13 -13
- data/lib/scmd/command.rb +52 -37
- data/lib/scmd/command_spy.rb +22 -24
- data/lib/scmd/stored_commands.rb +10 -14
- data/lib/scmd/version.rb +3 -1
- data/scmd.gemspec +10 -7
- data/script/bench.rb +6 -7
- data/test/helper.rb +5 -3
- data/test/support/factory.rb +3 -2
- data/test/system/command_tests.rb +22 -27
- data/test/unit/command_spy_tests.rb +15 -17
- data/test/unit/command_tests.rb +8 -9
- data/test/unit/scmd_tests.rb +17 -22
- data/test/unit/stored_commands_tests.rb +6 -8
- data/tmp/.gitkeep +0 -0
- metadata +58 -44
- data/.gitignore +0 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
---
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 67125e428f1adb1fe7f302c3d0276a0384d5b41a74be0a40b52256043dc22632
|
4
|
+
data.tar.gz: c1dcc9b7152046ff0a5af224acc3c31f3124c423e818d048f8879310d2b9d645
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 74b33660ba6eab558d637797e1e03ec67607a0110be680822a22851fa7068d14b60a4d8f2fb1ff58ad1867f1c964bd34c619838efa7187c775eb491b6cef04c3
|
7
|
+
data.tar.gz: 17ea7892c22832d00868a8b9659ba8aabfc57b1c0c3df0a91e41a929d47af039ac40110b3a3b58a3688e09db61a42a531b68903a23f0ec4c8e978bec8deb3002
|
data/Gemfile
CHANGED
data/README.md
CHANGED
data/bench/results.txt
CHANGED
@@ -2,79 +2,79 @@ echo hi: 1 times
|
|
2
2
|
----------------
|
3
3
|
whysoslow? ..
|
4
4
|
|
5
|
-
mem @ start
|
6
|
-
mem @ finish
|
5
|
+
mem @ start 17 MB ??
|
6
|
+
mem @ finish 17 MB [31m+ 0 MB, 0%[0m
|
7
7
|
|
8
|
-
|
9
|
-
time
|
8
|
+
user system total real
|
9
|
+
time 0.5820000000000001 ms 0.5519999999999999 ms 3.786 ms 3.7030000000000003 ms
|
10
10
|
|
11
11
|
echo hi: 10 times
|
12
12
|
-----------------
|
13
13
|
whysoslow? ..
|
14
14
|
|
15
|
-
mem @ start
|
16
|
-
mem @ finish
|
15
|
+
mem @ start 17 MB ??
|
16
|
+
mem @ finish 17 MB [31m+ 0 MB, 0%[0m
|
17
17
|
|
18
|
-
|
19
|
-
time
|
18
|
+
user system total real
|
19
|
+
time 2.475 ms 3.822 ms 32.675999999999995 ms 34.702 ms
|
20
20
|
|
21
21
|
echo hi: 100 times
|
22
22
|
------------------
|
23
23
|
whysoslow? ..
|
24
24
|
|
25
|
-
mem @ start
|
26
|
-
mem @ finish
|
25
|
+
mem @ start 17 MB ??
|
26
|
+
mem @ finish 18 MB [31m+ 0 MB, 2%[0m
|
27
27
|
|
28
|
-
|
29
|
-
time
|
28
|
+
user system total real
|
29
|
+
time 19.75 ms 31.77 ms 281.766 ms 306.74899999999997 ms
|
30
30
|
|
31
31
|
echo hi: 1000 times
|
32
32
|
-------------------
|
33
33
|
whysoslow? ..
|
34
34
|
|
35
|
-
mem @ start
|
36
|
-
mem @ finish
|
35
|
+
mem @ start 18 MB ??
|
36
|
+
mem @ finish 29 MB [31m+ 11 MB, 61%[0m
|
37
37
|
|
38
|
-
|
39
|
-
time
|
38
|
+
user system total real
|
39
|
+
time 161.98399999999998 ms 271.296 ms 2432.76 ms 2662.98 ms
|
40
40
|
|
41
41
|
cat test/support/bigger-than-64k.txt: 1 times
|
42
42
|
---------------------------------------------
|
43
43
|
whysoslow? ..
|
44
44
|
|
45
|
-
mem @ start
|
46
|
-
mem @ finish
|
45
|
+
mem @ start 31 MB ??
|
46
|
+
mem @ finish 31 MB [31m+ 0 MB, 1%[0m
|
47
47
|
|
48
|
-
|
49
|
-
time
|
48
|
+
user system total real
|
49
|
+
time 0.412 ms 0.504 ms 4.343999999999999 ms 4.654 ms
|
50
50
|
|
51
51
|
cat test/support/bigger-than-64k.txt: 10 times
|
52
52
|
----------------------------------------------
|
53
53
|
whysoslow? ..
|
54
54
|
|
55
|
-
mem @ start
|
56
|
-
mem @ finish
|
55
|
+
mem @ start 31 MB ??
|
56
|
+
mem @ finish 34 MB [31m+ 2 MB, 7%[0m
|
57
57
|
|
58
|
-
|
59
|
-
time
|
58
|
+
user system total real
|
59
|
+
time 3.2880000000000003 ms 4.386 ms 43.447 ms 46.552 ms
|
60
60
|
|
61
61
|
cat test/support/bigger-than-64k.txt: 100 times
|
62
62
|
-----------------------------------------------
|
63
63
|
whysoslow? ..
|
64
64
|
|
65
|
-
mem @ start
|
66
|
-
mem @ finish
|
65
|
+
mem @ start 33 MB ??
|
66
|
+
mem @ finish 56 MB [31m+ 23 MB, 68%[0m
|
67
67
|
|
68
|
-
|
69
|
-
time
|
68
|
+
user system total real
|
69
|
+
time 28.892999999999997 ms 40.599000000000004 ms 407.804 ms 440.11 ms
|
70
70
|
|
71
71
|
cat test/support/bigger-than-64k.txt: 1000 times
|
72
72
|
------------------------------------------------
|
73
73
|
whysoslow? ..
|
74
74
|
|
75
|
-
mem @ start
|
76
|
-
mem @ finish
|
75
|
+
mem @ start 44 MB ??
|
76
|
+
mem @ finish 297 MB [31m+ 254 MB, 582%[0m
|
77
77
|
|
78
|
-
|
79
|
-
time
|
78
|
+
user system total real
|
79
|
+
time 285.236 ms 408.677 ms 4097.647 ms 4428.276999999999 ms
|
80
80
|
|
data/bench/runner.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
|
-
|
2
|
-
require 'scmd'
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
4
|
-
|
3
|
+
require "whysoslow"
|
4
|
+
require "scmd"
|
5
5
|
|
6
|
+
class ScmdBenchRunner
|
6
7
|
attr_reader :result
|
7
8
|
|
8
9
|
def self.run(*args)
|
9
|
-
|
10
|
+
new(*args).run
|
10
11
|
end
|
11
12
|
|
12
13
|
def initialize(printer_io, cmd, num_times = 10)
|
@@ -15,15 +16,16 @@ class ScmdBenchRunner
|
|
15
16
|
num_times.times{ cmd.run! }
|
16
17
|
end
|
17
18
|
|
18
|
-
@printer =
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
@printer =
|
20
|
+
Whysoslow::DefaultPrinter.new(
|
21
|
+
printer_io,
|
22
|
+
title: "#{@cmd.cmd_str}: #{num_times} times",
|
23
|
+
verbose: true,
|
24
|
+
)
|
22
25
|
@runner = Whysoslow::Runner.new(@printer)
|
23
26
|
end
|
24
27
|
|
25
28
|
def run
|
26
|
-
@runner.run
|
29
|
+
@runner.run(&@proc)
|
27
30
|
end
|
28
|
-
|
29
31
|
end
|
data/lib/scmd.rb
CHANGED
@@ -1,42 +1,43 @@
|
|
1
|
-
|
2
|
-
require 'scmd/command'
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
4
|
-
|
3
|
+
require "scmd/version"
|
4
|
+
require "scmd/command"
|
5
5
|
|
6
|
+
module Scmd
|
6
7
|
# Scmd can be run in "test mode". This means that command spies will be used
|
7
8
|
# in place of "live" commands, each time a command is run or started will be
|
8
9
|
# logged in a collection and option-specific spies can be added and used to
|
9
10
|
# "stub" spies with specific attributes in specific contexts.
|
10
11
|
|
11
12
|
def self.new(*args)
|
12
|
-
if !ENV[
|
13
|
+
if !ENV["SCMD_TEST_MODE"]
|
13
14
|
Command.new(*args)
|
14
15
|
else
|
15
|
-
|
16
|
+
commands.get(*args)
|
16
17
|
end
|
17
18
|
end
|
18
19
|
|
19
20
|
def self.commands
|
20
|
-
raise NoMethodError
|
21
|
+
raise NoMethodError unless ENV["SCMD_TEST_MODE"]
|
21
22
|
@commands ||= begin
|
22
|
-
require
|
23
|
+
require "scmd/stored_commands"
|
23
24
|
StoredCommands.new
|
24
25
|
end
|
25
26
|
end
|
26
27
|
|
27
28
|
def self.calls
|
28
|
-
raise NoMethodError
|
29
|
+
raise NoMethodError unless ENV["SCMD_TEST_MODE"]
|
29
30
|
@calls ||= []
|
30
31
|
end
|
31
32
|
|
32
33
|
def self.reset
|
33
|
-
raise NoMethodError
|
34
|
-
|
35
|
-
|
34
|
+
raise NoMethodError unless ENV["SCMD_TEST_MODE"]
|
35
|
+
calls.clear
|
36
|
+
commands.remove_all
|
36
37
|
end
|
37
38
|
|
38
39
|
def self.add_command(cmd_str, &block)
|
39
|
-
|
40
|
+
commands.add(cmd_str, &block)
|
40
41
|
end
|
41
42
|
|
42
43
|
class Call < Struct.new(:cmd_str, :input, :cmd)
|
@@ -53,5 +54,4 @@ module Scmd
|
|
53
54
|
set_backtrace(called_from || caller)
|
54
55
|
end
|
55
56
|
end
|
56
|
-
|
57
57
|
end
|
data/lib/scmd/command.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "thread"
|
4
|
+
require "posix-spawn"
|
5
|
+
require "scmd"
|
4
6
|
|
5
7
|
# Scmd::Command is a base wrapper for handling system commands. Initialize it
|
6
8
|
# with with a string specifying the command to execute. You can then run the
|
@@ -8,7 +10,6 @@ require 'scmd'
|
|
8
10
|
# create a more custom command wrapper.
|
9
11
|
|
10
12
|
module Scmd
|
11
|
-
|
12
13
|
class Command
|
13
14
|
READ_SIZE = 10240 # bytes
|
14
15
|
READ_CHECK_TIMEOUT = 0.001 # seconds
|
@@ -26,7 +27,11 @@ module Scmd
|
|
26
27
|
end
|
27
28
|
|
28
29
|
def run(input = nil)
|
29
|
-
|
30
|
+
begin
|
31
|
+
run!(input)
|
32
|
+
rescue
|
33
|
+
RunError
|
34
|
+
end
|
30
35
|
self
|
31
36
|
end
|
32
37
|
|
@@ -34,11 +39,13 @@ module Scmd
|
|
34
39
|
start_err_msg, start_err_bt = nil, nil
|
35
40
|
begin
|
36
41
|
start(input)
|
37
|
-
rescue
|
38
|
-
start_err_msg, start_err_bt =
|
42
|
+
rescue => ex
|
43
|
+
start_err_msg, start_err_bt = ex.message, ex.backtrace
|
39
44
|
ensure
|
40
45
|
wait # indefinitely until cmd is done running
|
41
|
-
|
46
|
+
unless success?
|
47
|
+
raise RunError.new(start_err_msg || @stderr, start_err_bt || caller)
|
48
|
+
end
|
42
49
|
end
|
43
50
|
|
44
51
|
self
|
@@ -53,15 +60,15 @@ module Scmd
|
|
53
60
|
while @child_process.check_for_exit
|
54
61
|
begin
|
55
62
|
read_output
|
56
|
-
rescue EOFError
|
63
|
+
rescue EOFError # rubocop:disable Lint/SuppressedException
|
57
64
|
end
|
58
65
|
end
|
59
|
-
@stop_w.write_nonblock(
|
66
|
+
@stop_w.write_nonblock(".")
|
60
67
|
end
|
61
68
|
end
|
62
69
|
|
63
70
|
def wait(timeout = nil)
|
64
|
-
return
|
71
|
+
return unless running?
|
65
72
|
|
66
73
|
wait_for_exit(timeout)
|
67
74
|
if @child_process.running?
|
@@ -78,18 +85,18 @@ module Scmd
|
|
78
85
|
end
|
79
86
|
|
80
87
|
def stop(timeout = nil)
|
81
|
-
return
|
88
|
+
return unless running?
|
82
89
|
|
83
90
|
send_term
|
84
91
|
begin
|
85
92
|
wait(timeout || DEFAULT_STOP_TIMEOUT)
|
86
|
-
rescue TimeoutError
|
93
|
+
rescue TimeoutError
|
87
94
|
kill
|
88
95
|
end
|
89
96
|
end
|
90
97
|
|
91
98
|
def kill(signal = nil)
|
92
|
-
return
|
99
|
+
return unless running?
|
93
100
|
|
94
101
|
send_kill(signal)
|
95
102
|
wait # indefinitely until cmd is killed
|
@@ -108,25 +115,28 @@ module Scmd
|
|
108
115
|
end
|
109
116
|
|
110
117
|
def inspect
|
111
|
-
reference =
|
118
|
+
reference = "0x0%x" % (object_id << 1)
|
112
119
|
"#<#{self.class}:#{reference}"\
|
113
|
-
" @cmd_str=#{
|
120
|
+
" @cmd_str=#{cmd_str.inspect}"\
|
114
121
|
" @exitstatus=#{@exitstatus.inspect}>"
|
115
122
|
end
|
116
123
|
|
117
124
|
private
|
118
125
|
|
119
126
|
def read_output
|
120
|
-
@child_process.read(READ_SIZE)
|
127
|
+
@child_process.read(READ_SIZE) do |out, err|
|
128
|
+
@stdout += out
|
129
|
+
@stderr += err
|
130
|
+
end
|
121
131
|
end
|
122
132
|
|
123
133
|
def wait_for_exit(timeout)
|
124
|
-
ios, _, _ = IO.select([
|
125
|
-
@stop_r.read_nonblock(1) if ios
|
134
|
+
ios, _, _ = IO.select([@stop_r], nil, nil, timeout)
|
135
|
+
@stop_r.read_nonblock(1) if ios&.include?(@stop_r)
|
126
136
|
end
|
127
137
|
|
128
138
|
def reset_attrs
|
129
|
-
@stdout, @stderr, @pid, @exitstatus =
|
139
|
+
@stdout, @stderr, @pid, @exitstatus = +"", +"", nil, nil
|
130
140
|
end
|
131
141
|
|
132
142
|
def setup_run
|
@@ -145,15 +155,15 @@ module Scmd
|
|
145
155
|
end
|
146
156
|
|
147
157
|
def send_term
|
148
|
-
send_signal
|
158
|
+
send_signal "TERM"
|
149
159
|
end
|
150
160
|
|
151
161
|
def send_kill(signal = nil)
|
152
|
-
send_signal(signal ||
|
162
|
+
send_signal(signal || "KILL")
|
153
163
|
end
|
154
164
|
|
155
165
|
def send_signal(sig)
|
156
|
-
return
|
166
|
+
return unless running?
|
157
167
|
@child_process.send_signal(sig)
|
158
168
|
end
|
159
169
|
|
@@ -164,14 +174,13 @@ module Scmd
|
|
164
174
|
end
|
165
175
|
|
166
176
|
class ChildProcess
|
167
|
-
|
168
177
|
attr_reader :pid, :stdin, :stdout, :stderr
|
169
178
|
|
170
179
|
def initialize(cmd_str, env, options)
|
171
|
-
@pid, @stdin, @stdout, @stderr = *::POSIX::Spawn
|
180
|
+
@pid, @stdin, @stdout, @stderr = *::POSIX::Spawn.popen4(
|
172
181
|
env,
|
173
182
|
cmd_str,
|
174
|
-
options
|
183
|
+
options,
|
175
184
|
)
|
176
185
|
@wait_pid, @wait_status = nil, nil
|
177
186
|
end
|
@@ -194,25 +203,34 @@ module Scmd
|
|
194
203
|
end
|
195
204
|
|
196
205
|
def write(input)
|
197
|
-
|
206
|
+
unless input.nil?
|
198
207
|
[*input].each{ |line| @stdin.puts line.to_s }
|
199
208
|
@stdin.close
|
200
209
|
end
|
201
210
|
end
|
202
211
|
|
203
212
|
def read(size)
|
204
|
-
ios, _, _ =
|
213
|
+
ios, _, _ =
|
214
|
+
IO.select([@stdout, @stderr], nil, nil, READ_CHECK_TIMEOUT)
|
205
215
|
if ios && block_given?
|
206
|
-
yield
|
216
|
+
yield(
|
217
|
+
read_if_ready(ios, @stdout, size),
|
218
|
+
read_if_ready(ios, @stderr, size)
|
219
|
+
)
|
207
220
|
end
|
208
221
|
end
|
209
222
|
|
210
223
|
def send_signal(sig)
|
211
|
-
process_kill(sig,
|
224
|
+
process_kill(sig, pid)
|
212
225
|
end
|
213
226
|
|
214
|
-
def flush_stdout
|
215
|
-
|
227
|
+
def flush_stdout
|
228
|
+
@stdout.read
|
229
|
+
end
|
230
|
+
|
231
|
+
def flush_stderr
|
232
|
+
@stderr.read
|
233
|
+
end
|
216
234
|
|
217
235
|
def teardown
|
218
236
|
[@stdin, @stdout, @stderr].each{ |fd| fd.close if fd && !fd.closed? }
|
@@ -221,7 +239,7 @@ module Scmd
|
|
221
239
|
private
|
222
240
|
|
223
241
|
def read_if_ready(ready_ios, io, size)
|
224
|
-
ready_ios.include?(io) ? read_by_size(io, size) :
|
242
|
+
ready_ios.include?(io) ? read_by_size(io, size) : ""
|
225
243
|
end
|
226
244
|
|
227
245
|
def read_by_size(io, size)
|
@@ -238,11 +256,8 @@ module Scmd
|
|
238
256
|
end
|
239
257
|
|
240
258
|
def pgrep
|
241
|
-
@pgrep ||= Command.new(
|
259
|
+
@pgrep ||= Command.new("which pgrep").run.stdout.strip
|
242
260
|
end
|
243
|
-
|
244
261
|
end
|
245
|
-
|
246
262
|
end
|
247
|
-
|
248
263
|
end
|