File: file.rb

package info (click to toggle)
puppet-agent 7.23.0-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 19,092 kB
  • sloc: ruby: 245,074; sh: 456; makefile: 38; xml: 33
file content (129 lines) | stat: -rw-r--r-- 2,984 bytes parent folder | download
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