diff --git a/lib/pdf_cover/converter.rb b/lib/pdf_cover/converter.rb index ccfb3bb..660fa46 100644 --- a/lib/pdf_cover/converter.rb +++ b/lib/pdf_cover/converter.rb @@ -1,3 +1,5 @@ +require "open3" + module PdfCover class Converter # NOTE: Update the generate_jpegs.sh script when changing these values @@ -5,6 +7,12 @@ class Converter DEFAULT_QUALITY = 85 DEFAULT_RESOLUTION = 300 + class CommandFailedError < StandardError + def initialize(stdout_str, stderr_str) + super("PDF conversion failed:\nSTDOUT: #{stdout_str}\nSTDERR: #{stderr_str}") + end + end + class CommandNotFoundError < StandardError def initialize super("Could not run the `gs` command. Make sure that GhostScript is in your PATH.") @@ -23,15 +31,19 @@ def initialize(file, options = {}) end # @raises PdfCover::Converter::CommandNotFoundError if GhostScript is not found + # @raises PdfCover::Converter::CommandFailedError if GhostScript returns a non-zero status def converted_file - case convert_file - when :ok - destination_file - when :command_failed - @file - when :command_not_found - fail CommandNotFoundError + parameters = build_parameters(file_path, device) + stdout_str, stderr_str, status = execute_command("gs #{parameters}") + + case status + when 0 then destination_file + when 127 then fail CommandNotFoundError + else fail CommandFailedError.new(stdout_str, stderr_str) end + rescue => e + destination_file.close + raise e end private @@ -40,8 +52,8 @@ def basename @basename ||= File.basename(@file.path, File.extname(@file.path)) end - def build_parameters(source, device, destination) - %W(-sOutputFile='#{destination}' -dNOPAUSE + def build_parameters(source, device) + %W(-sOutputFile='#{destination_path}' -dNOPAUSE -sDEVICE='#{device}' -dJPEGQ=#{@quality} -dFirstPage=1 -dLastPage=1 -r#{@resolution} -q '#{source}' @@ -49,29 +61,22 @@ def build_parameters(source, device, destination) ).join(" ") end - def convert_file - parameters = build_parameters(file_path, device, File.expand_path(destination_file.path)) - result = execute_command("gs #{parameters}") - - if result - :ok - else - failed_result(result) - end - end - def destination_file @destination_file ||= Tempfile.new([basename, ".#{@format}"]).tap do |file| file.binmode end end + def destination_path + File.expand_path(destination_file.path) + end + def device @format.to_s == "jpg" ? "jpeg" : @format.to_s end def execute_command(command) - Kernel.system(command) + Open3.capture3(command) end def extract_options(options) @@ -84,23 +89,8 @@ def extract_options(options) fail InvalidOption.new(:resolution, @resolution) unless @resolution > 1 end - def failed_result(result) - destination_file.close - - if result == false - logger.warn("GhostScript execution failed: #{$CHILD_STATUS}") - :command_failed - else - :command_not_found - end - end - def file_path @file_path ||= File.expand_path(@file.path) end - - def logger - @logger ||= defined?(Rails) ? Rails.logger : Logger.new(STDERR) - end end end diff --git a/spec/xing/pdf_cover/converter_spec.rb b/spec/xing/pdf_cover/converter_spec.rb index 457f660..3464cb6 100644 --- a/spec/xing/pdf_cover/converter_spec.rb +++ b/spec/xing/pdf_cover/converter_spec.rb @@ -80,7 +80,7 @@ end context "the conversion goes fine" do - let(:execution_result) { true } + let(:execution_result) { ["", "", 0] } it "returns the generated file" do expect(subject.converted_file).to eq(destination_file) @@ -93,23 +93,16 @@ end context "because the command execution failed" do - let(:execution_result) { false } + let(:execution_result) { ["", "", 1] } let(:logger) { double(Logger) } - const_set(:CHILD_STATUS, "something went wrong") - - before do - expect(subject).to receive(:logger).and_return(logger) - expect(logger).to receive(:warn) - end - - it "returns the original file" do - expect(subject.converted_file).to eq(source_file) + it "generates an error" do + expect { subject.converted_file }.to raise_error(PdfCover::Converter::CommandFailedError) end end context "because the GhostScript command is not found" do - let(:execution_result) { nil } + let(:execution_result) { ["", "", 127] } it "generates an error" do expect { subject.converted_file }.to raise_error(PdfCover::Converter::CommandNotFoundError)