Danny van Dyk wrote:  [Wed Jul 12 2006, 09:16:30AM EDT]
> There are 505 ebuilds which are missing use flags in IUSE that they use 
> in other places.

I once wrote a script (attached) to update IUSE automatically.  To use
it, simply:

$ cd games-emulation/xmess
$ fixiuse

It reports what it changed, and give you a resulting repoman commit
line which you can cut-and-paste.

Aron
#!/usr/bin/ruby -w
#
# fixiuse: update IUSE based on apparent usage in ebuild(s)
#

PORTDIR = %x{portageq envvar PORTDIR}.strip
ARCHLIST = IO.read(PORTDIR + '/profiles/arch.list').split(/\s+/)

$added = []
$removed = []

class Regexp
  def +(rxp)
    Regexp.new(self.to_s + rxp.to_s)
  end
end

class Efile
  attr_reader :inherits

  FLAG = /['"]?!?(\w[-\w+.]*)['"]?/  # regex to match a USE-flag and put it in 
$1

  def initialize(filename)
    @filename = filename
    @old_iuse = nil
    @new_iuse = nil
    @inherits = []

    if File.exists?(@filename)
      @e = IO.read(@filename)
    else
      @e = IO.read(PORTDIR + "/eclass/" + @filename + ".eclass")
    end
  end

  def inherits?(name)
    name == @filename.sub(/\.eclass$/, '') or @inherits.index(name)
  end

  def write
    # Short-circuit if there's nothing to do
    return if @new_iuse == @old_iuse

    # Remove the existing IUSE and remember the location
    iuse_location = @e.index(/^IUSE=/)
    @e.gsub!(/\bIUSE=(?:$|(['"]).*?\1)/m, "")

    # Insert at remembered location or just after KEYWORDS
    if iuse_location.nil?
      iuse_location = @e.index(/^KEYWORDS.*\n/) || @e.index(/\n\n/)
      iuse_location += $&.length
      @e.insert(iuse_location, "\n")
    end
    @e.insert(iuse_location, %Q(IUSE="[EMAIL PROTECTED] ' '}"))

    # Rewrite file
    File.open(@filename, "w") { |ios| ios.puts @e }

    # Announce what we did
    a = @new_iuse - @old_iuse
    r = @old_iuse - @new_iuse
    puts "##### [EMAIL PROTECTED]"
    if a.size != 0
      puts "+++++ Added #{a.join ' '}"
      puts "+" * 70
      a.each do |x| 
        system("fgrep", "--color=always", "-C2", x, @filename) 
        puts '--'
      end
    end
    if r.size != 0
      puts "----- Removed #{r.join ' '}"
      puts "-" * 70
      (r + ['$IUSE', '${IUSE}']).each do |x| 
        system("fgrep", "--color=always", "-C2", x, @filename) 
        puts '--'
      end
    end
    puts

    # Add to the global accumulators
    $added |= a
    $removed |= r
  end

  def scan
    # Collect the USE variables from inherited eclasses
    inherited_iuse = []
    @e.scan(/^inherit\s.*/).each do |line|
      line.sub(/#.*/, "").split.each do |name|
        next if self.inherits?(name)
        @inherits << name
        eclass = Efile.new(name)
        inherited_iuse << eclass.scan
        @inherits << eclass.inherits
      end
    end

    # Collect the content of the old IUSE
    if @e =~ %r{^IUSE=.(.*?)['"]}m
      @old_iuse = $1.split.sort
    else
      @old_iuse = []
    end

    # Strip false matches to create e_nc (no comments)
    e_nc = @e.gsub(/#.*/, "")
    e_nc.gsub!(/\b(?:echo|einfo|ewarn|eerror|ebegin|die)\b.*/, "")
    e_nc.gsub!(/^DESCRIPTION=(["']).*?\1[^\n]*/m, "")

    # Find candidates for IUSE
    @new_iuse = e_nc.scan(/\b(?:use_enable|use_with|use[qv]?)\s+/ + 
FLAG).flatten
    e_nc.scan(/(?:\bSRC_URI|\b[RP]?DEPEND)=.(.*?)["']/m).flatten.each do |dep|
      @new_iuse += dep.scan(FLAG + /(?=\?)/).flatten
    end
    @new_iuse << 'boundschecking' if e_nc =~ /\bwant_boundschecking\b/
    @new_iuse << 'nopie' if e_nc =~ /\bwant_pie\b/
    @new_iuse << 'nossp' if e_nc =~ /\bwant_ssp\b/

    # Special treatment for ebuilds that inherit particular eclasses
    if self.inherits? 'confutils'
      @new_iuse += e_nc.scan(%r{\b
        (?: confutils_use_conflict | confutils_use_depend_all | 
confutils_use_depend_any )
        }x + ('(?:\s+' + FLAG.to_s + ')+')).flatten
      @new_iuse += e_nc.scan(%r{\b
        (?: enable_extension_enable | enable_extension_disable | 
enable_extension_enableonly |
        enable_extension_without | enable_with | enable_withonly )
        \s+}x + FLAG).flatten
    end
    if self.inherits? 'mozconfig'
      @new_iuse += e_nc.scan(/\bmozconfig_use_(?:enable|with|extension)\s+/ + 
FLAG).flatten
    end
    if self.inherits? 'x11'
      @new_iuse += e_nc.scan(/\buse_build\s+/ + FLAG).flatten
    end

    # Special treatment for some ebuilds...
    case @filename
    when /^wine-/
      @new_iuse += e_nc.scan(/\bconfig_cache\s+/ + FLAG).flatten
    when /^qt-\d/
      @new_iuse += e_nc.scan(/\bqt_use\s+/ + FLAG).flatten
    when /^ezm3-\d/
      @new_iuse += e_nc.scan(/\bseduse\s+/ + FLAG).flatten
    when /^xmess-\d/
      @new_iuse += e_nc.scan(/\btoggle_feature2?\s+/ + FLAG).flatten
      @new_iuse += e_nc.scan(/\btoggle_feature2\s+\S+\s+/ + FLAG).flatten
    end

    # Clean up
    @new_iuse -= [ 'the' ]      # common false matches
    @new_iuse -= ARCHLIST
    @new_iuse.reject! { |x| x =~ 
/^kernel_|^elibc_|^linguas_|^video_cards_|^input_devices_/ }
    (@old_iuse - @new_iuse).each do |u|
      # don't remove items from IUSE that are in an inherited eclass, because
      # really it's broken either way
      @new_iuse << u if inherited_iuse.index(u)
    end
    # don't add or remove build or bootstrap; just ignore them
    @new_iuse -= %w(build bootstrap)
    @new_iuse += (@old_iuse & %w(build bootstrap))

    # Final result
    @new_iuse = @new_iuse.uniq.sort
  end
end

ebuilds = ARGV
ebuilds += Dir['*.ebuild'] if ebuilds.empty?
ebuilds.each do |ebuild|
  ef = Efile.new(ebuild)
  ef.scan
  ef.write
end

system("cvs diff #{ebuilds.join ' '}")
exit if $? == 0

common = $added & $removed
$added -= common
$removed -= common

rc_string = "repoman commit -m 'sync IUSE"
unless $added.empty? and $removed.empty?
  rc_string += " (" 
  rc_string += $added.map {|x| '+' + x}.join(' ')
  rc_string += " " unless $added.empty? or $removed.empty?
  rc_string += $removed.map {|x| '-' + x}.join(' ')
  rc_string += ")"
end
rc_string += "'"
puts rc_string

Reply via email to