Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

executable file 880 lines (825 sloc) 27.088 kb
#!/usr/bin/ruby
require 'solv'
require 'rubygems'
require 'inifile'
require 'tempfile'
class Repo_generic
def initialize(name, type, attribs = {})
@name = name
@type = type
@attribs = attribs.dup
@incomplete = false
end
def enabled?
return @attribs['enabled'].to_i != 0
end
def autorefresh?
return @attribs['autorefresh'].to_i != 0
end
def calc_cookie_fp(f)
chksum = Solv::Chksum.new(Solv::REPOKEY_TYPE_SHA256)
chksum.add_fp(f)
return chksum.raw
end
def calc_cookie_file(filename)
chksum = Solv::Chksum.new(Solv::REPOKEY_TYPE_SHA256)
chksum.add("1.1")
chksum.add_stat(filename)
return chksum.raw
end
def cachepath(ext = nil)
path = @name.sub(/^\./, '_')
path += ext ? "_#{ext}.solvx" : '.solv'
return '/var/cache/solv/' + path.gsub(/\//, '_')
end
def load(pool)
@handle = pool.add_repo(@name)
@handle.appdata = self
@handle.priority = 99 - @attribs['priority'].to_i if @attribs['priority']
dorefresh = autorefresh?
if dorefresh
begin
s = File.stat(cachepath)
dorefresh = false if s && Time.now - s.mtime < @attribs['metadata_expire'].to_i
rescue SystemCallError
end
end
@cookie = nil
if !dorefresh && usecachedrepo(nil)
puts "repo: '#{@name}' cached"
return true
end
return load_if_changed()
end
def load_ext(repodata)
return false
end
def load_if_changed
return false
end
def download(file, uncompress, chksum, markincomplete = false)
url = @attribs['baseurl']
if !url
puts "%{@name}: no baseurl"
return nil
end
url = url.sub(/\/$/, '') + "/#{file}"
f = Tempfile.new('rbsolv')
f.unlink
st = system('curl', '-f', '-s', '-L', '-o', "/dev/fd/" + f.fileno.to_s, '--', url)
return nil if f.stat.size == 0 && (st || !chksum)
if !st
puts "#{file}: download error #{$? >> 8}"
@incomplete = true if markincomplete
return nil
end
if chksum
fchksum = Solv::Chksum.new(chksum.type)
fchksum.add_fd(f.fileno)
if !fchksum == chksum
puts "#{file}: checksum error"
@incomplete = true if markincomplete
return nil
end
end
if uncompress
return Solv::xfopen_dup(file, f.fileno)
else
return Solv::xfopen_dup('', f.fileno)
end
end
def download_location(location, chksum)
f = download(location, false, chksum)
abort("\n#{@name}: #{location} not found in repository\n") unless f
return f
end
def usecachedrepo(ext, mark = false)
cookie = ext ? @extcookie : @cookie
begin
repopath = cachepath(ext)
f = File.new(repopath, "r")
f.sysseek(-32, IO::SEEK_END)
fcookie = f.sysread(32)
return false if fcookie.length != 32
return false if cookie && fcookie != cookie
if !ext && @type != 'system'
f.sysseek(-32 * 2, IO::SEEK_END)
fextcookie = f.sysread(32)
return false if fextcookie.length != 32
end
f.sysseek(0, IO::SEEK_SET)
f = Solv::xfopen_dup('', f.fileno)
flags = ext ? Solv::Repo::REPO_USE_LOADING|Solv::Repo::REPO_EXTEND_SOLVABLES : 0
flags |= Solv::Repo::REPO_LOCALPOOL if ext && ext != 'DL'
if ! @handle.add_solv(f, flags)
Solv::xfclose(f)
return false
end
Solv::xfclose(f)
@cookie = fcookie unless ext
@extcookie = fextcookie if !ext && @type != 'system'
now = Time.now
begin
File::utime(now, now, repopath) if mark
rescue SystemCallError
end
return true
rescue SystemCallError
return false
end
return true
end
def genextcookie(f)
chksum = Solv::Chksum.new(Solv::REPOKEY_TYPE_SHA256)
chksum.add(@cookie)
if f
s = f.stat()
chksum.add(s.dev.to_s)
chksum.add(s.ino.to_s)
chksum.add(s.size.to_s)
chksum.add(s.mtime.to_s)
end
@extcookie = chksum.raw()
@extcookie[0] = 1 if @extcookie[0] == 0
end
def writecachedrepo(ext, info = nil)
begin
Dir::mkdir("/var/cache/solv", 0755) unless FileTest.directory?("/var/cache/solv")
f = Tempfile.new('.newsolv-', '/var/cache/solv')
f.chmod(0444)
sf = Solv::xfopen_dup('', f.fileno)
if !info
@handle.write(sf)
elsif ext
info.write(sf)
else
@handle.write_first_repodata(sf)
end
Solv::xfclose(sf)
f.sysseek(0, IO::SEEK_END)
if @type != 'system' && !ext
genextcookie(f) unless @extcookie
f.syswrite(@extcookie)
end
f.syswrite(ext ? @extcookie : @cookie)
f.close(false)
if @handle.iscontiguous?
sf = Solv::xfopen(f.path)
if sf
if !ext
@handle.empty()
abort("internal error, cannot reload solv file") unless @handle.add_solv(sf, Solv::Repo::SOLV_ADD_NO_STUBS)
else
info.extend_to_repo()
info.add_solv(sf, Solv::Repo::REPO_EXTEND_SOLVABLES)
end
Solv::xfclose(sf)
end
end
File.rename(f.path, cachepath(ext))
f.unlink
return true
rescue SystemCallError
return false
end
end
def updateaddedprovides(addedprovides)
return if @incomplete
return unless @handle && !@handle.isempty?
repodata = @handle.first_repodata()
return unless repodata
oldaddedprovides = repodata.lookup_idarray(Solv::SOLVID_META, Solv::REPOSITORY_ADDEDFILEPROVIDES)
return if (oldaddedprovides | addedprovides) == oldaddedprovides
for id in addedprovides
repodata.add_idarray(Solv::SOLVID_META, Solv::REPOSITORY_ADDEDFILEPROVIDES, id)
end
repodata.internalize()
writecachedrepo(nil, repodata)
end
end
class Repo_rpmmd < Repo_generic
def find(what)
di = @handle.Dataiterator(Solv::SOLVID_META, Solv::REPOSITORY_REPOMD_TYPE, what, Solv::Dataiterator::SEARCH_STRING)
di.prepend_keyname(Solv::REPOSITORY_REPOMD)
for d in di
dp = d.parentpos()
filename = dp.lookup_str(Solv::REPOSITORY_REPOMD_LOCATION)
next unless filename
checksum = dp.lookup_checksum(Solv::REPOSITORY_REPOMD_CHECKSUM)
if !checksum
puts "no #{filename} checksum!"
return nil, nil
end
return filename, checksum
end
return nil, nil
end
def load_if_changed
print "rpmmd repo '#{@name}: "
f = download("repodata/repomd.xml", false, nil, nil)
if !f
puts "no repomd.xml file, skipped"
@handle.free(true)
@handle = nil
return false
end
@cookie = calc_cookie_fp(f)
if usecachedrepo(nil, true)
puts "cached"
Solv.xfclose(f)
return true
end
@handle.add_repomdxml(f, 0)
Solv::xfclose(f)
puts "fetching"
filename, filechksum = find('primary')
if filename
f = download(filename, true, filechksum, true)
if f
@handle.add_rpmmd(f, nil, 0)
Solv::xfclose(f)
end
return false if @incomplete
end
filename, filechksum = find('updateinfo')
if filename
f = download(filename, true, filechksum, true)
if f
@handle.add_updateinfoxml(f, 0)
Solv::xfclose(f)
end
end
add_exts()
writecachedrepo(nil) unless @incomplete
@handle.create_stubs()
return true
end
def add_ext(repodata, what, ext)
filename, filechksum = find(what)
filename, filechksum = find('prestodelta') if !filename && what == 'deltainfo'
return unless filename
h = repodata.new_handle()
repodata.set_poolstr(h, Solv::REPOSITORY_REPOMD_TYPE, what)
repodata.set_str(h, Solv::REPOSITORY_REPOMD_LOCATION, filename)
repodata.set_checksum(h, Solv::REPOSITORY_REPOMD_CHECKSUM, filechksum)
if ext == 'DL'
repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOSITORY_DELTAINFO)
repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOKEY_TYPE_FLEXARRAY)
elsif ext == 'FL'
repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::SOLVABLE_FILELIST)
repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOKEY_TYPE_DIRSTRARRAY)
end
repodata.add_flexarray(Solv::SOLVID_META, Solv::REPOSITORY_EXTERNAL, h)
end
def add_exts
repodata = @handle.add_repodata(0)
add_ext(repodata, 'deltainfo', 'DL')
add_ext(repodata, 'filelists', 'FL')
repodata.internalize()
end
def load_ext(repodata)
repomdtype = repodata.lookup_str(Solv::SOLVID_META, Solv::REPOSITORY_REPOMD_TYPE)
if repomdtype == 'filelists'
ext = 'FL'
elsif repomdtype == 'deltainfo'
ext = 'DL'
else
return false
end
print "[#{@name}:#{ext}: "
STDOUT.flush
if usecachedrepo(ext)
puts "cached]\n"
return true
end
puts "fetching]\n"
filename = repodata.lookup_str(Solv::SOLVID_META, Solv::REPOSITORY_REPOMD_LOCATION)
filechksum = repodata.lookup_checksum(Solv::SOLVID_META, Solv::REPOSITORY_REPOMD_CHECKSUM)
f = download(filename, true, filechksum)
return false unless f
if ext == 'FL'
@handle.add_rpmmd(f, 'FL', Solv::Repo::REPO_USE_LOADING|Solv::Repo::REPO_EXTEND_SOLVABLES)
elsif ext == 'DL'
@handle.add_deltainfoxml(f, Solv::Repo::REPO_USE_LOADING)
end
Solv::xfclose(f)
writecachedrepo(ext, repodata)
return true
end
end
class Repo_susetags < Repo_generic
def find(what)
di = @handle.Dataiterator(Solv::SOLVID_META, Solv::SUSETAGS_FILE_NAME, what, Solv::Dataiterator::SEARCH_STRING)
di.prepend_keyname(Solv::SUSETAGS_FILE)
for d in di
dp = d.parentpos()
checksum = dp.lookup_checksum(Solv::SUSETAGS_FILE_CHECKSUM)
return what, checksum
end
return nil, nil
end
def load_if_changed
print "susetags repo '#{@name}: "
f = download("content", false, nil, nil)
if !f
puts "no content file, skipped"
@handle.free(true)
@handle = nil
return false
end
@cookie = calc_cookie_fp(f)
if usecachedrepo(nil, true)
puts "cached"
Solv.xfclose(f)
return true
end
@handle.add_content(f, 0)
Solv::xfclose(f)
puts "fetching"
defvendorid = @handle.lookup_id(Solv::SOLVID_META, Solv::SUSETAGS_DEFAULTVENDOR)
descrdir = @handle.lookup_str(Solv::SOLVID_META, Solv::SUSETAGS_DESCRDIR)
descrdir = "suse/setup/descr" unless descrdir
(filename, filechksum) = find('packages.gz')
(filename, filechksum) = find('packages') unless filename
if filename
f = download("#{descrdir}/#{filename}", true, filechksum, true)
if f
@handle.add_susetags(f, defvendorid, nil, Solv::Repo::REPO_NO_INTERNALIZE|Solv::Repo::SUSETAGS_RECORD_SHARES)
Solv::xfclose(f)
(filename, filechksum) = find('packages.en.gz')
(filename, filechksum) = find('packages.en') unless filename
if filename
f = download("#{descrdir}/#{filename}", true, filechksum, true)
if f
@handle.add_susetags(f, defvendorid, nil, Solv::Repo::REPO_NO_INTERNALIZE|Solv::Repo::REPO_REUSE_REPODATA|Solv::Repo::REPO_EXTEND_SOLVABLES)
Solv::xfclose(f)
end
end
@handle.internalize()
end
end
add_exts()
writecachedrepo(nil) unless @incomplete
@handle.create_stubs()
return true
end
@@langtags = {
Solv::SOLVABLE_SUMMARY => Solv::REPOKEY_TYPE_STR,
Solv::SOLVABLE_DESCRIPTION => Solv::REPOKEY_TYPE_STR,
Solv::SOLVABLE_EULA => Solv::REPOKEY_TYPE_STR,
Solv::SOLVABLE_MESSAGEINS => Solv::REPOKEY_TYPE_STR,
Solv::SOLVABLE_MESSAGEDEL => Solv::REPOKEY_TYPE_STR,
Solv::SOLVABLE_CATEGORY => Solv::REPOKEY_TYPE_ID,
}
def add_ext(repodata, what, ext)
(filename, filechksum) = find(what)
h = repodata.new_handle()
repodata.set_str(h, Solv::SUSETAGS_FILE_NAME, filename)
repodata.set_checksum(h, Solv::SUSETAGS_FILE_CHECKSUM, filechksum)
if ext == 'DL'
repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOSITORY_DELTAINFO)
repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOKEY_TYPE_FLEXARRAY)
elsif ext == 'DU'
repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::SOLVABLE_DISKUSAGE)
repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOKEY_TYPE_DIRNUMNUMARRAY)
elsif ext == 'FL'
repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::SOLVABLE_FILELIST)
repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOKEY_TYPE_DIRSTRARRAY)
else
@@langtags.sort.each do |langid, langtype|
repodata.add_idarray(h, Solv::REPOSITORY_KEYS, @handle.pool.id2langid(langid, ext, true))
repodata.add_idarray(h, Solv::REPOSITORY_KEYS, langtype)
end
end
repodata.add_flexarray(Solv::SOLVID_META, Solv::REPOSITORY_EXTERNAL, h)
end
def add_exts
repodata = @handle.add_repodata(0)
di = @handle.Dataiterator(Solv::SOLVID_META, Solv::SUSETAGS_FILE_NAME, nil, 0)
di.prepend_keyname(Solv::SUSETAGS_FILE)
for d in di
filename = d.str
next unless filename && filename =~ /^packages\.(..)(?:\..*)$/
next if $1 == 'en' || $1 == 'gz'
add_ext(repodata, filename, $1)
end
repodata.internalize()
end
def load_ext(repodata)
filename = repodata.lookup_str(Solv::SOLVID_META, Solv::SUSETAGS_FILE_NAME)
ext = filename[9,2]
print "[#{@name}:#{ext}: "
STDOUT.flush
if usecachedrepo(ext)
puts "cached]\n"
return true
end
puts "fetching]\n"
defvendorid = @handle.lookup_id(Solv::SOLVID_META, Solv::SUSETAGS_DEFAULTVENDOR)
descrdir = @handle.lookup_str(Solv::SOLVID_META, Solv::SUSETAGS_DESCRDIR)
descrdir = "suse/setup/descr" unless descrdir
filechksum = repodata.lookup_checksum(Solv::SOLVID_META, Solv::SUSETAGS_FILE_CHECKSUM)
f = download("#{descrdir}/#{filename}", true, filechksum)
return false unless f
@handle.add_susetags(f, defvendorid, ext, Solv::Repo::REPO_USE_LOADING|Solv::Repo::REPO_EXTEND_SOLVABLES)
Solv::xfclose(f)
writecachedrepo(ext, repodata)
return true
end
def download_location(location, chksum)
datadir = @handle.lookup_str(Solv::SOLVID_META, Solv::SUSETAGS_DATADIR)
datadir = "suse" unless datadir
super("#{datadir}/#{location}", chksum)
end
end
class Repo_unknown < Repo_generic
def load(pool)
puts "unsupported repo '#{@name}: skipped"
return false
end
end
class Repo_system < Repo_generic
def load(pool)
@handle = pool.add_repo(@name)
@handle.appdata = self
pool.installed = @handle
print "rpm database: "
@cookie = calc_cookie_file("/var/lib/rpm/Packages")
if usecachedrepo(nil)
puts "cached"
return true
end
puts "reading"
@handle.add_products("/etc/products.d", Solv::Repo::REPO_NO_INTERNALIZE)
@handle.add_rpmdb(nil, Solv::Repo::REPO_REUSE_REPODATA)
writecachedrepo(nil)
return true
end
end
def validarch?(pool, arch)
return false unless arch && arch != ''
id = pool.str2id(arch, false)
return id != 0 && pool.isknownarch?(id)
end
def depglob(pool, name, globname, globdep)
id = pool.str2id(name, false)
if id != 0
match = false
providers = pool.whatprovides(id)
if globname && providers.find {|s| s.nameid == id }
return [ pool.Job(Solv::Job::SOLVER_SOLVABLE_NAME, id) ]
end
if !providers.empty?
puts "[using capability match for '#{name}']" if globname && globdep
return [ pool.Job(Solv::Job::SOLVER_SOLVABLE_PROVIDES, id) ]
end
end
return [] unless name =~ /[\[*?]/
if globname
idmatches = {}
for d in pool.Dataiterator(0, Solv::SOLVABLE_NAME, name, Solv::Dataiterator::SEARCH_GLOB)
s = d.solvable
idmatches[s.nameid] = 1 if s.installable?
end
if !idmatches.empty?
return idmatches.keys.sort.collect { |id| pool.Job(Solv::Job::SOLVER_SOLVABLE_NAME, id) }
end
end
if globdep
idmatches = pool.matchprovidingids(name, Solv::Dataiterator::SEARCH_GLOB)
if !idmatches.empty?
puts "[using capability match for '#{name}']"
return idmatches.sort.collect { |id| pool.Job(Solv::Job::SOLVER_SOLVABLE_PROVIDES, id) }
end
end
return []
end
def limitjobs(pool, jobs, flags, evrstr)
njobs = []
evr = pool.str2id(evrstr)
for j in jobs
how = j.how
sel = how & Solv::Job::SOLVER_SELECTMASK
what = pool.rel2id(j.what, evr, flags)
if flags == Solv::REL_ARCH
how |= Solv::Job::SOLVER_SETARCH
elsif flags == Solv::REL_EQ && sel == Solv::Job::SOLVER_SOLVABLE_NAME
how |= evrstr.include?(?-) ? Solv::Job::SOLVER_SETEVR : Solv::Job::SOLVER_SETEV
end
njobs << pool.Job(how, what)
end
return njobs
end
def limitjobs_evrarch(pool, jobs, flags, evrstr)
if evrstr =~ /^(.+)\.(.+?)$/ && validarch?(pool, $2)
evrstr = $1
jobs = limitjobs(pool, jobs, Solv::REL_ARCH, $2)
end
return limitjobs(pool, jobs, flags, evrstr)
end
def mkjobs_rel(pool, cmd, name, rel, evr)
flags = 0
flags |= Solv::REL_LT if rel.include?(?<)
flags |= Solv::REL_EQ if rel.include?(?=)
flags |= Solv::REL_GT if rel.include?(?>)
jobs = depglob(pool, name, true, true)
return limitjobs(pool, jobs, flags, evr) unless jobs.empty?
if (name =~ /^(.+)\.(.+?)$/) && validarch?(pool, $2)
arch = $2
jobs = depglob(pool, name, true, true)
return [] if jobs.empty?
jobs = limitjobs(pool, jobs, Solv::REL_ARCH, arch)
return limitjobs(pool, jobs, flags, evr)
end
return []
end
def mkjobs_nevra(pool, cmd, arg)
jobs = depglob(pool, arg, true, true)
return jobs unless jobs.empty?
if ((arg =~ /^(.+)\.(.+?)$/) && validarch?(pool, $2))
arch = $2
jobs = depglob(pool, $1, true, true)
return limitjobs(pool, jobs, Solv::REL_ARCH, arch) unless jobs.empty?
end
if (arg =~ /^(.+)-(.+?)$/)
evr = $2
jobs = depglob(pool, $1, true, false)
return limitjobs_evrarch(pool, jobs, Solv::REL_EQ, evr) unless jobs.empty?
end
if (arg =~ /^(.+)-(.+?-.+?)$/)
evr = $2
jobs = depglob(pool, $1, true, false)
return limitjobs_evrarch(pool, jobs, Solv::REL_EQ, evr) unless jobs.empty?
end
return []
end
def mkjobs_filelist(pool, cmd, arg)
type = Solv::Dataiterator::SEARCH_STRING
type = Solv::Dataiterator::SEARCH_GLOB if arg =~ /[\[*?]/
if cmd == 'erase'
di = pool.installed.Dataiterator(0, Solv::SOLVABLE_FILELIST, arg, type | Solv::Dataiterator::SEARCH_FILES|Solv::Dataiterator::SEARCH_COMPLETE_FILELIST)
else
di = pool.Dataiterator(0, Solv::SOLVABLE_FILELIST, arg, type | Solv::Dataiterator::SEARCH_FILES|Solv::Dataiterator::SEARCH_COMPLETE_FILELIST)
end
matches = []
for d in di
s = d.solvable
next unless s && s.installable?
matches.push(s.id)
di.skip_solvable()
end
return [] if matches.empty?
puts "[using file list match for '#{arg}']"
if matches.length > 1
return [ pool.Job(Solv::Job::SOLVER_SOLVABLE_ONE_OF, pool.towhatprovides(matches)) ]
else
return [ pool.Job(Solv::Job::SOLVER_SOLVABLE | Solv::Job::SOLVER_NOAUTOSET, matches[0]) ]
end
end
def mkjobs(pool, cmd, arg)
if arg =~ /^\//
jobs = mkjobs_filelist(pool, cmd, arg)
return jobs unless jobs.empty?
end
if (arg =~ /^(.+?)\s*([<=>]+)\s*(.+?)$/)
return mkjobs_rel(pool, cmd, $1, $2, $3)
else
return mkjobs_nevra(pool, cmd, arg)
end
end
args = ARGV
cmd = args.shift
cmd = 'list' if cmd == 'li'
cmd = 'install' if cmd == 'in'
cmd = 'erase' if cmd == 'rm'
cmd = 'verify' if cmd == 've'
cmd = 'search' if cmd == 'se'
repos = []
for reposdir in [ '/etc/zypp/repos.d' ] do
next unless FileTest.directory?(reposdir)
for reponame in Dir["#{reposdir}/*.repo"].sort do
cfg = IniFile.new(reponame)
cfg.each_section do |ali|
repoattr = { 'alias' => ali, 'enabled' => 0, 'priority' => 99, 'autorefresh' => 1, 'type' => 'rpm-md', 'metadata_expire' => 900}
repoattr.update(cfg[ali])
if repoattr['type'] == 'rpm-md'
repo = Repo_rpmmd.new(ali, 'repomd', repoattr)
elsif repoattr['type'] == 'yast2'
repo = Repo_susetags.new(ali, 'susetags', repoattr)
else
repo = Repo_unknown.new(ali, 'unknown', repoattr)
end
repos.push(repo)
end
end
end
pool = Solv::Pool.new()
# require 'sys/uname' ; sysarch = Sys::Uname.machine
sysarch = `uname -p`.strip
pool.setarch(sysarch)
pool.set_loadcallback { |repodata|
repo = repodata.repo.appdata
repo ? repo.load_ext(repodata) : false
}
sysrepo = Repo_system.new('@System', 'system')
sysrepo.load(pool)
for repo in repos
repo.load(pool) if repo.enabled?
end
if cmd == 'search'
matches = {}
for di in pool.Dataiterator(0, Solv::SOLVABLE_NAME, args[0], Solv::Dataiterator::SEARCH_SUBSTRING | Solv::Dataiterator::SEARCH_NOCASE)
matches[di.solvid] = true
end
for solvid in matches.keys.sort
s = pool.solvables[solvid]
puts "- #{s.str} [#{s.repo.name}]"
end
exit
end
addedprovides = pool.addfileprovides_queue()
if !addedprovides.empty?
sysrepo.updateaddedprovides(addedprovides)
for repo in repos
repo.updateaddedprovides(addedprovides)
end
end
pool.createwhatprovides()
jobs = []
for arg in args
njobs = mkjobs(pool, cmd, ARGV[0])
abort("nothing matches '#{arg}'") if njobs.empty?
jobs += njobs
end
if cmd == 'list' || cmd == 'info'
abort("no package matched.") if jobs.empty?
for job in jobs
for s in job.solvables()
if cmd == 'info'
puts "Name: #{s.str}"
puts "Repo: #{s.repo.name}"
puts "Summary: #{s.lookup_str(Solv::SOLVABLE_SUMMARY)}"
str = s.lookup_str(Solv::SOLVABLE_URL)
puts "Url: #{str}" if str
str = s.lookup_str(Solv::SOLVABLE_LICENSE)
puts "License: #{str}" if str
puts "Description:\n#{s.lookup_str(Solv::SOLVABLE_DESCRIPTION)}"
puts
else
puts " - #{s.str} [#{s.repo.name}]"
puts " #{s.lookup_str(Solv::SOLVABLE_SUMMARY)}"
end
end
end
exit
end
if cmd == 'install' || cmd == 'erase' || cmd == 'up' || cmd == 'dup' || cmd == 'verify'
if jobs.empty?
if cmd == 'up' || cmd == 'verify' || cmd == 'dup'
jobs = [ pool.Job(Solv::Job::SOLVER_SOLVABLE_ALL, 0) ]
else
abort("no package matched.")
end
end
for job in jobs
if cmd == 'up'
if job.how == Solv::Job::SOLVER_SOLVABLE_ALL || job.solvables.any? {|s| s.isinstalled?}
job.how |= Solv::Job::SOLVER_UPDATE
else
job.how |= Solv::Job::SOLVER_INSTALL
end
elsif cmd == 'install'
job.how |= Solv::Job::SOLVER_INSTALL
elsif cmd == 'erase'
job.how |= Solv::Job::SOLVER_ERASE
elsif cmd == 'dup'
job.how |= Solv::Job::SOLVER_DISTUPGRADE
elsif cmd == 'verify'
job.how |= Solv::Job::SOLVER_VERIFY
end
end
solver = nil
#pool.set_debuglevel(1)
while true
solver = pool.Solver
solver.set_flag(Solv::Solver::SOLVER_FLAG_SPLITPROVIDES, 1)
solver.set_flag(Solv::Solver::SOLVER_FLAG_ALLOW_UNINSTALL, 1) if cmd == 'erase'
problems = solver.solve(jobs)
break if problems.empty?
for problem in problems
puts "Problem #{problem.id}:"
puts problem.findproblemrule.info.problemstr
solutions = problem.solutions
for solution in solutions
puts " Solution #{solution.id}:"
elements = solution.elements(true)
for element in elements
puts " - #{element.str}"
end
puts
end
sol = nil
while true
print "Please choose a solution: "
STDOUT.flush
sol = STDIN.gets.strip
break if sol == 's' || sol == 'q'
break if sol =~ /^\d+$/ && sol.to_i >= 1 && sol.to_i <= solutions.length
end
next if sol == 's'
abort if sol == 'q'
solution = solutions[sol.to_i - 1]
for element in solution.elements
newjob = element.Job()
if element.type == Solv::Solver::SOLVER_SOLUTION_JOB
jobs[element.jobidx] = newjob
else
jobs.push(newjob) if newjob && !jobs.include?(newjob)
end
end
end
end
trans = solver.transaction
solver = nil
if trans.isempty?
puts "Nothing to do."
exit
end
puts "\nTransaction summary:\n"
for cl in trans.classify()
if cl.type == Solv::Transaction::SOLVER_TRANSACTION_ERASE
puts "#{cl.count} erased packages:"
elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_INSTALL
puts "#{cl.count} installed packages:"
elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_REINSTALLED
puts "#{cl.count} reinstalled packages:"
elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_DOWNGRADED
puts "#{cl.count} downgraded packages:"
elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_CHANGED
puts "#{cl.count} changed packages:"
elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_UPGRADED
puts "#{cl.count} upgraded packages:"
elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_VENDORCHANGE
puts "#{cl.count} vendor changes from '#{pool.id2str(cl.fromid)}' to '#{pool.id2str(cl.toid)}':"
elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_ARCHCHANGE
puts "#{cl.count} arch changes from '#{pool.id2str(cl.fromid)}' to '#{pool.id2str(cl.toid)}':"
else
next
end
for p in cl.solvables
if cl.type == Solv::Transaction::SOLVER_TRANSACTION_UPGRADED || cl.type == Solv::Transaction::SOLVER_TRANSACTION_DOWNGRADED
puts " - #{p.str} -> #{trans.othersolvable(p).str}"
else
puts " - #{p.str}"
end
end
puts
end
puts "install size change: #{trans.calc_installsizechange()} K\n\n"
while true:
print("OK to continue (y/n)? ")
STDOUT.flush
yn = STDIN.gets.strip
break if yn == 'y'
abort if yn == 'n'
end
newpkgs = trans.newpackages()
newpkgsfp = {}
if !newpkgs.empty?
downloadsize = 0
for p in newpkgs
downloadsize += p.lookup_num(Solv::SOLVABLE_DOWNLOADSIZE)
end
puts "Downloading #{newpkgs.length} packages, #{downloadsize} K"
for p in newpkgs
repo = p.repo.appdata
location, medianr = p.lookup_location()
next unless location
chksum = p.lookup_checksum(Solv::SOLVABLE_CHECKSUM)
f = repo.download_location(location, chksum)
newpkgsfp[p.id] = f
print "."
STDOUT.flush()
end
puts
end
puts "Committing transaction:"
puts
trans.order(0)
for p in trans.steps
steptype = trans.steptype(p, Solv::Transaction::SOLVER_TRANSACTION_RPM_ONLY)
if steptype == Solv::Transaction::SOLVER_TRANSACTION_ERASE
puts "erase #{p.str}"
next unless p.lookup_num(Solv::RPM_RPMDBID)
evr = p.evr.sub(/^[0-9]+:/, '')
system('rpm', '-e', '--nodeps', '--nodigest', '--nosignature', "#{p.name}-#{evr}.#{p.arch}") || abort("rpm failed: #{$? >> 8}")
elsif (steptype == Solv::Transaction::SOLVER_TRANSACTION_INSTALL || steptype == Solv::Transaction::SOLVER_TRANSACTION_MULTIINSTALL)
puts "install #{p.str}"
f = newpkgsfp.delete(p.id)
next unless f
mode = steptype == Solv::Transaction::SOLVER_TRANSACTION_INSTALL ? '-U' : '-i'
system('rpm', mode, '--force', '--nodeps', '--nodigest', '--nosignature', "/dev/fd/#{Solv::xfileno(f).to_s}") || abort("rpm failed: #{$? >> 8}")
solv::xfclose(f)
end
end
end
Jump to Line
Something went wrong with that request. Please try again.