scmd 3.0.3 → 3.0.4
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 -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
data/lib/scmd/command_spy.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require "scmd"
|
4
4
|
|
5
|
+
module Scmd
|
5
6
|
class CommandSpy
|
6
|
-
|
7
7
|
attr_reader :cmd_str, :env, :options
|
8
8
|
attr_reader :run_calls, :run_bang_calls, :start_calls
|
9
9
|
attr_reader :wait_calls, :stop_calls, :kill_calls
|
@@ -20,12 +20,12 @@ module Scmd
|
|
20
20
|
|
21
21
|
@running = false
|
22
22
|
|
23
|
-
@stdout, @stderr, @pid, @exitstatus =
|
23
|
+
@stdout, @stderr, @pid, @exitstatus = "", "", 1, 0
|
24
24
|
end
|
25
25
|
|
26
26
|
def run(input = nil)
|
27
27
|
@run_calls.push(InputCall.new(input))
|
28
|
-
Scmd.calls.push(Scmd::Call.new(self, input)) if ENV[
|
28
|
+
Scmd.calls.push(Scmd::Call.new(self, input)) if ENV["SCMD_TEST_MODE"]
|
29
29
|
self
|
30
30
|
end
|
31
31
|
|
@@ -35,7 +35,7 @@ module Scmd
|
|
35
35
|
|
36
36
|
def run!(input = nil)
|
37
37
|
@run_bang_calls.push(InputCall.new(input))
|
38
|
-
Scmd.calls.push(Scmd::Call.new(self, input)) if ENV[
|
38
|
+
Scmd.calls.push(Scmd::Call.new(self, input)) if ENV["SCMD_TEST_MODE"]
|
39
39
|
self
|
40
40
|
end
|
41
41
|
|
@@ -45,7 +45,7 @@ module Scmd
|
|
45
45
|
|
46
46
|
def start(input = nil)
|
47
47
|
@start_calls.push(InputCall.new(input))
|
48
|
-
Scmd.calls.push(Scmd::Call.new(self, input)) if ENV[
|
48
|
+
Scmd.calls.push(Scmd::Call.new(self, input)) if ENV["SCMD_TEST_MODE"]
|
49
49
|
@running = true
|
50
50
|
end
|
51
51
|
|
@@ -92,21 +92,21 @@ module Scmd
|
|
92
92
|
@cmd_str.to_s
|
93
93
|
end
|
94
94
|
|
95
|
-
def ==(
|
96
|
-
if
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
95
|
+
def ==(other)
|
96
|
+
if other.is_a?(CommandSpy)
|
97
|
+
cmd_str == other.cmd_str &&
|
98
|
+
env == other.env &&
|
99
|
+
options == other.options &&
|
100
|
+
run_calls == other.run_calls &&
|
101
|
+
run_bang_calls == other.run_bang_calls &&
|
102
|
+
start_calls == other.start_calls &&
|
103
|
+
wait_calls == other.wait_calls &&
|
104
|
+
stop_calls == other.stop_calls &&
|
105
|
+
kill_calls == other.kill_calls &&
|
106
|
+
pid == other.pid &&
|
107
|
+
exitstatus == other.exitstatus &&
|
108
|
+
stdout == other.stdout &&
|
109
|
+
stderr == other.stderr
|
110
110
|
else
|
111
111
|
super
|
112
112
|
end
|
@@ -115,7 +115,5 @@ module Scmd
|
|
115
115
|
InputCall = Struct.new(:input)
|
116
116
|
TimeoutCall = Struct.new(:timeout)
|
117
117
|
SignalCall = Struct.new(:signal)
|
118
|
-
|
119
118
|
end
|
120
|
-
|
121
119
|
end
|
data/lib/scmd/stored_commands.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require "scmd/command_spy"
|
4
4
|
|
5
|
+
module Scmd
|
5
6
|
class StoredCommands
|
6
|
-
|
7
7
|
attr_reader :hash
|
8
8
|
|
9
9
|
def initialize
|
@@ -30,16 +30,15 @@ module Scmd
|
|
30
30
|
@hash.empty?
|
31
31
|
end
|
32
32
|
|
33
|
-
def ==(
|
34
|
-
if
|
35
|
-
|
33
|
+
def ==(other)
|
34
|
+
if other.is_a?(StoredCommands)
|
35
|
+
hash == other.hash
|
36
36
|
else
|
37
37
|
super
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
41
|
class Stub
|
42
|
-
|
43
42
|
attr_reader :cmd_str, :hash
|
44
43
|
|
45
44
|
def initialize(cmd_str)
|
@@ -62,17 +61,14 @@ module Scmd
|
|
62
61
|
CommandSpy.new(@cmd_str, opts).tap(&block)
|
63
62
|
end
|
64
63
|
|
65
|
-
def ==(
|
66
|
-
if
|
67
|
-
|
68
|
-
|
64
|
+
def ==(other)
|
65
|
+
if other.is_a?(Stub)
|
66
|
+
cmd_str == other.cmd_str &&
|
67
|
+
hash == other.hash
|
69
68
|
else
|
70
69
|
super
|
71
70
|
end
|
72
71
|
end
|
73
|
-
|
74
72
|
end
|
75
|
-
|
76
73
|
end
|
77
|
-
|
78
74
|
end
|
data/lib/scmd/version.rb
CHANGED
data/scmd.gemspec
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
5
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
6
|
require "scmd/version"
|
5
7
|
|
@@ -8,18 +10,19 @@ Gem::Specification.new do |gem|
|
|
8
10
|
gem.version = Scmd::VERSION
|
9
11
|
gem.authors = ["Kelly Redding", "Collin Redding"]
|
10
12
|
gem.email = ["kelly@kellyredding.com", "collin.redding@me.com"]
|
11
|
-
gem.summary =
|
12
|
-
gem.description =
|
13
|
+
gem.summary = "Build and run system commands."
|
14
|
+
gem.description = "Build and run system commands."
|
13
15
|
gem.homepage = "http://github.com/redding/scmd"
|
14
|
-
gem.license =
|
16
|
+
gem.license = "MIT"
|
17
|
+
|
18
|
+
gem.files = `git ls-files | grep "^[^.]"`.split($INPUT_RECORD_SEPARATOR)
|
15
19
|
|
16
|
-
gem.files = `git ls-files`.split($/)
|
17
20
|
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
18
21
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
19
22
|
gem.require_paths = ["lib"]
|
20
23
|
|
21
|
-
gem.add_development_dependency("
|
24
|
+
gem.add_development_dependency("much-style-guide", ["~> 0.6.0"])
|
25
|
+
gem.add_development_dependency("assert", ["~> 2.19.2"])
|
22
26
|
|
23
27
|
gem.add_dependency("posix-spawn", ["~> 0.3.11"])
|
24
|
-
|
25
28
|
end
|
data/script/bench.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# $ bundle exec ruby script/bench.rb
|
2
4
|
|
3
|
-
|
5
|
+
require_relative "../bench/runner"
|
4
6
|
|
5
7
|
class ScmdBenchLogger
|
6
|
-
|
7
8
|
def initialize(file_path)
|
8
|
-
@file = File.open(file_path,
|
9
|
+
@file = File.open(file_path, "w")
|
9
10
|
@ios = [@file, $stdout]
|
10
11
|
yield self
|
11
12
|
@file.close
|
@@ -17,10 +18,9 @@ class ScmdBenchLogger
|
|
17
18
|
end
|
18
19
|
end
|
19
20
|
|
20
|
-
def
|
21
|
+
def respond_to_missing?(*args)
|
21
22
|
@ios.first.respond_to?(args.first.to_s) ? true : super
|
22
23
|
end
|
23
|
-
|
24
24
|
end
|
25
25
|
|
26
26
|
def run_cmd(logger, *args)
|
@@ -33,7 +33,7 @@ def run_cmd(logger, *args)
|
|
33
33
|
GC.start
|
34
34
|
end
|
35
35
|
|
36
|
-
ScmdBenchLogger.new(
|
36
|
+
ScmdBenchLogger.new("bench/results.txt") do |logger|
|
37
37
|
run_cmd(logger, Scmd.new("echo hi"), 1)
|
38
38
|
run_cmd(logger, Scmd.new("echo hi"), 10)
|
39
39
|
run_cmd(logger, Scmd.new("echo hi"), 100)
|
@@ -44,4 +44,3 @@ ScmdBenchLogger.new('bench/results.txt') do |logger|
|
|
44
44
|
run_cmd(logger, Scmd.new("cat test/support/bigger-than-64k.txt"), 100)
|
45
45
|
run_cmd(logger, Scmd.new("cat test/support/bigger-than-64k.txt"), 1000)
|
46
46
|
end
|
47
|
-
|
data/test/helper.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# this file is automatically required when you run `assert`
|
2
4
|
# put any test helpers here
|
3
5
|
|
@@ -6,14 +8,14 @@ ROOT_PATH = File.expand_path("../..", __FILE__)
|
|
6
8
|
$LOAD_PATH.unshift(ROOT_PATH)
|
7
9
|
|
8
10
|
# require pry for debugging (`binding.pry`)
|
9
|
-
require
|
11
|
+
require "pry"
|
10
12
|
|
11
|
-
require
|
13
|
+
require "test/support/factory"
|
12
14
|
|
13
15
|
# 1.8.7 backfills
|
14
16
|
|
15
17
|
# Array#sample
|
16
|
-
if !(a =
|
18
|
+
if !(a = []).respond_to?(:sample) && a.respond_to?(:choice)
|
17
19
|
class Array
|
18
20
|
alias_method :sample, :choice
|
19
21
|
end
|
data/test/support/factory.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "assert"
|
2
|
-
require
|
4
|
+
require "scmd/command"
|
3
5
|
|
4
6
|
class Scmd::Command
|
5
|
-
|
6
7
|
class SystemTests < Assert::Context
|
7
8
|
desc "Scmd::Command"
|
8
9
|
setup do
|
@@ -17,27 +18,28 @@ class Scmd::Command
|
|
17
18
|
assert_equal 0, @success_cmd.exitstatus
|
18
19
|
assert @success_cmd.success?
|
19
20
|
assert_equal "hi\n", @success_cmd.stdout
|
20
|
-
assert_equal
|
21
|
+
assert_equal "", @success_cmd.stderr
|
21
22
|
|
22
23
|
@failure_cmd.run
|
23
24
|
|
24
25
|
assert_not_nil @failure_cmd.pid
|
25
26
|
assert_not_equal 0, @failure_cmd.exitstatus
|
26
27
|
assert_not @failure_cmd.success?
|
27
|
-
assert_equal
|
28
|
-
assert_not_equal
|
28
|
+
assert_equal "", @failure_cmd.stdout
|
29
|
+
assert_not_equal "", @failure_cmd.stderr
|
29
30
|
end
|
30
31
|
|
31
32
|
should "raise an exception with proper backtrace on `run!`" do
|
32
|
-
err =
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
33
|
+
err =
|
34
|
+
begin
|
35
|
+
@failure_cmd.run!
|
36
|
+
rescue => ex
|
37
|
+
ex
|
38
|
+
end
|
37
39
|
|
38
40
|
assert_kind_of Scmd::RunError, err
|
39
|
-
assert_includes
|
40
|
-
assert_includes
|
41
|
+
assert_includes "No such file or directory", err.message
|
42
|
+
assert_includes "test/system/command_tests.rb:", err.backtrace.first
|
41
43
|
end
|
42
44
|
|
43
45
|
should "return itself on `run`, `run!`" do
|
@@ -57,7 +59,6 @@ class Scmd::Command
|
|
57
59
|
cmd.wait
|
58
60
|
assert_not cmd.running?
|
59
61
|
end
|
60
|
-
|
61
62
|
end
|
62
63
|
|
63
64
|
class InputTests < SystemTests
|
@@ -65,7 +66,7 @@ class Scmd::Command
|
|
65
66
|
setup do
|
66
67
|
@cmd = Scmd::Command.new("sh")
|
67
68
|
end
|
68
|
-
subject
|
69
|
+
subject{ @cmd }
|
69
70
|
|
70
71
|
should "run the command given a single line of input" do
|
71
72
|
subject.run "echo hi"
|
@@ -81,7 +82,6 @@ class Scmd::Command
|
|
81
82
|
assert_equal "hi\n", @cmd.stdout
|
82
83
|
assert_equal "err\n", @cmd.stderr
|
83
84
|
end
|
84
|
-
|
85
85
|
end
|
86
86
|
|
87
87
|
class LongRunningTests < SystemTests
|
@@ -124,21 +124,20 @@ class Scmd::Command
|
|
124
124
|
|
125
125
|
should "be killable with a non-default signal" do
|
126
126
|
@long_cmd.start
|
127
|
-
@long_cmd.kill(
|
127
|
+
@long_cmd.kill("INT")
|
128
128
|
|
129
129
|
assert_not @long_cmd.running?
|
130
130
|
end
|
131
|
-
|
132
131
|
end
|
133
132
|
|
134
133
|
class BufferDeadlockTests < SystemTests
|
135
134
|
desc "when capturing data from an output buffer"
|
136
135
|
setup do
|
137
|
-
@small_path = File.join(ROOT_PATH,
|
136
|
+
@small_path = File.join(ROOT_PATH, "test/support/smaller-than-64k.txt")
|
138
137
|
@small_data = File.read(@small_path)
|
139
138
|
@small_cmd = Scmd::Command.new("cat #{@small_path}")
|
140
139
|
|
141
|
-
@big_path = File.join(ROOT_PATH,
|
140
|
+
@big_path = File.join(ROOT_PATH, "test/support/bigger-than-64k.txt")
|
142
141
|
@big_data = File.read(@big_path)
|
143
142
|
@big_cmd = Scmd::Command.new("cat #{@big_path}")
|
144
143
|
end
|
@@ -152,15 +151,14 @@ class Scmd::Command
|
|
152
151
|
assert_nothing_raised{ @big_cmd.wait(1) }
|
153
152
|
assert_equal @big_data, @big_cmd.stdout
|
154
153
|
end
|
155
|
-
|
156
154
|
end
|
157
155
|
|
158
156
|
class WithEnvVarTests < SystemTests
|
159
157
|
desc "with environment variables"
|
160
158
|
setup do
|
161
159
|
@cmd = Scmd::Command.new("echo $SCMD_TEST_VAR", {
|
162
|
-
:
|
163
|
-
})
|
160
|
+
env: { "SCMD_TEST_VAR" => "test" },
|
161
|
+
},)
|
164
162
|
end
|
165
163
|
|
166
164
|
should "use them when running the command" do
|
@@ -168,7 +166,6 @@ class Scmd::Command
|
|
168
166
|
assert @cmd.success?
|
169
167
|
assert_equal "test\n", @cmd.stdout
|
170
168
|
end
|
171
|
-
|
172
169
|
end
|
173
170
|
|
174
171
|
class WithOptionsTests < SystemTests
|
@@ -177,8 +174,8 @@ class Scmd::Command
|
|
177
174
|
@path = "/"
|
178
175
|
# `chdir` is the only one that reliably worked
|
179
176
|
@cmd = Scmd::Command.new("pwd", {
|
180
|
-
:
|
181
|
-
})
|
177
|
+
options: { chdir: @path },
|
178
|
+
},)
|
182
179
|
end
|
183
180
|
|
184
181
|
should "use them when running the command" do
|
@@ -188,7 +185,5 @@ class Scmd::Command
|
|
188
185
|
assert_not_equal "#{Dir.pwd}\n", @cmd.stdout
|
189
186
|
assert_equal "#{@path}\n", @cmd.stdout
|
190
187
|
end
|
191
|
-
|
192
188
|
end
|
193
|
-
|
194
189
|
end
|
@@ -1,20 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "assert"
|
2
|
-
require
|
4
|
+
require "scmd/command_spy"
|
3
5
|
|
4
6
|
class Scmd::CommandSpy
|
5
|
-
|
6
7
|
class UnitTests < Assert::Context
|
7
8
|
desc "Scmd::CommandSpy"
|
8
9
|
setup do
|
9
10
|
@spy_class = Scmd::CommandSpy
|
10
11
|
end
|
11
|
-
|
12
12
|
end
|
13
13
|
|
14
14
|
class InitTests < UnitTests
|
15
15
|
setup do
|
16
|
-
@orig_scmd_test_mode = ENV[
|
17
|
-
ENV[
|
16
|
+
@orig_scmd_test_mode = ENV["SCMD_TEST_MODE"]
|
17
|
+
ENV["SCMD_TEST_MODE"] = "1"
|
18
18
|
Scmd.reset
|
19
19
|
|
20
20
|
@cmd_str = Factory.string
|
@@ -22,7 +22,7 @@ class Scmd::CommandSpy
|
|
22
22
|
end
|
23
23
|
teardown do
|
24
24
|
Scmd.reset
|
25
|
-
ENV[
|
25
|
+
ENV["SCMD_TEST_MODE"] = @orig_scmd_test_mode
|
26
26
|
end
|
27
27
|
subject{ @spy }
|
28
28
|
|
@@ -54,17 +54,17 @@ class Scmd::CommandSpy
|
|
54
54
|
|
55
55
|
assert_equal 1, subject.pid
|
56
56
|
assert_equal 0, subject.exitstatus
|
57
|
-
assert_equal
|
58
|
-
assert_equal
|
57
|
+
assert_equal "", subject.stdout
|
58
|
+
assert_equal "", subject.stderr
|
59
59
|
end
|
60
60
|
|
61
61
|
should "allow specifying env and options" do
|
62
62
|
opts = { Factory.string => Factory.string }
|
63
63
|
cmd = Scmd::Command.new(Factory.string, {
|
64
|
-
:
|
65
|
-
:
|
66
|
-
})
|
67
|
-
exp = {
|
64
|
+
env: { SCMD_TEST_VAR: 1 },
|
65
|
+
options: opts,
|
66
|
+
},)
|
67
|
+
exp = { "SCMD_TEST_VAR" => "1" }
|
68
68
|
assert_equal exp, cmd.env
|
69
69
|
assert_equal opts, cmd.options
|
70
70
|
end
|
@@ -162,7 +162,7 @@ class Scmd::CommandSpy
|
|
162
162
|
end
|
163
163
|
|
164
164
|
should "not track global run, run! or start calls if not in test mode" do
|
165
|
-
ENV.delete(
|
165
|
+
ENV.delete("SCMD_TEST_MODE")
|
166
166
|
|
167
167
|
input = Factory.string
|
168
168
|
# if `Scmd.calls` is called when not in test mode it will raise an error,
|
@@ -174,7 +174,7 @@ class Scmd::CommandSpy
|
|
174
174
|
subject.start(input)
|
175
175
|
end
|
176
176
|
|
177
|
-
ENV[
|
177
|
+
ENV["SCMD_TEST_MODE"] = "1"
|
178
178
|
end
|
179
179
|
|
180
180
|
should "track its wait calls" do
|
@@ -232,13 +232,11 @@ class Scmd::CommandSpy
|
|
232
232
|
:pid,
|
233
233
|
:exitstatus,
|
234
234
|
:stdout,
|
235
|
-
:stderr
|
235
|
+
:stderr,
|
236
236
|
].sample
|
237
237
|
Assert.stub(spy2, a){ Factory.string }
|
238
238
|
|
239
239
|
assert_not_equal spy1, spy2
|
240
240
|
end
|
241
|
-
|
242
241
|
end
|
243
|
-
|
244
242
|
end
|