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.



14
15
16
17
18
19
20
21
22
23
24
# File 'lib/rpm/transaction.rb', line 14

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



10
11
12
# File 'lib/rpm/transaction.rb', line 10

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

Instance Method Details

#checkObject



139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/rpm/transaction.rb', line 139

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.



135
136
137
# File 'lib/rpm/transaction.rb', line 135

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:



166
167
168
169
170
171
172
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
# File 'lib/rpm/transaction.rb', line 166

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

    if block_given?
      package = hdr.null? ? nil : Package.new(hdr)
      data = CallbackData.new(type, key, package, amount, total)
      yield(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 do |hdr, type, amount, total, key_ptr, data_ignored|
    key_id = key_ptr.address
    key = @keys.include?(key_id) ? @keys[key_id] : nil

    if block_given?
      package = hdr.null? ? nil : Package.new(hdr)
      data = CallbackData.new(type, key, package, amount, total)
      ret = yield(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
        unless 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 "Can't use opened file #{data.key}: #{RPM::C.Fstrerror(fdt)}"
          RPM::C.Fclose(fdt) unless 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



245
246
247
# File 'lib/rpm/transaction.rb', line 245

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

#delete(pkg) ⇒ Object

Add a delete operation to the transaction

Parameters:



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/rpm/transaction.rb', line 85

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 "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



65
66
67
# File 'lib/rpm/transaction.rb', line 65

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



50
51
52
53
54
55
56
# File 'lib/rpm/transaction.rb', line 50

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

  return it unless block_given?

  it.each(&block)
end

#flagsObject



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

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

#flags=(fl) ⇒ Object



115
116
117
# File 'lib/rpm/transaction.rb', line 115

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)


27
28
29
30
31
32
33
34
# File 'lib/rpm/transaction.rb', line 27

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?
  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



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

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.



130
131
132
# File 'lib/rpm/transaction.rb', line 130

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

#root_dirString

Returns the root directory for this transaction.

Returns:

  • (String)

    the root directory for this transaction



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

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

#root_dir=(dir) ⇒ Object

Sets the root directory for this transaction

Parameters:

  • root (String)

    directory



105
106
107
108
# File 'lib/rpm/transaction.rb', line 105

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



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

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