+universal していないパッケージをぜんぶ入れ替える Ruby スクリプト
昨日のエントリではワンライナでやっていて、依存関係を考えてなかったので大変なことになった。2パスでいいだろうとか考えていたけど甘かった。
ということで、Ruby で依存関係に従った順序で置き換えるスクリプトを書きました。
def active_version_variants(x, installed) /@[^+]+/.match(installed[x].keys.select{|var| installed[x][var] }[0]) return [$&, $' ? $'.scan(/\+[^+]+/) : []] end def active_variants(x, installed) return active_version_variants(x, installed)[1] end def active_deps(x, installed) var = active_variants(x, installed) deps = [] open("| port deps #{x} #{var.join}") do |f| f.each_line do |line| line.strip! deps << line if line !~ /:/ end end return deps end def has_universal?(x) open("| port variants #{x}") do |f| return f.read =~ /\s+universal:/ end end def is_active_universal?(x, installed) return active_variants(x, installed).include?('+universal') end def has_active?(x, installed) return installed[x].keys.any?{|var| installed[x][var] } end def is_installed(x, installed) return installed.has_key?(x) && !installed[x].empty? end def deactivate(x, vv) puts "sudo port deactivate #{x} #{vv}" system('sudo', 'port', 'deactivate', x, vv) end def install(x, v) puts "sudo port install #{x} #{v}" system('sudo', 'port', 'install', x, v) end def uninstall(x, vv) puts "sudo port uninstall #{x} #{vv}" system('sudo', 'port', 'uninstall', x, vv) end def universalize(x, remained, installed) remained.delete(x) if has_universal?(x) && !is_active_universal?(x, installed) active_deps(x, installed).each {|y| universalize(y, remained, installed) if remained.include?(y) } if has_active?(x, installed) vv = active_version_variants(x, installed) deactivate(x, vv.join) elsif installed[x].length == 1 /@[^+]+/.match(installed[x].keys[0]) vv = [$&, $'.scan(/\+[^+]+/)] else raise "there are multiple deactivated ports: #{x}" end install(x, [vv[1], '+universal'].join) uninstall(x, vv.join) if has_active?(x, installed) || installed[x].length == 1 installed[x].delete(vv.join) vv[1] << '+universal' vv[1].sort! installed[x][vv.join] = '(active)' end return true end installed_ports = {} open('| port installed') do |f| f.gets # drop the first line f.each_line do |line| name, ver, active = line.split installed_ports[name] ||= {} installed_ports[name][ver] = active end end remained = installed_ports.keys until remained.empty? universalize(remained[0], remained, installed_ports) end