scmd 1.1.0 → 2.0.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.
- data/README.md +9 -9
- data/lib/scmd/command.rb +49 -33
- data/lib/scmd/version.rb +1 -1
- data/scmd.gemspec +5 -5
- data/test/command_tests.rb +12 -6
- metadata +18 -15
data/README.md
CHANGED
@@ -24,12 +24,12 @@ Create a command object:
|
|
24
24
|
cmd = Scmd.new("echo hi")
|
25
25
|
|
26
26
|
cmd.to_s #=> "echo hi"
|
27
|
-
cmd.inspect #=> #<Scmd::Command:0x83220514 @cmd_str="echo hi" @
|
27
|
+
cmd.inspect #=> #<Scmd::Command:0x83220514 @cmd_str="echo hi" @exitstatus=nil>
|
28
28
|
|
29
|
-
cmd.pid
|
30
|
-
cmd.
|
31
|
-
cmd.stdout
|
32
|
-
cmd.stderr
|
29
|
+
cmd.pid #=> nil
|
30
|
+
cmd.exitstatus #=> nil
|
31
|
+
cmd.stdout #=> ''
|
32
|
+
cmd.stderr #=> ''
|
33
33
|
```
|
34
34
|
|
35
35
|
Run it:
|
@@ -42,10 +42,10 @@ Results:
|
|
42
42
|
|
43
43
|
```ruby
|
44
44
|
# written to the cmd instance
|
45
|
-
cmd.pid
|
46
|
-
cmd.
|
47
|
-
cmd.stdout
|
48
|
-
cmd.stderr
|
45
|
+
cmd.pid #=> 12345
|
46
|
+
cmd.exitstatus #=> 0
|
47
|
+
cmd.stdout #=> 'hi'
|
48
|
+
cmd.stderr #=> ''
|
49
49
|
|
50
50
|
# the cmd instance is returned by `run` for chaining as well
|
51
51
|
cmd.run.stdout #=> 'hi'
|
data/lib/scmd/command.rb
CHANGED
@@ -2,66 +2,82 @@
|
|
2
2
|
# with with a string specifying the command to execute. You can then run the
|
3
3
|
# command and inspect its results. It can be used as is, or inherited from to
|
4
4
|
# create a more custom command wrapper.
|
5
|
-
#
|
6
|
-
# Notes:
|
7
|
-
# * Uses `open4`. Open4 is more reliable for actually getting the subprocesses
|
8
|
-
# exit code (compared to `open3`).
|
9
|
-
# * The inspect method is overwritten to only display the name of the class and
|
10
|
-
# the command string. This is to help reduce ridiculous inspect strings due to
|
11
|
-
# result data that is stored in instance variables.
|
12
|
-
# * See the README.md for a walkthrough of the API.
|
13
5
|
|
14
|
-
require '
|
6
|
+
require 'posix-spawn'
|
15
7
|
|
16
8
|
module Scmd
|
17
|
-
class Command
|
18
9
|
|
19
|
-
|
10
|
+
class RunError < ::RuntimeError
|
11
|
+
def initialize(stderr, called_from)
|
12
|
+
super(stderr)
|
13
|
+
set_backtrace(called_from)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class Command
|
20
18
|
|
21
19
|
attr_reader :cmd_str
|
22
|
-
attr_reader :pid, :
|
20
|
+
attr_reader :pid, :exitstatus, :stdout, :stderr
|
23
21
|
|
24
22
|
def initialize(cmd_str)
|
25
23
|
@cmd_str = cmd_str
|
26
24
|
reset_results
|
27
25
|
end
|
28
26
|
|
29
|
-
def
|
30
|
-
|
27
|
+
def reset_results
|
28
|
+
@pid = @exitstatus = nil
|
29
|
+
@stdout = @stderr = ''
|
30
|
+
end
|
31
|
+
|
32
|
+
def success?
|
33
|
+
@exitstatus == 0
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_s
|
37
|
+
@cmd_str.to_s
|
38
|
+
end
|
39
|
+
|
31
40
|
def inspect
|
32
|
-
|
41
|
+
reference = '0x0%x' % (self.object_id << 1)
|
42
|
+
"#<#{self.class}:#{reference}"\
|
43
|
+
" @cmd_str=#{self.cmd_str.inspect}"\
|
44
|
+
" @exitstatus=#{@exitstatus.inspect}>"
|
33
45
|
end
|
34
46
|
|
35
47
|
def run(input=nil)
|
36
|
-
run!(input) rescue
|
48
|
+
run!(input) rescue RunError
|
37
49
|
self
|
38
50
|
end
|
39
51
|
|
40
52
|
def run!(input=nil)
|
53
|
+
called_from = caller
|
54
|
+
|
41
55
|
begin
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
end
|
47
|
-
@pid = pid.to_i
|
48
|
-
@stdout += stdout.read.strip
|
49
|
-
@stderr += stderr.read.strip
|
56
|
+
pid, stdin, stdout, stderr = POSIX::Spawn::popen4(@cmd_str)
|
57
|
+
if !input.nil?
|
58
|
+
[*input].each{|line| stdin.puts line.to_s}
|
59
|
+
stdin.close
|
50
60
|
end
|
51
|
-
@
|
61
|
+
@pid = pid.to_i
|
62
|
+
@stdout += stdout.read.strip
|
63
|
+
@stderr += stderr.read.strip
|
52
64
|
rescue Errno::ENOENT => err
|
53
|
-
@
|
54
|
-
@stderr
|
65
|
+
@exitstatus = -1
|
66
|
+
@stderr = err.message
|
67
|
+
ensure
|
68
|
+
[stdin, stdout, stderr].each{|io| io.close if !io.closed?}
|
69
|
+
::Process::waitpid(pid)
|
70
|
+
|
71
|
+
# `$?` is a thread-safe predefined variable that returns the exit status
|
72
|
+
# of the last child process to terminate:
|
73
|
+
# http://phrogz.net/ProgrammingRuby/language.html#predefinedvariables
|
74
|
+
@exitstatus ||= $?.exitstatus
|
75
|
+
|
76
|
+
raise RunError.new(@stderr, called_from) if !success?
|
55
77
|
end
|
56
78
|
|
57
|
-
raise Failure, @stderr if !success?
|
58
79
|
self
|
59
80
|
end
|
60
81
|
|
61
|
-
def reset_results
|
62
|
-
@pid = @exitcode = nil
|
63
|
-
@stdout = @stderr = ''
|
64
|
-
end
|
65
|
-
|
66
82
|
end
|
67
83
|
end
|
data/lib/scmd/version.rb
CHANGED
data/scmd.gemspec
CHANGED
@@ -4,11 +4,11 @@ require File.expand_path('../lib/scmd/version', __FILE__)
|
|
4
4
|
Gem::Specification.new do |gem|
|
5
5
|
gem.name = "scmd"
|
6
6
|
gem.version = Scmd::VERSION
|
7
|
-
gem.description = %q{
|
8
|
-
gem.summary = %q{
|
7
|
+
gem.description = %q{Build and run system commands.}
|
8
|
+
gem.summary = %q{Build and run system commands.}
|
9
9
|
|
10
|
-
gem.authors = ["Kelly Redding"]
|
11
|
-
gem.email = ["kelly@kellyredding.com"]
|
10
|
+
gem.authors = ["Kelly Redding", "Collin Redding"]
|
11
|
+
gem.email = ["kelly@kellyredding.com", "collin.redding@me.com"]
|
12
12
|
gem.homepage = "http://github.com/redding/scmd"
|
13
13
|
|
14
14
|
gem.files = `git ls-files`.split("\n")
|
@@ -17,5 +17,5 @@ Gem::Specification.new do |gem|
|
|
17
17
|
gem.require_paths = ["lib"]
|
18
18
|
|
19
19
|
gem.add_development_dependency("assert")
|
20
|
-
gem.add_dependency("
|
20
|
+
gem.add_dependency("posix-spawn")
|
21
21
|
end
|
data/test/command_tests.rb
CHANGED
@@ -11,7 +11,7 @@ module Scmd
|
|
11
11
|
end
|
12
12
|
subject { @success_cmd }
|
13
13
|
|
14
|
-
should have_readers :cmd_str, :pid, :
|
14
|
+
should have_readers :cmd_str, :pid, :exitstatus, :stdout, :stderr
|
15
15
|
should have_instance_methods :run, :run!
|
16
16
|
|
17
17
|
should "know and return its cmd string" do
|
@@ -21,7 +21,7 @@ module Scmd
|
|
21
21
|
|
22
22
|
should "default its result values" do
|
23
23
|
assert_nil subject.pid
|
24
|
-
assert_nil subject.
|
24
|
+
assert_nil subject.exitstatus
|
25
25
|
assert_equal '', subject.stdout
|
26
26
|
assert_equal '', subject.stderr
|
27
27
|
end
|
@@ -30,7 +30,7 @@ module Scmd
|
|
30
30
|
@success_cmd.run
|
31
31
|
|
32
32
|
assert_not_nil @success_cmd.pid
|
33
|
-
assert_equal 0, @success_cmd.
|
33
|
+
assert_equal 0, @success_cmd.exitstatus
|
34
34
|
assert @success_cmd.success?
|
35
35
|
assert_equal 'hi', @success_cmd.stdout
|
36
36
|
assert_equal '', @success_cmd.stderr
|
@@ -38,16 +38,22 @@ module Scmd
|
|
38
38
|
@failure_cmd.run
|
39
39
|
|
40
40
|
assert_not_nil @failure_cmd.pid
|
41
|
-
assert_not_equal 0, @failure_cmd.
|
41
|
+
assert_not_equal 0, @failure_cmd.exitstatus
|
42
42
|
assert_not @failure_cmd.success?
|
43
43
|
assert_equal '', @failure_cmd.stdout
|
44
44
|
assert_not_equal '', @failure_cmd.stderr
|
45
45
|
end
|
46
46
|
|
47
|
-
should "raise an exception on `run!`
|
48
|
-
|
47
|
+
should "raise an exception with proper backtrace on `run!`" do
|
48
|
+
err = begin;
|
49
49
|
@failure_cmd.run!
|
50
|
+
rescue Exception => err
|
51
|
+
err
|
50
52
|
end
|
53
|
+
|
54
|
+
assert_kind_of Scmd::RunError, err
|
55
|
+
assert_includes 'No such file or directory', err.message
|
56
|
+
assert_includes 'test/command_tests.rb:', err.backtrace.first
|
51
57
|
end
|
52
58
|
|
53
59
|
should "return itself on `run`, `run!`" do
|
metadata
CHANGED
@@ -1,25 +1,27 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: scmd
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 15
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
|
-
-
|
8
|
-
- 1
|
7
|
+
- 2
|
9
8
|
- 0
|
10
|
-
|
9
|
+
- 0
|
10
|
+
version: 2.0.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Kelly Redding
|
14
|
+
- Collin Redding
|
14
15
|
autorequire:
|
15
16
|
bindir: bin
|
16
17
|
cert_chain: []
|
17
18
|
|
18
|
-
date: 2012-
|
19
|
+
date: 2012-11-08 00:00:00 Z
|
19
20
|
dependencies:
|
20
21
|
- !ruby/object:Gem::Dependency
|
21
22
|
name: assert
|
22
|
-
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
23
25
|
none: false
|
24
26
|
requirements:
|
25
27
|
- - ">="
|
@@ -29,11 +31,11 @@ dependencies:
|
|
29
31
|
- 0
|
30
32
|
version: "0"
|
31
33
|
type: :development
|
32
|
-
|
33
|
-
prerelease: false
|
34
|
+
version_requirements: *id001
|
34
35
|
- !ruby/object:Gem::Dependency
|
35
|
-
name:
|
36
|
-
|
36
|
+
name: posix-spawn
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
37
39
|
none: false
|
38
40
|
requirements:
|
39
41
|
- - ">="
|
@@ -43,11 +45,11 @@ dependencies:
|
|
43
45
|
- 0
|
44
46
|
version: "0"
|
45
47
|
type: :runtime
|
46
|
-
|
47
|
-
|
48
|
-
description: Wrapper to `open4` for running system commands.
|
48
|
+
version_requirements: *id002
|
49
|
+
description: Build and run system commands.
|
49
50
|
email:
|
50
51
|
- kelly@kellyredding.com
|
52
|
+
- collin.redding@me.com
|
51
53
|
executables: []
|
52
54
|
|
53
55
|
extensions: []
|
@@ -97,12 +99,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
97
99
|
requirements: []
|
98
100
|
|
99
101
|
rubyforge_project:
|
100
|
-
rubygems_version: 1.8.
|
102
|
+
rubygems_version: 1.8.15
|
101
103
|
signing_key:
|
102
104
|
specification_version: 3
|
103
|
-
summary:
|
105
|
+
summary: Build and run system commands.
|
104
106
|
test_files:
|
105
107
|
- test/command_tests.rb
|
106
108
|
- test/helper.rb
|
107
109
|
- test/irb.rb
|
108
110
|
- test/scmd_tests.rb
|
111
|
+
has_rdoc:
|