Example #1
0
    def run_and_throw_if_fail(self, args, quiet=False, decode_output=True, **kwargs):
        # Cache the child's output locally so it can be used for error reports.
        child_out_file = unicode_compatibility.StringIO()
        tee_stdout = sys.stdout
        try:
            if quiet:
                dev_null = open(os.devnull, "w")  # FIXME: Does this need an encoding?
                tee_stdout = dev_null
            child_stdout = Tee(child_out_file, tee_stdout)
            exit_code = self._run_command_with_teed_output(args, child_stdout, **kwargs)
        finally:
            if quiet:
                dev_null.close()

        child_output = child_out_file.getvalue()
        child_out_file.close()

        if decode_output:
            child_output = unicode_compatibility.decode_if_necessary(child_output, self._child_process_encoding())
        else:
            child_output = unicode_compatibility.encode_if_necessary(child_output, self._child_process_encoding())

        if exit_code:
            raise ScriptError(script_args=args,
                              exit_code=exit_code,
                              output=child_output)
        return child_output
Example #2
0
    def generate_crash_log(self, stdout, stderr):
        pid_representation = str(self.pid or '<unknown>')
        log_directory = os.environ.get("WEBKIT_CORE_DUMPS_DIRECTORY")
        errors = []
        crash_log = ''
        expected_crash_dump_filename = "core-pid_%s.dump" % pid_representation
        proc_name = "%s" % (self.name)

        def match_filename(filesystem, directory, filename):
            if self.pid:
                return filename == expected_crash_dump_filename
            return filename.find(self.name) > -1

        # Poor man which, ignore any failure.
        for coredumpctl in [['coredumpctl'], ['flatpak-spawn', '--host', 'coredumpctl'], []]:
            try:
                if not self._executive.run_command(coredumpctl, return_exit_code=True):
                    break
            except:
                continue

        if log_directory:
            dumps = self._filesystem.files_under(
                log_directory, file_filter=match_filename)
            if dumps:
                # Get the most recent coredump matching the pid and/or process name.
                coredump_path = list(reversed(sorted(dumps)))[0]
                if not self.newer_than or self._filesystem.mtime(coredump_path) > self.newer_than:
                    crash_log, errors = self._get_gdb_output(coredump_path)
        elif coredumpctl:
            crash_log, errors = self._get_trace_from_systemd(coredumpctl, pid_representation)

        stderr_lines = errors + decode_if_necessary(str(stderr or '<empty>'), errors='ignore').splitlines()
        errors_str = '\n'.join(('STDERR: ' + stderr_line) for stderr_line in stderr_lines)
        cppfilt_proc = self._executive.popen(
            ['c++filt'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        errors_str = cppfilt_proc.communicate(errors_str)[0]

        if not crash_log:
            if not log_directory:
                log_directory = "/path/to/coredumps"
            core_pattern = self._filesystem.join(log_directory, "core-pid_%p.dump")
            crash_log = """\
Coredump %(expected_crash_dump_filename)s not found. To enable crash logs:

- run this command as super-user: echo "%(core_pattern)s" > /proc/sys/kernel/core_pattern
- enable core dumps: ulimit -c unlimited
- set the WEBKIT_CORE_DUMPS_DIRECTORY environment variable: export WEBKIT_CORE_DUMPS_DIRECTORY=%(log_directory)s

""" % locals()

        return (stderr, """\
crash log for %(proc_name)s (pid %(pid_representation)s):

%(crash_log)s
%(errors_str)s""" % locals())
Example #3
0
    def run_command(self,
                    args,
                    cwd=None,
                    env=None,
                    input=None,
                    error_handler=None,
                    ignore_errors=False,
                    return_exit_code=False,
                    return_stderr=True,
                    decode_output=True):
        """Popen wrapper for convenience and to work around python bugs."""
        assert(isinstance(args, list) or isinstance(args, tuple))
        start_time = time.time()

        stdin, string_to_communicate = self._compute_stdin(input)
        stderr = self.STDOUT if return_stderr else None

        process = self.popen(args,
                             stdin=stdin,
                             stdout=self.PIPE,
                             stderr=stderr,
                             cwd=cwd,
                             env=env,
                             close_fds=self._should_close_fds())
        with process:
            if not string_to_communicate:
                output = process.communicate()[0]
            else:
                output = process.communicate(unicode_compatibility.encode_if_necessary(string_to_communicate, 'utf-8'))[0]

            # run_command automatically decodes to unicode() and converts CRLF to LF unless explicitly told not to.
            if decode_output:
                output = unicode_compatibility.decode_if_necessary(output, self._child_process_encoding()).replace('\r\n', '\n')

            # wait() is not threadsafe and can throw OSError due to:
            # http://bugs.python.org/issue1731717
            exit_code = process.wait()

            _log.debug('"%s" took %.2fs' % (self.command_for_printing(args), time.time() - start_time))

            if return_exit_code:
                return exit_code

            if exit_code:
                script_error = ScriptError(script_args=args,
                                           exit_code=exit_code,
                                           output=output,
                                           cwd=cwd)

                if ignore_errors:
                    assert error_handler is None, "don't specify error_handler if ignore_errors is True"
                    error_handler = Executive.ignore_error

                (error_handler or self.default_error_handler)(script_error)
            return output
Example #4
0
    def test_find_all_log_darwin(self):
        if not SystemHost().platform.is_mac():
            return

        crash_logs = self.create_crash_logs_darwin()
        all_logs = crash_logs.find_all_logs()
        self.assertEqual(len(all_logs), 8)

        for test, crash_log in all_logs.items():
            self.assertTrue(crash_log in [unicode_compatibility.decode_if_necessary(value) for value in self.files.values()])
            if test.split('-')[0] != 'Sandbox':
                self.assertTrue(test == "Unknown" or int(test.split("-")[1]) in range(28527, 28531))
Example #5
0
    def _get_trace_from_flatpak(self):
        if self.newer_than:
            coredump_since = "--gdb-stack-trace=@%f" % self.newer_than
        else:
            coredump_since = "--gdb-stack-trace"
        webkit_flatpak_path = self._webkit_finder.path_to_script('webkit-flatpak')
        cmd = ['flatpak-spawn', '--host', webkit_flatpak_path, '--%s' % self._port_name,
               "--%s" % self._configuration.lower(), coredump_since]

        proc = self._executive.popen(cmd, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        crash_log, stderr = proc.communicate()
        errors = decode_if_necessary(str(stderr or '<empty>'), errors='ignore').splitlines()
        return crash_log, errors
Example #6
0
    def test_run_command_with_unicode(self):
        """Validate that it is safe to pass unicode() objects
        to Executive.run* methods, and they will return unicode()
        objects by default unless decode_output=False"""
        unicode_tor_input = u"WebKit \u2661 Tor Arne Vestb\u00F8!"
        if sys.platform.startswith('win'):
            encoding = 'mbcs'
        else:
            encoding = 'utf-8'
        encoded_tor = unicode_compatibility.encode_if_necessary(
            unicode_tor_input, encoding)
        # On Windows, we expect the unicode->mbcs->unicode roundtrip to be
        # lossy. On other platforms, we expect a lossless roundtrip.
        if sys.platform.startswith('win'):
            unicode_tor_output = unicode_compatibility.decode_if_necessary(
                encoded_tor, encoding)
        else:
            unicode_tor_output = unicode_tor_input

        executive = Executive()

        output = executive.run_command(command_line('cat'),
                                       input=unicode_tor_input)
        self.assertEqual(output, unicode_tor_output)

        output = executive.run_command(command_line('echo', unicode_tor_input))
        self.assertEqual(output, unicode_tor_output)

        output = executive.run_command(command_line('echo', unicode_tor_input),
                                       decode_output=False)
        self.assertEqual(output, encoded_tor)

        # Make sure that str() input also works.
        output = executive.run_command(command_line('cat'),
                                       input=encoded_tor,
                                       decode_output=False)
        self.assertEqual(output, encoded_tor)

        # FIXME: We should only have one run* method to test
        output = executive.run_and_throw_if_fail(command_line(
            'echo', unicode_tor_input),
                                                 quiet=True)
        self.assertEqual(output, unicode_tor_output)

        output = executive.run_and_throw_if_fail(command_line(
            'echo', unicode_tor_input),
                                                 quiet=True,
                                                 decode_output=False)
        self.assertEqual(output, encoded_tor)
Example #7
0
    def _find_newest_log_win(self, process_name, pid, include_errors,
                             newer_than):
        def is_crash_log(fs, dirpath, basename):
            if self._crash_logs_to_skip and fs.join(
                    dirpath, basename) in self._crash_logs_to_skip:
                return False
            return basename.startswith("CrashLog")

        logs = self._host.filesystem.files_under(self._crash_log_directory,
                                                 file_filter=is_crash_log)
        errors = u''
        for path in reversed(sorted(logs)):
            try:
                if not newer_than or self._host.filesystem.mtime(
                        path) > newer_than:
                    log_file = unicode_compatibility.decode_if_necessary(
                        self._host.filesystem.read_binary_file(path), 'ascii',
                        'ignore')
                    match = self.GLOBAL_PID_REGEX.search(log_file)
                    if match:
                        if int(match.group('pid')) == pid:
                            return errors + log_file
                    match = self.EXIT_PROCESS_PID_REGEX.search(log_file)
                    if match is None:
                        continue
                    # Note: This output comes from a program that shows PID in hex:
                    if int(match.group('pid'), 16) == pid:
                        return errors + log_file
            except IOError as e:
                if include_errors:
                    errors += u"ERROR: Failed to read '%s': %s\n" % (path,
                                                                     str(e))
            except OSError as e:
                if include_errors:
                    errors += u"ERROR: Failed to read '%s': %s\n" % (path,
                                                                     str(e))
            except UnicodeDecodeError as e:
                if include_errors:
                    errors += u"ERROR: Failed to decode '%s' as ascii: %s\n" % (
                        path, str(e))

        if include_errors and errors:
            return errors
        return None
Example #8
0
 def command_for_printing(self, args):
     """Returns a print-ready string representing command args.
     The string should be copy/paste ready for execution in a shell."""
     args = self._stringify_args(args)
     return unicode_compatibility.decode_if_necessary(unicode_compatibility.encode_if_necessary(' '.join(args), 'unicode_escape'))
Example #9
0
    def write_text_file(self, path, contents, errors='strict'):
        """Write the contents to the file at the given location.

        The file is written encoded as UTF-8 with no BOM."""
        with codecs.open(path, 'w', 'utf-8', errors=errors) as f:
            f.write(decode_if_necessary(contents, errors=errors))