arr-pm 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
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
|