Commit adf3e2af by Jon Yurek

Added a CommandLine class to handle all the running and the whatnot.

parent ae9d7e91
...@@ -38,6 +38,7 @@ require 'paperclip/interpolations' ...@@ -38,6 +38,7 @@ require 'paperclip/interpolations'
require 'paperclip/style' require 'paperclip/style'
require 'paperclip/attachment' require 'paperclip/attachment'
require 'paperclip/callback_compatability' require 'paperclip/callback_compatability'
require 'paperclip/command_line'
require 'paperclip/railtie' require 'paperclip/railtie'
if defined?(Rails.root) && Rails.root if defined?(Rails.root) && Rails.root
Dir.glob(File.join(File.expand_path(Rails.root), "lib", "paperclip_processors", "*.rb")).each do |processor| Dir.glob(File.join(File.expand_path(Rails.root), "lib", "paperclip_processors", "*.rb")).each do |processor|
......
module Paperclip
class CommandLine
class << self
attr_accessor :path
end
def initialize(binary, params = "", options = {})
@binary = binary.dup
@params = params.dup
@options = options.dup
@swallow_stderr = @options.delete(:swallow_stderr)
@expected_outcodes = @options.delete(:expected_outcodes)
@expected_outcodes ||= [0]
end
def command
cmd = []
cmd << full_path(@binary)
cmd << interpolate(@params, @options)
cmd << bit_bucket if @swallow_stderr
cmd.join(" ")
end
def run
output = `#{command}`
unless @expected_outcodes.include?($?.exitstatus)
raise Paperclip::PaperclipCommandLineError, "Command '#{command}' returned #{$?.exitstatus}. Expected #{@expected_outcodes.join(", ")}"
end
output
end
private
def full_path(binary)
[self.class.path, binary].compact.join("/")
end
def interpolate(pattern, vars)
# interpolates :variables and :{variables}
pattern.gsub(%r#:(?:\w+|\{\w+\})#) do |match|
key = match[1..-1]
key = key[1..-2] if key[0,1] == '{'
if invalid_variables.include?(key)
raise PaperclipCommandLineError,
"Interpolation of #{key} isn't allowed."
end
shell_quote(vars[key.to_sym])
end
end
def invalid_variables
%w(expected_outcodes swallow_stderr)
end
def shell_quote(string)
return "" if string.nil? or string.blank?
string.split("'").map{|m| "'#{m}'" }.join("\\'")
end
def bit_bucket
return "2>NUL" unless File.exist?("/dev/null")
"2>/dev/null"
end
end
end
require 'test/helper'
class CommandLineTest < Test::Unit::TestCase
def setup
Paperclip::CommandLine.path = nil
end
should "take a command and parameters and produce a shell command for bash" do
cmd = Paperclip::CommandLine.new("convert", "a.jpg b.png")
assert_equal "convert a.jpg b.png", cmd.command
end
should "be able to set a path and produce commands with that path" do
Paperclip::CommandLine.path = "/opt/bin"
cmd = Paperclip::CommandLine.new("convert", "a.jpg b.png")
assert_equal "/opt/bin/convert a.jpg b.png", cmd.command
end
should "be able to interpolate quoted variables into the parameters" do
cmd = Paperclip::CommandLine.new("convert",
":one :{two}",
:one => "a.jpg",
:two => "b.png")
assert_equal "convert 'a.jpg' 'b.png'", cmd.command
end
should "be able to quote and interpolate dangerous variables" do
cmd = Paperclip::CommandLine.new("convert",
":one :two",
:one => "`rm -rf`.jpg",
:two => "ha'ha.png")
assert_equal "convert '`rm -rf`.jpg' 'ha'\\''ha.png'", cmd.command
end
should "add redirection to get rid of stderr in bash" do
File.stubs(:exist?).with("/dev/null").returns(true)
cmd = Paperclip::CommandLine.new("convert",
"a.jpg b.png",
:swallow_stderr => true)
assert_equal "convert a.jpg b.png 2>/dev/null", cmd.command
end
should "add redirection to get rid of stderr in cmd.exe" do
File.stubs(:exist?).with("/dev/null").returns(false)
cmd = Paperclip::CommandLine.new("convert",
"a.jpg b.png",
:swallow_stderr => true)
assert_equal "convert a.jpg b.png 2>NUL", cmd.command
end
should "raise if trying to interpolate :swallow_stderr or :expected_outcodes" do
cmd = Paperclip::CommandLine.new("convert",
":swallow_stderr :expected_outcodes",
:swallow_stderr => false,
:expected_outcodes => [0, 1])
assert_raise(Paperclip::PaperclipCommandLineError) do
cmd.command
end
end
should "run the #command it's given and return the output" do
cmd = Paperclip::CommandLine.new("convert", "a.jpg b.png")
cmd.stubs(:"`").with("convert a.jpg b.png").returns(:correct_value)
with_exitstatus_returning(0) do
assert_equal :correct_value, cmd.run
end
end
should "raise a PaperclipCommandLineError if the result code isn't expected" do
cmd = Paperclip::CommandLine.new("convert", "a.jpg b.png")
cmd.stubs(:"`").with("convert a.jpg b.png").returns(:correct_value)
with_exitstatus_returning(1) do
assert_raises(Paperclip::PaperclipCommandLineError) do
cmd.run
end
end
end
should "not raise a PaperclipCommandLineError if the result code is expected" do
cmd = Paperclip::CommandLine.new("convert",
"a.jpg b.png",
:expected_outcodes => [0, 1])
cmd.stubs(:"`").with("convert a.jpg b.png").returns(:correct_value)
with_exitstatus_returning(1) do
assert_nothing_raised do
cmd.run
end
end
end
end
...@@ -146,3 +146,13 @@ def should_reject_dummy_class ...@@ -146,3 +146,13 @@ def should_reject_dummy_class
assert_rejects @matcher, @dummy_class.new assert_rejects @matcher, @dummy_class.new
end end
end end
def with_exitstatus_returning(code)
saved_exitstatus = $?.nil? ? 0 : $?.exitstatus
begin
`ruby -e 'exit #{code.to_i}'`
yield
ensure
`ruby -e 'exit #{saved_exitstatus.to_i}'`
end
end
...@@ -87,8 +87,8 @@ class PaperclipTest < Test::Unit::TestCase ...@@ -87,8 +87,8 @@ class PaperclipTest < Test::Unit::TestCase
Paperclip.options[:command_path] = nil Paperclip.options[:command_path] = nil
Paperclip.options[:log_command] = false Paperclip.options[:log_command] = false
Paperclip.options[:swallow_stderr] = false Paperclip.options[:swallow_stderr] = false
Paperclip.expects(:"`").with(%q[this 'is' 'jack'\''s' '`command`' 'line!']) Paperclip.expects(:"`").with(%q[this is 'jack'\''s' '`command`' 'line!'])
Paperclip.run("this", "is", "jack's", "`command`", "line!") Paperclip.run("this", "is :one :two :three", :one => "jack's", :two => "`command`", :three => "line!")
end end
context "Paperclip.bit_bucket" do context "Paperclip.bit_bucket" do
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment