rpm 0.0.2 → 0.0.3

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