Class: RPM::Transaction

Inherits:
Object
  • Object
show all
Defined in:
lib/rpm/transaction.rb

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ Transaction

Returns a new instance of Transaction.



19
20
21
22
23
24
25
26
27
28
29
# File 'lib/rpm/transaction.rb', line 19

def initialize(opts={})
  # http://markmail.org/message/ypsiqxop442p7rzz
  # The key pointer needs to stay valid during commit 
  # so we keep a reference to them mapping from
  # object_id to ruby object.
  @keys = {}
  opts[:root] ||= '/'

  @ptr = ::FFI::AutoPointer.new(RPM::C.rpmtsCreate, Transaction.method(:release))
  RPM::C.rpmtsSetRootDir(@ptr, opts[:root])
end

Class Method Details

.release(ptr) ⇒ Object



15
16
17
# File 'lib/rpm/transaction.rb', line 15

def self.release(ptr)
  RPM::C.rpmtsFree(ptr)
end

Instance Method Details

#checkObject



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/rpm/transaction.rb', line 146

def check
  rc = RPM::C.rpmtsCheck(@ptr)
  probs = RPM::C.rpmtsProblems(@ptr)

  return if rc < 0
  begin
    psi = RPM::C.rpmpsInitIterator(probs)
    while (RPM::C.rpmpsNextIterator(psi) >= 0)
      problem = Problem.from_ptr(RPM::C.rpmpsGetProblem(psi))
      yield problem
    end
  ensure
    RPM::C.rpmpsFree(probs)
  end
end

#cleanObject

Free memory needed only for dependency checks and ordering.



142
143
144
# File 'lib/rpm/transaction.rb', line 142

def clean
  RPM::C.rpmtsClean(@ptr)
end

#commit {|CallbackData| ... } ⇒ Object

Performs the transaction. You can supply your own callback end

Examples:

transaction.commit
transaction.commit do |data|
end

Parameters:

  • flag (Number)

    Transaction flags, default RPM::TRANS_FLAG_NONE

  • filter (Number)

    Transaction filter, default RPM::PROB_FILTER_NONE

Yields:



173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
# File 'lib/rpm/transaction.rb', line 173

def commit(&user_callback)
  flags = RPM::C::TransFlags[:none]

  callback = Proc.new do |hdr, type, amount, total, key_ptr, data_ignored|
    key_id = key_ptr.address
    key = @keys.include?(key_id) ? @keys[key_id] : nil

    case
      when block_given?
        package = hdr.null? ? nil : Package.new(hdr)
        data = CallbackData.new(type, key, package, amount, total)
        user_callback.call(data)
      else
        RPM::C.rpmShowProgress(hdr, type, amount, total, key, data_ignored)
    end
  end
  # We create a callback to pass to the C method and we
  # call the user supplied callback from there
  #
  # The C callback expects you to return a file handle,
  # We expect from the user to get a File, which we
  # then convert to a file handle to return.
  callback = Proc.new do |hdr, type, amount, total, key_ptr, data_ignored|
    key_id = key_ptr.address
    key = @keys.include?(key_id) ? @keys[key_id] : nil

    case
      when block_given?
        package = hdr.null? ? nil : Package.new(hdr)
        data = CallbackData.new(type, key, package, amount, total)
        ret = user_callback.call(data)

        # For OPEN_FILE we need to do some type conversion
        # for certain callback types we need to do some
        case type
          when :inst_open_file
            # For :inst_open_file the user callback has to
            # return the open file
            if !ret.is_a?(::File)
              raise TypeError, "illegal return value type #{ret.class}. Expected File."
            end
            fdt = RPM::C.fdDup(ret.to_i)
            if (fdt.null? || RPM::C.Ferror(fdt) != 0)
              raise RuntimeError, "Can't use opened file #{data.key}: #{RPM::C.Fstrerror(fdt)}"
              RPM::C.Fclose(fdt) if not fdt.nil?
            else
              fdt = RPM::C.fdLink(fdt)
              @fdt = fdt
            end
            # return the (RPM type) file handle
            fdt
          when :inst_close_file
            fdt = @fdt
            RPM::C.Fclose(fdt)
            @fdt = nil
          else
            ret
        end
      else
        # No custom callback given, use the default to show progress
        RPM::C.rpmShowProgress(hdr, type, amount, total, key, data_ignored)
    end
  end

  rc = RPM::C.rpmtsSetNotifyCallback(@ptr, callback, nil)
  raise "Can't set commit callback" if rc != 0

  rc = RPM::C.rpmtsRun(@ptr, nil, :none)

  raise "#{self}: #{RPM::C.rpmlogMessage}" if rc < 0

  if rc > 0
    ps = RPM::C.rpmtsProblems(@ptr)
    psi = RPM::C.rpmpsInitIterator(ps)
    while (RPM::C.rpmpsNextIterator(psi) >= 0)
      problem = Problem.from_ptr(RPM::C.rpmpsGetProblem(psi))
      STDERR.puts problem
    end
    RPM::C.rpmpsFree(ps)
  end
end

#dbDB

Returns the database associated with this transaction.

Returns:

  • (DB)

    the database associated with this transaction



256
257
258
# File 'lib/rpm/transaction.rb', line 256

def db
  RPM::DB.new(self)
end

#delete(pkg) ⇒ Object

Add a delete operation to the transaction

Parameters:



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/rpm/transaction.rb', line 92

def delete(pkg)
  iterator = case pkg
  when Package
    pkg[:sigmd5] ? each_match(:sigmd5, pkg[:sigmd5]) : each_match(:label, pkg[:label])
  when String
    each_match(:label, pkg)
  when Dependency
    each_match(:label, pkg.name).set_iterator_version(pkg.version)
  else
    raise TypeError, "illegal argument type"
  end

  iterator.each do |header|
    ret = RPM::C.rpmtsAddEraseElement(@ptr, header.ptr, iterator.offset)
    raise RuntimeError, "Error while adding erase/#{pkg} to transaction" if ret != 0
  end
end

#each {|Package| ... } ⇒ Object

Examples:

db.each do |pkg|
  puts pkg.name
end

Yields:

  • (Package)

    Called for each package in the database



72
73
74
# File 'lib/rpm/transaction.rb', line 72

def each(&block)
  each_match(0, nil, &block)
end

#each_match(key, val) {|Package| ... } ⇒ Object

Examples:

RPM.transaction do |t|
  t.each_match(RPM::TAG_ARCH, "x86_64") do |pkg|
    puts pkg.name
  end
end

Parameters:

  • key (Number)

    RPM tag key

  • val (String)

    Value to match

Yields:

  • (Package)

    Called for each match



57
58
59
60
61
62
63
# File 'lib/rpm/transaction.rb', line 57

def each_match(key, val, &block)
  it = init_iterator(key, val)

  return it unless block_given?

  it.each(&block)
end

#flagsObject



126
127
128
# File 'lib/rpm/transaction.rb', line 126

def flags
  RPM::C.rpmtsFlags(@ptr)
end

#flags=(fl) ⇒ Object



122
123
124
# File 'lib/rpm/transaction.rb', line 122

def flags=(fl)
  RPM::C.rpmtsSetFlags(@ptr, fl)
end

#init_iterator(tag, val) ⇒ RPM::MatchIterator

Returns Creates an iterator for tag and val.

Returns:

Raises:

  • (TypeError)


32
33
34
35
36
37
38
39
# File 'lib/rpm/transaction.rb', line 32

def init_iterator(tag, val)
  raise TypeError if (val && !val.is_a?(String))

  it_ptr = RPM::C.rpmtsInitIterator(@ptr, tag.nil? ? 0 : tag, val, 0)

  raise "Can't init iterator for [#{tag}] -> '#{val}'" if it_ptr.null?
  return MatchIterator.from_ptr(it_ptr)
end

#install(pkg, key) ⇒ Object

Add a install operation to the transaction

Parameters:

  • pkg (Package)

    Package to install

  • key (String)

    e.g. filename where to install from



79
80
81
# File 'lib/rpm/transaction.rb', line 79

def install(pkg, key)
  install_element(pkg, key, :upgrade => false)
end

#orderObject

Determine package order in the transaction according to dependencies

The final order ends up as installed packages followed by removed packages, with packages removed for upgrades immediately following the new package to be installed.



137
138
139
# File 'lib/rpm/transaction.rb', line 137

def order
  RPM::C.rpmtsOrder(@ptr)
end

#root_dirString

Returns the root directory for this transaction.

Returns:

  • (String)

    the root directory for this transaction



118
119
120
# File 'lib/rpm/transaction.rb', line 118

def root_dir
  RPM::C.rpmtsRootDir(@ptr)
end

#root_dir=(dir) ⇒ Object

Sets the root directory for this transaction

Parameters:

  • root (String)

    directory



112
113
114
115
# File 'lib/rpm/transaction.rb', line 112

def root_dir=(dir)
  rc = RPM::C.rpmtsSetRootDir(@ptr, dir)
  raise "Can't set #{dir} as root directory" if rc < 0
end

#upgrade(pkg, key) ⇒ Object

Add an upgrade operation to the transaction

Parameters:

  • pkg (Package)

    Package to upgrade

  • key (String)

    e.g. filename where to install from



86
87
88
# File 'lib/rpm/transaction.rb', line 86

def upgrade(pkg, key)
  install_element(pkg, key, :upgrade => true)
end