Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

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

  • Loading branch information...
commit adf3e2af394b71268014810092462621a803db79 1 parent ae9d7e9
@jyurek jyurek authored
View
1  lib/paperclip.rb
@@ -38,6 +38,7 @@
require 'paperclip/style'
require 'paperclip/attachment'
require 'paperclip/callback_compatability'
+require 'paperclip/command_line'
require 'paperclip/railtie'
if defined?(Rails.root) && Rails.root
Dir.glob(File.join(File.expand_path(Rails.root), "lib", "paperclip_processors", "*.rb")).each do |processor|
View
65 lib/paperclip/command_line.rb
@@ -0,0 +1,65 @@
+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
View
92 test/command_line_test.rb
@@ -0,0 +1,92 @@
+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
View
10 test/helper.rb
@@ -146,3 +146,13 @@ def should_reject_dummy_class
assert_rejects @matcher, @dummy_class.new
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
View
4 test/paperclip_test.rb
@@ -87,8 +87,8 @@ class PaperclipTest < Test::Unit::TestCase
Paperclip.options[:command_path] = nil
Paperclip.options[:log_command] = false
Paperclip.options[:swallow_stderr] = false
- Paperclip.expects(:"`").with(%q[this 'is' 'jack'\''s' '`command`' 'line!'])
- Paperclip.run("this", "is", "jack's", "`command`", "line!")
+ Paperclip.expects(:"`").with(%q[this is 'jack'\''s' '`command`' 'line!'])
+ Paperclip.run("this", "is :one :two :three", :one => "jack's", :two => "`command`", :three => "line!")
end
context "Paperclip.bit_bucket" do
Please sign in to comment.
Something went wrong with that request. Please try again.