## @file
# Run a makefile as part of a PREBUILD or POSTBUILD action.
#
# Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution.  The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#

'''
RunMakefile.py
'''

import os
import sys
import argparse
import subprocess

#
# Globals for help information
#
__prog__        = 'RunMakefile'
__version__     = '%s Version %s' % (__prog__, '1.0')
__copyright__   = 'Copyright (c) 2017, Intel Corporation. All rights reserved.'
__description__ = 'Run a makefile as part of a PREBUILD or POSTBUILD action.\n'

#
# Globals
#
gArgs = None

def Log(Message):
  if not gArgs.Verbose:
    return
  sys.stdout.write (__prog__ + ': ' + Message + '\n')

def Error(Message, ExitValue=1):
  sys.stderr.write (__prog__ + ': ERROR: ' + Message + '\n')
  sys.exit (ExitValue)

def RelativePath(target):
  return os.path.relpath (target, gWorkspace)

def NormalizePath(target):
  if isinstance(target, tuple):
    return os.path.normpath (os.path.join (*target))
  else:
    return os.path.normpath (target)

if __name__ == '__main__':
  #
  # Create command line argument parser object
  #
  parser = argparse.ArgumentParser (
                      prog = __prog__,
                      version = __version__,
                      description = __description__ + __copyright__,
                      conflict_handler = 'resolve'
                      )
  parser.add_argument (
           '-a', '--arch', dest = 'Arch', nargs = '+', action = 'append',
           required = True,
           help = '''ARCHS is one of list: IA32, X64, IPF, ARM, AARCH64 or EBC,
                     which overrides target.txt's TARGET_ARCH definition. To
                     specify more archs, please repeat this option.'''
           )
  parser.add_argument (
           '-t', '--tagname', dest = 'ToolChain', required = True,
           help = '''Using the Tool Chain Tagname to build the platform,
                     overriding target.txt's TOOL_CHAIN_TAG definition.'''
           )
  parser.add_argument (
           '-p', '--platform', dest = 'PlatformFile', required = True,
           help = '''Build the platform specified by the DSC file name argument,
                     overriding target.txt's ACTIVE_PLATFORM definition.'''
           )
  parser.add_argument (
           '-b', '--buildtarget', dest = 'BuildTarget', required = True,
           help = '''Using the TARGET to build the platform, overriding
                     target.txt's TARGET definition.'''
           )
  parser.add_argument (
           '--conf=', dest = 'ConfDirectory', required = True,
           help = '''Specify the customized Conf directory.'''
           )
  parser.add_argument (
           '-D', '--define', dest = 'Define', nargs='*', action = 'append',
           help = '''Macro: "Name [= Value]".'''
           )
  parser.add_argument (
           '--makefile', dest = 'Makefile', required = True,
           help = '''Makefile to run passing in arguments as makefile defines.'''
           )
  parser.add_argument (
           '-v', '--verbose', dest = 'Verbose', action = 'store_true',
           help = '''Turn on verbose output with informational messages printed'''
           )

  #
  # Parse command line arguments
  #
  gArgs, remaining = parser.parse_known_args()
  gArgs.BuildType = 'all'
  for BuildType in ['all', 'fds', 'genc', 'genmake', 'clean', 'cleanall', 'modules', 'libraries', 'run']:
    if BuildType in remaining:
      gArgs.BuildType = BuildType
      remaining.remove(BuildType)
      break
  gArgs.Remaining = ' '.join(remaining)

  #
  # Start
  #
  Log ('Start')

  #
  # Find makefile in WORKSPACE or PACKAGES_PATH
  #
  PathList = ['']
  try:
    PathList.append(os.environ['WORKSPACE'])
  except:
    Error ('WORKSPACE environment variable not set')
  try:
    PathList += os.environ['PACKAGES_PATH'].split(os.pathsep)
  except:
    pass
  for Path in PathList:
    Makefile = NormalizePath((Path, gArgs.Makefile))
    if os.path.exists (Makefile):
      break
  if not os.path.exists(Makefile):
    Error ('makefile %s not found' % (gArgs.Makefile))

  #
  # Build command line arguments converting build arguments to makefile defines
  #
  CommandLine = [Makefile]
  CommandLine.append('TARGET_ARCH="%s"' % (' '.join([Item[0] for Item in gArgs.Arch])))
  CommandLine.append('TOOL_CHAIN_TAG="%s"' % (gArgs.ToolChain))
  CommandLine.append('TARGET="%s"' % (gArgs.BuildTarget))
  CommandLine.append('ACTIVE_PLATFORM="%s"' % (gArgs.PlatformFile))
  CommandLine.append('CONF_DIRECTORY="%s"' % (gArgs.ConfDirectory))
  if gArgs.Define:
    for Item in gArgs.Define:
      if '=' not in Item[0]:
        continue
      Item = Item[0].split('=', 1)
      CommandLine.append('%s="%s"' % (Item[0], Item[1]))
  CommandLine.append('EXTRA_FLAGS="%s"' % (gArgs.Remaining))
  CommandLine.append(gArgs.BuildType)
  if sys.platform == "win32":
    CommandLine = 'nmake /f %s' % (' '.join(CommandLine))
  else:
    CommandLine = 'make -f %s' % (' '.join(CommandLine))

  #
  # Run the makefile
  #
  try:
    Process = subprocess.Popen(CommandLine, shell=True)
  except:
    Error ('make command not available.  Please verify PATH')
  Process.communicate()

  #
  # Done
  #
  Log ('Done')

  #
  # Return status from running the makefile
  #
  sys.exit(Process.returncode)
