16 def initialize(name, type, attribs = {})
19 @attribs = attribs.dup
24 return @attribs['enabled'].to_i != 0
28 return @attribs['autorefresh'].to_i != 0
32 chksum = Solv::Chksum.new(Solv::REPOKEY_TYPE_SHA256)
37 def calc_cookie_file(filename)
38 chksum = Solv::Chksum.new(Solv::REPOKEY_TYPE_SHA256)
40 chksum.add_stat(filename)
44 def cachepath(ext = nil)
45 path = @name.sub(/^\./, '_')
46 path += ext ? "_#{ext}.solvx" : '.solv'
47 return '/var/cache/solv/' + path.gsub(/\//, '_')
51 @handle = pool.add_repo(@name)
52 @handle.appdata = self
53 @handle.priority = 99 - @attribs['priority'].to_i if @attribs['priority']
54 dorefresh = autorefresh?
57 s = File.stat(cachepath)
58 dorefresh = false if s && Time.now - s.mtime < @attribs['metadata_expire'].to_i
59 rescue SystemCallError
63 if !dorefresh && usecachedrepo(nil)
64 puts "repo: '#{@name}' cached"
67 return load_if_changed()
70 def load_ext(repodata)
78 def download(file, uncompress, chksum, markincomplete = false)
79 url = @attribs['baseurl']
81 puts "%{@name}: no baseurl"
84 url = url.sub(/\/$/, '') + "/#{file}"
85 f = Tempfile.new('rbsolv')
87 st = system('curl', '-f', '-s', '-L', '-o', "/dev/fd/" + f.fileno.to_s, '--', url)
88 return nil if f.stat.size == 0 && (st || !chksum)
90 puts "#{file}: download error #{$? >> 8}"
91 @incomplete = true if markincomplete
95 fchksum = Solv::Chksum.new(chksum.type)
96 fchksum.add_fd(f.fileno)
97 if !fchksum.matches(chksum)
98 puts "#{file}: checksum error"
99 @incomplete = true if markincomplete
104 return Solv::xfopen_dup(file, f.fileno)
106 return Solv::xfopen_dup('', f.fileno)
110 def usecachedrepo(ext, mark = false)
111 cookie = ext ? @extcookie : @cookie
113 repopath = cachepath(ext)
114 f = File.new(repopath, "r")
115 f.sysseek(-32, IO::SEEK_END)
116 fcookie = f.sysread(32)
117 return false if fcookie.length != 32
118 return false if cookie && fcookie != cookie
119 if !ext && @type != 'system'
120 f.sysseek(-32 * 2, IO::SEEK_END)
121 fextcookie = f.sysread(32)
122 return false if fextcookie.length != 32
124 f.sysseek(0, IO::SEEK_SET)
125 f = Solv::xfopen_dup('', f.fileno)
126 flags = ext ? Solv::Repo::REPO_USE_LOADING|Solv::Repo::REPO_EXTEND_SOLVABLES : 0
127 flags |= Solv::Repo::REPO_LOCALPOOL if ext && ext != 'DL'
128 if ! @handle.add_solv(f, flags)
133 @cookie = fcookie unless ext
134 @extcookie = fextcookie if !ext && @type != 'system'
137 File::utime(now, now, repopath) if mark
138 rescue SystemCallError
141 rescue SystemCallError
148 chksum = Solv::Chksum.new(Solv::REPOKEY_TYPE_SHA256)
152 chksum.add(s.dev.to_s);
153 chksum.add(s.ino.to_s);
154 chksum.add(s.size.to_s);
155 chksum.add(s.mtime.to_s);
157 @extcookie = chksum.raw()
158 @extcookie[0] = 1 if @extcookie[0] == 0
161 def writecachedrepo(ext, info = nil)
163 Dir::mkdir("/var/cache/solv", 0755) unless FileTest.directory?("/var/cache/solv")
164 f = Tempfile.new('.newsolv-', '/var/cache/solv')
166 sf = Solv::xfopen_dup('', f.fileno)
172 @handle.write_first_repodata(sf)
175 f.sysseek(0, IO::SEEK_END)
176 if @type != 'system' && !ext
177 genextcookie(f) unless @extcookie
178 f.syswrite(@extcookie)
180 f.syswrite(ext ? @extcookie : @cookie)
182 if @handle.iscontiguous?
183 sf = Solv::xfopen(f.path)
187 abort("internal error, cannot reload solv file") unless @handle.add_solv(sf, Solv::Repo::SOLV_ADD_NO_STUBS)
189 info.extend_to_repo()
190 info.add_solv(sf, Solv::Repo::REPO_EXTEND_SOLVABLES)
195 File.rename(f.path, cachepath(ext))
198 rescue SystemCallError
203 def updateaddedprovides(addedprovides)
204 return if @incomplete
205 return unless @handle && !@handle.isempty?
206 repodata = @handle.first_repodata()
207 return unless repodata
208 oldaddedprovides = repodata.lookup_idarray(Solv::SOLVID_META, Solv::REPOSITORY_ADDEDFILEPROVIDES)
209 return if (oldaddedprovides | addedprovides) == oldaddedprovides
210 for id in addedprovides
211 repodata.add_idarray(Solv::SOLVID_META, Solv::REPOSITORY_ADDEDFILEPROVIDES, id)
213 repodata.internalize()
214 writecachedrepo(nil, repodata)
218 class Repo_rpmmd < Repo_generic
221 di = @handle.Dataiterator(Solv::SOLVID_META, Solv::REPOSITORY_REPOMD_TYPE, what, Solv::Dataiterator::SEARCH_STRING)
222 di.prepend_keyname(Solv::REPOSITORY_REPOMD)
225 filename = d.pool.lookup_str(Solv::SOLVID_POS, Solv::REPOSITORY_REPOMD_LOCATION)
227 checksum = d.pool.lookup_checksum(Solv::SOLVID_POS, Solv::REPOSITORY_REPOMD_CHECKSUM)
229 puts "no #{filename} checksum!"
232 return filename, checksum
238 print "rpmmd repo '#{@name}: "
239 f = download("repodata/repomd.xml", false, nil, nil)
241 puts "no repomd.xml file, skipped"
246 @cookie = calc_cookie_fp(f)
247 if usecachedrepo(nil, true)
252 @handle.add_repomdxml(f, 0)
255 filename, filechksum = find('primary')
257 f = download(filename, true, filechksum, true)
259 @handle.add_rpmmd(f, nil, 0)
262 return false if @incomplete
264 filename, filechksum = find('updateinfo')
266 f = download(filename, true, filechksum, true)
268 @handle.add_updateinfoxml(f, 0)
273 writecachedrepo(nil) unless @incomplete
274 @handle.create_stubs()
278 def add_ext(repodata, what, ext)
279 filename, filechksum = find(what)
280 filename, filechksum = find('prestodelta') if !filename && what == 'deltainfo'
281 return unless filename
282 h = repodata.new_handle()
283 repodata.set_poolstr(h, Solv::REPOSITORY_REPOMD_TYPE, what)
284 repodata.set_str(h, Solv::REPOSITORY_REPOMD_LOCATION, filename)
285 repodata.set_checksum(h, Solv::REPOSITORY_REPOMD_CHECKSUM, filechksum)
287 repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOSITORY_DELTAINFO)
288 repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOKEY_TYPE_FLEXARRAY)
290 repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::SOLVABLE_FILELIST)
291 repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOKEY_TYPE_DIRSTRARRAY)
293 repodata.add_flexarray(Solv::SOLVID_META, Solv::REPOSITORY_EXTERNAL, h)
297 repodata = @handle.add_repodata(0)
298 add_ext(repodata, 'deltainfo', 'DL')
299 add_ext(repodata, 'filelists', 'FL')
300 repodata.internalize()
303 def load_ext(repodata)
304 repomdtype = repodata.lookup_str(Solv::SOLVID_META, Solv::REPOSITORY_REPOMD_TYPE)
305 if repomdtype == 'filelists'
307 elsif repomdtype == 'deltainfo'
312 print "[#{@name}:#{ext}: "
314 if usecachedrepo(ext)
319 filename = repodata.lookup_str(Solv::SOLVID_META, Solv::REPOSITORY_REPOMD_LOCATION)
320 filechksum = repodata.lookup_checksum(Solv::SOLVID_META, Solv::REPOSITORY_REPOMD_CHECKSUM)
321 f = download(filename, true, filechksum)
322 return false unless f
324 @handle.add_rpmmd(f, 'FL', Solv::Repo::REPO_USE_LOADING|Solv::Repo::REPO_EXTEND_SOLVABLES)
326 @handle.add_deltainfoxml(f, Solv::Repo::REPO_USE_LOADING)
329 writecachedrepo(ext, repodata)
335 class Repo_susetags < Repo_generic
338 di = @handle.Dataiterator(Solv::SOLVID_META, Solv::SUSETAGS_FILE_NAME, what, Solv::Dataiterator::SEARCH_STRING)
339 di.prepend_keyname(Solv::SUSETAGS_FILE)
342 checksum = d.pool.lookup_checksum(Solv::SOLVID_POS, Solv::SUSETAGS_FILE_CHECKSUM)
343 return what, checksum
349 print "susetags repo '#{@name}: "
350 f = download("content", false, nil, nil)
352 puts "no content file, skipped"
357 @cookie = calc_cookie_fp(f)
358 if usecachedrepo(nil, true)
363 @handle.add_content(f, 0)
366 defvendorid = @handle.lookup_id(Solv::SOLVID_META, Solv::SUSETAGS_DEFAULTVENDOR)
367 descrdir = @handle.lookup_str(Solv::SOLVID_META, Solv::SUSETAGS_DESCRDIR)
368 descrdir = "suse/setup/descr" unless descrdir
369 (filename, filechksum) = find('packages.gz')
370 (filename, filechksum) = find('packages') unless filename
372 f = download("#{descrdir}/#{filename}", true, filechksum, true)
374 @handle.add_susetags(f, defvendorid, nil, Solv::Repo::REPO_NO_INTERNALIZE|Solv::Repo::SUSETAGS_RECORD_SHARES)
376 (filename, filechksum) = find('packages.en.gz')
377 (filename, filechksum) = find('packages.en') unless filename
379 f = download("#{descrdir}/#{filename}", true, filechksum, true)
381 @handle.add_susetags(f, defvendorid, nil, Solv::Repo::REPO_NO_INTERNALIZE|Solv::Repo::REPO_REUSE_REPODATA|Solv::Repo::REPO_EXTEND_SOLVABLES)
385 @handle.internalize()
389 writecachedrepo(nil) unless @incomplete
390 @handle.create_stubs()
395 Solv::SOLVABLE_SUMMARY => Solv::REPOKEY_TYPE_STR,
396 Solv::SOLVABLE_DESCRIPTION => Solv::REPOKEY_TYPE_STR,
397 Solv::SOLVABLE_EULA => Solv::REPOKEY_TYPE_STR,
398 Solv::SOLVABLE_MESSAGEINS => Solv::REPOKEY_TYPE_STR,
399 Solv::SOLVABLE_MESSAGEDEL => Solv::REPOKEY_TYPE_STR,
400 Solv::SOLVABLE_CATEGORY => Solv::REPOKEY_TYPE_ID,
403 def add_ext(repodata, what, ext)
404 (filename, filechksum) = find(what)
405 h = repodata.new_handle()
406 repodata.set_str(h, Solv::SUSETAGS_FILE_NAME, filename)
407 repodata.set_checksum(h, Solv::SUSETAGS_FILE_CHECKSUM, filechksum)
409 repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOSITORY_DELTAINFO)
410 repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOKEY_TYPE_FLEXARRAY)
412 repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::SOLVABLE_DISKUSAGE)
413 repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOKEY_TYPE_DIRNUMNUMARRAY)
415 repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::SOLVABLE_FILELIST)
416 repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOKEY_TYPE_DIRSTRARRAY)
418 @@langtags.sort.each do |langid, langtype|
419 repodata.add_idarray(h, Solv::REPOSITORY_KEYS, @handle.pool.id2langid(langid, ext, true))
420 repodata.add_idarray(h, Solv::REPOSITORY_KEYS, langtype)
423 repodata.add_flexarray(Solv::SOLVID_META, Solv::REPOSITORY_EXTERNAL, h)
427 repodata = @handle.add_repodata(0)
428 di = @handle.Dataiterator(Solv::SOLVID_META, Solv::SUSETAGS_FILE_NAME, nil, 0)
429 di.prepend_keyname(Solv::SUSETAGS_FILE)
431 filename = d.match_str
432 next unless filename && filename =~ /^packages\.(..)(?:\..*)$/
433 next if $1 == 'en' || $1 == 'gz'
434 add_ext(repodata, filename, $1)
436 repodata.internalize()
439 def load_ext(repodata)
440 filename = repodata.lookup_str(Solv::SOLVID_META, Solv::SUSETAGS_FILE_NAME)
442 print "[#{@name}:#{ext}: "
444 if usecachedrepo(ext)
449 defvendorid = @handle.lookup_id(Solv::SOLVID_META, Solv::SUSETAGS_DEFAULTVENDOR)
450 descrdir = @handle.lookup_str(Solv::SOLVID_META, Solv::SUSETAGS_DESCRDIR)
451 descrdir = "suse/setup/descr" unless descrdir
452 filechksum = repodata.lookup_checksum(Solv::SOLVID_META, Solv::SUSETAGS_FILE_CHECKSUM)
453 f = download("#{descrdir}/#{filename}", true, filechksum)
454 return false unless f
455 @handle.add_susetags(f, defvendorid, ext, Solv::Repo::REPO_USE_LOADING|Solv::Repo::REPO_EXTEND_SOLVABLES)
457 writecachedrepo(ext, repodata)
463 class Repo_unknown < Repo_generic
465 puts "unsupported repo '#{@name}: skipped"
470 class Repo_system < Repo_generic
472 @handle = pool.add_repo(@name)
473 @handle.appdata = self
474 pool.installed = @handle
475 print "rpm database: "
476 @cookie = calc_cookie_file("/var/lib/rpm/Packages")
477 if usecachedrepo(nil)
482 @handle.add_products("/etc/products.d", Solv::Repo::REPO_NO_INTERNALIZE)
483 @handle.add_rpmdb(nil, Solv::Repo::REPO_REUSE_REPODATA)
490 def validarch?(pool, arch)
491 return false unless arch && arch != ''
492 id = pool.str2id(arch, false)
493 return id != 0 && pool.isknownarch?(id)
496 def depglob(pool, name, globname, globdep)
497 id = pool.str2id(name, false)
500 providers = pool.providers(id)
501 if globname && providers.find {|s| s.nameid == id }
502 return [ pool.Job(Solv::Job::SOLVER_SOLVABLE_NAME, id) ]
505 puts "[using capability match for '#{name}']" if globname && globdep
506 return [ pool.Job(Solv::Job::SOLVER_SOLVABLE_PROVIDES, id) ]
509 return [] unless name =~ /[\[*?]/;
512 for d in pool.Dataiterator(0, Solv::SOLVABLE_NAME, name, Solv::Dataiterator::SEARCH_GLOB)
514 idmatches[s.nameid] = 1 if s.installable?
517 return idmatches.keys.sort.collect { |id| pool.Job(Solv::Job::SOLVER_SOLVABLE_NAME, id) }
521 idmatches = pool.matchprovidingids(name, Solv::Dataiterator::SEARCH_GLOB);
523 puts "[using capability match for '#{name}']"
524 return idmatches.sort.collect { |id| pool.Job(Solv::Job::SOLVER_SOLVABLE_PROVIDES, id) }
530 def limitjobs(pool, jobs, flags, evrstr)
532 evr = pool.str2id(evrstr)
535 sel = how & Solv::Job::SOLVER_SELECTMASK
536 what = pool.rel2id(j.what, evr, flags)
537 if flags == Solv::REL_ARCH
538 how |= Solv::Job::SOLVER_SETARCH
539 elsif flags == Solv::REL_EQ && sel == Solv::Job::SOLVER_SOLVABLE_NAME
540 how |= evrstr.include?(?-) ? Solv::Job::SOLVER_SETEVR : Solv::Job::SOLVER_SETEV
542 njobs << pool.Job(how, what)
547 def limitjobs_evrarch(pool, jobs, flags, evrstr)
548 if evrstr =~ /^(.+)\.(.+?)$/ && validarch?(pool, $2)
550 jobs = limitjobs(pool, jobs, Solv::REL_ARCH, $2)
552 return limitjobs(pool, jobs, flags, evrstr)
555 def mkjobs_rel(pool, cmd, name, rel, evr)
557 flags |= Solv::REL_LT if rel.include?(?<)
558 flags |= Solv::REL_EQ if rel.include?(?=)
559 flags |= Solv::REL_GT if rel.include?(?>)
560 jobs = depglob(pool, name, true, true)
561 return limitjobs(pool, jobs, flags, evr) unless jobs.empty?
562 if (name =~ /^(.+)\.(.+?)$/) && validarch?(pool, $2)
564 jobs = depglob(pool, name, true, true)
565 return [] if jobs.empty?
566 jobs = limitjobs(pool, jobs, Solv::REL_ARCH, arch)
567 return limitjobs(pool, jobs, flags, evr)
572 def mkjobs_nevra(pool, cmd, arg)
573 jobs = depglob(pool, arg, true, true)
574 return jobs unless jobs.empty?
575 if ((arg =~ /^(.+)\.(.+?)$/) && validarch?(pool, $2))
577 jobs = depglob(pool, $1, true, true)
578 return limitjobs(pool, jobs, Solv::REL_ARCH, arch) unless jobs.empty?
580 if (arg =~ /^(.+)-(.+?)$/)
582 jobs = depglob(pool, $1, true, false)
583 return limitjobs_evrarch(pool, jobs, Solv::REL_EQ, evr) unless jobs.empty?
585 if (arg =~ /^(.+)-(.+?-.+?)$/)
587 jobs = depglob(pool, $1, true, false)
588 return limitjobs_evrarch(pool, jobs, Solv::REL_EQ, evr) unless jobs.empty?
593 def mkjobs_filelist(pool, cmd, arg)
594 type = Solv::Dataiterator::SEARCH_STRING
595 type = Solv::Dataiterator::SEARCH_GLOB if arg =~ /[\[*?]/
597 di = pool.installed.Dataiterator(0, Solv::SOLVABLE_FILELIST, arg, type | Solv::Dataiterator::SEARCH_FILES|Solv::Dataiterator::SEARCH_COMPLETE_FILELIST)
599 di = pool.Dataiterator(0, Solv::SOLVABLE_FILELIST, arg, type | Solv::Dataiterator::SEARCH_FILES|Solv::Dataiterator::SEARCH_COMPLETE_FILELIST)
604 next unless s && s.installable?
608 return [] if matches.empty?
609 puts "[using file list match for '#{arg}']"
610 if matches.length > 1
611 return [ pool.Job(Solv::Job::SOLVER_SOLVABLE_ONE_OF, pool.towhatprovides(matches)) ]
613 return [ pool.Job(Solv::Job::SOLVER_SOLVABLE | Solv::Job::SOLVER_NOAUTOSET, matches[0]) ]
617 def mkjobs(pool, cmd, arg)
619 jobs = mkjobs_filelist(pool, cmd, arg)
620 return jobs unless jobs.empty?
622 if (arg =~ /^(.+?)\s*([<=>]+)\s*(.+?)$/)
623 return mkjobs_rel(pool, cmd, $1, $2, $3)
625 return mkjobs_nevra(pool, cmd, arg)
631 cmd = 'list' if cmd == 'li'
632 cmd = 'install' if cmd == 'in'
633 cmd = 'erase' if cmd == 'rm'
634 cmd = 'verify' if cmd == 've'
635 cmd = 'search' if cmd == 'se'
638 for reposdir in [ '/etc/zypp/repos.d' ] do
639 next unless FileTest.directory?(reposdir)
640 for reponame in Dir["#{reposdir}/*.repo"].sort do
641 cfg = IniFile.new(reponame)
642 cfg.each_section do |ali|
643 repoattr = { 'alias' => ali, 'enabled' => 0, 'priority' => 99, 'autorefresh' => 1, 'type' => 'rpm-md', 'metadata_expire' => 900}
644 repoattr.update(cfg[ali])
645 if repoattr['type'] == 'rpm-md'
646 repo = Repo_rpmmd.new(ali, 'repomd', repoattr)
647 elsif repoattr['type'] == 'yast2'
648 repo = Repo_susetags.new(ali, 'susetags', repoattr)
650 repo = Repo_unknown.new(ali, 'unknown', repoattr)
657 pool = Solv::Pool.new()
658 # require 'sys/uname' ; sysarch = Sys::Uname.machine
659 sysarch = `uname -p`.strip
660 pool.setarch(sysarch)
662 pool.set_loadcallback { |repodata|
663 repo = repodata.repo.appdata
664 repo ? repo.load_ext(repodata) : false
667 sysrepo = Repo_system.new('@System', 'system')
670 repo.load(pool) if repo.enabled?
675 for di in pool.Dataiterator(0, Solv::SOLVABLE_NAME, args[0], Solv::Dataiterator::SEARCH_SUBSTRING | Solv::Dataiterator::SEARCH_NOCASE)
676 matches[di.solvid] = true
678 for solvid in matches.keys.sort
679 s = pool.solvables[solvid]
680 puts "- #{s.str} [#{s.repo.name}]"
685 addedprovides = pool.addfileprovides_ids()
686 if !addedprovides.empty?
687 sysrepo.updateaddedprovides(addedprovides)
689 repo.updateaddedprovides(addedprovides)
692 pool.createwhatprovides()
696 njobs = mkjobs(pool, cmd, ARGV[0])
697 abort("nothing matches '#{arg}'") if njobs.empty?
701 if cmd == 'list' || cmd == 'info'
702 abort("no package matched.") if jobs.empty?
704 for s in job.solvables()
706 puts "Name: #{s.str}"
707 puts "Repo: #{s.repo.name}"
708 puts "Summary: #{s.lookup_str(Solv::SOLVABLE_SUMMARY)}"
709 str = s.lookup_str(Solv::SOLVABLE_URL)
710 puts "Url: #{str}" if str
711 str = s.lookup_str(Solv::SOLVABLE_LICENSE)
712 puts "License: #{str}" if str
713 puts "Description:\n#{s.lookup_str(Solv::SOLVABLE_DESCRIPTION)}"
716 puts " - #{s.str} [#{s.repo.name}]"
717 puts " #{s.lookup_str(Solv::SOLVABLE_SUMMARY)}"
724 if cmd == 'install' || cmd == 'erase' || cmd == 'up' || cmd == 'dup' || cmd == 'verify'
726 if cmd == 'up' || cmd == 'verify'
727 jobs = [ pool.Job(Solv::Job::SOLVER_SOLVABLE_ALL, 0) ]
729 abort("no package matched.")
734 if job.how == Solv::Job::SOLVER_SOLVABLE_ALL || job.solvables.any? {|s| s.isinstalled?}
735 job.how |= Solv::Job::SOLVER_UPDATE
737 job.how |= Solv::Job::SOLVER_INSTALL
739 elsif cmd == 'install'
740 job.how |= Solv::Job::SOLVER_INSTALL
742 job.how |= Solv::Job::SOLVER_ERASE
744 job.how |= Solv::Job::SOLVER_DISTUPGRADE
745 elsif cmd == 'verify'
746 job.how |= Solv::Job::SOLVER_VERIFY
751 #pool.set_debuglevel(1)
754 solver.ignorealreadyrecommended = true
755 solver.allowuninstall = true if cmd == 'erase'
756 if cmd == 'dup' && jobs.empty?
757 solver.distupgrade = true
758 solver.updatesystem = true
759 solver.allowdowngrade = true
760 solver.allowvendorchange = true
761 solver.allowarchchange = true
762 solver.dosplitprovides = true
763 elsif cmd == 'up' && jobs.length == 1 && jobs[0].how == (Solv::Job::SOLVER_UPDATE | Solv::Job::SOLVER_SOLVABLE_ALL)
764 solver.dosplitprovides = true
766 problems = solver.solve(jobs)
767 break if problems.empty?
768 for problem in problems
769 puts "Problem #{problem.id}:"
770 puts problem.findproblemrule.info.problemstr
771 solutions = problem.solutions
772 for solution in solutions
773 puts " Solution #{solution.id}:"
774 elements = solution.elements(true)
775 for element in elements
776 puts " - #{element.str}"
782 trans = solver.transaction
785 puts "Nothing to do."
788 puts "\nTransaction summary:\n"
789 for cl in trans.classify()
790 if cl.type == Solv::Transaction::SOLVER_TRANSACTION_ERASE
791 puts "#{cl.count} erased packages:"
792 elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_INSTALL
793 puts "#{cl.count} installed packages:"
794 elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_REINSTALLED
795 puts "#{cl.count} reinstalled packages:"
796 elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_DOWNGRADED
797 puts "#{cl.count} downgraded packages:"
798 elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_CHANGED
799 puts "#{cl.count} changed packages:"
800 elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_UPGRADED
801 puts "#{cl.count} upgraded packages:"
802 elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_VENDORCHANGE
803 puts "#{cl.count} vendor changes from '#{pool.id2str(cl.fromid)}' to '#{pool.id2str(cl.toid)}':"
804 elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_ARCHCHANGE
805 puts "#{cl.count} arch changes from '#{pool.id2str(cl.fromid)}' to '#{pool.id2str(cl.toid)}':"
809 for p in cl.solvables
810 if cl.type == Solv::Transaction::SOLVER_TRANSACTION_UPGRADED || cl.type == Solv::Transaction::SOLVER_TRANSACTION_DOWNGRADED
811 puts " - #{p.str} -> #{trans.othersolvable(p).str}"
818 puts "install size change: #{trans.calc_installsizechange()} K\n\n"