diff --git a/lib/puppet/file_system/file19.rb b/lib/puppet/file_system/file19.rb index fce9a6a82..8872ba6fc 100644 --- a/lib/puppet/file_system/file19.rb +++ b/lib/puppet/file_system/file19.rb @@ -1,5 +1,46 @@ class Puppet::FileSystem::File19 < Puppet::FileSystem::FileImpl def binread(path) path.binread end + + # Provide an encoding agnostic version of compare_stream + # + # The FileUtils implementation in Ruby 2.0+ was modified in a manner where + # it cannot properly compare File and StringIO instances. To sidestep that + # issue this method reimplements the faster 2.0 version that will correctly + # compare binary File and StringIO streams. + def compare_stream(path, stream) + open(path, 0, 'rb') do |this| + bsize = stream_blksize(this, stream) + sa = "".force_encoding('ASCII-8BIT') + sb = "".force_encoding('ASCII-8BIT') + begin + this.read(bsize, sa) + stream.read(bsize, sb) + return true if sa.empty? && sb.empty? + end while sa == sb + false + end + end + + private + def stream_blksize(*streams) + streams.each do |s| + next unless s.respond_to?(:stat) + size = blksize(s.stat) + return size if size + end + default_blksize() + end + + def blksize(st) + s = st.blksize + return nil unless s + return nil if s == 0 + s + end + + def default_blksize + 1024 + end end diff --git a/spec/integration/file_bucket/file_spec.rb b/spec/integration/file_bucket/file_spec.rb index 2c411fdf7..f0dbecaa3 100644 --- a/spec/integration/file_bucket/file_spec.rb +++ b/spec/integration/file_bucket/file_spec.rb @@ -1,44 +1,65 @@ #! /usr/bin/env ruby require 'spec_helper' require 'puppet/file_bucket/file' describe Puppet::FileBucket::File do describe "#indirection" do before :each do # Never connect to the network, no matter what described_class.indirection.terminus(:rest).class.any_instance.stubs(:find) end describe "when running the master application" do before :each do Puppet::Application[:master].setup_terminuses end { "md5/d41d8cd98f00b204e9800998ecf8427e" => :file, "https://puppetmaster:8140/production/file_bucket_file/md5/d41d8cd98f00b204e9800998ecf8427e" => :file, }.each do |key, terminus| it "should use the #{terminus} terminus when requesting #{key.inspect}" do described_class.indirection.terminus(terminus).class.any_instance.expects(:find) described_class.indirection.find(key) end end end describe "when running another application" do { "md5/d41d8cd98f00b204e9800998ecf8427e" => :file, "https://puppetmaster:8140/production/file_bucket_file/md5/d41d8cd98f00b204e9800998ecf8427e" => :rest, }.each do |key, terminus| it "should use the #{terminus} terminus when requesting #{key.inspect}" do described_class.indirection.terminus(terminus).class.any_instance.expects(:find) described_class.indirection.find(key) end end end end + + describe "saving binary files" do + describe "on Ruby 1.8.7", :if => RUBY_VERSION.match(/^1\.8/) do + let(:binary) { "\xD1\xF2\r\n\x81NuSc\x00" } + + it "does not error when the same contents are saved twice" do + bucket_file = Puppet::FileBucket::File.new(binary) + Puppet::FileBucket::File.indirection.save(bucket_file, bucket_file.name) + Puppet::FileBucket::File.indirection.save(bucket_file, bucket_file.name) + end + end + describe "on Ruby 1.9+", :if => RUBY_VERSION.match(/^1\.9|^2/) do + let(:binary) { "\xD1\xF2\r\n\x81NuSc\x00".force_encoding(Encoding::ASCII_8BIT) } + + it "does not error when the same contents are saved twice" do + bucket_file = Puppet::FileBucket::File.new(binary) + Puppet::FileBucket::File.indirection.save(bucket_file, bucket_file.name) + Puppet::FileBucket::File.indirection.save(bucket_file, bucket_file.name) + end + end + end end