arr-pm 0.0.5 → 0.0.6
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.
- data/arr-pm.gemspec +1 -1
- data/lib/arr-pm.rb +0 -63
- data/lib/arr-pm/file.rb +66 -23
- metadata +1 -1
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.6"
|
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.rb
CHANGED
@@ -1,65 +1,2 @@
|
|
1
1
|
require "arr-pm/namespace"
|
2
2
|
require "arr-pm/file"
|
3
|
-
|
4
|
-
# This class is not yet complete, it is in prototype.
|
5
|
-
#
|
6
|
-
# Please use {RPM::File} instead
|
7
|
-
class RPM
|
8
|
-
private
|
9
|
-
|
10
|
-
def initialize
|
11
|
-
#@requires = []
|
12
|
-
#@conflicts = []
|
13
|
-
#@provides = []
|
14
|
-
#@files = []
|
15
|
-
#@scripts = {}
|
16
|
-
end
|
17
|
-
|
18
|
-
def requires(name, operator=nil, version=nil)
|
19
|
-
@requires << [name, operator, version]
|
20
|
-
end # def requires
|
21
|
-
|
22
|
-
def conflicts(name, operator=nil, version=nil)
|
23
|
-
@conflicts << [name, operator, version]
|
24
|
-
end
|
25
|
-
|
26
|
-
def provides(name)
|
27
|
-
@provides << name
|
28
|
-
end
|
29
|
-
|
30
|
-
def self.read(path_or_io)
|
31
|
-
rpmfile = RPM::File.new(path_or_io)
|
32
|
-
signature = rpmfile.signature
|
33
|
-
header = rpmfile.header
|
34
|
-
|
35
|
-
header.tags.each do |tag|
|
36
|
-
p tag
|
37
|
-
end
|
38
|
-
|
39
|
-
# Things we care about in the header:
|
40
|
-
# * name, version, release, epoch, summary, description
|
41
|
-
# *
|
42
|
-
# * requires, provides, conflicts
|
43
|
-
# * scripts
|
44
|
-
# * payload format
|
45
|
-
|
46
|
-
#payload = rpmfile.payload
|
47
|
-
# Parse the payload, check the rpmfile.header to find tags describing the
|
48
|
-
# format of the payload.
|
49
|
-
# Initial target should be gzipped cpio.
|
50
|
-
end # def self.read
|
51
|
-
|
52
|
-
def files
|
53
|
-
return @files
|
54
|
-
end
|
55
|
-
|
56
|
-
# Write this RPM to an IO-like object (must respond to 'write')
|
57
|
-
def write(io)
|
58
|
-
# write the lead
|
59
|
-
# write the signature?
|
60
|
-
# write the header
|
61
|
-
# write the payload
|
62
|
-
end
|
63
|
-
|
64
|
-
public(:files, :requires, :conflicts, :provides, :write)
|
65
|
-
end # class RPM
|
data/lib/arr-pm/file.rb
CHANGED
@@ -14,6 +14,9 @@ class RPM::File
|
|
14
14
|
FLAG_GREATER = (1 << 2) # RPMSENSE_GREATER = (1 << 2),
|
15
15
|
FLAG_EQUAL = (1 << 3) # RPMSENSE_EQUAL = (1 << 3),
|
16
16
|
|
17
|
+
# from rpm/rpmfi.h
|
18
|
+
FLAG_CONFIG_FILE = (1 << 0) # RPMFILE_CONFIG = (1 << 0)
|
19
|
+
|
17
20
|
def initialize(file)
|
18
21
|
if file.is_a?(String)
|
19
22
|
file = File.new(file, "r")
|
@@ -78,9 +81,9 @@ class RPM::File
|
|
78
81
|
@payload = @file.clone
|
79
82
|
# The payload starts after the lead, signature, and header. Remember the signature has an
|
80
83
|
# 8-byte boundary-rounding.
|
81
|
-
@payload.seek(@lead.length + @signature.length + @signature.length % 8 + @header.length, IO::SEEK_SET)
|
82
84
|
end
|
83
85
|
|
86
|
+
@payload.seek(@lead.length + @signature.length + @signature.length % 8 + @header.length, IO::SEEK_SET)
|
84
87
|
return @payload
|
85
88
|
end # def payload
|
86
89
|
|
@@ -93,25 +96,17 @@ class RPM::File
|
|
93
96
|
if !File.directory?(target)
|
94
97
|
raise Errno::ENOENT.new(target)
|
95
98
|
end
|
96
|
-
|
97
|
-
tags = {}
|
98
|
-
header.tags.each do |tag|
|
99
|
-
tags[tag.tag] = tag.value
|
100
|
-
end
|
101
99
|
|
102
|
-
#
|
103
|
-
#tags[:payloadcompressor] # "xz" or "gzip" or ..?
|
104
|
-
#tags[:payloadformat] # "cpio"
|
105
|
-
|
106
|
-
extractor = IO.popen("#{tags[:payloadcompressor]} -d | (cd #{target}; cpio -i --make-directories)", "w")
|
100
|
+
extractor = IO.popen("#{tags[:payloadcompressor]} -d | (cd #{target}; cpio -i --quiet --make-directories)", "w")
|
107
101
|
buffer = ""
|
108
102
|
buffer.force_encoding("BINARY")
|
109
|
-
payload_fd = payload
|
103
|
+
payload_fd = payload.clone
|
110
104
|
loop do
|
111
|
-
data =
|
105
|
+
data = payload_fd.read(16384, buffer)
|
112
106
|
break if data.nil? # eof
|
113
107
|
extractor.write(data)
|
114
108
|
end
|
109
|
+
payload_fd.close
|
115
110
|
extractor.close
|
116
111
|
end # def extract
|
117
112
|
|
@@ -170,20 +165,68 @@ class RPM::File
|
|
170
165
|
#
|
171
166
|
# @return Array of [ [name, operator, version], ... ]
|
172
167
|
def provides
|
173
|
-
return
|
168
|
+
return relation(:provides)
|
174
169
|
end # def provides
|
175
170
|
|
176
|
-
|
177
|
-
|
178
|
-
|
171
|
+
# Get an array of config files
|
172
|
+
def config_files
|
173
|
+
# this stuff seems to be in the 'enum rpmfileAttrs_e' from rpm/rpmfi.h
|
174
|
+
results = []
|
175
|
+
tags[:fileflags].each_with_index do |flag, i|
|
176
|
+
# The :fileflags (and other :file... tags) are an array, in order of
|
177
|
+
# files in the rpm payload, we want a list of paths of config files.
|
178
|
+
results << files[i] if mask?(flag, FLAG_CONFIG_FILE)
|
179
179
|
end
|
180
|
+
return results
|
181
|
+
end # def config_files
|
182
|
+
|
183
|
+
# List the files in this RPM.
|
184
|
+
#
|
185
|
+
# This should have roughly the same effect as:
|
186
|
+
#
|
187
|
+
# % rpm2cpio blah.rpm | cpio -it
|
188
|
+
def files
|
189
|
+
return @files unless @files.nil?
|
180
190
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
191
|
+
lister = IO.popen("#{tags[:payloadcompressor]} -d | cpio -it --quiet", "r+")
|
192
|
+
buffer = ""
|
193
|
+
buffer.force_encoding("BINARY")
|
194
|
+
payload_fd = payload.clone
|
195
|
+
output = ""
|
196
|
+
loop do
|
197
|
+
data = payload_fd.read(16384, buffer)
|
198
|
+
break if data.nil? # listerextractor.write(data)
|
199
|
+
lister.write(data)
|
200
|
+
|
201
|
+
# Read output from the pipe.
|
202
|
+
begin
|
203
|
+
output << lister.read_nonblock(16384)
|
204
|
+
rescue Errno::EAGAIN
|
205
|
+
# do nothing
|
206
|
+
end
|
207
|
+
end
|
208
|
+
lister.close_write
|
209
|
+
# Read remaining output
|
210
|
+
output << lister.read
|
211
|
+
# Split output by newline and strip leading "."
|
212
|
+
@files = output.split("\n").collect { |s| s.gsub(/^\./, "") }
|
213
|
+
return @files
|
214
|
+
ensure
|
215
|
+
lister.close unless lister.nil?
|
216
|
+
payload_fd.close unless payload_fd.nil?
|
217
|
+
end # def files
|
218
|
+
|
219
|
+
def mask?(value, mask)
|
220
|
+
return (value & mask) == mask
|
221
|
+
end # def mask?
|
222
|
+
|
223
|
+
def operator(flag)
|
224
|
+
return "<=" if mask?(flag, FLAG_LESS | FLAG_EQUAL)
|
225
|
+
return ">=" if mask?(flag, FLAG_GREATER | FLAG_EQUAL)
|
226
|
+
return "=" if mask?(flag, FLAG_EQUAL)
|
227
|
+
return "<" if mask?(flag, FLAG_LESS)
|
228
|
+
return ">" if mask?(flag, FLAG_GREATER)
|
186
229
|
end # def operator
|
187
230
|
|
188
|
-
public(:extract, :payload, :header, :lead, :signature, :initialize, :requires)
|
231
|
+
public(:extract, :payload, :header, :lead, :signature, :initialize, :requires, :conflicts, :provides)
|
189
232
|
end # class RPM::File
|