#! /bin/env python

# Selects the correct executable for a platform and then either
#   - Executes it, OR
#   - Prints it out
#
# This is a command-line-friendly wrapper around the HostMatcher
# module.

import HostMatcher

from sys import stderr, stdout, exit

USAGE = """
Usage:
  <command> [ options... ] -- <program-prefix> [ <program-args>... ]

<program-prefix>
   The relative or absolute path to the executables.  You
   should only provide the prefix.  For example, if you have
   two executables:
       tools/bork.Linux-i386
       tools/bork.Windows.exe
   The prefix you should provide is 'tools/bork'.

<program-args>
   Arguments to relay to the program.

-o|--os <os-name>
   Set the host OS name ('Linux', 'Windows', 'FreeBSD', etc.)
   If this is not set, we'll try to autodetect it.

-i|--isa <isa-name>
   Set the host instruction set architecture ('i386', 'i686',
   'ia64', 'amd64', etc.).  If this is not set, we'll try to
   autodetect it.

-p|--print
   Just print the path to the matching executable.  Don't launch
   the program.  If this option is specified, <program-args> will
   be ignored.

-h|--help
   Prints this message.

-v|--verbose
   Prints verbose output to help diagnose problems.
"""

def main(argv=None):
   if argv is None:
      import sys
      argv = sys.argv

   # Load options
   try:
      import getopt
      (opts, argv) = getopt.getopt(argv[1:], "hvpo:i:", ["help", "verbose", "print", "os=", "isa="])
   except getopt.GetoptError, e:
      stderr.write("Error: " + e.msg + "\n")
      printUsageInfo(stderr)
      exit(2)

   verbose = False
   explicitHostInfo = {}
   printOnly = False

   # Process options
   for (opt, arg) in opts:

      if opt in ("-h", "--help"):
         printUsageInfo(stdout)
         exit()

      elif opt in ("-o", "--os"):
         explicitHostInfo['OS'] = arg

      elif opt in ("-i", "--isa"):
         explicitHostInfo['ISA'] = arg

      elif opt in ("-v", "--verbose"):
         verbose = True

      elif opt in ("-p", "--print"):
         printOnly = True

      else:
         stderr.write("WTF?")
         raise Error

   if verbose:
      stderr.writelines("V: Explicit host info: " + str(explicitHostInfo) + "\n")

   hostInfo = HostMatcher.detectDefaultHostInfo()

   if verbose:
      stderr.writelines("V: Default host info: " + str(hostInfo) + "\n")

   hostInfo.update(explicitHostInfo)

   if verbose:
      stderr.write("V: Final host info: " + str(hostInfo) + "\n")

   # Make sure we have the 'prefix' argument
   nExtraArgs = argv.__len__()
   if nExtraArgs < 1:
      stderr.write("Error: expecting at least one argument after options\n")
      printUsageInfo(stderr)
      exit(2)

   prefix = argv[0]
   programArgs = argv[1:]

   # Load a list of all the available executables
   import glob
   executables = glob.glob(prefix + '.*')

   # Make sure there's at least one executable
   if executables.__len__() == 0:
      stderr.write("Error: couldn't find files matching '" + prefix + ".*'\n")
      exit(3)

   # VERBOSE: print all the executables we found
   if verbose:
      stderr.write("V: Executables:\n")
      for e in executables:
         stderr.write("V:  " + str(e))

   # Parse out the arch information from the executable names
   import re
   pattern = re.compile('^' + re.escape(prefix) + '\.([^\.]*)(?:\..*)?$');
   (targets, mappings) = HostMatcher.createHostTargets(executables, pattern)

   # VERBOSE: Print mappings
   if verbose:
      stderr.write('V: Generated mappings:')
      for (key, value) in mappings.iteritems():
         stderr.write('V:   ' + str(key) + ':' + str(value))

   # Run the matching algorithm
   result = HostMatcher.match(hostInfo, targets)

   # If we didn't find a match, print out detailed info and quit
   if result == None:
      stderr.write("Error: couldn't find a match.")
      if not verbose:
         stderr.write("(run with '--verbose' for more info)")
      exit(4)

   # VERBOSE: Print matching target
   if verbose:
      stderr.write("V: Match:" + str(result))

   # Get executable name
   from HashableMap import HashableMap
   executable = mappings[HashableMap(result)]
   stdout.write(executable)

   if printOnly:
      stdout.write(executable + "\n")
   else:
      runProgram(executable, programArgs)

def runProgram(executable, programArgs):
   from os import execl
   execl(executable, executable, *programArgs)
      
def printUsageInfo(stream):
   stream.write(USAGE)

if __name__ == "__main__":
   main()

