Class: ReaperMan::PackageList::Processor::Rpm

Inherits:
ReaperMan::PackageList::Processor show all
Defined in:
lib/reaper-man/package_list/rpm.rb

Overview

Package list process for RPM packages

Constant Summary collapse

DEFAULT_ROOT =

default package root prefix

"pool"
DEFAULT_BUCKET =

default namespace for packages

"public"
DEFAULT_ALL_MAP =

default architectures to define

["amd64", "i386"]

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Utils::Checksum

#checksum

Methods included from Utils::Process

#child_process_command, #mixlib_shellout_command, #shellout

Constructor Details

#initialize(args = {}) ⇒ Rpm

Create new instance

Parameters:

  • args (Hash) (defaults to: {})

Options Hash (args):

  • :origin (String)
  • :codename (String)
  • :component (String)
  • :package_root (String)
  • :package_bucket (String)
  • :all_map (Array<String>)


38
39
40
41
42
43
44
45
46
47
48
# File 'lib/reaper-man/package_list/rpm.rb', line 38

def initialize(args = {})
  @origin = args[:origin].to_s
  @dist = args[:codename].to_s
  @component = args[:component].to_s
  @package_root = args.fetch(:package_root, DEFAULT_ROOT)
  @package_bucket = args.fetch(:package_bucket, DEFAULT_BUCKET)
  if dist.empty? || component.empty?
    raise "Both `codename` and `component` must contain valid values"
  end
  @all_map = args.fetch(:all_map, DEFAULT_ALL_MAP)
end

Instance Attribute Details

#all_mapArray<String> (readonly)

Returns architectures.

Returns:

  • (Array<String>)

    architectures



16
17
18
# File 'lib/reaper-man/package_list/rpm.rb', line 16

def all_map
  @all_map
end

#componentString (readonly)

Returns:

  • (String)


14
15
16
# File 'lib/reaper-man/package_list/rpm.rb', line 14

def component
  @component
end

#distString (readonly)

Returns:

  • (String)


12
13
14
# File 'lib/reaper-man/package_list/rpm.rb', line 12

def dist
  @dist
end

#originString (readonly)

Returns:

  • (String)


10
11
12
# File 'lib/reaper-man/package_list/rpm.rb', line 10

def origin
  @origin
end

#package_bucketString (readonly)

Returns namespace for packages.

Returns:

  • (String)

    namespace for packages



20
21
22
# File 'lib/reaper-man/package_list/rpm.rb', line 20

def package_bucket
  @package_bucket
end

#package_rootString (readonly)

Returns prefix for package file location.

Returns:

  • (String)

    prefix for package file location



18
19
20
# File 'lib/reaper-man/package_list/rpm.rb', line 18

def package_root
  @package_root
end

Instance Method Details

#add(hash, package) ⇒ Object

Add a package to the list

Parameters:

  • conf (Hash)
  • package (String)

    path to package



54
55
56
57
58
59
# File 'lib/reaper-man/package_list/rpm.rb', line 54

def add(hash, package)
  info = extract_fields(package)
  info.merge!(generate_checksums(package))
  filenames = inject_package(hash, info, package)
  filenames
end

#extract_fields(package) ⇒ Hash

Extract package metadata

Parameters:

  • package (String)

    path to package

Returns:

  • (Hash)


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
# File 'lib/reaper-man/package_list/rpm.rb', line 87

def extract_fields(package)
  fields = shellout("rpm --querytags").stdout.split("\n").map do |line|
    line.strip!
    unless line.empty? || line.start_with?("HEADER")
      line
    end
  end.compact

  fmt = fields.map do |k|
    ["\\[#{k}\\]", "[%{#{k}}\n]"]
  end.flatten.join("\n")

  cmd = "rpm -q -p #{package} --queryformat 'output:\n#{fmt}'"
  result = shellout(cmd).stdout.sub(/.*output:/, "")

  data = Smash.new
  key = nil
  result.split("\n").each do |item|
    item.strip!
    next if item.empty?
    if item.start_with?("[") && item.end_with?("]")
      key = item.tr("[]", "")
    else
      if data[key]
        if !data[key].is_a?(Array)
          data[key] = [data[key]]
        end
        data[key] << item
      else
        data[key] = item
      end
    end
  end
  data[:generated_sha] = checksum(File.open(package, "r"), :sha1)
  data[:generated_size] = File.size(package)
  data[:generated_header] = extract_header_information(package)
  data
end

#extract_header_information(package) ⇒ Smash<start,end>

Extract the start and end points of the header within the package

Parameters:

  • package (String)

    path to package

Returns:

  • (Smash<start,end>)


181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
# File 'lib/reaper-man/package_list/rpm.rb', line 181

def extract_header_information(package)
  io = File.open(package, "rb")

  # read past lead and 8 bytes of signature header
  io.seek(104)
  binindex = io.read(4)
  sigindex, _ = binindex.unpack("I>")

  bindata = io.read(4)
  sigdata, _ = bindata.unpack("I>")

  # seeked in to 112 bytes

  # each index is 4 32bit segments == 16 bytes

  sigindexsize = sigindex * 16
  sigsize = sigdata + sigindexsize

  # Round to next 8 byte boundary

  disttoboundary = (sigsize % 8)
  unless disttoboundary == 0
    disttoboundary = 8 - disttoboundary
  end

  # 112 bytes - 96 == lead
  # 8 == magic and reserved
  # 8 == signature header data

  hdrstart = 112 + sigsize + disttoboundary

  # seek to start of header
  io.seek(hdrstart)
  # seek past magic
  io.seek(8, IO::SEEK_CUR)

  binindex = io.read(4)

  hdrindex, _ = binindex.unpack("I>")
  bindata = io.read(4)
  hdrdata, _ = bindata.unpack("I>")

  # each index is 4 32bit segments - so each is 16 bytes

  hdrindexsize = hdrindex * 16

  # add 16 to the hdrsize to account for 16 bytes of misc data
  # between the end of the sig and the header

  hdrsize = hdrdata + hdrindexsize + 16

  # header end is hdrstart + hdrsize

  hdrend = hdrstart + hdrsize

  Smash.new(
    :start => hdrstart,
    :end => hdrend,
  )
end

#generate_checksums(package) ⇒ Hash

Generate required checksums for given package

Parameters:

  • package (String)

    path to package file

Returns:

  • (Hash)

    checksums



165
166
167
168
169
170
171
172
173
# File 'lib/reaper-man/package_list/rpm.rb', line 165

def generate_checksums(package)
  File.open(package, "r") do |pkg|
    {
      "MD5sum" => checksum(pkg.rewind && pkg, :md5),
      "SHA1" => checksum(pkg.rewind && pkg, :sha1),
      "SHA256" => checksum(pkg.rewind && pkg, :sha256),
    }
  end
end

#inject_package(hash, info, package) ⇒ Array<String>

Insert package information into package list

Parameters:

  • hash (Hash)

    package list contents

  • info (Hash)

    package information

  • package (String)

    path to package file

Returns:

  • (Array<String>)

    package paths within package list contents



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/reaper-man/package_list/rpm.rb', line 132

def inject_package(hash, info, package)
  arch = info["ARCH"]
  arch = arch == "all" ? all_map : [arch]
  arch.map do |arch|
    package_file_name = File.join(
      package_root, package_bucket, origin,
      dist, component, File.basename(package)
    )
    hash.deep_merge!(
      "yum" => {
        origin => {
          dist => {
            "components" => {
              component => {
                arch => {
                  info["NAME"] => {
                    info["NEVR"] => info.merge(:generated_path => package_file_name),
                  },
                },
              },
            },
          },
        },
      },
    )
    File.join("yum", origin, package_file_name)
  end
end

#remove(hash, package_name, version, args = {}) ⇒ Object

Remove package from the list

Parameters:

  • conf (Hash)

    configuration hash

  • package_name (String)

    name

  • version (String)


66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/reaper-man/package_list/rpm.rb', line 66

def remove(hash, package_name, version, args = {})
  hash = hash.to_smash
  arch = [args.fetch(:arch, all_map)].flatten.compact
  deleted = false
  arch.each do |arch_name|
    arch_name = "binary-#{arch_name}"
    if hash.get(:yum, origin, dist, :components, component, arch_name, package_name)
      if version
        deleted = hash[:yum][origin][dist][:components][component][arch_name][package_name].delete(version)
      else
        deleted = hash[:yum][origin][dist][:components][component][arch_name].delete(package_name)
      end
    end
  end
  !!deleted
end