9 def initialize(name, type, attribs = {})
12 @attribs = attribs.dup
17 return @attribs['enabled'].to_i != 0
21 return @attribs['autorefresh'].to_i != 0
25 chksum = Solv::Chksum.new(Solv::REPOKEY_TYPE_SHA256)
30 def calc_cookie_file(filename)
31 chksum = Solv::Chksum.new(Solv::REPOKEY_TYPE_SHA256)
33 chksum.add_stat(filename)
37 def cachepath(ext = nil)
38 path = @name.sub(/^\./, '_')
39 path += ext ? "_#{ext}.solvx" : '.solv'
40 return '/var/cache/solv/' + path.gsub(/\//, '_')
44 @handle = pool.add_repo(@name)
45 @handle.appdata = self
46 @handle.priority = 99 - @attribs['priority'].to_i if @attribs['priority']
47 dorefresh = autorefresh?
50 s = File.stat(cachepath)
51 dorefresh = false if s && Time.now - s.mtime < @attribs['metadata_expire'].to_i
52 rescue SystemCallError
56 if !dorefresh && usecachedrepo(nil)
57 puts "repo: '#{@name}' cached"
60 return load_if_changed()
63 def load_ext(repodata)
71 def download(file, uncompress, chksum, markincomplete = false)
72 url = @attribs['baseurl']
74 puts "%{@name}: no baseurl"
77 url = url.sub(/\/$/, '') + "/#{file}"
78 f = Tempfile.new('rbsolv')
80 st = system('curl', '-f', '-s', '-L', '-o', "/dev/fd/" + f.fileno.to_s, '--', url)
81 return nil if f.stat.size == 0 && (st || !chksum)
83 puts "#{file}: download error #{$? >> 8}"
84 @incomplete = true if markincomplete
88 fchksum = Solv::Chksum.new(chksum.type)
89 fchksum.add_fd(f.fileno)
91 puts "#{file}: checksum error"
92 @incomplete = true if markincomplete
97 return Solv::xfopen_dup(file, f.fileno)
99 return Solv::xfopen_dup('', f.fileno)
103 def download_location(location, chksum)
104 f = download(location, false, chksum)
105 abort("\n#{@name}: #{location} not found in repository\n") unless f
109 def usecachedrepo(ext, mark = false)
110 cookie = ext ? @extcookie : @cookie
112 repopath = cachepath(ext)
113 f = File.new(repopath, "r")
114 f.sysseek(-32, IO::SEEK_END)
115 fcookie = f.sysread(32)
116 return false if fcookie.length != 32
117 return false if cookie && fcookie != cookie
118 if !ext && @type != 'system'
119 f.sysseek(-32 * 2, IO::SEEK_END)
120 fextcookie = f.sysread(32)
121 return false if fextcookie.length != 32
123 f.sysseek(0, IO::SEEK_SET)
124 f = Solv::xfopen_dup('', f.fileno)
125 flags = ext ? Solv::Repo::REPO_USE_LOADING|Solv::Repo::REPO_EXTEND_SOLVABLES : 0
126 flags |= Solv::Repo::REPO_LOCALPOOL if ext && ext != 'DL'
127 if ! @handle.add_solv(f, flags)
132 @cookie = fcookie unless ext
133 @extcookie = fextcookie if !ext && @type != 'system'
136 File::utime(now, now, repopath) if mark
137 rescue SystemCallError
140 rescue SystemCallError
147 chksum = Solv::Chksum.new(Solv::REPOKEY_TYPE_SHA256)
151 chksum.add(s.dev.to_s)
152 chksum.add(s.ino.to_s)
153 chksum.add(s.size.to_s)
154 chksum.add(s.mtime.to_s)
156 @extcookie = chksum.raw()
157 @extcookie[0] = 1 if @extcookie[0] == 0
160 def writecachedrepo(ext, info = nil)
162 Dir::mkdir("/var/cache/solv", 0755) unless FileTest.directory?("/var/cache/solv")
163 f = Tempfile.new('.newsolv-', '/var/cache/solv')
165 sf = Solv::xfopen_dup('', f.fileno)
171 @handle.write_first_repodata(sf)
174 f.sysseek(0, IO::SEEK_END)
175 if @type != 'system' && !ext
176 genextcookie(f) unless @extcookie
177 f.syswrite(@extcookie)
179 f.syswrite(ext ? @extcookie : @cookie)
181 if @handle.iscontiguous?
182 sf = Solv::xfopen(f.path)
186 abort("internal error, cannot reload solv file") unless @handle.add_solv(sf, Solv::Repo::SOLV_ADD_NO_STUBS)
188 info.extend_to_repo()
189 info.add_solv(sf, Solv::Repo::REPO_EXTEND_SOLVABLES)
194 File.rename(f.path, cachepath(ext))
197 rescue SystemCallError
202 def updateaddedprovides(addedprovides)
203 return if @incomplete
204 return unless @handle && !@handle.isempty?
205 repodata = @handle.first_repodata()
206 return unless repodata
207 oldaddedprovides = repodata.lookup_idarray(Solv::SOLVID_META, Solv::REPOSITORY_ADDEDFILEPROVIDES)
208 return if (oldaddedprovides | addedprovides) == oldaddedprovides
209 for id in addedprovides
210 repodata.add_idarray(Solv::SOLVID_META, Solv::REPOSITORY_ADDEDFILEPROVIDES, id)
212 repodata.internalize()
213 writecachedrepo(nil, repodata)
217 class Repo_rpmmd < Repo_generic
220 di = @handle.Dataiterator(Solv::SOLVID_META, Solv::REPOSITORY_REPOMD_TYPE, what, Solv::Dataiterator::SEARCH_STRING)
221 di.prepend_keyname(Solv::REPOSITORY_REPOMD)
224 filename = dp.lookup_str(Solv::REPOSITORY_REPOMD_LOCATION)
226 checksum = dp.lookup_checksum(Solv::REPOSITORY_REPOMD_CHECKSUM)
228 puts "no #{filename} checksum!"
231 return filename, checksum
237 print "rpmmd repo '#{@name}: "
238 f = download("repodata/repomd.xml", false, nil, nil)
240 puts "no repomd.xml file, skipped"
245 @cookie = calc_cookie_fp(f)
246 if usecachedrepo(nil, true)
251 @handle.add_repomdxml(f, 0)
254 filename, filechksum = find('primary')
256 f = download(filename, true, filechksum, true)
258 @handle.add_rpmmd(f, nil, 0)
261 return false if @incomplete
263 filename, filechksum = find('updateinfo')
265 f = download(filename, true, filechksum, true)
267 @handle.add_updateinfoxml(f, 0)
272 writecachedrepo(nil) unless @incomplete
273 @handle.create_stubs()
277 def add_ext(repodata, what, ext)
278 filename, filechksum = find(what)
279 filename, filechksum = find('prestodelta') if !filename && what == 'deltainfo'
280 return unless filename
281 h = repodata.new_handle()
282 repodata.set_poolstr(h, Solv::REPOSITORY_REPOMD_TYPE, what)
283 repodata.set_str(h, Solv::REPOSITORY_REPOMD_LOCATION, filename)
284 repodata.set_checksum(h, Solv::REPOSITORY_REPOMD_CHECKSUM, filechksum)
286 repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOSITORY_DELTAINFO)
287 repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOKEY_TYPE_FLEXARRAY)
289 repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::SOLVABLE_FILELIST)
290 repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOKEY_TYPE_DIRSTRARRAY)
292 repodata.add_flexarray(Solv::SOLVID_META, Solv::REPOSITORY_EXTERNAL, h)
296 repodata = @handle.add_repodata(0)
297 add_ext(repodata, 'deltainfo', 'DL')
298 add_ext(repodata, 'filelists', 'FL')
299 repodata.internalize()
302 def load_ext(repodata)
303 repomdtype = repodata.lookup_str(Solv::SOLVID_META, Solv::REPOSITORY_REPOMD_TYPE)
304 if repomdtype == 'filelists'
306 elsif repomdtype == 'deltainfo'
311 print "[#{@name}:#{ext}: "
313 if usecachedrepo(ext)
318 filename = repodata.lookup_str(Solv::SOLVID_META, Solv::REPOSITORY_REPOMD_LOCATION)
319 filechksum = repodata.lookup_checksum(Solv::SOLVID_META, Solv::REPOSITORY_REPOMD_CHECKSUM)
320 f = download(filename, true, filechksum)
321 return false unless f
323 @handle.add_rpmmd(f, 'FL', Solv::Repo::REPO_USE_LOADING|Solv::Repo::REPO_EXTEND_SOLVABLES)
325 @handle.add_deltainfoxml(f, Solv::Repo::REPO_USE_LOADING)
328 writecachedrepo(ext, repodata)
334 class Repo_susetags < Repo_generic
337 di = @handle.Dataiterator(Solv::SOLVID_META, Solv::SUSETAGS_FILE_NAME, what, Solv::Dataiterator::SEARCH_STRING)
338 di.prepend_keyname(Solv::SUSETAGS_FILE)
341 checksum = dp.lookup_checksum(Solv::SUSETAGS_FILE_CHECKSUM)
342 return what, checksum
348 print "susetags repo '#{@name}: "
349 f = download("content", false, nil, nil)
351 puts "no content file, skipped"
356 @cookie = calc_cookie_fp(f)
357 if usecachedrepo(nil, true)
362 @handle.add_content(f, 0)
365 defvendorid = @handle.lookup_id(Solv::SOLVID_META, Solv::SUSETAGS_DEFAULTVENDOR)
366 descrdir = @handle.lookup_str(Solv::SOLVID_META, Solv::SUSETAGS_DESCRDIR)
367 descrdir = "suse/setup/descr" unless descrdir
368 (filename, filechksum) = find('packages.gz')
369 (filename, filechksum) = find('packages') unless filename
371 f = download("#{descrdir}/#{filename}", true, filechksum, true)
373 @handle.add_susetags(f, defvendorid, nil, Solv::Repo::REPO_NO_INTERNALIZE|Solv::Repo::SUSETAGS_RECORD_SHARES)
375 (filename, filechksum) = find('packages.en.gz')
376 (filename, filechksum) = find('packages.en') unless filename
378 f = download("#{descrdir}/#{filename}", true, filechksum, true)
380 @handle.add_susetags(f, defvendorid, nil, Solv::Repo::REPO_NO_INTERNALIZE|Solv::Repo::REPO_REUSE_REPODATA|Solv::Repo::REPO_EXTEND_SOLVABLES)
384 @handle.internalize()
388 writecachedrepo(nil) unless @incomplete
389 @handle.create_stubs()
394 Solv::SOLVABLE_SUMMARY => Solv::REPOKEY_TYPE_STR,
395 Solv::SOLVABLE_DESCRIPTION => Solv::REPOKEY_TYPE_STR,
396 Solv::SOLVABLE_EULA => Solv::REPOKEY_TYPE_STR,
397 Solv::SOLVABLE_MESSAGEINS => Solv::REPOKEY_TYPE_STR,
398 Solv::SOLVABLE_MESSAGEDEL => Solv::REPOKEY_TYPE_STR,
399 Solv::SOLVABLE_CATEGORY => Solv::REPOKEY_TYPE_ID,
402 def add_ext(repodata, what, ext)
403 (filename, filechksum) = find(what)
404 h = repodata.new_handle()
405 repodata.set_str(h, Solv::SUSETAGS_FILE_NAME, filename)
406 repodata.set_checksum(h, Solv::SUSETAGS_FILE_CHECKSUM, filechksum)
408 repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOSITORY_DELTAINFO)
409 repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOKEY_TYPE_FLEXARRAY)
411 repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::SOLVABLE_DISKUSAGE)
412 repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOKEY_TYPE_DIRNUMNUMARRAY)
414 repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::SOLVABLE_FILELIST)
415 repodata.add_idarray(h, Solv::REPOSITORY_KEYS, Solv::REPOKEY_TYPE_DIRSTRARRAY)
417 @@langtags.sort.each do |langid, langtype|
418 repodata.add_idarray(h, Solv::REPOSITORY_KEYS, @handle.pool.id2langid(langid, ext, true))
419 repodata.add_idarray(h, Solv::REPOSITORY_KEYS, langtype)
422 repodata.add_flexarray(Solv::SOLVID_META, Solv::REPOSITORY_EXTERNAL, h)
426 repodata = @handle.add_repodata(0)
427 di = @handle.Dataiterator(Solv::SOLVID_META, Solv::SUSETAGS_FILE_NAME, nil, 0)
428 di.prepend_keyname(Solv::SUSETAGS_FILE)
431 next unless filename && filename =~ /^packages\.(..)(?:\..*)$/
432 next if $1 == 'en' || $1 == 'gz'
433 add_ext(repodata, filename, $1)
435 repodata.internalize()
438 def load_ext(repodata)
439 filename = repodata.lookup_str(Solv::SOLVID_META, Solv::SUSETAGS_FILE_NAME)
441 print "[#{@name}:#{ext}: "
443 if usecachedrepo(ext)
448 defvendorid = @handle.lookup_id(Solv::SOLVID_META, Solv::SUSETAGS_DEFAULTVENDOR)
449 descrdir = @handle.lookup_str(Solv::SOLVID_META, Solv::SUSETAGS_DESCRDIR)
450 descrdir = "suse/setup/descr" unless descrdir
451 filechksum = repodata.lookup_checksum(Solv::SOLVID_META, Solv::SUSETAGS_FILE_CHECKSUM)
452 f = download("#{descrdir}/#{filename}", true, filechksum)
453 return false unless f
454 @handle.add_susetags(f, defvendorid, ext, Solv::Repo::REPO_USE_LOADING|Solv::Repo::REPO_EXTEND_SOLVABLES)
456 writecachedrepo(ext, repodata)
460 def download_location(location, chksum)
461 datadir = @handle.lookup_str(Solv::SOLVID_META, Solv::SUSETAGS_DATADIR)
462 datadir = "suse" unless datadir
463 super("#{datadir}/#{location}", chksum)
468 class Repo_unknown < Repo_generic
470 puts "unsupported repo '#{@name}: skipped"
475 class Repo_system < Repo_generic
477 @handle = pool.add_repo(@name)
478 @handle.appdata = self
479 pool.installed = @handle
480 print "rpm database: "
481 @cookie = calc_cookie_file("/var/lib/rpm/Packages")
482 if usecachedrepo(nil)
487 if @handle.respond_to? :add_products
488 @handle.add_products("/etc/products.d", Solv::Repo::REPO_NO_INTERNALIZE)
490 @handle.add_rpmdb(nil, Solv::Repo::REPO_REUSE_REPODATA)
497 def validarch?(pool, arch)
498 return false unless arch && arch != ''
499 id = pool.str2id(arch, false)
500 return id != 0 && pool.isknownarch?(id)
503 def depglob(pool, name, globname, globdep)
504 id = pool.str2id(name, false)
507 providers = pool.whatprovides(id)
508 if globname && providers.find {|s| s.nameid == id }
509 return [ pool.Job(Solv::Job::SOLVER_SOLVABLE_NAME, id) ]
512 puts "[using capability match for '#{name}']" if globname && globdep
513 return [ pool.Job(Solv::Job::SOLVER_SOLVABLE_PROVIDES, id) ]
516 return [] unless name =~ /[\[*?]/
519 for d in pool.Dataiterator(0, Solv::SOLVABLE_NAME, name, Solv::Dataiterator::SEARCH_GLOB)
521 idmatches[s.nameid] = 1 if s.installable?
524 return idmatches.keys.sort.collect { |id| pool.Job(Solv::Job::SOLVER_SOLVABLE_NAME, id) }
528 idmatches = pool.matchprovidingids(name, Solv::Dataiterator::SEARCH_GLOB)
530 puts "[using capability match for '#{name}']"
531 return idmatches.sort.collect { |id| pool.Job(Solv::Job::SOLVER_SOLVABLE_PROVIDES, id) }
537 def limitjobs(pool, jobs, flags, evrstr)
539 evr = pool.str2id(evrstr)
542 sel = how & Solv::Job::SOLVER_SELECTMASK
543 what = pool.rel2id(j.what, evr, flags)
544 if flags == Solv::REL_ARCH
545 how |= Solv::Job::SOLVER_SETARCH
546 elsif flags == Solv::REL_EQ && sel == Solv::Job::SOLVER_SOLVABLE_NAME
547 how |= evrstr.include?(?-) ? Solv::Job::SOLVER_SETEVR : Solv::Job::SOLVER_SETEV
549 njobs << pool.Job(how, what)
554 def limitjobs_evrarch(pool, jobs, flags, evrstr)
555 if evrstr =~ /^(.+)\.(.+?)$/ && validarch?(pool, $2)
557 jobs = limitjobs(pool, jobs, Solv::REL_ARCH, $2)
559 return limitjobs(pool, jobs, flags, evrstr)
562 def mkjobs_rel(pool, cmd, name, rel, evr)
564 flags |= Solv::REL_LT if rel.include?(?<)
565 flags |= Solv::REL_EQ if rel.include?(?=)
566 flags |= Solv::REL_GT if rel.include?(?>)
567 jobs = depglob(pool, name, true, true)
568 return limitjobs(pool, jobs, flags, evr) unless jobs.empty?
569 if (name =~ /^(.+)\.(.+?)$/) && validarch?(pool, $2)
571 jobs = depglob(pool, name, true, true)
572 return [] if jobs.empty?
573 jobs = limitjobs(pool, jobs, Solv::REL_ARCH, arch)
574 return limitjobs(pool, jobs, flags, evr)
579 def mkjobs_nevra(pool, cmd, arg)
580 jobs = depglob(pool, arg, true, true)
581 return jobs unless jobs.empty?
582 if ((arg =~ /^(.+)\.(.+?)$/) && validarch?(pool, $2))
584 jobs = depglob(pool, $1, true, true)
585 return limitjobs(pool, jobs, Solv::REL_ARCH, arch) unless jobs.empty?
587 if (arg =~ /^(.+)-(.+?)$/)
589 jobs = depglob(pool, $1, true, false)
590 return limitjobs_evrarch(pool, jobs, Solv::REL_EQ, evr) unless jobs.empty?
592 if (arg =~ /^(.+)-(.+?-.+?)$/)
594 jobs = depglob(pool, $1, true, false)
595 return limitjobs_evrarch(pool, jobs, Solv::REL_EQ, evr) unless jobs.empty?
600 def mkjobs_filelist(pool, cmd, arg)
601 type = Solv::Dataiterator::SEARCH_STRING
602 type = Solv::Dataiterator::SEARCH_GLOB if arg =~ /[\[*?]/
604 di = pool.installed.Dataiterator(0, Solv::SOLVABLE_FILELIST, arg, type | Solv::Dataiterator::SEARCH_FILES|Solv::Dataiterator::SEARCH_COMPLETE_FILELIST)
606 di = pool.Dataiterator(0, Solv::SOLVABLE_FILELIST, arg, type | Solv::Dataiterator::SEARCH_FILES|Solv::Dataiterator::SEARCH_COMPLETE_FILELIST)
611 next unless s && s.installable?
615 return [] if matches.empty?
616 puts "[using file list match for '#{arg}']"
617 if matches.length > 1
618 return [ pool.Job(Solv::Job::SOLVER_SOLVABLE_ONE_OF, pool.towhatprovides(matches)) ]
620 return [ pool.Job(Solv::Job::SOLVER_SOLVABLE | Solv::Job::SOLVER_NOAUTOSET, matches[0]) ]
624 def mkjobs(pool, cmd, arg)
626 jobs = mkjobs_filelist(pool, cmd, arg)
627 return jobs unless jobs.empty?
629 if (arg =~ /^(.+?)\s*([<=>]+)\s*(.+?)$/)
630 return mkjobs_rel(pool, cmd, $1, $2, $3)
632 return mkjobs_nevra(pool, cmd, arg)
638 cmd = 'list' if cmd == 'li'
639 cmd = 'install' if cmd == 'in'
640 cmd = 'erase' if cmd == 'rm'
641 cmd = 'verify' if cmd == 've'
642 cmd = 'search' if cmd == 'se'
645 for reposdir in [ '/etc/zypp/repos.d' ] do
646 next unless FileTest.directory?(reposdir)
647 for reponame in Dir["#{reposdir}/*.repo"].sort do
648 cfg = IniFile.new(reponame)
649 cfg.each_section do |ali|
650 repoattr = { 'alias' => ali, 'enabled' => 0, 'priority' => 99, 'autorefresh' => 1, 'type' => 'rpm-md', 'metadata_expire' => 900}
651 repoattr.update(cfg[ali])
652 if repoattr['type'] == 'rpm-md'
653 repo = Repo_rpmmd.new(ali, 'repomd', repoattr)
654 elsif repoattr['type'] == 'yast2'
655 repo = Repo_susetags.new(ali, 'susetags', repoattr)
657 repo = Repo_unknown.new(ali, 'unknown', repoattr)
664 pool = Solv::Pool.new()
665 # require 'sys/uname' ; sysarch = Sys::Uname.machine
666 sysarch = `uname -p`.strip
667 pool.setarch(sysarch)
669 pool.set_loadcallback { |repodata|
670 repo = repodata.repo.appdata
671 repo ? repo.load_ext(repodata) : false
674 sysrepo = Repo_system.new('@System', 'system')
677 repo.load(pool) if repo.enabled?
682 for di in pool.Dataiterator(0, Solv::SOLVABLE_NAME, args[0], Solv::Dataiterator::SEARCH_SUBSTRING | Solv::Dataiterator::SEARCH_NOCASE)
683 matches[di.solvid] = true
685 for solvid in matches.keys.sort
686 s = pool.solvables[solvid]
687 puts "- #{s.str} [#{s.repo.name}]"
692 addedprovides = pool.addfileprovides_queue()
693 if !addedprovides.empty?
694 sysrepo.updateaddedprovides(addedprovides)
696 repo.updateaddedprovides(addedprovides)
699 pool.createwhatprovides()
703 njobs = mkjobs(pool, cmd, ARGV[0])
704 abort("nothing matches '#{arg}'") if njobs.empty?
708 if cmd == 'list' || cmd == 'info'
709 abort("no package matched.") if jobs.empty?
711 for s in job.solvables()
713 puts "Name: #{s.str}"
714 puts "Repo: #{s.repo.name}"
715 puts "Summary: #{s.lookup_str(Solv::SOLVABLE_SUMMARY)}"
716 str = s.lookup_str(Solv::SOLVABLE_URL)
717 puts "Url: #{str}" if str
718 str = s.lookup_str(Solv::SOLVABLE_LICENSE)
719 puts "License: #{str}" if str
720 puts "Description:\n#{s.lookup_str(Solv::SOLVABLE_DESCRIPTION)}"
723 puts " - #{s.str} [#{s.repo.name}]"
724 puts " #{s.lookup_str(Solv::SOLVABLE_SUMMARY)}"
731 if cmd == 'install' || cmd == 'erase' || cmd == 'up' || cmd == 'dup' || cmd == 'verify'
733 if cmd == 'up' || cmd == 'verify' || cmd == 'dup'
734 jobs = [ pool.Job(Solv::Job::SOLVER_SOLVABLE_ALL, 0) ]
736 abort("no package matched.")
741 if job.how == Solv::Job::SOLVER_SOLVABLE_ALL || job.solvables.any? {|s| s.isinstalled?}
742 job.how |= Solv::Job::SOLVER_UPDATE
744 job.how |= Solv::Job::SOLVER_INSTALL
746 elsif cmd == 'install'
747 job.how |= Solv::Job::SOLVER_INSTALL
749 job.how |= Solv::Job::SOLVER_ERASE
751 job.how |= Solv::Job::SOLVER_DISTUPGRADE
752 elsif cmd == 'verify'
753 job.how |= Solv::Job::SOLVER_VERIFY
758 #pool.set_debuglevel(1)
761 solver.set_flag(Solv::Solver::SOLVER_FLAG_SPLITPROVIDES, 1)
762 solver.set_flag(Solv::Solver::SOLVER_FLAG_ALLOW_UNINSTALL, 1) if cmd == 'erase'
763 problems = solver.solve(jobs)
764 break if problems.empty?
765 for problem in problems
766 puts "Problem #{problem.id}:"
767 puts problem.findproblemrule.info.problemstr
768 solutions = problem.solutions
769 for solution in solutions
770 puts " Solution #{solution.id}:"
771 elements = solution.elements(true)
772 for element in elements
773 puts " - #{element.str}"
779 print "Please choose a solution: "
781 sol = STDIN.gets.strip
782 break if sol == 's' || sol == 'q'
783 break if sol =~ /^\d+$/ && sol.to_i >= 1 && sol.to_i <= solutions.length
787 solution = solutions[sol.to_i - 1]
788 for element in solution.elements
789 newjob = element.Job()
790 if element.type == Solv::Solver::SOLVER_SOLUTION_JOB
791 jobs[element.jobidx] = newjob
793 jobs.push(newjob) if newjob && !jobs.include?(newjob)
798 trans = solver.transaction
801 puts "Nothing to do."
804 puts "\nTransaction summary:\n"
805 for cl in trans.classify()
806 if cl.type == Solv::Transaction::SOLVER_TRANSACTION_ERASE
807 puts "#{cl.count} erased packages:"
808 elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_INSTALL
809 puts "#{cl.count} installed packages:"
810 elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_REINSTALLED
811 puts "#{cl.count} reinstalled packages:"
812 elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_DOWNGRADED
813 puts "#{cl.count} downgraded packages:"
814 elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_CHANGED
815 puts "#{cl.count} changed packages:"
816 elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_UPGRADED
817 puts "#{cl.count} upgraded packages:"
818 elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_VENDORCHANGE
819 puts "#{cl.count} vendor changes from '#{pool.id2str(cl.fromid)}' to '#{pool.id2str(cl.toid)}':"
820 elsif cl.type == Solv::Transaction::SOLVER_TRANSACTION_ARCHCHANGE
821 puts "#{cl.count} arch changes from '#{pool.id2str(cl.fromid)}' to '#{pool.id2str(cl.toid)}':"
825 for p in cl.solvables
826 if cl.type == Solv::Transaction::SOLVER_TRANSACTION_UPGRADED || cl.type == Solv::Transaction::SOLVER_TRANSACTION_DOWNGRADED
827 puts " - #{p.str} -> #{trans.othersolvable(p).str}"
834 puts "install size change: #{trans.calc_installsizechange()} K\n\n"
836 print("OK to continue (y/n)? ")
838 yn = STDIN.gets.strip
842 newpkgs = trans.newpackages()
847 downloadsize += p.lookup_num(Solv::SOLVABLE_DOWNLOADSIZE)
849 puts "Downloading #{newpkgs.length} packages, #{downloadsize} K"
851 repo = p.repo.appdata
852 location, medianr = p.lookup_location()
854 chksum = p.lookup_checksum(Solv::SOLVABLE_CHECKSUM)
855 f = repo.download_location(location, chksum)
862 puts "Committing transaction:"
866 steptype = trans.steptype(p, Solv::Transaction::SOLVER_TRANSACTION_RPM_ONLY)
867 if steptype == Solv::Transaction::SOLVER_TRANSACTION_ERASE
868 puts "erase #{p.str}"
869 next unless p.lookup_num(Solv::RPM_RPMDBID)
870 evr = p.evr.sub(/^[0-9]+:/, '')
871 system('rpm', '-e', '--nodeps', '--nodigest', '--nosignature', "#{p.name}-#{evr}.#{p.arch}") || abort("rpm failed: #{$? >> 8}")
872 elsif (steptype == Solv::Transaction::SOLVER_TRANSACTION_INSTALL || steptype == Solv::Transaction::SOLVER_TRANSACTION_MULTIINSTALL)
873 puts "install #{p.str}"
874 f = newpkgsfp.delete(p.id)
876 mode = steptype == Solv::Transaction::SOLVER_TRANSACTION_INSTALL ? '-U' : '-i'
877 system('rpm', mode, '--force', '--nodeps', '--nodigest', '--nosignature', "/dev/fd/#{Solv::xfileno(f).to_s}") || abort("rpm failed: #{$? >> 8}")