arr-pm 0.0.10 → 0.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of arr-pm might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/Guardfile +77 -0
- data/arr-pm.gemspec +1 -1
- data/lib/arr-pm/file.rb +6 -4
- data/lib/arr-pm/file/header.rb +2 -10
- data/lib/arr-pm/namespace.rb +6 -0
- data/lib/arr-pm/v2/architecture.rb +32 -0
- data/lib/arr-pm/v2/error.rb +32 -0
- data/lib/arr-pm/v2/format.rb +16 -0
- data/lib/arr-pm/v2/header.rb +35 -0
- data/lib/arr-pm/v2/header_header.rb +36 -0
- data/lib/arr-pm/v2/lead.rb +121 -0
- data/lib/arr-pm/v2/package.rb +18 -0
- data/lib/arr-pm/v2/tag.rb +295 -0
- data/lib/arr-pm/v2/type.rb +15 -0
- data/spec/arr-pm/v2/header_spec.rb +34 -0
- data/spec/arr-pm/v2/lead_spec.rb +125 -0
- data/spec/fixtures/example-1.0-1.x86_64.rpm +0 -0
- data/spec/fixtures/example.json +55 -0
- metadata +21 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ceb08ab00b24c659ee4f0fd42d8f5c8ad77416ffff3f89e8ee18ec46ddc58383
|
4
|
+
data.tar.gz: b53d4d64c24362fb2cf27606842d8352e9f7d184f9ba3b76eb1e33b3e13b2775
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 441b7c7a0d0851c3c4cadaf7e2e0f20d32388ba4df722ee3f76bfb3a34bb072739daf63739cf19e9d8f221a40a80f999ca47b2825043ded493d1f3363dec3e54
|
7
|
+
data.tar.gz: 815d8fff66bc8672b7e212f6c138795a9029b5e78032d26051ac114e306084f97d01519060427aeb50e9bca29dd49af5d5567370904d8881fc99179184811cd3
|
data/Guardfile
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
## Uncomment and set this to only include directories you want to watch
|
5
|
+
# directories %w(app lib config test spec features)
|
6
|
+
|
7
|
+
## Uncomment to clear the screen before every task
|
8
|
+
# clearing :on
|
9
|
+
|
10
|
+
## Guard internally checks for changes in the Guardfile and exits.
|
11
|
+
## If you want Guard to automatically start up again, run guard in a
|
12
|
+
## shell loop, e.g.:
|
13
|
+
##
|
14
|
+
## $ while bundle exec guard; do echo "Restarting Guard..."; done
|
15
|
+
##
|
16
|
+
## Note: if you are using the `directories` clause above and you are not
|
17
|
+
## watching the project directory ('.'), then you will want to move
|
18
|
+
## the Guardfile to a watched dir and symlink it back, e.g.
|
19
|
+
#
|
20
|
+
# $ mkdir config
|
21
|
+
# $ mv Guardfile config/
|
22
|
+
# $ ln -s config/Guardfile .
|
23
|
+
#
|
24
|
+
# and, you'll have to watch "config/Guardfile" instead of "Guardfile"
|
25
|
+
|
26
|
+
# Note: The cmd option is now required due to the increasing number of ways
|
27
|
+
# rspec may be run, below are examples of the most common uses.
|
28
|
+
# * bundler: 'bundle exec rspec'
|
29
|
+
# * bundler binstubs: 'bin/rspec'
|
30
|
+
# * spring: 'bin/rspec' (This will use spring if running and you have
|
31
|
+
# installed the spring binstubs per the docs)
|
32
|
+
# * zeus: 'zeus rspec' (requires the server to be started separately)
|
33
|
+
# * 'just' rspec: 'rspec'
|
34
|
+
|
35
|
+
guard :rspec, cmd: "bundle exec rspec" do
|
36
|
+
require "guard/rspec/dsl"
|
37
|
+
dsl = Guard::RSpec::Dsl.new(self)
|
38
|
+
|
39
|
+
# Feel free to open issues for suggestions and improvements
|
40
|
+
|
41
|
+
# RSpec files
|
42
|
+
rspec = dsl.rspec
|
43
|
+
watch(rspec.spec_helper) { rspec.spec_dir }
|
44
|
+
watch(rspec.spec_support) { rspec.spec_dir }
|
45
|
+
watch(rspec.spec_files)
|
46
|
+
|
47
|
+
# Ruby files
|
48
|
+
ruby = dsl.ruby
|
49
|
+
dsl.watch_spec_files_for(ruby.lib_files)
|
50
|
+
|
51
|
+
# Rails files
|
52
|
+
rails = dsl.rails(view_extensions: %w(erb haml slim))
|
53
|
+
dsl.watch_spec_files_for(rails.app_files)
|
54
|
+
dsl.watch_spec_files_for(rails.views)
|
55
|
+
|
56
|
+
watch(rails.controllers) do |m|
|
57
|
+
[
|
58
|
+
rspec.spec.("routing/#{m[1]}_routing"),
|
59
|
+
rspec.spec.("controllers/#{m[1]}_controller"),
|
60
|
+
rspec.spec.("acceptance/#{m[1]}")
|
61
|
+
]
|
62
|
+
end
|
63
|
+
|
64
|
+
# Rails config changes
|
65
|
+
watch(rails.spec_helper) { rspec.spec_dir }
|
66
|
+
watch(rails.routes) { "#{rspec.spec_dir}/routing" }
|
67
|
+
watch(rails.app_controller) { "#{rspec.spec_dir}/controllers" }
|
68
|
+
|
69
|
+
# Capybara features specs
|
70
|
+
watch(rails.view_dirs) { |m| rspec.spec.("features/#{m[1]}") }
|
71
|
+
|
72
|
+
# Turnip features and steps
|
73
|
+
watch(%r{^spec/acceptance/(.+)\.feature$})
|
74
|
+
watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) do |m|
|
75
|
+
Dir[File.join("**/#{m[1]}.feature")][0] || "spec/acceptance"
|
76
|
+
end
|
77
|
+
end
|
data/arr-pm.gemspec
CHANGED
@@ -2,7 +2,7 @@ Gem::Specification.new do |spec|
|
|
2
2
|
files = %x{git ls-files}.split("\n")
|
3
3
|
|
4
4
|
spec.name = "arr-pm"
|
5
|
-
spec.version = "0.0.
|
5
|
+
spec.version = "0.0.11"
|
6
6
|
spec.summary = "RPM reader and writer library"
|
7
7
|
spec.description = "This library allows to you to read and write rpm " \
|
8
8
|
"packages. Written in pure ruby because librpm is not available " \
|
data/lib/arr-pm/file.rb
CHANGED
@@ -179,10 +179,12 @@ class RPM::File
|
|
179
179
|
results = []
|
180
180
|
# short-circuit if there's no :fileflags tag
|
181
181
|
return results unless tags.include?(:fileflags)
|
182
|
-
tags[:fileflags].
|
183
|
-
|
184
|
-
|
185
|
-
|
182
|
+
if !tags[:fileflags].nil?
|
183
|
+
tags[:fileflags].each_with_index do |flag, i|
|
184
|
+
# The :fileflags (and other :file... tags) are an array, in order of
|
185
|
+
# files in the rpm payload, we want a list of paths of config files.
|
186
|
+
results << files[i] if mask?(flag, FLAG_CONFIG_FILE)
|
187
|
+
end
|
186
188
|
end
|
187
189
|
return results
|
188
190
|
end # def config_files
|
data/lib/arr-pm/file/header.rb
CHANGED
@@ -12,16 +12,8 @@ class RPM::File::Header
|
|
12
12
|
attr_accessor :data_length # rpmlib calls this field 'dl' unhelpfully
|
13
13
|
|
14
14
|
HEADER_SIGNED_TYPE = 5
|
15
|
-
|
16
|
-
|
17
|
-
# Ruby 2 forces all strings to be UTF-8, so "\x01" becomes "\u0001"
|
18
|
-
# which is two bytes 00 01 which is not what we want. I can't find
|
19
|
-
# a sane way to create a string without this madness in Ruby 2,
|
20
|
-
# so let's just pack two 4-byte integers and go about our day.
|
21
|
-
HEADER_MAGIC = [0x8eade801, 0x00000000].pack("NN")
|
22
|
-
else
|
23
|
-
HEADER_MAGIC = "\x8e\xad\xe8\x01\x00\x00\x00\x00"
|
24
|
-
end
|
15
|
+
HEADER_MAGIC = "\x8e\xad\xe8\x01\x00\x00\x00\x00".force_encoding("BINARY")
|
16
|
+
|
25
17
|
# magic + index_count + data_length
|
26
18
|
HEADER_HEADER_LENGTH = HEADER_MAGIC.length + 4 + 4
|
27
19
|
TAG_ENTRY_SIZE = 16 # tag id, type, offset, count == 16 bytes
|
data/lib/arr-pm/namespace.rb
CHANGED
@@ -0,0 +1,32 @@
|
|
1
|
+
require "arr-pm/namespace"
|
2
|
+
|
3
|
+
module ArrPM::V2::Architecture
|
4
|
+
|
5
|
+
NOARCH = 0
|
6
|
+
I386 = 1
|
7
|
+
ALPHA = 2
|
8
|
+
SPARC = 3
|
9
|
+
MIPS = 4
|
10
|
+
PPC = 5
|
11
|
+
M68K = 6
|
12
|
+
IP = 7
|
13
|
+
RS6000 = 8
|
14
|
+
IA64 = 9
|
15
|
+
SPARC64 = 10
|
16
|
+
MIPSEL = 11
|
17
|
+
ARM = 12
|
18
|
+
MK68KMINT = 13
|
19
|
+
S390 = 14
|
20
|
+
S390X = 15
|
21
|
+
PPC64 = 16
|
22
|
+
SH = 17
|
23
|
+
XTENSA = 18
|
24
|
+
X86_64 = 19
|
25
|
+
|
26
|
+
module_function
|
27
|
+
|
28
|
+
# Is a given rpm architecture value valid?
|
29
|
+
def valid?(value)
|
30
|
+
return value >= 0 && value <= 19
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "arr-pm/namespace"
|
4
|
+
require "arr-pm/v2/format"
|
5
|
+
|
6
|
+
module ArrPM::V2::Error
|
7
|
+
class Base < StandardError; end
|
8
|
+
|
9
|
+
class InvalidMagicValue < Base
|
10
|
+
def initialize(value)
|
11
|
+
super("Got invalid magic value '#{value}'. Expected #{ArrPM::V2::Format::MAGIC}.")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class InvalidHeaderMagicValue < Base
|
16
|
+
def initialize(value)
|
17
|
+
super("Got invalid magic value '#{value}'. Expected #{ArrPM::V2::HeaderHeader::MAGIC}.")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class EmptyFile < Base; end
|
22
|
+
class ShortFile < Base; end
|
23
|
+
class InvalidVersion < Base; end
|
24
|
+
class InvalidType < Base
|
25
|
+
def initialize(value)
|
26
|
+
super("Invalid type: #{value.inspect}")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
class InvalidName < Base; end
|
30
|
+
class InvalidArchitecture < Base; end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "arr-pm/namespace"
|
4
|
+
|
5
|
+
module ArrPM::V2::Format
|
6
|
+
MAGIC = [0x8e, 0xad, 0xe8]
|
7
|
+
MAGIC_LENGTH = MAGIC.count
|
8
|
+
MAGIC_STRING = MAGIC.pack("C#{MAGIC_LENGTH}")
|
9
|
+
|
10
|
+
module_function
|
11
|
+
def valid_magic?(magic)
|
12
|
+
magic = magic.bytes if magic.is_a?(String)
|
13
|
+
|
14
|
+
magic == MAGIC
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "arr-pm/namespace"
|
4
|
+
require "arr-pm/v2/format"
|
5
|
+
require "arr-pm/v2/header_header"
|
6
|
+
require "arr-pm/v2/tag"
|
7
|
+
require "arr-pm/v2/error"
|
8
|
+
|
9
|
+
class ArrPM::V2::Header
|
10
|
+
attr_reader :tags
|
11
|
+
|
12
|
+
def load(io)
|
13
|
+
headerheader = ArrPM::V2::HeaderHeader.new
|
14
|
+
headerheader.load(io)
|
15
|
+
headerdata = io.read(headerheader.entries * 16)
|
16
|
+
tagdata = io.read(headerheader.bytesize)
|
17
|
+
parse(headerdata, headerheader.entries, tagdata)
|
18
|
+
|
19
|
+
# signature headers are padded up to an 8-byte boundar, details here:
|
20
|
+
# http://rpm.org/gitweb?p=rpm.git;a=blob;f=lib/signature.c;h=63e59c00f255a538e48cbc8b0cf3b9bd4a4dbd56;hb=HEAD#l204
|
21
|
+
# Throw away the pad.
|
22
|
+
io.read(tagdata.length % 8)
|
23
|
+
end
|
24
|
+
|
25
|
+
def parse(data, entry_count, tagdata)
|
26
|
+
@tags = entry_count.times.collect do |i|
|
27
|
+
tag_number, type_number, offset, count = data[i * 16, 16].unpack("NNNN")
|
28
|
+
|
29
|
+
tag = ArrPM::V2::Tag.new(tag_number, type_number)
|
30
|
+
tag.parse(tagdata, offset, count)
|
31
|
+
tag
|
32
|
+
end
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "arr-pm/namespace"
|
4
|
+
require "arr-pm/v2/format"
|
5
|
+
require "arr-pm/v2/error"
|
6
|
+
|
7
|
+
# The header of an rpm has ... a header. Funky naming :)
|
8
|
+
class ArrPM::V2::HeaderHeader
|
9
|
+
MAGIC = [ 0x8e, 0xad, 0xe8 ]
|
10
|
+
MAGIC_LENGTH = MAGIC.count
|
11
|
+
|
12
|
+
attr_accessor :version, :entries, :bytesize
|
13
|
+
|
14
|
+
def load(io)
|
15
|
+
data = io.read(16)
|
16
|
+
parse(data)
|
17
|
+
end
|
18
|
+
|
19
|
+
def parse(data)
|
20
|
+
magic, version, reserved, entries, bytesize = data.unpack("a3Ca4NN")
|
21
|
+
self.class.validate_magic(magic.bytes)
|
22
|
+
|
23
|
+
@version = version
|
24
|
+
@entries = entries
|
25
|
+
@bytesize = bytesize
|
26
|
+
nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def dump
|
30
|
+
[magic, 1, 0, @entries, @bytesize].pack("a3Ca4NN")
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.validate_magic(value)
|
34
|
+
raise ArrPM::V2::Error::InvalidHeaderMagicValue, value if value != MAGIC
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "arr-pm/namespace"
|
4
|
+
require "arr-pm/v2/format"
|
5
|
+
require "arr-pm/v2/error"
|
6
|
+
|
7
|
+
class ArrPM::V2::Lead
|
8
|
+
LENGTH = 96
|
9
|
+
MAGIC = [ 0xed, 0xab, 0xee, 0xdb ]
|
10
|
+
MAGIC_LENGTH = MAGIC.count
|
11
|
+
|
12
|
+
SIGNED_TYPE = 5
|
13
|
+
|
14
|
+
attr_accessor :major, :minor, :type, :architecture, :name, :os, :signature_type, :reserved
|
15
|
+
|
16
|
+
def validate
|
17
|
+
self.class.validate_type(type)
|
18
|
+
self.class.validate_architecture(architecture)
|
19
|
+
if name.length > 65
|
20
|
+
raise ArrPM::V2::Error::InvalidName, "Name is longer than 65 chracters. This is invalid."
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def dump(io)
|
25
|
+
io.write(serialize)
|
26
|
+
end
|
27
|
+
|
28
|
+
def serialize
|
29
|
+
validate
|
30
|
+
[ *MAGIC, major, minor, type, architecture, name, os, signature_type, *reserved ].pack("C4CCnnZ66nnC16")
|
31
|
+
end
|
32
|
+
|
33
|
+
def load(io)
|
34
|
+
data = io.read(LENGTH)
|
35
|
+
parse(data)
|
36
|
+
end
|
37
|
+
|
38
|
+
def parse(bytestring)
|
39
|
+
raise ArrPM::V2::Error::EmptyFile if bytestring.nil?
|
40
|
+
data = bytestring.bytes
|
41
|
+
|
42
|
+
@magic = self.class.parse_magic(data)
|
43
|
+
@major, @minor = self.class.parse_version(data)
|
44
|
+
@type = self.class.parse_type(data)
|
45
|
+
@architecture = self.class.parse_architecture(data)
|
46
|
+
@name = self.class.parse_name(data)
|
47
|
+
@os = self.class.parse_os(data)
|
48
|
+
@signature_type = self.class.parse_signature_type(data)
|
49
|
+
@reserved = self.class.parse_reserved(data)
|
50
|
+
self
|
51
|
+
end
|
52
|
+
|
53
|
+
def signature?
|
54
|
+
@signature_type == SIGNED_TYPE
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.valid_version?(version)
|
58
|
+
version == 1
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.parse_magic(data)
|
62
|
+
magic = data[0, MAGIC_LENGTH]
|
63
|
+
validate_magic(magic)
|
64
|
+
magic
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.validate_magic(magic)
|
68
|
+
raise ArrPM::V2::Error::InvalidMagicValue, magic unless magic == MAGIC
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.parse_version(data)
|
72
|
+
offset = MAGIC_LENGTH
|
73
|
+
major, minor = data[offset, 2]
|
74
|
+
return major, minor
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.parse_type(data)
|
78
|
+
offset = MAGIC_LENGTH + 2
|
79
|
+
type = data[offset, 2].pack("CC").unpack("n").first
|
80
|
+
validate_type(type)
|
81
|
+
type
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.validate_type(type)
|
85
|
+
raise ArrPM::V2::Error::InvalidType, type unless ArrPM::V2::Type.valid?(type)
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.parse_architecture(data)
|
89
|
+
offset = MAGIC_LENGTH + 4
|
90
|
+
architecture = data[offset, 2].pack("C*").unpack("n").first
|
91
|
+
validate_architecture(architecture)
|
92
|
+
architecture
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.validate_architecture(architecture)
|
96
|
+
raise ArrPM::V2::Error::InvalidArchitecture unless ArrPM::V2::Architecture.valid?(architecture)
|
97
|
+
end
|
98
|
+
|
99
|
+
def self.parse_name(data)
|
100
|
+
offset = MAGIC_LENGTH + 6
|
101
|
+
name = data[offset, 66]
|
102
|
+
length = name.find_index(0) # find the first null byte
|
103
|
+
raise ArrPM::V2::Error::InvalidName unless length
|
104
|
+
return name[0, length].pack("C*")
|
105
|
+
end
|
106
|
+
|
107
|
+
def self.parse_os(data)
|
108
|
+
offset = MAGIC_LENGTH + 72
|
109
|
+
data[offset, 2].pack("C*").unpack("n").first
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.parse_signature_type(data)
|
113
|
+
offset = MAGIC_LENGTH + 74
|
114
|
+
data[offset, 2].pack("C*").unpack("n").first
|
115
|
+
end
|
116
|
+
|
117
|
+
def self.parse_reserved(data)
|
118
|
+
offset = MAGIC_LENGTH + 76
|
119
|
+
data[offset, 16]
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "arr-pm/namespace"
|
4
|
+
|
5
|
+
class ArrPM::V2::RPM
|
6
|
+
attr_accessor :name
|
7
|
+
attr_accessor :epoch
|
8
|
+
attr_accessor :version
|
9
|
+
attr_accessor :release
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
defaults
|
13
|
+
end
|
14
|
+
|
15
|
+
def defaults
|
16
|
+
@type = Type::BINARY
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,295 @@
|
|
1
|
+
require "arr-pm/namespace"
|
2
|
+
|
3
|
+
class ArrPM::V2::Tag
|
4
|
+
module Type
|
5
|
+
NULL = 0
|
6
|
+
CHAR = 1
|
7
|
+
INT8 = 2
|
8
|
+
INT16 = 3
|
9
|
+
INT32 = 4
|
10
|
+
INT64 = 5
|
11
|
+
STRING = 6
|
12
|
+
BINARY = 7
|
13
|
+
STRING_ARRAY = 8
|
14
|
+
I18NSTRING = 9
|
15
|
+
|
16
|
+
TYPE_MAP = Hash[constants.collect { |c| [const_get(c), c] }]
|
17
|
+
|
18
|
+
def self.parse(data, type, offset, count)
|
19
|
+
case type
|
20
|
+
when NULL
|
21
|
+
nil
|
22
|
+
when CHAR
|
23
|
+
data[offset, count].unpack("A#{count}")
|
24
|
+
when INT8
|
25
|
+
data[offset, count].unpack("C" * count)
|
26
|
+
when INT16
|
27
|
+
data[offset, 2 * count].unpack("n" * count)
|
28
|
+
when INT32
|
29
|
+
data[offset, 4 * count].unpack("N" * count)
|
30
|
+
when INT64
|
31
|
+
a, b = data[offset, 8].unpack("NN")
|
32
|
+
a << 32 + b
|
33
|
+
when STRING, I18NSTRING
|
34
|
+
data[offset..-1][/^[^\0]*/]
|
35
|
+
when BINARY
|
36
|
+
data[offset, count]
|
37
|
+
when STRING_ARRAY
|
38
|
+
data[offset..-1].split("\0")[0...count]
|
39
|
+
else
|
40
|
+
raise ArrPM::V2::Error::InvalidType, type
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end # module Type
|
44
|
+
|
45
|
+
HEADERIMAGE = 61
|
46
|
+
HEADERSIGNATURES = 62
|
47
|
+
HEADERIMMUTABLE = 63
|
48
|
+
HEADERREGIONS = 64
|
49
|
+
HEADERI18NTABLE = 100
|
50
|
+
SIG_BASE = 256
|
51
|
+
|
52
|
+
SIGSIZE = 257
|
53
|
+
SIGLEMD5_1 = 258
|
54
|
+
SIGPGP = 259
|
55
|
+
SIGLEMD5_2 = 260
|
56
|
+
SIGMD5 = 261
|
57
|
+
SIGGPG = 262
|
58
|
+
SIGPGP5 = 263
|
59
|
+
BADSHA1_1 = 264
|
60
|
+
BADSHA1_2 = 265
|
61
|
+
PUBKEYS = 266
|
62
|
+
DSAHEADER = 267
|
63
|
+
RSAHEADER = 268
|
64
|
+
SHA1HEADER = 269
|
65
|
+
LONGSIGSIZE = 270
|
66
|
+
LONGARCHIVESIZE = 271
|
67
|
+
|
68
|
+
NAME = 1000
|
69
|
+
VERSION = 1001
|
70
|
+
RELEASE = 1002
|
71
|
+
EPOCH = 1003
|
72
|
+
SUMMARY = 1004
|
73
|
+
DESCRIPTION = 1005
|
74
|
+
BUILDTIME = 1006
|
75
|
+
BUILDHOST = 1007
|
76
|
+
INSTALLTIME = 1008
|
77
|
+
SIZE = 1009
|
78
|
+
DISTRIBUTION = 1010
|
79
|
+
VENDOR = 1011
|
80
|
+
GIF = 1012
|
81
|
+
XPM = 1013
|
82
|
+
LICENSE = 1014
|
83
|
+
PACKAGER = 1015
|
84
|
+
GROUP = 1016
|
85
|
+
CHANGELOG = 1017
|
86
|
+
SOURCE = 1018
|
87
|
+
PATCH = 1019
|
88
|
+
URL = 1020
|
89
|
+
OS = 1021
|
90
|
+
ARCH = 1022
|
91
|
+
PREIN = 1023
|
92
|
+
POSTIN = 1024
|
93
|
+
PREUN = 1025
|
94
|
+
POSTUN = 1026
|
95
|
+
OLDFILENAMES = 1027
|
96
|
+
FILESIZES = 1028
|
97
|
+
FILESTATES = 1029
|
98
|
+
FILEMODES = 1030
|
99
|
+
FILEUIDS = 1031
|
100
|
+
FILEGIDS = 1032
|
101
|
+
FILERDEVS = 1033
|
102
|
+
FILEMTIMES = 1034
|
103
|
+
FILEDIGESTS = 1035
|
104
|
+
FILELINKTOS = 1036
|
105
|
+
FILEFLAGS = 1037
|
106
|
+
ROOT = 1038
|
107
|
+
FILEUSERNAME = 1039
|
108
|
+
FILEGROUPNAME = 1040
|
109
|
+
EXCLUDE = 1041
|
110
|
+
EXCLUSIVE = 1042
|
111
|
+
ICON = 1043
|
112
|
+
SOURCERPM = 1044
|
113
|
+
FILEVERIFYFLAGS = 1045
|
114
|
+
ARCHIVESIZE = 1046
|
115
|
+
PROVIDENAME = 1047
|
116
|
+
REQUIREFLAGS = 1048
|
117
|
+
REQUIRENAME = 1049
|
118
|
+
REQUIREVERSION = 1050
|
119
|
+
NOSOURCE = 1051
|
120
|
+
NOPATCH = 1052
|
121
|
+
CONFLICTFLAGS = 1053
|
122
|
+
CONFLICTNAME = 1054
|
123
|
+
CONFLICTVERSION = 1055
|
124
|
+
DEFAULTPREFIX = 1056
|
125
|
+
BUILDROOT = 1057
|
126
|
+
INSTALLPREFIX = 1058
|
127
|
+
EXCLUDEARCH = 1059
|
128
|
+
EXCLUDEOS = 1060
|
129
|
+
EXCLUSIVEARCH = 1061
|
130
|
+
EXCLUSIVEOS = 1062
|
131
|
+
AUTOREQPROV = 1063
|
132
|
+
RPMVERSION = 1064
|
133
|
+
TRIGGERSCRIPTS = 1065
|
134
|
+
TRIGGERNAME = 1066
|
135
|
+
TRIGGERVERSION = 1067
|
136
|
+
TRIGGERFLAGS = 1068
|
137
|
+
TRIGGERINDEX = 1069
|
138
|
+
VERIFYSCRIPT = 1079
|
139
|
+
CHANGELOGTIME = 1080
|
140
|
+
CHANGELOGNAME = 1081
|
141
|
+
CHANGELOGTEXT = 1082
|
142
|
+
BROKENMD5 = 1083
|
143
|
+
PREREQ = 1084
|
144
|
+
PREINPROG = 1085
|
145
|
+
POSTINPROG = 1086
|
146
|
+
PREUNPROG = 1087
|
147
|
+
POSTUNPROG = 1088
|
148
|
+
BUILDARCHS = 1089
|
149
|
+
OBSOLETENAME = 1090
|
150
|
+
VERIFYSCRIPTPROG = 1091
|
151
|
+
TRIGGERSCRIPTPROG = 1092
|
152
|
+
DOCDIR = 1093
|
153
|
+
COOKIE = 1094
|
154
|
+
FILEDEVICES = 1095
|
155
|
+
FILEINODES = 1096
|
156
|
+
FILELANGS = 1097
|
157
|
+
PREFIXES = 1098
|
158
|
+
INSTPREFIXES = 1099
|
159
|
+
TRIGGERIN = 1100
|
160
|
+
TRIGGERUN = 1101
|
161
|
+
TRIGGERPOSTUN = 1102
|
162
|
+
AUTOREQ = 1103
|
163
|
+
AUTOPROV = 1104
|
164
|
+
CAPABILITY = 1105
|
165
|
+
SOURCEPACKAGE = 1106
|
166
|
+
OLDORIGFILENAMES = 1107
|
167
|
+
BUILDPREREQ = 1108
|
168
|
+
BUILDREQUIRES = 1109
|
169
|
+
BUILDCONFLICTS = 1110
|
170
|
+
BUILDMACROS = 1111
|
171
|
+
PROVIDEFLAGS = 1112
|
172
|
+
PROVIDEVERSION = 1113
|
173
|
+
OBSOLETEFLAGS = 1114
|
174
|
+
OBSOLETEVERSION = 1115
|
175
|
+
DIRINDEXES = 1116
|
176
|
+
BASENAMES = 1117
|
177
|
+
DIRNAMES = 1118
|
178
|
+
ORIGDIRINDEXES = 1119
|
179
|
+
ORIGBASENAMES = 1120
|
180
|
+
ORIGDIRNAMES = 1121
|
181
|
+
OPTFLAGS = 1122
|
182
|
+
DISTURL = 1123
|
183
|
+
PAYLOADFORMAT = 1124
|
184
|
+
PAYLOADCOMPRESSOR = 1125
|
185
|
+
PAYLOADFLAGS = 1126
|
186
|
+
INSTALLCOLOR = 1127
|
187
|
+
INSTALLTID = 1128
|
188
|
+
REMOVETID = 1129
|
189
|
+
SHA1RHN = 1130
|
190
|
+
RHNPLATFORM = 1131
|
191
|
+
PLATFORM = 1132
|
192
|
+
PATCHESNAME = 1133
|
193
|
+
PATCHESFLAGS = 1134
|
194
|
+
PATCHESVERSION = 1135
|
195
|
+
CACHECTIME = 1136
|
196
|
+
CACHEPKGPATH = 1137
|
197
|
+
CACHEPKGSIZE = 1138
|
198
|
+
CACHEPKGMTIME = 1139
|
199
|
+
FILECOLORS = 1140
|
200
|
+
FILECLASS = 1141
|
201
|
+
CLASSDICT = 1142
|
202
|
+
FILEDEPENDSX = 1143
|
203
|
+
FILEDEPENDSN = 1144
|
204
|
+
DEPENDSDICT = 1145
|
205
|
+
SOURCEPKGID = 1146
|
206
|
+
FILECONTEXTS = 1147
|
207
|
+
FSCONTEXTS = 1148
|
208
|
+
RECONTEXTS = 1149
|
209
|
+
POLICIES = 1150
|
210
|
+
PRETRANS = 1151
|
211
|
+
POSTTRANS = 1152
|
212
|
+
PRETRANSPROG = 1153
|
213
|
+
POSTTRANSPROG = 1154
|
214
|
+
DISTTAG = 1155
|
215
|
+
SUGGESTSNAME = 1156
|
216
|
+
SUGGESTSVERSION = 1157
|
217
|
+
SUGGESTSFLAGS = 1158
|
218
|
+
ENHANCESNAME = 1159
|
219
|
+
ENHANCESVERSION = 1160
|
220
|
+
ENHANCESFLAGS = 1161
|
221
|
+
PRIORITY = 1162
|
222
|
+
CVSID = 1163
|
223
|
+
BLINKPKGID = 1164
|
224
|
+
BLINKHDRID = 1165
|
225
|
+
BLINKNEVRA = 1166
|
226
|
+
FLINKPKGID = 1167
|
227
|
+
FLINKHDRID = 1168
|
228
|
+
FLINKNEVRA = 1169
|
229
|
+
PACKAGEORIGIN = 1170
|
230
|
+
TRIGGERPREIN = 1171
|
231
|
+
BUILDSUGGESTS = 1172
|
232
|
+
BUILDENHANCES = 1173
|
233
|
+
SCRIPTSTATES = 1174
|
234
|
+
SCRIPTMETRICS = 1175
|
235
|
+
BUILDCPUCLOCK = 1176
|
236
|
+
FILEDIGESTALGOS = 1177
|
237
|
+
VARIANTS = 1178
|
238
|
+
XMAJOR = 1179
|
239
|
+
XMINOR = 1180
|
240
|
+
REPOTAG = 1181
|
241
|
+
KEYWORDS = 1182
|
242
|
+
BUILDPLATFORMS = 1183
|
243
|
+
PACKAGECOLOR = 1184
|
244
|
+
PACKAGEPREFCOLOR = 1185
|
245
|
+
XATTRSDICT = 1186
|
246
|
+
FILEXATTRSX = 1187
|
247
|
+
DEPATTRSDICT = 1188
|
248
|
+
CONFLICTATTRSX = 1189
|
249
|
+
OBSOLETEATTRSX = 1190
|
250
|
+
PROVIDEATTRSX = 1191
|
251
|
+
REQUIREATTRSX = 1192
|
252
|
+
BUILDPROVIDES = 1193
|
253
|
+
BUILDOBSOLETES = 1194
|
254
|
+
DBINSTANCE = 1195
|
255
|
+
NVRA = 1196
|
256
|
+
FILENAMES = 5000
|
257
|
+
FILEPROVIDE = 5001
|
258
|
+
FILEREQUIRE = 5002
|
259
|
+
FSNAMES = 5003
|
260
|
+
FSSIZES = 5004
|
261
|
+
TRIGGERCONDS = 5005
|
262
|
+
TRIGGERTYPE = 5006
|
263
|
+
ORIGFILENAMES = 5007
|
264
|
+
LONGFILESIZES = 5008
|
265
|
+
LONGSIZE = 5009
|
266
|
+
FILECAPS = 5010
|
267
|
+
FILEDIGESTALGO = 5011
|
268
|
+
BUGURL = 5012
|
269
|
+
EVR = 5013
|
270
|
+
NVR = 5014
|
271
|
+
NEVR = 5015
|
272
|
+
NEVRA = 5016
|
273
|
+
HEADERCOLOR = 5017
|
274
|
+
VERBOSE = 5018
|
275
|
+
EPOCHNUM = 5019
|
276
|
+
ENCODING = 5062
|
277
|
+
|
278
|
+
TAG_MAP = Hash[constants.collect { |c| [const_get(c), c] }]
|
279
|
+
|
280
|
+
attr_accessor :tag, :type, :value
|
281
|
+
|
282
|
+
def initialize(tag_number, type_number)
|
283
|
+
@tag = self.class::TAG_MAP[tag_number] || tag_number
|
284
|
+
@type = type_number
|
285
|
+
end
|
286
|
+
|
287
|
+
def parse(data, offset, count)
|
288
|
+
@value = Type.parse(data, @type, offset, count)
|
289
|
+
nil
|
290
|
+
end
|
291
|
+
|
292
|
+
def inspect
|
293
|
+
format("<%s#%s> %s/%d value=%s>", self.class.name, self.object_id, @tag, @type, @value.inspect)
|
294
|
+
end
|
295
|
+
end # module ArrPM::V2::Tag
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "arr-pm/namespace"
|
2
|
+
|
3
|
+
module ArrPM::V2::Type
|
4
|
+
BINARY = 0
|
5
|
+
SOURCE = 1
|
6
|
+
|
7
|
+
module_function
|
8
|
+
|
9
|
+
# Is a given rpm type value valid?
|
10
|
+
#
|
11
|
+
# The only valid types are BINARY (0) or SOURCE (1)
|
12
|
+
def valid?(value)
|
13
|
+
return (value == BINARY || value == SOURCE)
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "flores/random"
|
4
|
+
|
5
|
+
require "arr-pm/v2/header"
|
6
|
+
require "arr-pm/v2/type"
|
7
|
+
require "arr-pm/v2/architecture"
|
8
|
+
require "json"
|
9
|
+
|
10
|
+
describe ArrPM::V2::Header do
|
11
|
+
context "with a known good rpm" do
|
12
|
+
let(:path) { File.join(File.dirname(__FILE__), "../../fixtures/example-1.0-1.x86_64.rpm") }
|
13
|
+
let(:file) { File.new(path) }
|
14
|
+
|
15
|
+
before do
|
16
|
+
lead = ArrPM::V2::Lead.new
|
17
|
+
lead.load(file)
|
18
|
+
|
19
|
+
# Throw away the signature if we have one
|
20
|
+
described_class.new.load(file) if lead.signature?
|
21
|
+
|
22
|
+
subject.load(file)
|
23
|
+
end
|
24
|
+
|
25
|
+
expectations = JSON.parse(File.read(File.join(File.dirname(__FILE__), "../../fixtures/example.json")))
|
26
|
+
|
27
|
+
expectations.each do |name, expected_value|
|
28
|
+
it "should have expected value for the #{name} tag" do
|
29
|
+
tag = subject.tags.find { |t| t.tag.to_s == name }
|
30
|
+
expect(tag.value).to be == expected_value
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "flores/random"
|
4
|
+
|
5
|
+
require "arr-pm/v2/lead"
|
6
|
+
require "arr-pm/v2/type"
|
7
|
+
require "arr-pm/v2/architecture"
|
8
|
+
|
9
|
+
describe ArrPM::V2::Lead do
|
10
|
+
let(:major) { Flores::Random.integer(0..255) }
|
11
|
+
let(:minor) { Flores::Random.integer(0..255) }
|
12
|
+
let(:magic) { described_class::MAGIC }
|
13
|
+
let(:type) { ArrPM::V2::Type::BINARY }
|
14
|
+
let(:architecture) { ArrPM::V2::Architecture::I386 }
|
15
|
+
let(:os) { 0 }
|
16
|
+
let(:os_bytes) { [os].pack("n").unpack("C2") }
|
17
|
+
let(:signature_type) { 0 }
|
18
|
+
let(:signature_type_bytes) { [signature_type].pack("n").unpack("C2") }
|
19
|
+
let(:longname) { "test-1.0-1" }
|
20
|
+
let(:longnamebytes) { longname.bytes + (66-longname.bytesize).times.collect { 0 } }
|
21
|
+
let(:leadbytes) { magic + [major, minor] + [0, type, 0, architecture] + longnamebytes + os_bytes + signature_type_bytes + 16.times.collect { 0 } }
|
22
|
+
let(:lead) { leadbytes.pack("C*") }
|
23
|
+
|
24
|
+
describe ".parse_magic" do
|
25
|
+
context "when given an invalid magic value" do
|
26
|
+
# Generate random bytes for the magic value, should be bad.
|
27
|
+
let(:magic) { Flores::Random.iterations(0..10).collect { Flores::Random.integer(0..255) } }
|
28
|
+
|
29
|
+
it "should fail" do
|
30
|
+
expect { described_class.parse_magic(leadbytes) }.to raise_error(ArrPM::V2::Error::InvalidMagicValue)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context "when given a valid magic value" do
|
35
|
+
it "should succeed" do
|
36
|
+
expect { described_class.parse_magic(leadbytes) }.not_to raise_error
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe ".parse_version" do
|
42
|
+
context "when given an invalid version value" do
|
43
|
+
let(:data) { magic + [major, minor] }
|
44
|
+
|
45
|
+
it "should return an array of two values " do
|
46
|
+
expect(described_class.parse_version(leadbytes)).to be == [major, minor]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe ".parse_type" do
|
52
|
+
context "when given an invalid type" do
|
53
|
+
let(:type) { Flores::Random.integer(2..1000) }
|
54
|
+
it "should fail" do
|
55
|
+
expect { described_class.parse_type(leadbytes) }.to raise_error(ArrPM::V2::Error::InvalidType)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
context "with a valid type" do
|
59
|
+
it "should return the type" do
|
60
|
+
expect(described_class.parse_type(leadbytes)).to be == type
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe ".parse_name" do
|
66
|
+
context "with a valid name" do
|
67
|
+
it "should return the name" do
|
68
|
+
expect(described_class.parse_name(leadbytes)).to be == longname
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe ".parse_signature_type" do
|
74
|
+
it "should return the signature type" do
|
75
|
+
expect(described_class.parse_signature_type(leadbytes)).to be == signature_type
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe ".parse_reserved" do
|
80
|
+
it "should return exactly 16 bytes" do
|
81
|
+
expect(described_class.parse_reserved(leadbytes).count).to be == 16
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe "#parse" do
|
86
|
+
before do
|
87
|
+
subject.parse(lead)
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should have a correct parsed values" do
|
91
|
+
expect(subject.name).to be == longname
|
92
|
+
expect(subject.major).to be == major
|
93
|
+
expect(subject.minor).to be == minor
|
94
|
+
expect(subject.type).to be == type
|
95
|
+
expect(subject.architecture).to be == architecture
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
describe "#dump" do
|
100
|
+
before do
|
101
|
+
subject.parse(lead)
|
102
|
+
end
|
103
|
+
|
104
|
+
let(:blob) { subject.serialize }
|
105
|
+
|
106
|
+
it "should parse successfully" do
|
107
|
+
subject.parse(blob)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
context "with a known good rpm" do
|
112
|
+
let(:path) { File.join(File.dirname(__FILE__), "../../fixtures/example-1.0-1.x86_64.rpm") }
|
113
|
+
|
114
|
+
before do
|
115
|
+
subject.load(File.new(path))
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should have expected values" do
|
119
|
+
expect(subject.name).to be == "example-1.0-1"
|
120
|
+
expect(subject.major).to be == 3
|
121
|
+
expect(subject.minor).to be == 0
|
122
|
+
expect(subject.architecture).to be == architecture
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
Binary file
|
@@ -0,0 +1,55 @@
|
|
1
|
+
{
|
2
|
+
"NAME": "example",
|
3
|
+
"VERSION": "1.0",
|
4
|
+
"RELEASE": "1",
|
5
|
+
"SUMMARY": "no description given",
|
6
|
+
"DESCRIPTION": "no description given",
|
7
|
+
"BUILDTIME": [
|
8
|
+
1466326707
|
9
|
+
],
|
10
|
+
"BUILDHOST": "localhost",
|
11
|
+
"SIZE": [
|
12
|
+
0
|
13
|
+
],
|
14
|
+
"VENDOR": "none",
|
15
|
+
"LICENSE": "unknown",
|
16
|
+
"PACKAGER": "<jls@localhost.localdomain>",
|
17
|
+
"GROUP": "default",
|
18
|
+
"URL": "http://example.com/no-uri-given",
|
19
|
+
"OS": "linux",
|
20
|
+
"ARCH": "x86_64",
|
21
|
+
"SOURCERPM": "example-1.0-1.src.rpm",
|
22
|
+
"PROVIDENAME": [
|
23
|
+
"example",
|
24
|
+
"example(x86-64)"
|
25
|
+
],
|
26
|
+
"REQUIREFLAGS": [
|
27
|
+
16777226,
|
28
|
+
16777226
|
29
|
+
],
|
30
|
+
"REQUIRENAME": [
|
31
|
+
"rpmlib(CompressedFileNames)",
|
32
|
+
"rpmlib(PayloadFilesHavePrefix)"
|
33
|
+
],
|
34
|
+
"REQUIREVERSION": [
|
35
|
+
"3.0.4-1",
|
36
|
+
"4.0-1"
|
37
|
+
],
|
38
|
+
"RPMVERSION": "4.13.0-rc1",
|
39
|
+
"PREFIXES": [
|
40
|
+
"/"
|
41
|
+
],
|
42
|
+
"PROVIDEFLAGS": [
|
43
|
+
8,
|
44
|
+
8
|
45
|
+
],
|
46
|
+
"PROVIDEVERSION": [
|
47
|
+
"1.0-1",
|
48
|
+
"1.0-1"
|
49
|
+
],
|
50
|
+
"PAYLOADFORMAT": "cpio",
|
51
|
+
"PAYLOADCOMPRESSOR": "gzip",
|
52
|
+
"PAYLOADFLAGS": "9",
|
53
|
+
"PLATFORM": "x86_64-redhat-linux-gnu",
|
54
|
+
"ENCODING": "utf-8"
|
55
|
+
}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: arr-pm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jordan Sissel
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-06-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cabin
|
@@ -50,6 +50,7 @@ files:
|
|
50
50
|
- ".gitignore"
|
51
51
|
- ".rubocop.yml"
|
52
52
|
- Gemfile
|
53
|
+
- Guardfile
|
53
54
|
- LICENSE
|
54
55
|
- Makefile
|
55
56
|
- README.md
|
@@ -63,11 +64,24 @@ files:
|
|
63
64
|
- lib/arr-pm/file/tag.rb
|
64
65
|
- lib/arr-pm/namespace.rb
|
65
66
|
- lib/arr-pm/requires.rb
|
66
|
-
|
67
|
+
- lib/arr-pm/v2/architecture.rb
|
68
|
+
- lib/arr-pm/v2/error.rb
|
69
|
+
- lib/arr-pm/v2/format.rb
|
70
|
+
- lib/arr-pm/v2/header.rb
|
71
|
+
- lib/arr-pm/v2/header_header.rb
|
72
|
+
- lib/arr-pm/v2/lead.rb
|
73
|
+
- lib/arr-pm/v2/package.rb
|
74
|
+
- lib/arr-pm/v2/tag.rb
|
75
|
+
- lib/arr-pm/v2/type.rb
|
76
|
+
- spec/arr-pm/v2/header_spec.rb
|
77
|
+
- spec/arr-pm/v2/lead_spec.rb
|
78
|
+
- spec/fixtures/example-1.0-1.x86_64.rpm
|
79
|
+
- spec/fixtures/example.json
|
80
|
+
homepage:
|
67
81
|
licenses:
|
68
82
|
- Apache 2
|
69
83
|
metadata: {}
|
70
|
-
post_install_message:
|
84
|
+
post_install_message:
|
71
85
|
rdoc_options: []
|
72
86
|
require_paths:
|
73
87
|
- lib
|
@@ -83,9 +97,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
83
97
|
- !ruby/object:Gem::Version
|
84
98
|
version: '0'
|
85
99
|
requirements: []
|
86
|
-
|
87
|
-
|
88
|
-
signing_key:
|
100
|
+
rubygems_version: 3.2.15
|
101
|
+
signing_key:
|
89
102
|
specification_version: 4
|
90
103
|
summary: RPM reader and writer library
|
91
104
|
test_files: []
|