1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
|
require_relative '../../puppet/file_bucket'
require_relative '../../puppet/indirector'
require_relative '../../puppet/util/checksums'
require 'digest/md5'
require 'stringio'
class Puppet::FileBucket::File
# This class handles the abstract notion of a file in a filebucket.
# There are mechanisms to save and load this file locally and remotely in puppet/indirector/filebucketfile/*
# There is a compatibility class that emulates pre-indirector filebuckets in Puppet::FileBucket::Dipper
extend Puppet::Indirector
indirects :file_bucket_file, :terminus_class => :selector
attr :bucket_path
def self.supported_formats
[:binary]
end
def initialize(contents, options = {})
case contents
when String
@contents = StringContents.new(contents)
when Pathname
@contents = FileContents.new(contents)
else
raise ArgumentError.new(_("contents must be a String or Pathname, got a %{contents_class}") % { contents_class: contents.class })
end
@bucket_path = options.delete(:bucket_path)
@checksum_type = Puppet[:digest_algorithm].to_sym
raise ArgumentError.new(_("Unknown option(s): %{opts}") % { opts: options.keys.join(', ') }) unless options.empty?
end
# @return [Num] The size of the contents
def size
@contents.size()
end
# @return [IO] A stream that reads the contents
def stream(&block)
@contents.stream(&block)
end
def checksum_type
@checksum_type.to_s
end
def checksum
"{#{checksum_type}}#{checksum_data}"
end
def checksum_data
@checksum_data ||= @contents.checksum_data(@checksum_type)
end
def to_s
to_binary
end
def to_binary
@contents.to_binary
end
def contents
to_binary
end
def name
"#{checksum_type}/#{checksum_data}"
end
def self.from_binary(contents)
self.new(contents)
end
class StringContents
def initialize(content)
@contents = content;
end
def stream(&block)
s = StringIO.new(@contents)
begin
block.call(s)
ensure
s.close
end
end
def size
@contents.size
end
def checksum_data(base_method)
Puppet.info(_("Computing checksum on string"))
Puppet::Util::Checksums.method(base_method).call(@contents)
end
def to_binary
# This is not so horrible as for FileContent, but still possible to mutate the content that the
# checksum is based on... so semi horrible...
return @contents;
end
end
class FileContents
def initialize(path)
@path = path
end
def stream(&block)
Puppet::FileSystem.open(@path, nil, 'rb', &block)
end
def size
Puppet::FileSystem.size(@path)
end
def checksum_data(base_method)
Puppet.info(_("Computing checksum on file %{path}") % { path: @path })
Puppet::Util::Checksums.method(:"#{base_method}_file").call(@path)
end
def to_binary
Puppet::FileSystem::binread(@path)
end
end
end
|