Class: Depot::RpmPackage

Inherits:
Object
  • Object
show all
Defined in:
lib/depot/packages/rpm.rb

Defined Under Namespace

Classes: FormatError

Constant Summary collapse

MAGIC =
"\xED\xAB\xEE\xDB".b.freeze
HEADER_MAGIC =
"\x8E\xAD\xE8".b.freeze
HICOLOR_ICON_PATH =
%r{/icons/hicolor/([^/]+)/apps/([^/]+)\.(png|svg|xpm)\z}i
IMAGE_EXT =
/\.(png|svg|xpm)\z/i
SCRIPT_TAGS =
{
  1023 => "preinstall",
  1024 => "postinstall",
  1025 => "preuninstall",
  1026 => "postuninstall",
  1065 => "verify",
  1085 => "triggerinstall",
  1086 => "triggeruninstall",
  1087 => "triggerpostuninstall"
}.freeze
TAGS =
{
  1000 => "Name",
  1001 => "Version",
  1002 => "Release",
  1004 => "Summary",
  1005 => "Description",
  1014 => "License",
  1015 => "Packager",
  1020 => "URL",
  1021 => "OS",
  1022 => "Architecture",
  1049 => "Requires",
  1116 => "DirIndexes",
  1117 => "BaseNames",
  1118 => "DirNames",
  1124 => "PayloadFormat",
  1125 => "PayloadCompressor",
  1126 => "PayloadFlags"
}.merge(SCRIPT_TAGS.transform_values { |name| "Script:#{name}" }).freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path) ⇒ RpmPackage

Returns a new instance of RpmPackage.



44
45
46
# File 'lib/depot/packages/rpm.rb', line 44

def initialize(path)
  @path = path
end

Instance Attribute Details

#pathObject (readonly)

Returns the value of attribute path.



42
43
44
# File 'lib/depot/packages/rpm.rb', line 42

def path
  @path
end

Instance Method Details

#clean_membersObject



100
101
102
# File 'lib/depot/packages/rpm.rb', line 100

def clean_members
  members.map { |entry| clean_entry(entry) }
end

#desktop_entriesObject



104
105
106
# File 'lib/depot/packages/rpm.rb', line 104

def desktop_entries
  payload_entries.select { |entry| entry.end_with?(".desktop") }
end

#display_nameObject



76
77
78
# File 'lib/depot/packages/rpm.rb', line 76

def display_name
  header_fields["Name"] || File.basename(path, ".rpm")
end

#executable_candidatesObject



120
121
122
123
124
# File 'lib/depot/packages/rpm.rb', line 120

def executable_candidates
  payload_entries.reject { |entry| entry.end_with?("/") }
                 .select { |entry| executable_name?(entry) }
                 .first(24)
end

#extract_to(destination) ⇒ Object

Raises:



157
158
159
160
161
162
163
# File 'lib/depot/packages/rpm.rb', line 157

def extract_to(destination)
  FileUtils.mkdir_p(destination)
  assert_bsdtar!
  assert_safe_entries!
  stdout, stderr, status = Open3.capture3("bsdtar", "-xf", path, "-C", destination)
  raise FormatError, "Could not extract RPM payload: #{stderr.empty? ? stdout : stderr}" unless status.success?
end

#file_entriesObject



126
127
128
129
# File 'lib/depot/packages/rpm.rb', line 126

def file_entries
  entries = header_file_entries
  entries.empty? ? clean_members : entries
end

#header_fieldsObject



54
55
56
# File 'lib/depot/packages/rpm.rb', line 54

def header_fields
  @header_fields ||= parse_main_header
end

#header_file_entriesObject



131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/depot/packages/rpm.rb', line 131

def header_file_entries
  fields = header_fields
  bases = Array(fields["BaseNames"])
  dirs = Array(fields["DirNames"])
  indexes = Array(fields["DirIndexes"])
  return [] if bases.empty? || dirs.empty? || indexes.empty?

  bases.each_with_index.map do |base, index|
    dir = dirs[indexes[index].to_i].to_s
    clean_entry(File.join(dir, base))
  end
end

#icon_entriesObject



116
117
118
# File 'lib/depot/packages/rpm.rb', line 116

def icon_entries
  payload_entries.select { |entry| entry.match?(HICOLOR_ICON_PATH) }
end

#image_entriesObject



112
113
114
# File 'lib/depot/packages/rpm.rb', line 112

def image_entries
  payload_entries.select { |entry| entry.match?(IMAGE_EXT) }
end

#membersObject



96
97
98
# File 'lib/depot/packages/rpm.rb', line 96

def members
  @members ||= list_payload
end

#package_fieldsObject



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/depot/packages/rpm.rb', line 58

def package_fields
  fields = header_fields
  {
    "Name" => fields["Name"],
    "Version" => fields["Version"],
    "Release" => fields["Release"],
    "Architecture" => fields["Architecture"],
    "Summary" => fields["Summary"],
    "Description" => fields["Description"],
    "License" => fields["License"],
    "Packager" => fields["Packager"],
    "URL" => fields["URL"],
    "PayloadFormat" => fields["PayloadFormat"],
    "PayloadCompressor" => fields["PayloadCompressor"],
    "PayloadFlags" => fields["PayloadFlags"]
  }.compact
end

#primary_desktop_entryObject



108
109
110
# File 'lib/depot/packages/rpm.rb', line 108

def primary_desktop_entry
  desktop_entries.min_by { |entry| desktop_score(entry) }
end

#read_entry(entry) ⇒ Object

Raises:



144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/depot/packages/rpm.rb', line 144

def read_entry(entry)
  wanted = clean_entry(entry)
  candidates = [wanted, "./#{wanted}"].uniq
  candidates.each do |candidate|
    stdout, stderr, status = Open3.capture3("bsdtar", "-xOf", path, candidate)
    return stdout if status.success?

    @last_read_error = stderr.empty? ? stdout : stderr
  end

  raise FormatError, "Could not read #{entry}: #{@last_read_error}"
end

#requiresObject



84
85
86
# File 'lib/depot/packages/rpm.rb', line 84

def requires
  Array(header_fields["Requires"]).reject { |name| name.start_with?("rpmlib(") }.uniq
end

#scriptletsObject



88
89
90
91
92
93
94
# File 'lib/depot/packages/rpm.rb', line 88

def scriptlets
  header_fields.filter_map do |key, value|
    next unless key.start_with?("Script:") && value.to_s.strip != ""

    key.delete_prefix("Script:")
  end
end

#valid?Boolean

Returns:

  • (Boolean)


48
49
50
51
52
# File 'lib/depot/packages/rpm.rb', line 48

def valid?
  rpm_magic? && header_fields.any?
rescue FormatError
  false
end

#version_labelObject



80
81
82
# File 'lib/depot/packages/rpm.rb', line 80

def version_label
  [header_fields["Version"], header_fields["Release"]].compact.join("-")
end