#!/usr/bin/ruby -w
# Parse log files and extract info about packages that failed to build
# because of dependancies problems.
#
# Usage:
# (in the directory containing all the logs:)
# agf.rb <aptgf|ld> <file with TODO lines>

def gcc_getlines(lines, file)
  g = lines.grep(/\d: error: /)
  ig = lines.index(g[0])
  ih = ig - 1
  while (ih > 0)
    if lines[ih] =~ /^\s+from / or
      lines[ih] =~ /^In file included from / or
      lines[ih] =~ /: In (member )?function / or
      lines[ih] =~ /: warning: / or
      lines[ih] =~ /: In constructor / or
      lines[ih] =~ /^\s*\^+\s*$/ or
      lines[ih] =~ / is deprecated. Use/ or
      lines[ih] =~ /: At global scope:/
      ih -= 1
    else
      if lines[ih] !~ /^\s*(gcc|cc|g\+\+|c\+\+|nasm)/
#         puts "FNML: #{lines[ih]}"
      end
      ih += 1
      break
    end
  end
  return lines[ih..ig]
end

def ld_getlines(lines, file)
  g = lines.grep(/ld returned 1 exit status$/)
  ig = lines.index(g[0])
  ih = ig - 1
  while (ih > 0)
    if lines[ih] =~ /undefined reference to/ or 
      lines[ih] =~ / In function / or 
      lines[ih] =~ / final link failed:/ or 
      lines[ih] =~ /: first defined here/ or
      lines[ih] =~ /: cannot find / or
      lines[ih] =~ /: unknown architecture of input file/ or
      lines[ih] =~ /: hidden symbol / or
      lines[ih] =~ /: multiple definition of / or
      lines[ih] =~ /: warning: .* is deprecated; use .* instead/ or
      lines[ih] =~ / cannot be preloaded: ignored./
      ih -= 1
    else
      if lines[ih] !~ /^(gcc|cc|g\+\+|ld|c\+\+)/
#        puts "FNML: #{lines[ih]}"
      end
      ih = ih += 1
      break
    end
  end
  if ih == ig
    puts "NO LINES FOUND #{file}"
    exit 1
  end
  return lines[ih...ig]
end

def aptgf_getlines(lines, file)
  if not (g = lines.grep(/^The following packages have unmet dependencies:$/)).empty?
    bps = lines.index(g[0]) + 1
    g = lines.grep(/^E: Broken packages$/)
    agf = lines.index(g[0]) - 1
    buglog = lines[bps..agf]
    return buglog
  elsif not (g = lines.grep(/^E: Couldn't find package /)).empty?
             return g 
  elsif not (g = lines.grep(/^E: Package .* has no installation candidate$/)).empty?
             return g 
  elsif not (g = lines.grep(/^Errors were encountered while processing:$/)).empty?
    bps = lines.index(g[0])
    g = lines.grep(/^apt-get failed.$/)
    agf = lines.index(g[0]) - 1
    buglog = lines[bps..agf]
    return buglog
  else
    puts "NO LINES FOUND #{file}"
    exit 1
  end
end

type = ARGV[0]
todo = ' TODO'
#todo = '' # for debugging
regexp = {
  'aptgf' => / APT_GET_FAILED.*#{todo}/,
  'ld' => /LD_ERROR.*#{todo}/,
  'gcc' => /GCC_ERROR.*#{todo}/
}
IO::read(ARGV[1]).split(/\n/).grep(regexp[type]).each do |l|
  pkg, rest = l.split(' ')
  lst = Dir::glob("#{pkg}_*")
  if lst.length == 0
    puts "No matching logfile."
    exit 1
  elsif lst.length > 1
    lst2 = lst.join("\n  ")
    puts "Several matching logfiles:\n  #{lst2}"
    exit 1
  else
    file = lst[0]
  end
  flines = IO::read(file).split(/\n/)
  case type
  when 'aptgf' then
    lines = aptgf_getlines(flines, file)
  when 'ld' then
    lines = ld_getlines(flines, file)
  when 'gcc' then
    lines = gcc_getlines(flines, file)
  end
  lines.each do |l2|
    printf "%-20s %s\n" % [pkg, l2]
  end
end
