# Copyright (C) 2014-2019 Apple Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1.  Redistributions of source code must retain the above copyright
#     notice, this list of conditions and the following disclaimer.
# 2.  Redistributions in binary form must reproduce the above copyright
#     notice, this list of conditions and the following disclaimer in the
#     documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import logging
import os
import time

from webkitpy.common.memoized import memoized
from webkitpy.common.system.crashlogs import CrashLogs
from webkitpy.common.system.executive import ScriptError
from webkitpy.port.apple import ApplePort
from webkitpy.port.leakdetector import LeakDetector


_log = logging.getLogger(__name__)


class DarwinPort(ApplePort):

    CURRENT_VERSION = None
    SDK = None

    def __init__(self, host, port_name, **kwargs):
        ApplePort.__init__(self, host, port_name, **kwargs)

        self._leak_detector = LeakDetector(self)
        if self.get_option("leaks"):
            # DumpRenderTree slows down noticably if we run more than about 1000 tests in a batch
            # with MallocStackLogging enabled.
            self.set_option_default("batch_size", 1000)

    def default_timeout_ms(self):
        if self.get_option('guard_malloc'):
            return 350 * 1000
        return super(DarwinPort, self).default_timeout_ms()

    def _port_specific_expectations_files(self, device_type=None):
        return list(reversed([self._filesystem.join(self._webkit_baseline_path(p), 'TestExpectations') for p in self.baseline_search_path(device_type=device_type)]))

    def check_for_leaks(self, process_name, process_id):
        if not self.get_option('leaks'):
            return

        # We could use http://code.google.com/p/psutil/ to get the process_name from the pid.
        self._leak_detector.check_for_leaks(process_name, process_id)

    def print_leaks_summary(self):
        if not self.get_option('leaks'):
            return
        # We're in the manager process, so the leak detector will not have a valid list of leak files.
        # FIXME: This is a hack, but we don't have a better way to get this information from the workers yet.
        # FIXME: This will include too many leaks in subsequent runs until the results directory is cleared!
        leaks_files = self._leak_detector.leaks_files_in_directory(self.results_directory())
        if not leaks_files:
            return
        total_bytes_string, unique_leaks = self._leak_detector.count_total_bytes_and_unique_leaks(leaks_files)
        total_leaks = self._leak_detector.count_total_leaks(leaks_files)
        _log.info("%s total leaks found for a total of %s." % (total_leaks, total_bytes_string))
        _log.info("%s unique leaks found." % unique_leaks)

    def _path_to_webcore_library(self):
        return self._build_path('WebCore.framework/Versions/A/WebCore')

    def show_results_html_file(self, results_filename):
        # We don't use self._run_script() because we don't want to wait for the script
        # to exit and we want the output to show up on stdout in case there are errors
        # launching the browser.
        with open(os.devnull) as devnull:
            self._executive.popen([self.path_to_script('run-safari')] + self._arguments_for_configuration() + ['--no-saved-state', '-NSOpen', results_filename],
                cwd=self.webkit_base(), stdout=devnull, stderr=devnull)

    @memoized
    def path_to_crash_logs(self):
        log_directory = self.host.filesystem.expanduser('~')
        log_directory = self.host.filesystem.join(log_directory, 'Library', 'Logs')
        diagnositc_reports_directory = self.host.filesystem.join(log_directory, 'DiagnosticReports')
        if self.host.filesystem.exists(diagnositc_reports_directory):
            return diagnositc_reports_directory
        return self.host.filesystem.join(log_directory, 'CrashReporter')

    def _merge_crash_logs(self, logs, new_logs, crashed_processes):
        for test, crash_log in new_logs.items():
            try:
                if test.split('-')[0] == 'Sandbox':
                    process_name = test.split('-')[1]
                    pid = int(test.split('-')[2])
                else:
                    process_name = test.split('-')[0]
                    pid = int(test.split('-')[1])
            except (IndexError, ValueError):
                continue
            if not any(entry[1] == process_name and entry[2] == pid for entry in crashed_processes):
                # if this is a new crash, then append the logs
                logs[test] = crash_log
        return logs

    def _look_for_all_crash_logs_in_log_dir(self, newer_than):
        crash_log = CrashLogs(self.host, self.path_to_crash_logs(), crash_logs_to_skip=self._crash_logs_to_skip_for_host.get(self.host, []))
        return crash_log.find_all_logs(newer_than=newer_than)

    def _get_crash_log(self, name, pid, stdout, stderr, newer_than, time_fn=None, sleep_fn=None, wait_for_log=True, target_host=None):
        # Note that we do slow-spin here and wait, since it appears the time
        # ReportCrash takes to actually write and flush the file varies when there are
        # lots of simultaneous crashes going on.
        time_fn = time_fn or time.time
        sleep_fn = sleep_fn or time.sleep
        crash_log = ''
        crash_logs = CrashLogs(target_host or self.host, self.path_to_crash_logs(), crash_logs_to_skip=self._crash_logs_to_skip_for_host.get(target_host or self.host, []))
        now = time_fn()
        deadline = now + 5 * int(self.get_option('child_processes', 1))
        while not crash_log and now <= deadline:
            crash_log = crash_logs.find_newest_log(name, pid, include_errors=True, newer_than=newer_than)
            if not wait_for_log:
                break
            if not crash_log or not [line for line in crash_log.splitlines() if not line.startswith('ERROR')]:
                sleep_fn(0.1)
                now = time_fn()

        if not crash_log:
            return (stderr, None)
        return (stderr, crash_log)

    def look_for_new_crash_logs(self, crashed_processes, start_time):
        """Since crash logs can take a long time to be written out if the system is
           under stress do a second pass at the end of the test run.

           crashes: test_name -> pid, process_name tuple of crashed process
           start_time: time the tests started at.  We're looking for crash
               logs after that time.
        """
        crash_logs = {}
        for (test_name, process_name, pid) in crashed_processes:
            # Passing None for output.  This is a second pass after the test finished so
            # if the output had any logging we would have already collected it.
            crash_log = self._get_crash_log(process_name, pid, None, None, start_time, wait_for_log=False)[1]
            if not crash_log:
                continue
            crash_logs[test_name] = crash_log
        all_crash_log = self._look_for_all_crash_logs_in_log_dir(start_time)
        return self._merge_crash_logs(crash_logs, all_crash_log, crashed_processes)

    def sample_process(self, name, pid, target_host=None):
        host = target_host or self.host
        tempdir = host.filesystem.mkdtemp()
        temp_tailspin_file_path = host.filesystem.join(str(tempdir), "{0}-{1}-tailspin-temp.txt".format(name, pid))
        command = [
            '/usr/bin/tailspin',
            'save',
            '-n',
            temp_tailspin_file_path,
        ]
        if host.platform.is_mac():
            command = ['/usr/bin/sudo', '-n'] + command

        exit_status = host.executive.run_command(command, return_exit_code=True)
        if not exit_status:  # Symbolicate tailspin log using spindump
            spindump_command = [
                '/usr/sbin/spindump',
                '-i', temp_tailspin_file_path,
                '-file', DarwinPort.tailspin_file_path(host, name, pid, str(tempdir)),
            ]
            try:
                exit_code = host.executive.run_command(spindump_command + ['-noBulkSymbolication'], return_exit_code=True)

                # FIXME: Remove the fallback when we no longer support Catalina.
                if exit_code:
                    host.executive.run_command(spindump_command)
                host.filesystem.move_to_base_host(DarwinPort.tailspin_file_path(host, name, pid, str(tempdir)),
                                                  DarwinPort.tailspin_file_path(self.host, name, pid, self.results_directory()))
            except (IOError, ScriptError) as e:
                _log.warning('Unable to symbolicate tailspin log of process:' + str(e))
        else:  # Tailspin failed, run sample instead
            try:
                host.executive.run_command([
                    '/usr/bin/sample',
                    pid,
                    10,
                    10,
                    '-file',
                    DarwinPort.sample_file_path(host, name, pid, str(tempdir)),
                ])
                host.filesystem.move_to_base_host(DarwinPort.sample_file_path(host, name, pid, str(tempdir)),
                                                  DarwinPort.sample_file_path(self.host, name, pid, self.results_directory()))
            except ScriptError as e:
                _log.warning('Unable to sample process:' + str(e))
        host.filesystem.rmtree(str(tempdir))

    @staticmethod
    def sample_file_path(host, name, pid, directory):
        return host.filesystem.join(directory, "{0}-{1}-sample.txt".format(name, pid))

    @staticmethod
    def tailspin_file_path(host, name, pid, directory):
        return host.filesystem.join(directory, "{0}-{1}-tailspin.txt".format(name, pid))

    def look_for_new_samples(self, unresponsive_processes, start_time):
        sample_files = {}
        for (test_name, process_name, pid) in unresponsive_processes:
            sample_file = DarwinPort.sample_file_path(self.host, process_name, pid, self.results_directory())
            if self._filesystem.isfile(sample_file):
                sample_files[test_name] = sample_file
            else:
                tailspin_file = DarwinPort.tailspin_file_path(self.host, process_name, pid, self.results_directory())
                if self._filesystem.isfile(tailspin_file):
                    sample_files[test_name] = tailspin_file
        return sample_files

    def _path_to_image_diff(self):
        # ImageDiff for DarwinPorts is a little complicated. It will either be in
        # a directory named ../mac relative to the port build directory, in a directory
        # named ../<build-type> relative to the port build directory or in the port build directory
        _image_diff_in_build_path = super(DarwinPort, self)._path_to_image_diff()
        _port_build_dir = self.host.filesystem.dirname(_image_diff_in_build_path)

        # Test ../mac
        _path_to_test = self.host.filesystem.join(_port_build_dir, '..', 'mac', 'ImageDiff')
        if self.host.filesystem.exists(_path_to_test):
            return _path_to_test

        # Test ../<build-type>
        _build_type = self.host.filesystem.basename(_port_build_dir).split('-')[0]
        _path_to_test = self.host.filesystem.join(_port_build_dir, '..', _build_type, 'ImageDiff')
        if self.host.filesystem.exists(_path_to_test):
            return _path_to_test

        return _image_diff_in_build_path

    def make_command(self):
        return self.xcrun_find('make', '/usr/bin/make')

    def xcrun_find(self, command, fallback=None):
        fallback = fallback or command
        try:
            return self._executive.run_command(['xcrun', '--sdk', self.SDK, '-find', command]).rstrip()
        except ScriptError:
            _log.warn("xcrun failed; falling back to '%s'." % fallback)
            return fallback

    @memoized
    def _plist_data_from_bundle(self, app_bundle, entry):
        plist_path = self._filesystem.join(app_bundle, 'Info.plist')
        if not self._filesystem.exists(plist_path):
            plist_path = self._filesystem.join(app_bundle, 'Contents', 'Info.plist')
        if not self._filesystem.exists(plist_path):
            return None
        return self._executive.run_command(['/usr/libexec/PlistBuddy', '-c', 'Print {}'.format(entry), plist_path]).rstrip()

    def app_identifier_from_bundle(self, app_bundle):
        return self._plist_data_from_bundle(app_bundle, 'CFBundleIdentifier')

    def app_executable_from_bundle(self, app_bundle):
        return self._plist_data_from_bundle(app_bundle, 'CFBundleExecutable')

    def environment_for_api_tests(self):
        environment = super(DarwinPort, self).environment_for_api_tests()
        build_root_path = str(self._build_path())
        for name in ['DYLD_LIBRARY_PATH', '__XPC_DYLD_LIBRARY_PATH', 'DYLD_FRAMEWORK_PATH', '__XPC_DYLD_FRAMEWORK_PATH']:
            self._append_value_colon_separated(environment, name, build_root_path)
        return environment
