cocaine 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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