#!/usr/bin/ruby
#
# gem-would-update.rb
# ===================
#
# Issue "gem query --local" (issue a local repository query). Then
# issue the same, with "--remote" (remote repository query). Capture
# and process the output to get a list of local gem names with the
# biggest version number plus the same for remote gems. For each
# local gem find the equivalent remote gem and warn if the highest
# version numbers differ.
#
# Free for use, reuse, modification, adaptation etc. by anyone for
# any purpose, no strings - i.e., do whatever you want with this!
#
#
# History
# -------
#
# 2006-07-09 (ADH): Quick and dirty, first version.

# parse_gem_output(command)
#
# NB: This doesn't work:
#
#   gem_loc = `gem query --no-details`
#
#   ...Perhaps because 'gem' is a Ruby program? It's late and I'm tired
#   so I'm not going to spend all day scratching my head - instead I'll
#   use system() and redirect output to a file, then parse the file.
#
# Given 'capture_string = `gem <something>`' doesn't work, ask Tempfile
# for a temporary file, read its path, close it, then use the path as a
# redirection location for the given command. Read the file contents
# grabbing Gem names and version numbers from lines following the rough
# pattern "GemName (version[, version])". Returns an array of 2-element
# arrays containing the gem name string in the first element and gem
# version string in the second element.

def parse_gem_output(command)

  # Run the command with output redirected to a hard-coded temp file.
  # This can of course fail if other programs running at the same time
  # cause the Tempfile-chosen path to become invalid or in use, but
  # there seems to be no API for "reserve me a filename for someone
  # else to use in a minute" :-)

  tmp_path = '/home/adh/gwutemp'
  system("#{command} > #{tmp_path}")

  # Grab the contents back into a hash - we're interested in lines
  # of the form "GemName (version[, version])", not in lines starting
  # with white space (those are gem descriptions).

  tmp_file = File.open(tmp_path)
  gem_data = Hash.new

  # For the remote case we may capture some garbage from the first
  # few lines if gem updates indices or whatever. It doesn't matter
  # as we're only going to list items in the remote hash that match
  # gem names in the local hash (this function is very much *not* a
  # general purpose item!).

  tmp_file.each_line { |line|
    if (line && line[0] != '*')
      gem_name    = line.slice!(/^\w[-\w]+[_\w]+/)
      gem_version = line.strip

      gem_data[gem_name] = gem_version
    end
  }

  # Tidy up

  tmp_file.close()
  File.delete(tmp_path)

  return gem_data
end

# First dump the local output to a file

puts('Building local gem list')
gem_loc = parse_gem_output('gem query --local')

puts('Building remote gem list - this can take a while...')
gem_rem = parse_gem_output('gem query --remote')

# Compare versions, reporting results as we go

puts('')
get_vsn = Regexp.new(/^\([0-9]+\.[0-9]+\.[0-9]+(\)|,)/)
found = false

gem_loc.each { |key, value|
  if (key && value && gem_rem[key])

    # Extract version numbers

    gem_version_loc =        value.slice(get_vsn)
    gem_version_rem = gem_rem[key].slice(get_vsn)

    if (gem_version_loc && gem_version_rem)
      loc = gem_version_loc[1..-2]
      rem = gem_version_rem[1..-2]

      if (loc > rem)
        found = true
        print("#{key}: Local version #{loc} newer than remote version #{rem}!\n")
      elsif (loc < rem)
        found = true
        print("#{key}: Local version #{loc} would be updated to #{rem}.\n")
      end
    end
  end
}

# If there seems to be nothing to do, report it

puts('Nothing to update.') unless found

# End of file.
