mock-gui/locallibs/ruby-rpm-ffi/lib/rpm/package.rb

334 lines
10 KiB

module RPM
class ChangeLog
attr_accessor :time, :name, :text
end
class Package
# Create a new package object from data
# @param [String] str Header data
# @return [Package]
def load(_data)
raise NotImplementedError
end
def self.create(name, version)
unless name.is_a?(String)
raise TypeError, 'illegal argument type: name should be String'
end
unless version.is_a?(RPM::Version)
raise TypeError, 'illegal argument type: version should be RPM::Version'
end
hdr = RPM::C.headerNew
if RPM::C.headerPutString(hdr, :name, name) != 1
raise "Can't set package name: #{name}"
end
if RPM::C.headerPutString(hdr, :version, version.v) != 1
raise "Can't set package version: #{version.v}"
end
if version.e
if RPM::C.headerPutUint32(hdr, :epoch, version.e) != 1
raise "Can't set package epoch: #{version.e}"
end
end
Package.new(hdr)
end
# Add a dependency to the package header
# @param [Dependency] dep Dependency to add
def add_dependency(dep)
unless dep.is_a?(Dependency)
raise TypeError, 'illegal argument type: must be a Dependency'
end
raise NotImplementedError
end
# Add a int32 value to the package header
# @param [Number] tag Tag
# @param [Number] val Value
def add_int32(_tag, _val)
raise NotImplementedError
end
# Add a list of strings to the package header
# @param [Number] tag Tag
# @param [Array<String>] val Strings to add
def add_string_array(_tag, _val)
raise NotImplementedError
end
# Add a binary value to the package header
# @param [Number] tag Tag
# @param [String] val String to add
def add_string(_tag, _val)
raise NotImplementedError
end
# Add a binary value to the package header
# @param [Number] tag Tag
# @param [String] val Value
def add_binary(_tag, _val)
raise NotImplementedError
end
# Deletes a tag of the package header
# @param [Number] tag Tag
def delete_tag(_tag)
raise NotImplementedError
end
# @return a formated string
# @example
# pkg.sprintf("%{name}") => "apache2"
def sprintf(fmt)
error = ::FFI::MemoryPointer.new(:pointer, 1)
val = RPM::C.headerFormat(@hdr, fmt, error)
raise error.get_pointer(0).read_string if val.null?
val.read_string
end
# @return [Number] This package signature
def signature
sprintf('%{sigmd5}')
end
# @return [Array<RPM::File>] File list for this package
def files
basenames = self[:basenames]
return [] if basenames.nil?
dirnames = self[:dirnames]
diridxs = self[:dirindexes]
statelist = self[:filestates]
flaglist = self[:fileflags]
sizelist = self[:filesizes]
modelist = self[:filemodes]
mtimelist = self[:filemtimes]
rdevlist = self[:filerdevs]
linklist = self[:filelinktos]
md5list = self[:filemd5s]
ownerlist = self[:fileusername]
grouplist = self[:filegroupname]
ret = []
basenames.each_with_index do |_basename, i|
file = RPM::File.new("#{dirnames[diridxs[i]]}#{basenames[i]}",
md5list[i],
linklist[i],
sizelist[i],
mtimelist[i],
ownerlist[i],
grouplist[i],
rdevlist[i],
modelist[i],
flaglist.nil? ? RPM::C::FileAttrs[:none] : flaglist[i],
statelist.nil? ? RPM::C::FileState[:normal] : statelist[i])
ret << file
end
ret
end
# @return [Array<RPM::Dependency>] Dependencies for +klass+
# @example
# dependencies(RPM::Provide, :providename, :provideversion, :provideflags)
#
# @visibility private
def dependencies(klass, nametag, versiontag, flagtag)
deps = []
nametd = ::FFI::AutoPointer.new(RPM::C.rpmtdNew, Package.method(:release_td))
versiontd = ::FFI::AutoPointer.new(RPM::C.rpmtdNew, Package.method(:release_td))
flagtd = ::FFI::AutoPointer.new(RPM::C.rpmtdNew, Package.method(:release_td))
min = RPM::C::HEADERGET_MINMEM
return deps if RPM::C.headerGet(@hdr, nametag, nametd, min) != 1
return deps if RPM::C.headerGet(@hdr, versiontag, versiontd, min) != 1
return deps if RPM::C.headerGet(@hdr, flagtag, flagtd, min) != 1
RPM::C.rpmtdInit(nametd)
while RPM::C.rpmtdNext(nametd) != -1
deps << klass.new(RPM::C.rpmtdGetString(nametd),
RPM::Version.new(RPM::C.rpmtdNextString(versiontd)),
RPM::C.rpmtdNextUint32(flagtd).read_uint, self)
end
deps
end
# @return [Array<RPM::Provide>] Provides list for this package
def provides
dependencies(RPM::Provide, :providename, :provideversion, :provideflags)
end
# @return [Array<RPM::Require>] Requires list for this package
def requires
dependencies(RPM::Require, :requirename, :requireversion, :requireflags)
end
# @return [Array<RPM::Conflicts>] Conflicts list for this package
def conflicts
dependencies(RPM::Conflict, :conflictname, :conflictversion, :conflictflags)
end
# @return [Array<RPM::Obsolete>] Obsoletes list for this package
def obsoletes
dependencies(RPM::Obsolete, :obsoletename, :obsoleteversion, :obsoleteflags)
end
# @return [Array<RPM::Changelog>] changelog of the package as an array
def changelog
entries = []
nametd = ::FFI::AutoPointer.new(RPM::C.rpmtdNew, Package.method(:release_td))
timetd = ::FFI::AutoPointer.new(RPM::C.rpmtdNew, Package.method(:release_td))
texttd = ::FFI::AutoPointer.new(RPM::C.rpmtdNew, Package.method(:release_td))
min = RPM::C::HEADERGET_MINMEM
return deps if RPM::C.headerGet(@hdr, :changelogtime, timetd, min) != 1
return deps if RPM::C.headerGet(@hdr, :changelogname, nametd, min) != 1
return deps if RPM::C.headerGet(@hdr, :changelogtext, texttd, min) != 1
RPM::C.rpmtdInit(timetd)
while RPM::C.rpmtdNext(timetd) != -1
entry = RPM::ChangeLog.new
entry.time = RPM::C.rpmtdGetUint32(timetd)
entry.name = RPM::C.rpmtdNextString(nametd)
entry.text = RPM::C.rpmtdNextString(texttd)
entries << entry
end
entries
end
# Access a header entry
# @param [Number] tag Tag to return
# @return [] Value of the entry
# @example
# pkg => #<RPM::Package name="xmlgraphics-fop", version=#<RPM::Version v="1.0", r="22.4">>
# pkg[:name] => "xmlgraphics-fop"
#
# or if you have the old ruby-rpm compat loaded
#
# require 'rpm/compat'
# pkg[RPM::TAG_NAME] => "xmlgraphics-fop"
#
# @return [String, Fixnum, Array<String>, Array<Fixnum>, nil]
# The value of the entry
def [](tag)
val = nil
tagc = ::FFI::AutoPointer.new(RPM::C.rpmtdNew, Package.method(:release_td))
return nil if RPM::C.headerGet(ptr, tag, tagc,
RPM::C::HEADERGET_MINMEM) == 0
type = RPM::C.rpmtdType(tagc)
count = RPM::C.rpmtdCount(tagc)
ret_type = RPM::C.rpmTagGetReturnType(tag)
method_name = case type
when :int8_type, :char_type, :int16_type, :int32_type, :int64_type then :rpmtdGetNumber
when :string_type, :string_array_type, :bin_type then :rpmtdGetString
else raise NotImplementedError, "Don't know how to retrieve type '#{type}'"
end
is_array = if count > 1 then true
elsif ret_type == :array_return_type then true
elsif type == :string_array_type then true
else false
end
if is_array
ret = []
RPM::C.rpmtdInit(tagc)
ret << RPM::C.send(method_name, tagc) while RPM::C.rpmtdNext(tagc) != -1
return ret
end
RPM::C.send(method_name, tagc)
end
# @return [String] This package name
def name
self[:name]
end
# @return [String] This package architecture
def arch
self[:arch]
end
# TODO: signature
# @return [Version] Version for this package
def version
Version.new(self[:version], self[:release], self[:epoch])
end
# String representation of the package: "name-version-release-arch"
# @return [String]
def to_s
return '' if name.nil?
return name if version.nil?
return "#{name}-#{version}" if arch.nil?
"#{name}-#{version}-#{arch}"
end
def self.open(filename)
Package.new(filename)
end
# @visibility private
def self.release(ptr)
RPM::C.headerFree(ptr)
end
# @visibility private
def self.release_td(ptr)
RPM::C.rpmtdFree(ptr)
end
# @visibility private
def initialize(what)
case what
when String then initialize_from_filename(what)
else initialize_from_header(what)
end
end
# @visibility private
def initialize_from_header(hdr = nil)
if hdr.nil?
@hdr = ::FFI::AutoPointer.new(RPM::C.headerNew, Header.method(:release))
elsif hdr.is_a?(::FFI::Pointer)
# ref
hdr = RPM::C.headerLink(hdr)
@hdr = ::FFI::AutoPointer.new(hdr, Package.method(:release))
else
raise "Can't initialize header with '#{hdr}'"
end
end
def initialize_from_filename(filename)
# it sucks not using the std File.open here
hdr = ::FFI::MemoryPointer.new(:pointer)
fd = nil
begin
fd = RPM::C.Fopen(filename, 'r')
raise "#{filename} : #{RPM::C.Fstrerror(fd)}" if RPM::C.Ferror(fd) != 0
RPM.transaction do |ts|
rc = RPM::C.rpmReadPackageFile(ts.ptr, fd, filename, hdr)
end
ensure
RPM::C.Fclose(fd) unless fd.nil?
end
initialize_from_header(hdr.get_pointer(0))
end
# @return [RPM::C::Header] header pointer
# @visibility private
def ptr
@hdr
end
end
end