rpm 0.0.0 → 0.0.2
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.
- data/.gitignore +2 -0
- data/MIT-LICENSE +24 -0
- data/README.rdoc +298 -0
- data/Rakefile +32 -1
- data/lib/rpm/compat.rb +43 -0
- data/lib/rpm/db.rb +125 -0
- data/lib/rpm/dependency.rb +132 -0
- data/lib/rpm/ffi/header.rb +37 -0
- data/lib/rpm/ffi/rpmcallback.rb +26 -0
- data/lib/rpm/ffi/rpmdb.rb +22 -0
- data/lib/rpm/ffi/rpmds.rb +51 -0
- data/lib/rpm/ffi/rpmfi.rb +34 -0
- data/lib/rpm/ffi/rpmlib.rb +15 -0
- data/lib/rpm/ffi/rpmlog.rb +24 -0
- data/lib/rpm/ffi/rpmmacro.rb +38 -0
- data/lib/rpm/ffi/rpmprob.rb +42 -0
- data/lib/rpm/ffi/rpmps.rb +13 -0
- data/lib/rpm/ffi/rpmtag.rb +299 -0
- data/lib/rpm/ffi/rpmtd.rb +37 -0
- data/lib/rpm/ffi/rpmts.rb +70 -0
- data/lib/rpm/ffi/rpmtypes.rb +29 -0
- data/lib/rpm/ffi.rb +44 -0
- data/lib/rpm/file.rb +132 -0
- data/lib/rpm/gem_version.rb +7 -0
- data/lib/rpm/match_iterator.rb +73 -0
- data/lib/rpm/package.rb +344 -0
- data/lib/rpm/transaction.rb +130 -0
- data/lib/rpm/utils.rb +10 -0
- data/lib/rpm/version.rb +154 -1
- data/lib/rpm.rb +74 -3
- data/rpm.gemspec +10 -4
- data/test/data/a.spec +49 -0
- data/test/data/simple-1.0-0.i586.rpm +0 -0
- data/test/data/simple.spec +42 -0
- data/test/helper.rb +7 -0
- data/test/test_dependency.rb +29 -0
- data/test/test_file.rb +12 -0
- data/test/test_lib.rb +36 -0
- data/test/test_package.rb +60 -0
- data/test/test_rpm.rb +37 -0
- data/test/test_transaction.rb +61 -0
- data/test/test_version.rb +63 -0
- metadata +74 -13
- data/README +0 -3
@@ -0,0 +1,29 @@
|
|
1
|
+
|
2
|
+
module RPM
|
3
|
+
|
4
|
+
module FFI
|
5
|
+
|
6
|
+
Rc = enum(
|
7
|
+
:ok, 0,
|
8
|
+
:notfound, 1,
|
9
|
+
:fail, 2,
|
10
|
+
:nottrusted, 3,
|
11
|
+
:nokey, 4
|
12
|
+
)
|
13
|
+
|
14
|
+
typedef :int32, :rpm_tag_t
|
15
|
+
typedef :uint32, :rpm_tagtype_t;
|
16
|
+
typedef :uint32, :rpm_count_t
|
17
|
+
typedef :rpm_tag_t, :rpmTagVal;
|
18
|
+
typedef :rpm_tag_t, :rpmDbiTagVal
|
19
|
+
|
20
|
+
typedef :uint32, :rpmFlags
|
21
|
+
|
22
|
+
typedef :pointer, :FD_t
|
23
|
+
typedef :pointer, :fnpyKey
|
24
|
+
typedef :pointer, :rpmCallbackData
|
25
|
+
|
26
|
+
typedef :uint64, :rpm_loff_t
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
data/lib/rpm/ffi.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'ffi'
|
3
|
+
|
4
|
+
module RPM
|
5
|
+
module FFI
|
6
|
+
|
7
|
+
extend ::FFI::Library
|
8
|
+
|
9
|
+
begin
|
10
|
+
ffi_lib('rpm')
|
11
|
+
rescue LoadError => e
|
12
|
+
raise(
|
13
|
+
"Can't find rpm libs on your system: #{e.message}"
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
require 'rpm/ffi/rpmtypes'
|
21
|
+
require 'rpm/ffi/rpmcallback'
|
22
|
+
require 'rpm/ffi/rpmtag'
|
23
|
+
require 'rpm/ffi/rpmlib'
|
24
|
+
require 'rpm/ffi/rpmlog'
|
25
|
+
require 'rpm/ffi/rpmmacro'
|
26
|
+
require 'rpm/ffi/header'
|
27
|
+
require 'rpm/ffi/rpmprob'
|
28
|
+
require 'rpm/ffi/rpmps'
|
29
|
+
require 'rpm/ffi/rpmfi'
|
30
|
+
require 'rpm/ffi/rpmdb'
|
31
|
+
require 'rpm/ffi/rpmts'
|
32
|
+
require 'rpm/ffi/rpmds'
|
33
|
+
require 'rpm/ffi/rpmtd'
|
34
|
+
|
35
|
+
module RPM
|
36
|
+
module FFI
|
37
|
+
|
38
|
+
def self.rpm_version_code
|
39
|
+
ver = ::RPM::FFI.RPMVERSION.split('.', 3)
|
40
|
+
return (ver[0].to_i<<16) + (ver[1].to_i<<8) + (ver[2].to_i<<0)
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
data/lib/rpm/file.rb
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
|
2
|
+
module RPM
|
3
|
+
|
4
|
+
class File
|
5
|
+
|
6
|
+
# @return [String] file path
|
7
|
+
attr_accessor :path
|
8
|
+
# @return [String] md5sum as string
|
9
|
+
attr_accessor :md5sum
|
10
|
+
# @return [String] Path to the destination if the file is a symbolic link
|
11
|
+
# @note
|
12
|
+
# This path is sometimes relative. To convert an absolute path from relative path:
|
13
|
+
# File.expand_path (file.link_to, File.dirname (file.path))
|
14
|
+
attr_accessor :link_to
|
15
|
+
# @return [Number] File size
|
16
|
+
attr_accessor :size
|
17
|
+
# @return [Time] File modification time.
|
18
|
+
attr_accessor :mtime
|
19
|
+
# @return [String] File owner. Nil may be returned.
|
20
|
+
attr_accessor :owner
|
21
|
+
# @return [String] Group that owns the file. Nil may be returned.
|
22
|
+
attr_accessor :group
|
23
|
+
# @return [Number] Device type of the file
|
24
|
+
attr_accessor :mode
|
25
|
+
|
26
|
+
attr_accessor :attr
|
27
|
+
attr_accessor :state
|
28
|
+
attr_accessor :rdev
|
29
|
+
|
30
|
+
# @return [Boolean] True if the file is a symbolic link
|
31
|
+
def symlink?
|
32
|
+
! @link_to.nil?
|
33
|
+
end
|
34
|
+
|
35
|
+
# @return [Boolean] True if the file is marked as a configuration file
|
36
|
+
def config?
|
37
|
+
! (@attr & FileAttrs[:config]).zero?
|
38
|
+
end
|
39
|
+
|
40
|
+
# @return [Boolean] True if the file is marked as documentation
|
41
|
+
def doc?
|
42
|
+
! (@attr & FileAttrs[:doc]).zero?
|
43
|
+
end
|
44
|
+
|
45
|
+
# @return [Boolean] True if the file is marked as do not use
|
46
|
+
def donotuse?
|
47
|
+
! (@attr & FileAttrs[:donotuse]).zero?
|
48
|
+
end
|
49
|
+
|
50
|
+
# @return [Boolean] True if the file is marked that can be missing on disk
|
51
|
+
#
|
52
|
+
# This modifier is used for files or links that are created during the %post scripts
|
53
|
+
# but will need to be removed if the package is removed
|
54
|
+
def is_missingok?
|
55
|
+
! (@attr & FileAttrs[:missingok]).zero?
|
56
|
+
end
|
57
|
+
|
58
|
+
# @return [Boolean] True if the file is marked as configuration not to be replaced
|
59
|
+
#
|
60
|
+
# This flag is used to protect local modifications.
|
61
|
+
# If used, the file will not overwrite an existing file that has been modified.
|
62
|
+
# If the file has not been modified on disk, the rpm command will overwrite the file. But,
|
63
|
+
# if the file has been modified on disk, the rpm command will copy the new file with an extra
|
64
|
+
# file-name extension of .rpmnew.
|
65
|
+
def is_noreplace?
|
66
|
+
! (@attr & FileAttrs[:noreplace]).zero?
|
67
|
+
end
|
68
|
+
|
69
|
+
# @return [Boolean] True if the file is marked as a spec file
|
70
|
+
def is_specfile?
|
71
|
+
! (@attr & FileAttrs[:specfile]).zero?
|
72
|
+
end
|
73
|
+
|
74
|
+
# @return [Boolean] True if the file is marked as ghost
|
75
|
+
#
|
76
|
+
# This flag indicates the file should not be included in the package.
|
77
|
+
# It can be used to name the needed attributes for a file that the program, when installed,
|
78
|
+
# will create.
|
79
|
+
# For example, you may want to ensure that a program’s log file has certain attributes.
|
80
|
+
def ghost?
|
81
|
+
! (@attr & FileAttrs[:ghost]).zero?
|
82
|
+
end
|
83
|
+
|
84
|
+
# @return [Boolean] True if the file is a license
|
85
|
+
def license?
|
86
|
+
! (@attr & FileAttrs[:license]).zero?
|
87
|
+
end
|
88
|
+
|
89
|
+
# @return [Boolean] True if the file is a README
|
90
|
+
def readme?
|
91
|
+
! (@attr & FileAttrs[:readme]).zero?
|
92
|
+
end
|
93
|
+
|
94
|
+
# @return [Boolean] True if the file is listed in the exlude section
|
95
|
+
def exclude?
|
96
|
+
! (@attr & FileAttrs[:exclude]).zero?
|
97
|
+
end
|
98
|
+
|
99
|
+
# @return [Boolean] True if the file is replaced during installation
|
100
|
+
def replaced?
|
101
|
+
! (@attr & FileState[:replaced]).zero?
|
102
|
+
end
|
103
|
+
|
104
|
+
# @return [Boolean] True if the file is not installed
|
105
|
+
def notinstalled?
|
106
|
+
! (@attr & FileState[:notinstalled]).zero?
|
107
|
+
end
|
108
|
+
|
109
|
+
# @return [Boolean] True if the file is shared over the network
|
110
|
+
def netshared?
|
111
|
+
! (@attr & FileState[:netshared]).zero?
|
112
|
+
end
|
113
|
+
|
114
|
+
def initialize(path, md5sum, link_to, size, mtime, owner, group, rdev, mode, attr, state)
|
115
|
+
@path = path
|
116
|
+
@md5sum = md5sum
|
117
|
+
# If link_to is "" save it as nil
|
118
|
+
@link_to = ((link_to && link_to.empty?) ? nil : link_to)
|
119
|
+
@size = size
|
120
|
+
@mtime = mtime
|
121
|
+
@owner = owner
|
122
|
+
@group = group
|
123
|
+
@rdev = rdev
|
124
|
+
@mode = mode
|
125
|
+
@attr = attr
|
126
|
+
@state = state
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
|
2
|
+
module RPM
|
3
|
+
|
4
|
+
class MatchIterator
|
5
|
+
|
6
|
+
include Enumerable
|
7
|
+
|
8
|
+
# @visibility private
|
9
|
+
def self.release(ptr)
|
10
|
+
RPM::FFI.rpmdbFreeIterator(ptr)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Creates a managed MatchIterator from a raw pointer
|
14
|
+
# @visibility private
|
15
|
+
def self.from_ptr(ptr)
|
16
|
+
new(::FFI::AutoPointer.new(ptr, MatchIterator.method(:release)))
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(ptr)
|
20
|
+
@ptr = ptr
|
21
|
+
end
|
22
|
+
|
23
|
+
def each
|
24
|
+
while (pkg = next_iterator)
|
25
|
+
yield pkg
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def next_iterator
|
30
|
+
pkg_ptr = RPM::FFI.rpmdbNextIterator(@ptr)
|
31
|
+
if !pkg_ptr.null?
|
32
|
+
return RPM::Package.new(pkg_ptr)
|
33
|
+
end
|
34
|
+
return nil;
|
35
|
+
end
|
36
|
+
|
37
|
+
# @ return header join key for current position of rpm
|
38
|
+
# database iterator
|
39
|
+
def offset
|
40
|
+
RPM::FFI.rpmdbGetIteratorOffset(@ptr)
|
41
|
+
end
|
42
|
+
|
43
|
+
def set_iterator_re(tag, mode, string)
|
44
|
+
ret = RPM::FFI.rpmdbSetIteratorRE(@ptr, tag, mode, string)
|
45
|
+
raise "Error when setting regular expression '#{string}'" if ret != 0
|
46
|
+
self
|
47
|
+
end
|
48
|
+
|
49
|
+
alias :regexp :set_iterator_re
|
50
|
+
|
51
|
+
def set_iterator_version(version)
|
52
|
+
if not version.is_a?(RPM::Version)
|
53
|
+
raise TypeError, 'illegal argument type'
|
54
|
+
end
|
55
|
+
|
56
|
+
set_iterator_re(:version, :default, version.v)
|
57
|
+
if (version.r)
|
58
|
+
set_iterator_re(:release, :default, version.r)
|
59
|
+
end
|
60
|
+
self
|
61
|
+
end
|
62
|
+
|
63
|
+
alias :version :set_iterator_version
|
64
|
+
|
65
|
+
def get_iterator_count
|
66
|
+
RPM::FFI.rpmdbGetIteratorCount(@ptr)
|
67
|
+
end
|
68
|
+
|
69
|
+
alias :count :get_iterator_count
|
70
|
+
alias :length :get_iterator_count
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
data/lib/rpm/package.rb
ADDED
@@ -0,0 +1,344 @@
|
|
1
|
+
require 'rpm/ffi'
|
2
|
+
require 'rpm/file'
|
3
|
+
|
4
|
+
module RPM
|
5
|
+
|
6
|
+
class ChangeLog
|
7
|
+
attr_accessor :time, :name, :text
|
8
|
+
end
|
9
|
+
|
10
|
+
class Package
|
11
|
+
|
12
|
+
# Create a new package object from data
|
13
|
+
# @param [String] str Header data
|
14
|
+
# @return [Package]
|
15
|
+
def load(data)
|
16
|
+
raise NotImplementedError
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.create(name, version)
|
20
|
+
if not name.is_a?(String)
|
21
|
+
raise TypeError, "illegal argument type: name should be String"
|
22
|
+
end
|
23
|
+
if not version.is_a?(RPM::Version)
|
24
|
+
raise TypeError, "illegal argument type: version should be RPM::Version"
|
25
|
+
end
|
26
|
+
hdr = RPM::FFI.headerNew
|
27
|
+
if RPM::FFI.headerPutString(hdr, :name, name) != 1
|
28
|
+
raise "Can't set package name: #{name}"
|
29
|
+
end
|
30
|
+
if RPM::FFI.headerPutString(hdr, :version, version.v) != 1
|
31
|
+
raise "Can't set package version: #{version.v}"
|
32
|
+
end
|
33
|
+
if version.e
|
34
|
+
if RPM::FFI.headerPutUint32(hdr, :epoch, version.e) != 1
|
35
|
+
raise "Can't set package epoch: #{version.e}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
Package.new(hdr)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Add a dependency to the package header
|
42
|
+
# @param [Dependency] dep Dependency to add
|
43
|
+
def add_dependency(dep)
|
44
|
+
unless dep.is_a?(Dependency)
|
45
|
+
raise TypeError.new("illegal argument type: must be a Dependency")
|
46
|
+
end
|
47
|
+
|
48
|
+
raise NotImplementedError
|
49
|
+
end
|
50
|
+
|
51
|
+
# Add a int32 value to the package header
|
52
|
+
# @param [Number] tag Tag
|
53
|
+
# @param [Number] val Value
|
54
|
+
def add_int32(tag, val)
|
55
|
+
raise NotImplementedError
|
56
|
+
end
|
57
|
+
|
58
|
+
# Add a list of strings to the package header
|
59
|
+
# @param [Number] tag Tag
|
60
|
+
# @param [Array<String>] val Strings to add
|
61
|
+
def add_string_array(tag, val)
|
62
|
+
raise NotImplementedError
|
63
|
+
end
|
64
|
+
|
65
|
+
# Add a binary value to the package header
|
66
|
+
# @param [Number] tag Tag
|
67
|
+
# @param [String] val String to add
|
68
|
+
def add_string(tag, val)
|
69
|
+
raise NotImplementedError
|
70
|
+
end
|
71
|
+
|
72
|
+
# Add a binary value to the package header
|
73
|
+
# @param [Number] tag Tag
|
74
|
+
# @param [String] val Value
|
75
|
+
def add_binary(tag, val)
|
76
|
+
raise NotImplementedError
|
77
|
+
end
|
78
|
+
|
79
|
+
# Deletes a tag of the package header
|
80
|
+
# @param [Number] tag Tag
|
81
|
+
def delete_tag(tag)
|
82
|
+
raise NotImplementedError
|
83
|
+
end
|
84
|
+
|
85
|
+
# @return a formated string
|
86
|
+
# @example
|
87
|
+
# pkg.sprintf("%{name}") => "apache2"
|
88
|
+
def sprintf(fmt)
|
89
|
+
error = ::FFI::MemoryPointer.new(:pointer, 1)
|
90
|
+
val = RPM::FFI.headerFormat(@hdr, fmt, error)
|
91
|
+
raise error.get_pointer(0).read_string if val.null?
|
92
|
+
val.read_string
|
93
|
+
end
|
94
|
+
|
95
|
+
# @return [Number] This package signature
|
96
|
+
def signature
|
97
|
+
sprintf('%{sigmd5}')
|
98
|
+
end
|
99
|
+
|
100
|
+
# @return [Array<RPM::File>] File list for this package
|
101
|
+
def files
|
102
|
+
basenames = self[:basenames]
|
103
|
+
|
104
|
+
return [] if basenames.nil?
|
105
|
+
|
106
|
+
dirnames = self[:dirnames]
|
107
|
+
diridxs = self[:dirindexes]
|
108
|
+
statelist = self[:filestates]
|
109
|
+
flaglist = self[:fileflags]
|
110
|
+
sizelist = self[:filesizes]
|
111
|
+
modelist = self[:filemodes]
|
112
|
+
mtimelist = self[:filemtimes]
|
113
|
+
rdevlist = self[:filerdevs]
|
114
|
+
linklist = self[:filelinktos]
|
115
|
+
md5list = self[:filemd5s]
|
116
|
+
ownerlist = self[:fileusername]
|
117
|
+
grouplist = self[:filegroupname]
|
118
|
+
|
119
|
+
ret = []
|
120
|
+
|
121
|
+
basenames.each_with_index do |basename, i|
|
122
|
+
|
123
|
+
file = RPM::File.new("#{dirnames[diridxs[i]]}#{basenames[i]}",
|
124
|
+
md5list[i],
|
125
|
+
linklist[i],
|
126
|
+
sizelist[i],
|
127
|
+
mtimelist[i],
|
128
|
+
ownerlist[i],
|
129
|
+
grouplist[i],
|
130
|
+
rdevlist[i],
|
131
|
+
modelist[i],
|
132
|
+
flaglist.nil? ? RPM::FFI::FileAttrs[:none] : flaglist[i],
|
133
|
+
statelist.nil? ? RPM::FFI::FileState[:normal] : statelist[i]
|
134
|
+
)
|
135
|
+
ret << file
|
136
|
+
end
|
137
|
+
ret
|
138
|
+
end
|
139
|
+
|
140
|
+
# @return [Array<RPM::Dependency>] Dependencies for +klass+
|
141
|
+
# @example
|
142
|
+
# dependencies(RPM::Provide, :providename, :provideversion, :provideflags)
|
143
|
+
#
|
144
|
+
# @visibility private
|
145
|
+
def dependencies(klass, nametag, versiontag, flagtag)
|
146
|
+
deps = []
|
147
|
+
|
148
|
+
nametd = ::FFI::AutoPointer.new(RPM::FFI.rpmtdNew, Package.method(:release_td))
|
149
|
+
versiontd = ::FFI::AutoPointer.new(RPM::FFI.rpmtdNew, Package.method(:release_td))
|
150
|
+
flagtd = ::FFI::AutoPointer.new(RPM::FFI.rpmtdNew, Package.method(:release_td))
|
151
|
+
|
152
|
+
min = RPM::FFI::HEADERGET_MINMEM
|
153
|
+
return deps if (RPM::FFI.headerGet(@hdr, nametag, nametd, min) != 1)
|
154
|
+
return deps if (RPM::FFI.headerGet(@hdr, versiontag, versiontd, min) != 1)
|
155
|
+
return deps if (RPM::FFI.headerGet(@hdr, flagtag, flagtd, min) != 1)
|
156
|
+
|
157
|
+
RPM::FFI.rpmtdInit(nametd)
|
158
|
+
while RPM::FFI.rpmtdNext(nametd) != -1
|
159
|
+
deps << klass.new(RPM::FFI.rpmtdGetString(nametd),
|
160
|
+
RPM::Version.new(RPM::FFI.rpmtdNextString(versiontd)),
|
161
|
+
RPM::FFI.rpmtdNextUint32(flagtd).read_uint, self)
|
162
|
+
end
|
163
|
+
deps
|
164
|
+
end
|
165
|
+
|
166
|
+
# @return [Array<RPM::Provide>] Provides list for this package
|
167
|
+
def provides
|
168
|
+
dependencies(RPM::Provide, :providename, :provideversion, :provideflags)
|
169
|
+
end
|
170
|
+
|
171
|
+
# @return [Array<RPM::Require>] Requires list for this package
|
172
|
+
def requires
|
173
|
+
dependencies(RPM::Require, :requirename, :requireversion, :requireflags)
|
174
|
+
end
|
175
|
+
|
176
|
+
# @return [Array<RPM::Conflicts>] Conflicts list for this package
|
177
|
+
def conflicts
|
178
|
+
dependencies(RPM::conflicts, :conflictsname, :conflictsversion, :conflictsflags)
|
179
|
+
end
|
180
|
+
|
181
|
+
# @return [Array<RPM::Obsolete>] Obsoletes list for this package
|
182
|
+
def obsoletes
|
183
|
+
dependencies(RPM::Obsoletes, :obsoletename, :obsoleteversion, :obsoleteflags)
|
184
|
+
end
|
185
|
+
|
186
|
+
# @return [Array<RPM::Changelog>] changelog of the package as an array
|
187
|
+
def changelog
|
188
|
+
entries = []
|
189
|
+
nametd = ::FFI::AutoPointer.new(RPM::FFI.rpmtdNew, Package.method(:release_td))
|
190
|
+
timetd = ::FFI::AutoPointer.new(RPM::FFI.rpmtdNew, Package.method(:release_td))
|
191
|
+
texttd = ::FFI::AutoPointer.new(RPM::FFI.rpmtdNew, Package.method(:release_td))
|
192
|
+
|
193
|
+
min = RPM::FFI::HEADERGET_MINMEM
|
194
|
+
return deps if (RPM::FFI.headerGet(@hdr, :changelogtime, timetd, min) != 1)
|
195
|
+
return deps if (RPM::FFI.headerGet(@hdr, :changelogname, nametd, min) != 1)
|
196
|
+
return deps if (RPM::FFI.headerGet(@hdr, :changelogtext, texttd, min) != 1)
|
197
|
+
|
198
|
+
RPM::FFI.rpmtdInit(timetd)
|
199
|
+
while RPM::FFI.rpmtdNext(timetd) != -1
|
200
|
+
entry = RPM::ChangeLog.new
|
201
|
+
entry.time = RPM::FFI.rpmtdGetUint32(timetd)
|
202
|
+
entry.name = RPM::FFI.rpmtdNextString(nametd)
|
203
|
+
entry.text = RPM::FFI.rpmtdNextString(texttd)
|
204
|
+
entries << entry
|
205
|
+
end
|
206
|
+
entries
|
207
|
+
end
|
208
|
+
|
209
|
+
# Access a header entry
|
210
|
+
# @param [Number] tag Tag to return
|
211
|
+
# @return [] Value of the entry
|
212
|
+
# @example
|
213
|
+
# pkg => #<RPM::Package name="xmlgraphics-fop", version=#<RPM::Version v="1.0", r="22.4">>
|
214
|
+
# pkg[:name] => "xmlgraphics-fop"
|
215
|
+
#
|
216
|
+
# or if you have the old ruby-rpm compat loaded
|
217
|
+
#
|
218
|
+
# require 'rpm/compat'
|
219
|
+
# pkg[RPM::TAG_NAME] => "xmlgraphics-fop"
|
220
|
+
#
|
221
|
+
# @return [String, Fixnum, Array<String>, Array<Fixnum>, nil]
|
222
|
+
# The value of the entry
|
223
|
+
def [](tag)
|
224
|
+
val = nil
|
225
|
+
tagc = ::FFI::AutoPointer.new(RPM::FFI.rpmtdNew, Package.method(:release_td))
|
226
|
+
|
227
|
+
return nil if (RPM::FFI.headerGet(ptr, tag, tagc,
|
228
|
+
RPM::FFI::HEADERGET_MINMEM) == 0)
|
229
|
+
|
230
|
+
type = RPM::FFI.rpmtdType(tagc)
|
231
|
+
count = RPM::FFI.rpmtdCount(tagc)
|
232
|
+
ret_type = RPM::FFI.rpmTagGetReturnType(tag)
|
233
|
+
|
234
|
+
method_name = case type
|
235
|
+
when :int8_type, :char_type, :int16_type, :int32_type, :int64_type then :rpmtdGetNumber
|
236
|
+
when :string_type, :string_array_type, :bin_type then :rpmtdGetString
|
237
|
+
else raise NotImplementedError, "Don't know how to retrieve type '#{type}'"
|
238
|
+
end
|
239
|
+
|
240
|
+
is_array = case
|
241
|
+
when count > 1 then true
|
242
|
+
when ret_type == :array_return_type then true
|
243
|
+
when type == :string_array_type then true
|
244
|
+
else false
|
245
|
+
end
|
246
|
+
|
247
|
+
if is_array
|
248
|
+
ret = []
|
249
|
+
RPM::FFI.rpmtdInit(tagc)
|
250
|
+
while RPM::FFI.rpmtdNext(tagc) != -1
|
251
|
+
ret << RPM::FFI.send(method_name, tagc)
|
252
|
+
end
|
253
|
+
return ret
|
254
|
+
end
|
255
|
+
|
256
|
+
return RPM::FFI.send(method_name, tagc)
|
257
|
+
end
|
258
|
+
|
259
|
+
# @return [String] This package name
|
260
|
+
def name
|
261
|
+
self[:name]
|
262
|
+
end
|
263
|
+
|
264
|
+
# @return [String] This package architecture
|
265
|
+
def arch
|
266
|
+
self[:arch]
|
267
|
+
end
|
268
|
+
|
269
|
+
# TODO signature
|
270
|
+
|
271
|
+
# @return [Version] Version for this package
|
272
|
+
def version
|
273
|
+
v_ptr = ::FFI::MemoryPointer.new(:pointer, 1)
|
274
|
+
r_ptr = ::FFI::MemoryPointer.new(:pointer, 1)
|
275
|
+
|
276
|
+
RPM::FFI.headerNVR(ptr, nil, v_ptr, r_ptr)
|
277
|
+
v = v_ptr.read_pointer.read_string
|
278
|
+
r = r_ptr.read_pointer.read_string
|
279
|
+
v_ptr.free
|
280
|
+
r_ptr.free
|
281
|
+
Version.new(v, r, self[:epoch])
|
282
|
+
end
|
283
|
+
|
284
|
+
# String representation of the package: "name-version-release-arch"
|
285
|
+
# @return [String]
|
286
|
+
def to_s
|
287
|
+
return "" if name.nil?
|
288
|
+
return name if version.nil?
|
289
|
+
return "#{name}-#{version}" if arch.nil?
|
290
|
+
return "#{name}-#{version}-#{arch}"
|
291
|
+
end
|
292
|
+
|
293
|
+
def self.open(filename)
|
294
|
+
# it sucks not using the std File.open here
|
295
|
+
hdr = ::FFI::MemoryPointer.new(:pointer)
|
296
|
+
fd = nil
|
297
|
+
begin
|
298
|
+
fd = RPM::FFI.Fopen(filename, 'r')
|
299
|
+
if RPM::FFI.Ferror(fd) != 0
|
300
|
+
raise "#{filename} : #{RPM::FFI.Fstrerror(fd)}"
|
301
|
+
end
|
302
|
+
RPM.transaction do |ts|
|
303
|
+
rc = RPM::FFI.rpmReadPackageFile(ts.ptr, fd, filename, hdr)
|
304
|
+
end
|
305
|
+
ensure
|
306
|
+
RPM::FFI.Fclose(fd) unless fd.nil?
|
307
|
+
end
|
308
|
+
Package.new(hdr.get_pointer(0))
|
309
|
+
end
|
310
|
+
|
311
|
+
# @visibility private
|
312
|
+
def self.release(ptr)
|
313
|
+
RPM::FFI.headerFree(ptr)
|
314
|
+
end
|
315
|
+
|
316
|
+
# @visibility private
|
317
|
+
def self.release_td(ptr)
|
318
|
+
RPM::FFI.rpmtdFree(ptr)
|
319
|
+
end
|
320
|
+
|
321
|
+
# @visibility private
|
322
|
+
def initialize(hdr=nil)
|
323
|
+
if hdr.nil?
|
324
|
+
@hdr = ::FFI::AutoPointer.new(RPM::FFI.headerNew, Header.method(:release))
|
325
|
+
elsif hdr.is_a?(::FFI::Pointer)
|
326
|
+
# ref
|
327
|
+
hdr = RPM::FFI.headerLink(hdr)
|
328
|
+
@hdr = ::FFI::AutoPointer.new(hdr, Package.method(:release))
|
329
|
+
else
|
330
|
+
raise "Can't initialize header with '#{hdr}'"
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
# @return [RPM::FFI::Header] header pointer
|
335
|
+
# @visibility private
|
336
|
+
def ptr
|
337
|
+
@hdr
|
338
|
+
end
|
339
|
+
|
340
|
+
|
341
|
+
|
342
|
+
end
|
343
|
+
|
344
|
+
end
|