#!/usr/bin/env python
import argparse
import os, re
from os.path import exists, abspath
from glob import glob
import yaml
from commands import getstatusoutput
import logging
from alibuild_helpers.log import debug, error, banner, info, success, warning
from alibuild_helpers.log import logger_handler, logger, LogFormatter, ProgressPrint
from alibuild_helpers.utilities import getPackageList, format, detectArch
import subprocess

def execute(command):
  popen = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
  lines_iterator = iter(popen.stdout.readline, "")
  txt = ""
  for line in lines_iterator:
    txt += line # yield line
  txt += popen.communicate()[0]
  return (popen.returncode, txt)

def prunePaths(workDir):
  for x in ["PATH", "LD_LIBRARY_PATH", "DYLD_LIBRARY_PATH"]:
    if not x in os.environ:
      continue
    workDirEscaped = re.escape("%s" % workDir) + "[^:]*:?"
    os.environ[x] = re.sub(workDirEscaped, "", os.environ[x])

def checkPreferSystem(spec, cmd, homebrew_replacement):
    if cmd == "false":
      debug("Package %s can only be managed via alibuild." % spec["package"])
      return (1, "")
    cmd = homebrew_replacement + cmd
    err, out = execute(cmd)
    if not err:
      success("Package %s will be picked up from the system." % spec["package"])
      for x in out.split("\n"):
        debug(spec["package"] + ": " + x)
      return (err, "")

    warning(format("Package %(p)s cannot be picked up from the system and will be built by aliBuild.\n"
                   "This is due to the fact the following script fails:\n\n"
                   "%(cmd)s\n\n"
                   "with the following output:\n\n"
                   "%(error)s\n",
                   p=spec["package"],
                   cmd=cmd,
                   error="\n".join(["%s: %s" % (spec["package"],x) for x in out.split("\n")])))
    return (err, "")

def checkRequirements(spec, cmd, homebrew_replacement):
    if cmd == "false":
      debug("Package %s is not a system requirement." % spec["package"])
      return (0, "")
    cmd = homebrew_replacement + cmd
    err, out = execute(cmd)
    if not err:
      success("Required package %s will be picked up from the system." % spec["package"])
      debug(cmd)
      for x in out.split("\n"):
        debug(spec["package"] + ": " + x)
      return (0, "")
    error(format("Package %(p)s is a system requirement and cannot be found.\n"
                 "This is due to the fact that the following script fails:\n\n"
                 "%(cmd)s\n"
                 "with the following output:\n\n"
                 "%(error)s\n"
                 "%(help)s\n",
                 p=spec["package"],
                 cmd=cmd,
                 error="\n".join(["%s: %s" % (spec["package"],x) for x in out.split("\n")]),
                 help=spec.get("system_requirement_missing")))
    return (err, "")

if __name__ == "__main__":
  parser = argparse.ArgumentParser()
  parser.add_argument("-a", "--architecture", help="force architecture",
                      dest="architecture", default=detectArch())
  parser.add_argument("-c", "--config", help="path to alidist",
                      dest="config", default="alidist")
  parser.add_argument("-w", "--work-dir", help="path to work dir",
                      dest="workDir", default="workDir")
  parser.add_argument("-d", "--debug", help="Show also successful tests.",
                      dest="debug", action="store_true", default=False)
  parser.add_argument("packages", nargs="+", help="Package to test",
                      default=[])
  args = parser.parse_args()
  if not exists(args.config):
    parser.error("Wrong path to alidist specified: %s" % args.config)

  prunePaths(abspath(args.workDir))

  # Decide if we can use homebrew. If not, we replace it with "true" so
  # that we do not get spurious messages on linux
  homebrew_replacement = ""
  err, output = getstatusoutput("which brew")
  if err:
    homebrew_replacement = "brew() { true; }; "

  logger.setLevel(logging.BANNER)
  if args.debug:
    logger.setLevel(logging.DEBUG)

  specs = {}
  packages = []
  for p in args.packages:
    path = "%s/%s.sh" % (args.config, p.lower())
    if not exists(path):
      error("Cannot find recipe %s for package %s." % (path, p))
      continue
    packages.append(p)

  specs = {}
  def unreachable():
    assert(False)
  (fromSystem, own, failed) = getPackageList(packages=packages,
                                         specs=specs,
                                         configDir=args.config,
                                         preferSystem=False,
                                         noSystem=False,
                                         architecture=args.architecture,
                                         disable=[],
                                         defaults="release",
                                         dieOnError=lambda x, y : unreachable,
                                         performPreferCheck=lambda pkg, cmd : checkPreferSystem(pkg, cmd, homebrew_replacement),
                                         performRequirementCheck=lambda pkg, cmd : checkRequirements(pkg, cmd, homebrew_replacement))

  if fromSystem:
    banner("The following packages will be picked up from the system:\n\n- " +
           "\n- ".join(fromSystem) +
           "\n\nIf this is not you want, you have to uninstall / unload them.")
  if own:
    banner("The following packages will be build by aliBuild because they couldn't be picked up from the system:\n\n- " +
           "\n- ".join(own) +
           "\n\nThis is not a real issue, but it might take longer the first time you invoke aliBuild.")
  if failed:
    banner("The following packages are system dependencies and could not be found:\n\n- "+
          "\n- ".join(failed)
         )
    exit(1)
