class RPM::Transaction
Public Class Methods
# 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
# File lib/rpm/transaction.rb, line 15 def self.release(ptr) RPM::C.rpmtsFree(ptr) end
Public Instance Methods
# 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
Free memory needed only for dependency checks and ordering.
# File lib/rpm/transaction.rb, line 142 def clean RPM::C.rpmtsClean(@ptr) end
Performs the transaction. @param [Number] flag Transaction
flags, default RPM::TRANS_FLAG_NONE
@param [Number] filter Transaction
filter, default RPM::PROB_FILTER_NONE
@example
transaction.commit
You can supply your own callback @example
transaction.commit do |data| end
end @yield [CallbackData] sig Transaction
progress
# 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
@return [DB] the database associated with this transaction
# File lib/rpm/transaction.rb, line 256 def db RPM::DB.new(self) end
Add a delete operation to the transaction @param [String, Package
, Dependency] pkg Package
to delete
# 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
@yield [Package] Called for each package in the database @example
db.each do |pkg| puts pkg.name end
# File lib/rpm/transaction.rb, line 72 def each(&block) each_match(0, nil, &block) end
@yield [Package] Called for each match @param [Number] key RPM
tag key @param [String] val Value to match @example
RPM.transaction do |t| t.each_match(RPM::TAG_ARCH, "x86_64") do |pkg| puts pkg.name end end
# 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
# File lib/rpm/transaction.rb, line 126 def flags RPM::C.rpmtsFlags(@ptr) end
# File lib/rpm/transaction.rb, line 122 def flags=(fl) RPM::C.rpmtsSetFlags(@ptr, fl) end
@return [RPM::MatchIterator] Creates an iterator for tag
and val
# 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
Add a install operation to the transaction @param [Package] pkg Package
to install @param [String] key e.g. filename where to install from
# File lib/rpm/transaction.rb, line 79 def install(pkg, key) install_element(pkg, key, :upgrade => false) end
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.
@returns [Fixnum] no. of (added) packages that could not be ordered
# File lib/rpm/transaction.rb, line 137 def order RPM::C.rpmtsOrder(@ptr) end
@visibility private
# File lib/rpm/transaction.rb, line 42 def ptr @ptr end
@return [String ] the root directory for this transaction
# File lib/rpm/transaction.rb, line 118 def root_dir RPM::C.rpmtsRootDir(@ptr) end
Sets the root directory for this transaction @param [String] root directory
# 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
Add an upgrade operation to the transaction @param [Package] pkg Package
to upgrade @param [String] key e.g. filename where to install from
# File lib/rpm/transaction.rb, line 86 def upgrade(pkg, key) install_element(pkg, key, :upgrade => true) end
Private Instance Methods
@param [Package] pkg package to install @param [String] key e.g. filename where to install from @param opts options
@option :upgrade Upgrade packages if true
# File lib/rpm/transaction.rb, line 266 def install_element(pkg, key, opts={}) raise TypeError, "illegal argument type" if not pkg.is_a?(RPM::Package) raise ArgumentError, "#{self}: key '#{key}' must be unique" if @keys.include?(key.object_id) # keep a reference to the key as rpmtsAddInstallElement will keep a copy # of the passed pointer (we pass the object_id) @keys[key.object_id] = key ret = RPM::C.rpmtsAddInstallElement(@ptr, pkg.ptr, FFI::Pointer.new(key.object_id), opts[:upgrade] ? 1 : 0, nil) raise RuntimeError if ret != 0 nil end