rpm 0.0.2 → 0.0.3

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.
Files changed (44) hide show
  1. data/.travis.yml +10 -0
  2. data/ChangeLog +5 -0
  3. data/README.rdoc +11 -1
  4. data/lib/rpm/{ffi → c}/header.rb +1 -1
  5. data/lib/rpm/c/rpmcallback.rb +28 -0
  6. data/lib/rpm/c/rpmcli.rb +7 -0
  7. data/lib/rpm/{ffi → c}/rpmdb.rb +1 -1
  8. data/lib/rpm/{ffi → c}/rpmds.rb +1 -6
  9. data/lib/rpm/{ffi → c}/rpmfi.rb +1 -1
  10. data/lib/rpm/c/rpmio.rb +21 -0
  11. data/lib/rpm/{ffi → c}/rpmlib.rb +1 -1
  12. data/lib/rpm/{ffi → c}/rpmlog.rb +3 -1
  13. data/lib/rpm/{ffi → c}/rpmmacro.rb +1 -10
  14. data/lib/rpm/{ffi → c}/rpmprob.rb +17 -3
  15. data/lib/rpm/{ffi → c}/rpmps.rb +1 -1
  16. data/lib/rpm/{ffi → c}/rpmtag.rb +12 -4
  17. data/lib/rpm/{ffi → c}/rpmtd.rb +1 -1
  18. data/lib/rpm/{ffi → c}/rpmts.rb +6 -2
  19. data/lib/rpm/{ffi → c}/rpmtypes.rb +3 -1
  20. data/lib/rpm/c.rb +47 -0
  21. data/lib/rpm/db.rb +5 -5
  22. data/lib/rpm/dependency.rb +10 -10
  23. data/lib/rpm/gem_version.rb +1 -1
  24. data/lib/rpm/match_iterator.rb +5 -5
  25. data/lib/rpm/package.rb +55 -55
  26. data/lib/rpm/problem.rb +71 -0
  27. data/lib/rpm/transaction.rb +186 -35
  28. data/lib/rpm/version.rb +3 -4
  29. data/lib/rpm.rb +16 -24
  30. data/rpm.gemspec +1 -1
  31. data/test/data/simple-1.0-0.i586.rpm +0 -0
  32. data/test/data/simple.spec +0 -4
  33. data/test/data/simple_with_deps-1.0-0.i586.rpm +0 -0
  34. data/test/data/simple_with_deps.spec +41 -0
  35. data/test/helper.rb +1 -1
  36. data/test/test_dependency.rb +1 -1
  37. data/test/test_lib.rb +13 -13
  38. data/test/test_package.rb +24 -3
  39. data/test/test_problem.rb +20 -0
  40. data/test/test_transaction.rb +115 -14
  41. data/test/test_version.rb +2 -0
  42. metadata +80 -69
  43. data/lib/rpm/ffi/rpmcallback.rb +0 -26
  44. data/lib/rpm/ffi.rb +0 -44
@@ -3,5 +3,5 @@
3
3
  # is because it conflicts with the version.rb class
4
4
  module RPM
5
5
  PKG_NAME = "ruby-rpm"
6
- GEM_VERSION = "0.0.2"
6
+ GEM_VERSION = "0.0.3"
7
7
  end
@@ -7,7 +7,7 @@ module RPM
7
7
 
8
8
  # @visibility private
9
9
  def self.release(ptr)
10
- RPM::FFI.rpmdbFreeIterator(ptr)
10
+ RPM::C.rpmdbFreeIterator(ptr)
11
11
  end
12
12
 
13
13
  # Creates a managed MatchIterator from a raw pointer
@@ -27,7 +27,7 @@ module RPM
27
27
  end
28
28
 
29
29
  def next_iterator
30
- pkg_ptr = RPM::FFI.rpmdbNextIterator(@ptr)
30
+ pkg_ptr = RPM::C.rpmdbNextIterator(@ptr)
31
31
  if !pkg_ptr.null?
32
32
  return RPM::Package.new(pkg_ptr)
33
33
  end
@@ -37,11 +37,11 @@ module RPM
37
37
  # @ return header join key for current position of rpm
38
38
  # database iterator
39
39
  def offset
40
- RPM::FFI.rpmdbGetIteratorOffset(@ptr)
40
+ RPM::C.rpmdbGetIteratorOffset(@ptr)
41
41
  end
42
42
 
43
43
  def set_iterator_re(tag, mode, string)
44
- ret = RPM::FFI.rpmdbSetIteratorRE(@ptr, tag, mode, string)
44
+ ret = RPM::C.rpmdbSetIteratorRE(@ptr, tag, mode, string)
45
45
  raise "Error when setting regular expression '#{string}'" if ret != 0
46
46
  self
47
47
  end
@@ -63,7 +63,7 @@ module RPM
63
63
  alias :version :set_iterator_version
64
64
 
65
65
  def get_iterator_count
66
- RPM::FFI.rpmdbGetIteratorCount(@ptr)
66
+ RPM::C.rpmdbGetIteratorCount(@ptr)
67
67
  end
68
68
 
69
69
  alias :count :get_iterator_count
data/lib/rpm/package.rb CHANGED
@@ -1,4 +1,4 @@
1
- require 'rpm/ffi'
1
+ require 'rpm/c'
2
2
  require 'rpm/file'
3
3
 
4
4
  module RPM
@@ -23,15 +23,15 @@ module RPM
23
23
  if not version.is_a?(RPM::Version)
24
24
  raise TypeError, "illegal argument type: version should be RPM::Version"
25
25
  end
26
- hdr = RPM::FFI.headerNew
27
- if RPM::FFI.headerPutString(hdr, :name, name) != 1
26
+ hdr = RPM::C.headerNew
27
+ if RPM::C.headerPutString(hdr, :name, name) != 1
28
28
  raise "Can't set package name: #{name}"
29
29
  end
30
- if RPM::FFI.headerPutString(hdr, :version, version.v) != 1
30
+ if RPM::C.headerPutString(hdr, :version, version.v) != 1
31
31
  raise "Can't set package version: #{version.v}"
32
32
  end
33
33
  if version.e
34
- if RPM::FFI.headerPutUint32(hdr, :epoch, version.e) != 1
34
+ if RPM::C.headerPutUint32(hdr, :epoch, version.e) != 1
35
35
  raise "Can't set package epoch: #{version.e}"
36
36
  end
37
37
  end
@@ -87,7 +87,7 @@ module RPM
87
87
  # pkg.sprintf("%{name}") => "apache2"
88
88
  def sprintf(fmt)
89
89
  error = ::FFI::MemoryPointer.new(:pointer, 1)
90
- val = RPM::FFI.headerFormat(@hdr, fmt, error)
90
+ val = RPM::C.headerFormat(@hdr, fmt, error)
91
91
  raise error.get_pointer(0).read_string if val.null?
92
92
  val.read_string
93
93
  end
@@ -129,8 +129,8 @@ module RPM
129
129
  grouplist[i],
130
130
  rdevlist[i],
131
131
  modelist[i],
132
- flaglist.nil? ? RPM::FFI::FileAttrs[:none] : flaglist[i],
133
- statelist.nil? ? RPM::FFI::FileState[:normal] : statelist[i]
132
+ flaglist.nil? ? RPM::C::FileAttrs[:none] : flaglist[i],
133
+ statelist.nil? ? RPM::C::FileState[:normal] : statelist[i]
134
134
  )
135
135
  ret << file
136
136
  end
@@ -145,20 +145,20 @@ module RPM
145
145
  def dependencies(klass, nametag, versiontag, flagtag)
146
146
  deps = []
147
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))
148
+ nametd = ::FFI::AutoPointer.new(RPM::C.rpmtdNew, Package.method(:release_td))
149
+ versiontd = ::FFI::AutoPointer.new(RPM::C.rpmtdNew, Package.method(:release_td))
150
+ flagtd = ::FFI::AutoPointer.new(RPM::C.rpmtdNew, Package.method(:release_td))
151
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)
152
+ min = RPM::C::HEADERGET_MINMEM
153
+ return deps if (RPM::C.headerGet(@hdr, nametag, nametd, min) != 1)
154
+ return deps if (RPM::C.headerGet(@hdr, versiontag, versiontd, min) != 1)
155
+ return deps if (RPM::C.headerGet(@hdr, flagtag, flagtd, min) != 1)
156
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)
157
+ RPM::C.rpmtdInit(nametd)
158
+ while RPM::C.rpmtdNext(nametd) != -1
159
+ deps << klass.new(RPM::C.rpmtdGetString(nametd),
160
+ RPM::Version.new(RPM::C.rpmtdNextString(versiontd)),
161
+ RPM::C.rpmtdNextUint32(flagtd).read_uint, self)
162
162
  end
163
163
  deps
164
164
  end
@@ -175,32 +175,32 @@ module RPM
175
175
 
176
176
  # @return [Array<RPM::Conflicts>] Conflicts list for this package
177
177
  def conflicts
178
- dependencies(RPM::conflicts, :conflictsname, :conflictsversion, :conflictsflags)
178
+ dependencies(RPM::Conflict, :conflictname, :conflictversion, :conflictflags)
179
179
  end
180
180
 
181
181
  # @return [Array<RPM::Obsolete>] Obsoletes list for this package
182
182
  def obsoletes
183
- dependencies(RPM::Obsoletes, :obsoletename, :obsoleteversion, :obsoleteflags)
183
+ dependencies(RPM::Obsolete, :obsoletename, :obsoleteversion, :obsoleteflags)
184
184
  end
185
185
 
186
186
  # @return [Array<RPM::Changelog>] changelog of the package as an array
187
187
  def changelog
188
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))
189
+ nametd = ::FFI::AutoPointer.new(RPM::C.rpmtdNew, Package.method(:release_td))
190
+ timetd = ::FFI::AutoPointer.new(RPM::C.rpmtdNew, Package.method(:release_td))
191
+ texttd = ::FFI::AutoPointer.new(RPM::C.rpmtdNew, Package.method(:release_td))
192
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)
193
+ min = RPM::C::HEADERGET_MINMEM
194
+ return deps if (RPM::C.headerGet(@hdr, :changelogtime, timetd, min) != 1)
195
+ return deps if (RPM::C.headerGet(@hdr, :changelogname, nametd, min) != 1)
196
+ return deps if (RPM::C.headerGet(@hdr, :changelogtext, texttd, min) != 1)
197
197
 
198
- RPM::FFI.rpmtdInit(timetd)
199
- while RPM::FFI.rpmtdNext(timetd) != -1
198
+ RPM::C.rpmtdInit(timetd)
199
+ while RPM::C.rpmtdNext(timetd) != -1
200
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)
201
+ entry.time = RPM::C.rpmtdGetUint32(timetd)
202
+ entry.name = RPM::C.rpmtdNextString(nametd)
203
+ entry.text = RPM::C.rpmtdNextString(texttd)
204
204
  entries << entry
205
205
  end
206
206
  entries
@@ -222,14 +222,14 @@ module RPM
222
222
  # The value of the entry
223
223
  def [](tag)
224
224
  val = nil
225
- tagc = ::FFI::AutoPointer.new(RPM::FFI.rpmtdNew, Package.method(:release_td))
225
+ tagc = ::FFI::AutoPointer.new(RPM::C.rpmtdNew, Package.method(:release_td))
226
226
 
227
- return nil if (RPM::FFI.headerGet(ptr, tag, tagc,
228
- RPM::FFI::HEADERGET_MINMEM) == 0)
227
+ return nil if (RPM::C.headerGet(ptr, tag, tagc,
228
+ RPM::C::HEADERGET_MINMEM) == 0)
229
229
 
230
- type = RPM::FFI.rpmtdType(tagc)
231
- count = RPM::FFI.rpmtdCount(tagc)
232
- ret_type = RPM::FFI.rpmTagGetReturnType(tag)
230
+ type = RPM::C.rpmtdType(tagc)
231
+ count = RPM::C.rpmtdCount(tagc)
232
+ ret_type = RPM::C.rpmTagGetReturnType(tag)
233
233
 
234
234
  method_name = case type
235
235
  when :int8_type, :char_type, :int16_type, :int32_type, :int64_type then :rpmtdGetNumber
@@ -246,14 +246,14 @@ module RPM
246
246
 
247
247
  if is_array
248
248
  ret = []
249
- RPM::FFI.rpmtdInit(tagc)
250
- while RPM::FFI.rpmtdNext(tagc) != -1
251
- ret << RPM::FFI.send(method_name, tagc)
249
+ RPM::C.rpmtdInit(tagc)
250
+ while RPM::C.rpmtdNext(tagc) != -1
251
+ ret << RPM::C.send(method_name, tagc)
252
252
  end
253
253
  return ret
254
254
  end
255
255
 
256
- return RPM::FFI.send(method_name, tagc)
256
+ return RPM::C.send(method_name, tagc)
257
257
  end
258
258
 
259
259
  # @return [String] This package name
@@ -273,7 +273,7 @@ module RPM
273
273
  v_ptr = ::FFI::MemoryPointer.new(:pointer, 1)
274
274
  r_ptr = ::FFI::MemoryPointer.new(:pointer, 1)
275
275
 
276
- RPM::FFI.headerNVR(ptr, nil, v_ptr, r_ptr)
276
+ RPM::C.headerNVR(ptr, nil, v_ptr, r_ptr)
277
277
  v = v_ptr.read_pointer.read_string
278
278
  r = r_ptr.read_pointer.read_string
279
279
  v_ptr.free
@@ -295,43 +295,43 @@ module RPM
295
295
  hdr = ::FFI::MemoryPointer.new(:pointer)
296
296
  fd = nil
297
297
  begin
298
- fd = RPM::FFI.Fopen(filename, 'r')
299
- if RPM::FFI.Ferror(fd) != 0
300
- raise "#{filename} : #{RPM::FFI.Fstrerror(fd)}"
298
+ fd = RPM::C.Fopen(filename, 'r')
299
+ if RPM::C.Ferror(fd) != 0
300
+ raise "#{filename} : #{RPM::C.Fstrerror(fd)}"
301
301
  end
302
302
  RPM.transaction do |ts|
303
- rc = RPM::FFI.rpmReadPackageFile(ts.ptr, fd, filename, hdr)
303
+ rc = RPM::C.rpmReadPackageFile(ts.ptr, fd, filename, hdr)
304
304
  end
305
305
  ensure
306
- RPM::FFI.Fclose(fd) unless fd.nil?
306
+ RPM::C.Fclose(fd) unless fd.nil?
307
307
  end
308
308
  Package.new(hdr.get_pointer(0))
309
309
  end
310
310
 
311
311
  # @visibility private
312
312
  def self.release(ptr)
313
- RPM::FFI.headerFree(ptr)
313
+ RPM::C.headerFree(ptr)
314
314
  end
315
315
 
316
316
  # @visibility private
317
317
  def self.release_td(ptr)
318
- RPM::FFI.rpmtdFree(ptr)
318
+ RPM::C.rpmtdFree(ptr)
319
319
  end
320
320
 
321
321
  # @visibility private
322
322
  def initialize(hdr=nil)
323
323
  if hdr.nil?
324
- @hdr = ::FFI::AutoPointer.new(RPM::FFI.headerNew, Header.method(:release))
324
+ @hdr = ::FFI::AutoPointer.new(RPM::C.headerNew, Header.method(:release))
325
325
  elsif hdr.is_a?(::FFI::Pointer)
326
326
  # ref
327
- hdr = RPM::FFI.headerLink(hdr)
327
+ hdr = RPM::C.headerLink(hdr)
328
328
  @hdr = ::FFI::AutoPointer.new(hdr, Package.method(:release))
329
329
  else
330
330
  raise "Can't initialize header with '#{hdr}'"
331
331
  end
332
332
  end
333
333
 
334
- # @return [RPM::FFI::Header] header pointer
334
+ # @return [RPM::C::Header] header pointer
335
335
  # @visibility private
336
336
  def ptr
337
337
  @hdr
@@ -0,0 +1,71 @@
1
+
2
+ module RPM
3
+
4
+ class Problem
5
+
6
+ def self.release(ptr)
7
+ RPM::C.rpmProblemFree(ptr)
8
+ end
9
+
10
+ # Creates a problem from an existing C pointer, refcounting it
11
+ # first.
12
+ # @param [FFI::Pointer] ptr existing C pointer
13
+ # @return [RPM::Problem] wrapped object
14
+ def self.from_ptr(ptr)
15
+ case ptr
16
+ when FFI::Pointer
17
+ new(FFI::AutoPointer.new(RPM::C.rpmProblemLink(ptr), Problem.method(:release)))
18
+ else
19
+ raise "Can't initialize header with '#{ptr}'"
20
+ end
21
+ end
22
+
23
+ # Create a problem item.
24
+ # @param [RPM::ProblemType] type problem type
25
+ # @param [String] pkg_nver name-version-edition-release of the related package
26
+ # @param [String] key key of the related package
27
+ # @param [String] alt_nver name-version-edition-release of the other related package
28
+ # @param [String] str generic data string from a problem
29
+ def self.create(type, pkg_nevr, key, alt_nevr, str, number)
30
+ ptr = ::FFI::AutoPointer.new(RPM::C.rpmProblemCreate(type, pkg_nevr, key, alt_nevr, str, number), Problem.method(:release))
31
+ new(ptr)
32
+ end
33
+
34
+ # @visibility private
35
+ def initialize(ptr)
36
+ @ptr = ptr
37
+ end
38
+
39
+ # @return [RPM::ProblemType] type of problem (dependency, diskpace etc).
40
+ def type
41
+ RPM::C.rpmProblemGetType(@ptr)
42
+ end
43
+
44
+ # @return [String] filename or python object address of a problem.
45
+ def key
46
+ RPM::C.rpmProblemGetKey(@ptr).read_string
47
+ end
48
+
49
+ # @return [String] a generic data string from a problem.
50
+ def str
51
+ RPM::C.rpmProblemGetStr(@ptr)
52
+ end
53
+
54
+ # @return [String] formatted string representation of a problem
55
+ def to_s
56
+ RPM::C.rpmProblemString(@ptr)
57
+ end
58
+
59
+ # @return [Fixnum] compare two problems for equality.
60
+ def <=>(other)
61
+ RPM::C.rpmProblemCompare(@ptr, other.ptr)
62
+ end
63
+
64
+ # @visibility private
65
+ def ptr
66
+ @ptr
67
+ end
68
+
69
+ end
70
+
71
+ end
@@ -2,26 +2,38 @@ require 'rpm'
2
2
 
3
3
  module RPM
4
4
 
5
+ CallbackData = Struct.new(:type, :key, :package, :amount, :total) do
6
+
7
+
8
+ def to_s
9
+ "#{type} #{key} #{package} #{amount} #{total}"
10
+ end
11
+ end
12
+
5
13
  class Transaction
6
14
 
7
15
  def self.release(ptr)
8
- RPM::FFI.rpmtsFree(ptr)
16
+ RPM::C.rpmtsFree(ptr)
9
17
  end
10
18
 
11
19
  def initialize(opts={})
12
-
20
+ # http://markmail.org/message/ypsiqxop442p7rzz
21
+ # The key pointer needs to stay valid during commit
22
+ # so we keep a reference to them mapping from
23
+ # object_id to ruby object.
24
+ @keys = {}
13
25
  opts[:root] ||= '/'
14
26
 
15
- @ptr = ::FFI::AutoPointer.new(RPM::FFI.rpmtsCreate, Transaction.method(:release))
16
- RPM::FFI.rpmtsSetRootDir(@ptr, opts[:root])
27
+ @ptr = ::FFI::AutoPointer.new(RPM::C.rpmtsCreate, Transaction.method(:release))
28
+ RPM::C.rpmtsSetRootDir(@ptr, opts[:root])
17
29
  end
18
30
 
19
31
  # @return [RPM::MatchIterator] Creates an iterator for +tag+ and +val+
20
32
  def init_iterator(tag, val)
21
33
  raise TypeError if (val && !val.is_a?(String))
22
-
23
- it_ptr = RPM::FFI.rpmtsInitIterator(@ptr, tag.nil? ? 0 : tag, val, 0)
24
-
34
+
35
+ it_ptr = RPM::C.rpmtsInitIterator(@ptr, tag.nil? ? 0 : tag, val, 0)
36
+
25
37
  raise "Can't init iterator for [#{tag}] -> '#{val}'" if it_ptr.null?
26
38
  return MatchIterator.from_ptr(it_ptr)
27
39
  end
@@ -30,7 +42,7 @@ module RPM
30
42
  def ptr
31
43
  @ptr
32
44
  end
33
-
45
+
34
46
  #
35
47
  # @yield [Package] Called for each match
36
48
  # @param [Number] key RPM tag key
@@ -63,68 +75,207 @@ module RPM
63
75
 
64
76
  # Add a install operation to the transaction
65
77
  # @param [Package] pkg Package to install
78
+ # @param [String] key e.g. filename where to install from
66
79
  def install(pkg, key)
67
- raise TypeError if not pkg.is_a?(RPM::Package)
68
-
69
- @keys ||= Array.new
70
- raise ArgError, "key must be unique" if @keys.include?(key)
71
- @keys << key
72
-
73
- RPM::FFI.rpmtsAddInstallElement(@ptr, pkg.ptr, key.to_s, 0, nil)
74
- nil
80
+ install_element(pkg, key, :upgrade => false)
81
+ end
82
+
83
+ # Add an upgrade operation to the transaction
84
+ # @param [Package] pkg Package to upgrade
85
+ # @param [String] key e.g. filename where to install from
86
+ def upgrade(pkg, key)
87
+ install_element(pkg, key, :upgrade => true)
88
+ end
89
+
90
+ # Add a delete operation to the transaction
91
+ # @param [String, Package, Dependency] pkg Package to delete
92
+ def delete(pkg)
93
+ iterator = case pkg
94
+ when Package
95
+ pkg[:sigmd5] ? each_match(:sigmd5, pkg[:sigmd5]) : each_match(:label, pkg[:label])
96
+ when String
97
+ each_match(:label, pkg)
98
+ when Dependency
99
+ each_match(:label, pkg.name).set_iterator_version(pkg.version)
100
+ else
101
+ raise TypeError, "illegal argument type"
102
+ end
103
+
104
+ iterator.each do |header|
105
+ ret = RPM::C.rpmtsAddEraseElement(@ptr, header.ptr, iterator.offset)
106
+ raise RuntimeError, "Error while adding erase/#{pkg} to transaction" if ret != 0
107
+ end
75
108
  end
76
109
 
77
110
  # Sets the root directory for this transaction
78
111
  # @param [String] root directory
79
112
  def root_dir=(dir)
80
- rc = RPM::FFI.rpmtsSetRootDir(@ptr, dir)
113
+ rc = RPM::C.rpmtsSetRootDir(@ptr, dir)
81
114
  raise "Can't set #{dir} as root directory" if rc < 0
82
115
  end
83
116
 
84
117
  # @return [String ] the root directory for this transaction
85
118
  def root_dir
86
- RPM::FFI.rpmtsRootDir(@ptr)
119
+ RPM::C.rpmtsRootDir(@ptr)
87
120
  end
88
121
 
89
122
  def flags=(fl)
90
- RPM::FFI.rpmtsSetFlags(@ptr, fl)
123
+ RPM::C.rpmtsSetFlags(@ptr, fl)
91
124
  end
92
125
 
93
126
  def flags
94
- RPM::FFI.rpmtsFlags(@ptr)
127
+ RPM::C.rpmtsFlags(@ptr)
128
+ end
129
+
130
+ # Determine package order in the transaction according to dependencies
131
+ #
132
+ # The final order ends up as installed packages followed by removed
133
+ # packages, with packages removed for upgrades immediately following
134
+ # the new package to be installed.
135
+ #
136
+ # @returns [Fixnum] no. of (added) packages that could not be ordered
137
+ def order
138
+ RPM::C.rpmtsOrder(@ptr)
139
+ end
140
+
141
+ # Free memory needed only for dependency checks and ordering.
142
+ def clean
143
+ RPM::C.rpmtsClean(@ptr)
144
+ end
145
+
146
+ def check
147
+ rc = RPM::C.rpmtsCheck(@ptr)
148
+ probs = RPM::C.rpmtsProblems(@ptr)
149
+
150
+ return if rc < 0
151
+ begin
152
+ psi = RPM::C.rpmpsInitIterator(probs)
153
+ while (RPM::C.rpmpsNextIterator(psi) >= 0)
154
+ problem = Problem.from_ptr(RPM::C.rpmpsGetProblem(psi))
155
+ yield problem
156
+ end
157
+ ensure
158
+ RPM::C.rpmpsFree(probs)
159
+ end
95
160
  end
96
161
 
97
162
  # Performs the transaction.
98
163
  # @param [Number] flag Transaction flags, default +RPM::TRANS_FLAG_NONE+
99
164
  # @param [Number] filter Transaction filter, default +RPM::PROB_FILTER_NONE+
100
165
  # @example
101
- # transaction.commit do |sig|
166
+ # transaction.commit
167
+ # You can supply your own callback
168
+ # @example
169
+ # transaction.commit do |data|
170
+ # end
102
171
  # end
103
172
  # @yield [CallbackData] sig Transaction progress
104
- def commit
105
- self.flags = RPM::FFI::TransFlags[:none]
173
+ def commit(&user_callback)
174
+ flags = RPM::C::TransFlags[:none]
175
+
176
+ callback = Proc.new do |hdr, type, amount, total, key_ptr, data_ignored|
177
+ key_id = key_ptr.address
178
+ key = @keys.include?(key_id) ? @keys[key_id] : nil
179
+
180
+ case
181
+ when block_given?
182
+ package = hdr.null? ? nil : Package.new(hdr)
183
+ data = CallbackData.new(type, key, package, amount, total)
184
+ user_callback.call(data)
185
+ else
186
+ RPM::C.rpmShowProgress(hdr, type, amount, total, key, data_ignored)
187
+ end
188
+ end
189
+ # We create a callback to pass to the C method and we
190
+ # call the user supplied callback from there
191
+ #
192
+ # The C callback expects you to return a file handle,
193
+ # We expect from the user to get a File, which we
194
+ # then convert to a file handle to return.
195
+ callback = Proc.new do |hdr, type, amount, total, key_ptr, data_ignored|
196
+ key_id = key_ptr.address
197
+ key = @keys.include?(key_id) ? @keys[key_id] : nil
106
198
 
107
- callback = Proc.new do |h, what, amount, total, key, data|
108
- puts "#{h} #{what} #{amount} #{total} #{key} #{data}"
199
+ case
200
+ when block_given?
201
+ package = hdr.null? ? nil : Package.new(hdr)
202
+ data = CallbackData.new(type, key, package, amount, total)
203
+ ret = user_callback.call(data)
204
+
205
+ # For OPEN_FILE we need to do some type conversion
206
+ # for certain callback types we need to do some
207
+ case type
208
+ when :inst_open_file
209
+ # For :inst_open_file the user callback has to
210
+ # return the open file
211
+ if !ret.is_a?(::File)
212
+ raise TypeError, "illegal return value type #{ret.class}. Expected File."
213
+ end
214
+ fdt = RPM::C.fdDup(ret.to_i)
215
+ if (fdt.null? || RPM::C.Ferror(fdt) != 0)
216
+ raise RuntimeError, "Can't use opened file #{data.key}: #{RPM::C.Fstrerror(fdt)}"
217
+ RPM::C.Fclose(fdt) if not fdt.nil?
218
+ else
219
+ fdt = RPM::C.fdLink(fdt)
220
+ @fdt = fdt
221
+ end
222
+ # return the (RPM type) file handle
223
+ fdt
224
+ when :inst_close_file
225
+ fdt = @fdt
226
+ RPM::C.Fclose(fdt)
227
+ @fdt = nil
228
+ else
229
+ ret
230
+ end
231
+ else
232
+ # No custom callback given, use the default to show progress
233
+ RPM::C.rpmShowProgress(hdr, type, amount, total, key, data_ignored)
234
+ end
109
235
  end
110
236
 
111
- RPM::FFI.rpmtsSetNotifyCallback(@ts, callback, nil)
237
+ rc = RPM::C.rpmtsSetNotifyCallback(@ptr, callback, nil)
238
+ raise "Can't set commit callback" if rc != 0
239
+
240
+ rc = RPM::C.rpmtsRun(@ptr, nil, :none)
112
241
 
113
- rc = RPM::FFI.rpmtsRun(@ptr, nil, :none)
242
+ raise "#{self}: #{RPM::C.rpmlogMessage}" if rc < 0
114
243
 
115
- raise "Transaction Error" if rc < 0
116
-
117
244
  if rc > 0
118
- ps = RPM::FFI.rpmtsProblems(@ptr)
119
- psi = RPM::FFI.rpmpsInitIterator(ps)
120
- while (RPM::FFI.rpmpsNextIterator(psi) >= 0)
121
- problem = RPM::FFI.rpmpsGetProblem(psi)
122
- puts RPM::FFI.rpmProblemString.read_string
245
+ ps = RPM::C.rpmtsProblems(@ptr)
246
+ psi = RPM::C.rpmpsInitIterator(ps)
247
+ while (RPM::C.rpmpsNextIterator(psi) >= 0)
248
+ problem = Problem.from_ptr(RPM::C.rpmpsGetProblem(psi))
249
+ STDERR.puts problem
123
250
  end
124
- RPM::FFI.rpmpsFree(ps)
251
+ RPM::C.rpmpsFree(ps)
125
252
  end
126
253
  end
127
254
 
255
+ # @return [DB] the database associated with this transaction
256
+ def db
257
+ RPM::DB.new(self)
258
+ end
259
+
260
+ private
261
+
262
+ # @param [Package] pkg package to install
263
+ # @param [String] key e.g. filename where to install from
264
+ # @param opts options
265
+ # @option :upgrade Upgrade packages if true
266
+ def install_element(pkg, key, opts={})
267
+ raise TypeError, "illegal argument type" if not pkg.is_a?(RPM::Package)
268
+ raise ArgumentError, "#{self}: key '#{key}' must be unique" if @keys.include?(key.object_id)
269
+
270
+ # keep a reference to the key as rpmtsAddInstallElement will keep a copy
271
+ # of the passed pointer (we pass the object_id)
272
+ @keys[key.object_id] = key
273
+
274
+ ret = RPM::C.rpmtsAddInstallElement(@ptr, pkg.ptr, FFI::Pointer.new(key.object_id), opts[:upgrade] ? 1 : 0, nil)
275
+ raise RuntimeError if ret != 0
276
+ nil
277
+ end
278
+
128
279
  end
129
280
 
130
281
  end