#!/usr/bin/env ruby $version = '0.6' $aboutText = %Q{ This is rtkmerge version #{$version} usage: rtkmerge world -u rtkmerge ruby Always press the pretend-button to see which packages the current configuration will merge. It might be more then you expect. This program is licensed under GPL, Gnu Public License copyright: Daniel Forchheimer (upiom), 2003 } require 'tk' #user-options $disableWidgetsAsIs = true # false = disable all when you press Emerge! $commandToLaunchWebsite = "mozilla %s" # %s is the url $useProgressBar = true #almost user-options commandToGetList = "emerge #{$*.join(" ")} -pv --columns" $commandToEmergeSearch = "emerge search" # you can put for instance esearch here, don't use a search command with a different output then 'emerge search' $flagsWhenEmerge = "" # -p could be set here while debugging $flagsWhenPretend = $flagsWhenEmerge + " " + "-pv --columns" nUseFlaggorPerRad = 6; class Paket def initialize(fullStr) fullStr=fullStr[15..fullStr.length]; @paketArray = fullStr.split(' ') @toEmerge = "yes" @pTkWidgets = [] end def tkWidgets @pTkWidgets end def toEmerge=(b) @toEmerge = b; end def toEmerge @toEmerge end def namn @paketArray[0] end def kortNamn namn.split("/",2)[1] end def nyVersion @paketArray[1][1..@paketArray[1].length-2] end def instaleradVersion if @paketArray[2]!=nil then if @paketArray[2][0]==?[ then @paketArray[2][1..@paketArray[2].length-2] else "" end else "" end end def useArray if instaleradVersion == "" then start=2 else start=3 end @paketArray[start..@paketArray.length] || [] end def toggleUse(useString) ind = useArray.index(useString); if(useArray[ind][0]==43) useArray[ind][0]=45 else useArray[ind][0]=43 end useArray[ind] end def setBackground(color) @pTkWidgets.each { |w| # w.configure('background'=>color) if(w.class == TkCheckbutton) then w.configure('background'=>color) end } end def disableWidgets @pTkWidgets.each { |w| if (w.class == TkButton)||(w.class==TkCheckbutton) then w.configure('state'=>'disabled') end } end def info cmd = $commandToEmergeSearch + " ^" + kortNamn+"$" t= `#{cmd}` t= t.split("\n") t[4..t.length].join("\n") end def changelog cmd = "emerge -pl " + kortNamn t= `#{cmd}` t= t.split("\n") t[4..t.length].join("\n") end def launchWebsite website = "" cmd = $commandToEmergeSearch + " ^"+kortNamn+"$" output = `#{cmd}` output.each() { |s| if s.index( "Homepage:" ) website = s.slice( 19, s.length-19 ) end } website.chomp! cmd = $commandToLaunchWebsite.sub( '%s', website ) system( cmd+"&" ) end def splat sec = hour = min = 0 time = 0.0 str = `splat -s #{kortNamn}` str.each_line do |l| l.strip! if l[11]==?e then while l.index(/[0-9]/) do l = l[l.index(/[0-9]/)..l.length] num = l[0..l.index(' ')].to_i unit= l[l.index(' ')+1] l = l[l.index(' ')..l.length] case unit when ?s time+= num when ?m time+= num*60 when ?h time+= num*60*60 end end end end time end def compileTime # general class to calculate compiletime # various method may be used, for now only # splat is implemented (compile time is aproximated # to the avarage compile time) # # returns compile time in seconds or 0 if failed system("which splat > /dev/null") if $? == 0 then splat else 0 end end def emerge(argString) cmd = "USE=\"" useArray.each do |s| cmd<<" "<'x') orient 'horizontal' from 0 to 100 } end def abortPackage if(@tThread.alive?) then @tThread.kill end end def newPackage(package) totalTime = package.compileTime waitTime = totalTime/100.0 puts "waitTime är: " + waitTime.to_s if waitTime != 0.0 then @tThread = Thread.new { 101.times { |i| @scale.set i sleep waitTime } } else # we have to initialize tThread or abortPackage will be mad @tThread = Thread.new {} @scale.set 50 end end end class TextWindow < TkToplevel def initialize(text) super() frame = TkFrame.new(self) frame.pack bar =TkScrollbar.new(frame) { pack('side'=>'right','fill'=>'y') } text = TkText.new(frame) { pack('expand'=>'yes','fill'=>'both','side'=>'left') yscrollbar(bar) wrap 'word' insert('end',text) state 'disable' } end end # with help from: # tkpopup.rb : wrapper for tk_popup # by Masahiro SATO (m@sa.to) # Time-stamp: <99/08/14 10:49:28 msato> # http://members.at.infoseek.co.jp/shiroikumo/ruby/rubytk/index-en.html class PopupMenu < TkWindow extend Tk def initialize(pkt,x = 0, y = 0, entry = "") super() @menu = TkMenu.new('tearoff'=>'false') @menu.add("command","label"=>'Info',"command"=> proc { TextWindow.new("Estimated compile time: #{pkt.compileTime.to_s}s\n\n" + pkt.info) }) @menu.add("command","label"=>'ChangeLog',"command"=> proc { TextWindow.new(pkt.changelog) }) @menu.add("command","label"=>'Website',"command"=> proc { pkt.launchWebsite }) @x = x @x = x @y = y @entry = entry INTERP._eval("tk_popup " + [@menu.path, @x.to_s, @y.to_s, @entry.to_s].join(" ")) end end def aboutWindow aroot = TkToplevel.new(root) {title 'About'} atop = TkFrame.new(aroot) atop.pack TkLabel.new(atop) { pack('side'=>'top') text $aboutText } TkButton.new(atop) { pack('side'=>'top') text 'close' command proc { aroot.destroy } } end def pretendEmerge(mina_paket) pwin = TkToplevel.new(root) { title 'pretend' } bar =TkScrollbar.new(pwin) { pack('side'=>'right','fill'=>'y') } text = TkText.new(pwin) { pack('expand'=>'yes','fill'=>'both','side'=>'left') yscrollbar(bar) wrap 'word' } puts "Calculating dependencies" allToPretend = "These are the packages that I would merge, in order:\n" mina_paket.each { |pk| if pk.toEmerge == 'yes' then pk.emergeCapture($flagsWhenPretend).each_line {|l| if(l["[ebuild"]) then if !(allToPretend[l[16..l.length].split[0]]) then allToPretend << l end end } end } nameColor = TkTextTag.new(text,'foreground'=>'dark green') oldVersionColor= TkTextTag.new(text,'foreground'=>'blue') posColor = TkTextTag.new(text,'foreground'=>'dark red') negColor = TkTextTag.new(text,'foreground'=>'dark blue') uColor = TkTextTag.new(text,'foreground'=>'turquoise') nColor = TkTextTag.new(text,'foreground'=>'green') fColor = TkTextTag.new(text,'foreground'=>'red') rColor = TkTextTag.new(text,'foreground'=>'yellow') dColor = oldVersionColor allToPretend.each_line { |s| if(s.index("[ebuild")) then pk = Paket.new(s) text.insert('end',s[0..6]) s[7..15].each_byte { |apa| case apa when ?U text.insert('end',apa.chr,uColor) when ?N text.insert('end',apa.chr,nColor) when ?F text.insert('end',apa.chr,fColor) when ?R text.insert('end',apa.chr,rColor) when ?D text.insert('end',apa.chr,dColor) else text.insert('end',apa.chr) end } text.insert('end',pk.namn+"-"+pk.nyVersion,nameColor) text.insert('end'," ["+pk.instaleradVersion+"]",oldVersionColor) pk.useArray.each do |uf| if uf[0]==?+ then text.insert('end'," "+uf,posColor) else text.insert('end'," "+uf,negColor) end end text.insert('end',"\n") else text.insert('end',s) end } text.state('disabled') end def setButtonColor(u) if(u[0]==?+) background 'red' activebackground 'red4' else background 'blue' activebackground 'blue4' end end mina_paket = Array.new puts "Calculating #{$*[0]} dependencies" cmd = open("|"+commandToGetList) while (string=cmd.gets) if(string["[ebuild"]) mina_paket << Paket.new(string); end end cmd.close puts " ...done!" puts mina_paket.nitems.to_s+" packages to update." root = TkRoot.new { title "Ruby-Tk-Merge: #{$*[0]}" } top = TkFrame.new(root) { pack('padx'=>5,'pady'=>5,'fill'=>'x') } if $useProgressBar then pb = ProgressBar.new(root) end lineFrame = TkFrame.new(top) { pack('side'=>'top','fill'=>'both','pady'=>5) # background 'pink' border 1 relief 'solid' } spareWidgetsToDisable = [] TkButton.new(lineFrame) { pack('side'=>'left','anchor'=>'w') text "Emerge!" command proc { if(!$disableWidgetsAsIs) then mina_paket.each { |p| p.disableWidgets } end spareWidgetsToDisable.each { |w| w.configure('state'=>'disabled') } state 'disabled' mergeThread =Thread.new { mina_paket.each { |p| #print p.toEmerge.class #puts " " + p.toEmerge if($disableWidgetsAsIs) then p.disableWidgets end if p.toEmerge=='yes' then p.setBackground('yellow') if $useProgressBar then p.emerge("--fetchonly") pb.newPackage(p) end if (p == mina_paket.last) then # the last package could be a new package p.emerge($flagsWhenEmerge) else # some of these might be dep's and should not be added to world # the rest are allready in world p.emerge($flagsWhenEmerge+" --oneshot") end if $? == 0 then p.setBackground('green') else p.setBackground('red') end if $useProgressBar then pb.abortPackage end end } } } } spareWidgetsToDisable << TkButton.new(lineFrame) { pack('side'=>'left','anchor'=>'w') text "pretend" command proc {pretendEmerge(mina_paket) } } TkButton.new(lineFrame) { pack('side'=>'right','anchor'=>'e') text "quit" command proc { root.destroy} } TkButton.new(lineFrame) { pack('side'=>'right','anchor'=>'e') text "about" command proc {aboutWindow } } lineFrame = TkFrame.new(top) { pack('side'=>'top','fill'=>'both','anchor'=>'w') } checkButtons = [] spareWidgetsToDisable << TkButton.new(lineFrame) { pack('side'=>'left','anchor'=>'w') text 'all' command proc { checkButtons.each { |cb| cb.select } mina_paket.each { |pk| pk.toEmerge="yes" } } } spareWidgetsToDisable << TkButton.new(lineFrame) { pack('side'=>'left','anchor'=>'w') text 'none' command proc { checkButtons.each { |cb| cb.deselect } mina_paket.each { |p| p.toEmerge="no" } } } yb = TkScrollbar.new(root) { pack('side'=>'right','anchor'=>'e','fill'=>'y'); } center = TkText.new(root) { relief 'flat' cursor 'left_ptr' pack('side'=>'top','fill'=>'both','expand'=>'true') yscrollbar(yb) wrap 'none' } # create lines for all the packages mina_paket.each { |p| lineFrame = TkFrame.new(center) { # pack('side' => 'top','anchor'=>'w','fill'=>'x') } TkTextWindow.new(center,'end','window'=>lineFrame) center.insert('end',"\n") p.tkWidgets << lineFrame check = TkVariable.new p.tkWidgets << TkCheckbutton.new(lineFrame) { variable check check.value='yes' text p.namn+"-"+p.nyVersion onvalue 'yes' offvalue 'no' pack('side'=>'left','fill'=>'x','anchor'=>'nw') command proc { p.toEmerge=check.value; } bind('Button-3',proc { |x,y| PopupMenu.new(p,x,y) },"%X %Y") } checkButtons << p.tkWidgets.last if p.instaleradVersion!="" then p.tkWidgets << TkLabel.new(lineFrame) { text "["+p.instaleradVersion+"]" foreground 'blue' pack('side'=>'left','fill'=>'x','anchor'=>'nw') } end 0.step(p.useArray.length,nUseFlaggorPerRad) { |i| useLineFrame = TkFrame.new(lineFrame) { pack('side'=>'top','anchor'=>'w') } p.useArray[i..i+nUseFlaggorPerRad-1].each { |u| p.tkWidgets << TkButton.new(useLineFrame) { text u # relief 'solid' setButtonColor(u) command proc { newU = p.toggleUse(u); text newU setButtonColor(newU); } pack('fill' => 'x','side'=>'left','anchor'=>'w') } } } } center.state('disable'); if $useProgressBar then pb.pack('side'=>'top','fill'=>'x') end Tk.mainloop END { trap("SIGINT") {} Process.kill("SIGINT",0) }