cocaine 0.0.1

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.
@@ -0,0 +1,15 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'rake'
4
+ require 'rspec/core/rake_task'
5
+
6
+ desc 'Default: Run specs.'
7
+ task :default => 'spec:unit'
8
+
9
+ namespace :spec do
10
+ desc "Run unit specs"
11
+ RSpec::Core::RakeTask.new('unit') do |t|
12
+ t.pattern = 'spec/cocaine/**/*_spec.rb'
13
+ end
14
+ end
15
+
@@ -0,0 +1,5 @@
1
+ require 'cocaine/command_line'
2
+ require 'cocaine/exceptions'
3
+
4
+ module Cocaine
5
+ end
@@ -0,0 +1,85 @@
1
+ module Cocaine
2
+ class CommandLine
3
+ class << self
4
+ attr_accessor :path
5
+ end
6
+
7
+ def initialize(binary, params = "", options = {})
8
+ @binary = binary.dup
9
+ @params = params.dup
10
+ @options = options.dup
11
+ @swallow_stderr = @options.has_key?(:swallow_stderr) ? @options.delete(:swallow_stderr) : Cocaine.options[:swallow_stderr]
12
+ @expected_outcodes = @options.delete(:expected_outcodes)
13
+ @expected_outcodes ||= [0]
14
+ end
15
+
16
+ def command
17
+ cmd = []
18
+ cmd << full_path(@binary)
19
+ cmd << interpolate(@params, @options)
20
+ cmd << bit_bucket if @swallow_stderr
21
+ cmd.join(" ")
22
+ end
23
+
24
+ def run
25
+ begin
26
+ output = self.class.send(:'`', command)
27
+ rescue Errno::ENOENT
28
+ raise Cocaine::CommandNotFoundError
29
+ end
30
+ if $?.exitstatus == 127
31
+ raise Cocaine::CommandNotFoundError
32
+ end
33
+ unless @expected_outcodes.include?($?.exitstatus)
34
+ raise Cocaine::ExitStatusError, "Command '#{command}' returned #{$?.exitstatus}. Expected #{@expected_outcodes.join(", ")}"
35
+ end
36
+ output
37
+ end
38
+
39
+ private
40
+
41
+ def full_path(binary)
42
+ [self.class.path, binary].compact.join("/")
43
+ end
44
+
45
+ def interpolate(pattern, vars)
46
+ # interpolates :variables and :{variables}
47
+ pattern.gsub(%r#:(?:\w+|\{\w+\})#) do |match|
48
+ key = match[1..-1]
49
+ key = key[1..-2] if key[0,1] == '{'
50
+ if invalid_variables.include?(key)
51
+ raise InterpolationError,
52
+ "Interpolation of #{key} isn't allowed."
53
+ end
54
+ interpolation(vars, key) || match
55
+ end
56
+ end
57
+
58
+ def invalid_variables
59
+ %w(expected_outcodes swallow_stderr)
60
+ end
61
+
62
+ def interpolation(vars, key)
63
+ if vars.key?(key.to_sym)
64
+ shell_quote(vars[key.to_sym])
65
+ end
66
+ end
67
+
68
+ def shell_quote(string)
69
+ return "" if string.nil? or string.empty?
70
+ if self.class.unix?
71
+ string.split("'").map{|m| "'#{m}'" }.join("\\'")
72
+ else
73
+ %{"#{string}"}
74
+ end
75
+ end
76
+
77
+ def bit_bucket
78
+ self.class.unix? ? "2>/dev/null" : "2>NUL"
79
+ end
80
+
81
+ def self.unix?
82
+ File.exist?("/dev/null")
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,6 @@
1
+ module Cocaine
2
+ class CommandLineError < StandardError; end
3
+ class CommandNotFoundError < CommandLineError; end
4
+ class ExitStatusError < CommandLineError; end
5
+ class InterpolationError < CommandLineError; end
6
+ end
@@ -0,0 +1,3 @@
1
+ module Cocaine
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,132 @@
1
+ require 'spec_helper'
2
+
3
+ describe Cocaine::CommandLine do
4
+ before do
5
+ Cocaine::CommandLine.path = nil
6
+ File.stubs(:exist?).with("/dev/null").returns(true)
7
+ end
8
+
9
+ it "takes a command and parameters and produce a shell command for bash" do
10
+ cmd = Cocaine::CommandLine.new("convert", "a.jpg b.png", :swallow_stderr => false)
11
+ cmd.command.should == "convert a.jpg b.png"
12
+ end
13
+
14
+ it "can set a default path and produce commands with that path" do
15
+ Cocaine::CommandLine.path = "/opt/bin"
16
+ cmd = Cocaine::CommandLine.new("convert", "a.jpg b.png", :swallow_stderr => false)
17
+ cmd.command.should == "/opt/bin/convert a.jpg b.png"
18
+ end
19
+
20
+ it "can interpolate quoted variables into the parameters" do
21
+ cmd = Cocaine::CommandLine.new("convert",
22
+ ":one :{two}",
23
+ :one => "a.jpg",
24
+ :two => "b.png",
25
+ :swallow_stderr => false)
26
+ cmd.command.should == "convert 'a.jpg' 'b.png'"
27
+ end
28
+
29
+ it "quotes command line options differently if we're on windows" do
30
+ File.stubs(:exist?).with("/dev/null").returns(false)
31
+ cmd = Cocaine::CommandLine.new("convert",
32
+ ":one :{two}",
33
+ :one => "a.jpg",
34
+ :two => "b.png",
35
+ :swallow_stderr => false)
36
+ cmd.command.should == 'convert "a.jpg" "b.png"'
37
+ end
38
+
39
+ it "can quote and interpolate dangerous variables" do
40
+ cmd = Cocaine::CommandLine.new("convert",
41
+ ":one :two",
42
+ :one => "`rm -rf`.jpg",
43
+ :two => "ha'ha.png",
44
+ :swallow_stderr => false)
45
+ cmd.command.should == "convert '`rm -rf`.jpg' 'ha'\\''ha.png'"
46
+ end
47
+
48
+ it "can quote and interpolate dangerous variables even on windows" do
49
+ File.stubs(:exist?).with("/dev/null").returns(false)
50
+ cmd = Cocaine::CommandLine.new("convert",
51
+ ":one :two",
52
+ :one => "`rm -rf`.jpg",
53
+ :two => "ha'ha.png",
54
+ :swallow_stderr => false)
55
+ cmd.command.should == %{convert "`rm -rf`.jpg" "ha'ha.png"}
56
+ end
57
+
58
+ it "allows colons in parameters" do
59
+ cmd = Cocaine::CommandLine.new("convert", "'a.jpg' xc:black 'b.jpg'", :swallow_stderr => false)
60
+ cmd.command.should == "convert 'a.jpg' xc:black 'b.jpg'"
61
+ end
62
+
63
+ it "adds redirection to get rid of stderr in bash" do
64
+ File.stubs(:exist?).with("/dev/null").returns(true)
65
+ cmd = Cocaine::CommandLine.new("convert",
66
+ "a.jpg b.png",
67
+ :swallow_stderr => true)
68
+
69
+ cmd.command.should == "convert a.jpg b.png 2>/dev/null"
70
+ end
71
+
72
+ it "adds redirection to get rid of stderr in cmd.exe" do
73
+ File.stubs(:exist?).with("/dev/null").returns(false)
74
+ cmd = Cocaine::CommandLine.new("convert",
75
+ "a.jpg b.png",
76
+ :swallow_stderr => true)
77
+
78
+ cmd.command.should == "convert a.jpg b.png 2>NUL"
79
+ end
80
+
81
+ it "raises if trying to interpolate :swallow_stderr or :expected_outcodes" do
82
+ cmd = Cocaine::CommandLine.new("convert",
83
+ ":swallow_stderr :expected_outcodes",
84
+ :swallow_stderr => false,
85
+ :expected_outcodes => [0, 1])
86
+
87
+ lambda do
88
+ cmd.command
89
+ end.should raise_error(Cocaine::CommandLineError)
90
+ end
91
+
92
+ it "runs the #command it's given and return the output" do
93
+ cmd = Cocaine::CommandLine.new("convert", "a.jpg b.png", :swallow_stderr => false)
94
+ cmd.class.stubs(:"`").with("convert a.jpg b.png").returns(:correct_value)
95
+ with_exitstatus_returning(0) do
96
+ cmd.run.should == :correct_value
97
+ end
98
+ end
99
+
100
+ it "raises a CommandLineError if the result code isn't expected" do
101
+ cmd = Cocaine::CommandLine.new("convert", "a.jpg b.png", :swallow_stderr => false)
102
+ cmd.class.stubs(:"`").with("convert a.jpg b.png").returns(:correct_value)
103
+ with_exitstatus_returning(1) do
104
+ lambda do
105
+ cmd.run
106
+ end.should raise_error(Cocaine::CommandLineError)
107
+ end
108
+ end
109
+
110
+ it "does not raise a CommandLineError if the result code is expected" do
111
+ cmd = Cocaine::CommandLine.new("convert",
112
+ "a.jpg b.png",
113
+ :expected_outcodes => [0, 1],
114
+ :swallow_stderr => false)
115
+ cmd.class.stubs(:"`").with("convert a.jpg b.png").returns(:correct_value)
116
+ with_exitstatus_returning(1) do
117
+ lambda do
118
+ cmd.run
119
+ end.should_not raise_error
120
+ end
121
+ end
122
+
123
+ it "detects that the system is unix or windows based on presence of /dev/null" do
124
+ File.stubs(:exist?).returns(true)
125
+ Cocaine::CommandLine.unix?.should == true
126
+ end
127
+
128
+ it "detects that the system is not unix or windows based on absence of /dev/null" do
129
+ File.stubs(:exist?).returns(false)
130
+ Cocaine::CommandLine.unix?.should_not == true
131
+ end
132
+ end
@@ -0,0 +1,10 @@
1
+ require 'rspec'
2
+ require 'spec/support/with_exitstatus'
3
+ require 'mocha'
4
+ require 'bourne'
5
+ require 'cocaine'
6
+
7
+ RSpec.configure do |config|
8
+ config.mock_with :mocha
9
+ config.include WithExitstatus
10
+ end
@@ -0,0 +1,12 @@
1
+ module WithExitstatus
2
+ def with_exitstatus_returning(code)
3
+ saved_exitstatus = $?.nil? ? 0 : $?.exitstatus
4
+ begin
5
+ `ruby -e 'exit #{code.to_i}'`
6
+ yield
7
+ ensure
8
+ `ruby -e 'exit #{saved_exitstatus.to_i}'`
9
+ end
10
+ end
11
+ end
12
+
metadata ADDED
@@ -0,0 +1,115 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cocaine
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Jon Yurek
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-05-18 00:00:00 -04:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rspec
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :development
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: bourne
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
47
+ type: :development
48
+ version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ name: mocha
51
+ prerelease: false
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 3
58
+ segments:
59
+ - 0
60
+ version: "0"
61
+ type: :development
62
+ version_requirements: *id003
63
+ description: A small library for doing (command) lines
64
+ email: jyurek@thoughtbot.com
65
+ executables: []
66
+
67
+ extensions: []
68
+
69
+ extra_rdoc_files: []
70
+
71
+ files:
72
+ - Rakefile
73
+ - lib/cocaine.rb
74
+ - lib/cocaine/command_line.rb
75
+ - lib/cocaine/exceptions.rb
76
+ - lib/cocaine/version.rb
77
+ - spec/spec_helper.rb
78
+ - spec/cocaine/command_line_spec.rb
79
+ - spec/support/with_exitstatus.rb
80
+ has_rdoc: true
81
+ homepage: http://www.thoughtbot.com/projects/cocaine
82
+ licenses: []
83
+
84
+ post_install_message:
85
+ rdoc_options: []
86
+
87
+ require_paths:
88
+ - lib
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ hash: 3
95
+ segments:
96
+ - 0
97
+ version: "0"
98
+ required_rubygems_version: !ruby/object:Gem::Requirement
99
+ none: false
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ hash: 3
104
+ segments:
105
+ - 0
106
+ version: "0"
107
+ requirements: []
108
+
109
+ rubyforge_project:
110
+ rubygems_version: 1.5.2
111
+ signing_key:
112
+ specification_version: 3
113
+ summary: A small library for doing (command) lines
114
+ test_files:
115
+ - spec/cocaine/command_line_spec.rb