# Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
#
# Use of this source code is governed by a BSD-style license
# that can be found in the LICENSE file in the root of the source
# tree. An additional intellectual property rights grant can be found
# in the file PATENTS.  All contributing project authors may
# be found in the AUTHORS file in the root of the source tree.

import logging
import platform
import os
import signal
import subprocess
import sys
import time


class NotImplementedError(Exception):
  pass


class TimeoutError(Exception):
  pass


def RunSubprocessInBackground(proc):
  """Runs a subprocess in the background. Returns a handle to the process."""
  logging.info("running %s in the background" % " ".join(proc))
  return subprocess.Popen(proc)


def RunSubprocess(proc, timeout=0):
  """ Runs a subprocess, until it finishes or |timeout| is exceeded and the
  process is killed with taskkill.  A |timeout| <= 0  means no timeout.

  Args:
    proc: list of process components (exe + args)
    timeout: how long to wait before killing, <= 0 means wait forever
  """

  logging.info("running %s, timeout %d sec" % (" ".join(proc), timeout))
  sys.stdout.flush()
  sys.stderr.flush()

  # Manually read and print out stdout and stderr.
  # By default, the subprocess is supposed to inherit these from its parent,
  # however when run under buildbot, it seems unable to read data from a
  # grandchild process, so we have to read the child and print the data as if
  # it came from us for buildbot to read it.  We're not sure why this is
  # necessary.
  # TODO(erikkay): should we buffer stderr and stdout separately?
  p = subprocess.Popen(proc, universal_newlines=True,
                       bufsize=0,  # unbuffered
                       stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

  logging.info("started subprocess")

  did_timeout = False
  if timeout > 0:
    wait_until = time.time() + timeout
  while p.poll() is None and not did_timeout:
    # Have to use readline rather than readlines() or "for line in p.stdout:",
    # otherwise we get buffered even with bufsize=0.
    line = p.stdout.readline()
    while line and not did_timeout:
      sys.stdout.write(line)
      sys.stdout.flush()
      line = p.stdout.readline()
      if timeout > 0:
        did_timeout = time.time() > wait_until

  if did_timeout:
    logging.info("process timed out")
  else:
    logging.info("process ended, did not time out")

  if did_timeout:
    if IsWindows():
      subprocess.call(["taskkill", "/T", "/F", "/PID", str(p.pid)])
    else:
      # Does this kill all children, too?
      os.kill(p.pid, signal.SIGINT)
    logging.error("KILLED %d" % p.pid)
    # Give the process a chance to actually die before continuing
    # so that cleanup can happen safely.
    time.sleep(1.0)
    logging.error("TIMEOUT waiting for %s" % proc[0])
    raise TimeoutError(proc[0])
  else:
    for line in p.stdout:
      sys.stdout.write(line)
    if not IsMac():   # stdout flush fails on Mac
      logging.info("flushing stdout")
      sys.stdout.flush()

  logging.info("collecting result code")
  result = p.poll()
  if result:
    logging.error("%s exited with non-zero result code %d" % (proc[0], result))
  return result


def IsLinux():
  return sys.platform.startswith('linux')


def IsMac():
  return sys.platform.startswith('darwin')


def IsWindows():
  return sys.platform == 'cygwin' or sys.platform.startswith('win')


def WindowsVersionName():
  """Returns the name of the Windows version if it is known, or None.

  Possible return values are: xp, vista, 7, 8, or None
  """
  if sys.platform == 'cygwin':
    # Windows version number is hiding in system name.  Looks like:
    # CYGWIN_NT-6.1-WOW64
    try:
      version_str = platform.uname()[0].split('-')[1]
    except:
      return None
  elif sys.platform.startswith('win'):
    # Normal Windows version string.  Mine: 6.1.7601
    version_str = platform.version()
  else:
    return None

  parts = version_str.split('.')
  try:
    major = int(parts[0])
    minor = int(parts[1])
  except:
    return None  # Can't parse, unknown version.

  if major == 5:
    return 'xp'
  elif major == 6 and minor == 0:
    return 'vista'
  elif major == 6 and minor == 1:
    return '7'
  elif major == 6 and minor == 2:
    return '8'  # Future proof.  ;)
  return None


def PlatformNames():
  """Return an array of string to be used in paths for the platform
  (e.g. suppressions, gtest filters, ignore files etc.)
  The first element of the array describes the 'main' platform
  """
  if IsLinux():
    return ['linux']
  if IsMac():
    return ['mac']
  if IsWindows():
    names = ['win32']
    version_name = WindowsVersionName()
    if version_name is not None:
      names.append('win-%s' % version_name)
    return names
  raise NotImplementedError('Unknown platform "%s".' % sys.platform)


def PutEnvAndLog(env_name, env_value):
  os.putenv(env_name, env_value)
  logging.info('export %s=%s', env_name, env_value)

def BoringCallers(mangled, use_re_wildcards):
  """Return a list of 'boring' function names (optinally mangled)
  with */? wildcards (optionally .*/.).
  Boring = we drop off the bottom of stack traces below such functions.
  """

  need_mangling = [
    # Don't show our testing framework:
    ("testing::Test::Run",     "_ZN7testing4Test3RunEv"),
    ("testing::TestInfo::Run", "_ZN7testing8TestInfo3RunEv"),
    ("testing::internal::Handle*ExceptionsInMethodIfSupported*",
     "_ZN7testing8internal3?Handle*ExceptionsInMethodIfSupported*"),

    # Depend on scheduling:
    ("MessageLoop::Run",     "_ZN11MessageLoop3RunEv"),
    ("MessageLoop::RunTask", "_ZN11MessageLoop7RunTask*"),
    ("RunnableMethod*",      "_ZN14RunnableMethod*"),
    ("DispatchToMethod*",    "_Z*16DispatchToMethod*"),
    ("base::internal::Invoker*::DoInvoke*",
     "_ZN4base8internal8Invoker*DoInvoke*"),  # Invoker{1,2,3}
    ("base::internal::RunnableAdapter*::Run*",
     "_ZN4base8internal15RunnableAdapter*Run*"),
  ]

  ret = []
  for pair in need_mangling:
    ret.append(pair[1 if mangled else 0])

  ret += [
    # Also don't show the internals of libc/pthread.
    "start_thread",
    "main",
    "BaseThreadInitThunk",
  ]

  if use_re_wildcards:
    for i in range(0, len(ret)):
      ret[i] = ret[i].replace('*', '.*').replace('?', '.')

  return ret

def NormalizeWindowsPath(path):
  """If we're using Cygwin Python, turn the path into a Windows path.

  Don't turn forward slashes into backslashes for easier copy-pasting and
  escaping.

  TODO(rnk): If we ever want to cut out the subprocess invocation, we can use
  _winreg to get the root Cygwin directory from the registry key:
  HKEY_LOCAL_MACHINE\SOFTWARE\Cygwin\setup\rootdir.
  """
  if sys.platform.startswith("cygwin"):
    p = subprocess.Popen(["cygpath", "-m", path],
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE)
    (out, err) = p.communicate()
    if err:
      logging.warning("WARNING: cygpath error: %s", err)
    return out.strip()
  else:
    return path

############################
# Common output format code

def PrintUsedSuppressionsList(suppcounts):
  """ Prints out the list of used suppressions in a format common to all the
      memory tools. If the list is empty, prints nothing and returns False,
      otherwise True.

      suppcounts: a dictionary of used suppression counts,
                  Key -> name, Value -> count.
  """
  if not suppcounts:
    return False

  print "-----------------------------------------------------"
  print "Suppressions used:"
  print "  count name"
  for (name, count) in sorted(suppcounts.items(), key=lambda (k,v): (v,k)):
    print "%7d %s" % (count, name)
  print "-----------------------------------------------------"
  sys.stdout.flush()
  return True
