示例#1
0
    def Open(self):
        """Overridden connection creation."""
        # Kill all existing Chrome instances.
        killed_count = LocalChromeController.KillChromeProcesses()
        if killed_count > 0:
            logging.warning('Killed existing Chrome instance.')

        chrome_cmd = [OPTIONS.LocalBinary('chrome')]
        chrome_cmd.extend(self._GetChromeArguments())
        # Force use of simple cache.
        chrome_cmd.append('--use-simple-cache-backend=on')
        chrome_cmd.append('--user-data-dir=%s' % self._profile_dir)
        # Navigates to about:blank for couples of reasons:
        #   - To find the correct target descriptor at devtool connection;
        #   - To avoid cache and WPR pollution by the NTP.
        chrome_cmd.append('about:blank')

        tmp_log = \
            tempfile.NamedTemporaryFile(prefix="chrome_controller_", suffix='.log')
        chrome_process = None
        try:
            chrome_env_override = self._chrome_env_override.copy()
            if self._wpr_attributes:
                chrome_env_override.update(
                    self._wpr_attributes.chrome_env_override)

            chrome_env = os.environ.copy()
            chrome_env.update(chrome_env_override)

            # Launch Chrome.
            logging.info(
                common_util.GetCommandLineForLogging(chrome_cmd,
                                                     chrome_env_override))
            chrome_process = subprocess.Popen(chrome_cmd,
                                              stdout=tmp_log.file,
                                              stderr=tmp_log.file,
                                              env=chrome_env)
            # Attempt to connect to Chrome's devtools
            for attempt_id in xrange(self.DEVTOOLS_CONNECTION_ATTEMPTS):
                logging.info('Devtools connection attempt %d' % attempt_id)
                process_result = chrome_process.poll()
                if process_result is not None:
                    raise ChromeControllerInternalError(
                        'Unexpected Chrome exit: {}'.format(process_result))
                try:
                    connection = devtools_monitor.DevToolsConnection(
                        OPTIONS.devtools_hostname, OPTIONS.devtools_port)
                    break
                except socket.error as e:
                    if e.errno != errno.ECONNREFUSED:
                        raise
                    time.sleep(
                        self.DEVTOOLS_CONNECTION_ATTEMPT_INTERVAL_SECONDS)
            else:
                raise ChromeControllerInternalError(
                    'Failed to connect to Chrome devtools after {} '
                    'attempts.'.format(self.DEVTOOLS_CONNECTION_ATTEMPTS))
            # Start and yield the devtool connection.
            self._StartConnection(connection)
            yield connection
            if self._slow_death:
                connection.Close()
                chrome_process.wait()
                chrome_process = None
        except ChromeControllerError._PASSTHROUGH_WHITE_LIST:
            raise
        except Exception:
            raise ChromeControllerError(log=open(tmp_log.name).read())
        finally:
            if OPTIONS.local_noisy:
                sys.stderr.write(open(tmp_log.name).read())
            del tmp_log
            if chrome_process:
                try:
                    chrome_process.kill()
                except OSError:
                    pass  # Chrome is already dead.
示例#2
0
def ExecuteWithCommandLine(args, default_final_tasks):
    """Helper to execute tasks using command line arguments.

  Args:
    args: Command line argument parsed with CommandLineParser().
    default_final_tasks: Default final tasks if there is no -r command
      line arguments.

  Returns:
    0 if success or 1 otherwise
  """
    # Builds the scenario.
    final_tasks, frozen_tasks = _SelectTasksFromCommandLineRegexes(
        args, default_final_tasks)
    scenario = GenerateScenario(final_tasks, frozen_tasks)
    if len(scenario) == 0:
        logging.error('No tasks to build.')
        return 1

    if not os.path.isdir(args.output):
        os.makedirs(args.output)

    # Print the task dependency graph visualization.
    if args.output_graphviz:
        graphviz_path = os.path.join(args.output, _TASK_GRAPH_DOTFILE_NAME)
        png_graph_path = os.path.join(args.output, _TASK_GRAPH_PNG_NAME)
        with open(graphviz_path, 'w') as output:
            OutputGraphViz(scenario, final_tasks, output)
        subprocess.check_call(
            ['dot', '-Tpng', graphviz_path, '-o', png_graph_path])

    # Use the build scenario.
    if args.dry_run:
        for task in scenario:
            print task.name
        return 0

    # Run the Scenario while saving intermediate state to be able to resume later.
    failed_tasks = []
    tasks_to_skip = set()
    dependents_per_task = GenerateDependentSetPerTask(scenario)

    def MarkTaskNotToExecute(task):
        if task not in tasks_to_skip:
            logging.warning('can not execute task: %s', task.name)
            tasks_to_skip.add(task)
            for dependent in dependents_per_task[task]:
                MarkTaskNotToExecute(dependent)

    log_filename = datetime.datetime.now().strftime(
        _TASK_EXECUTION_LOG_NAME_FORMAT)
    log_path = os.path.join(args.output, _TASK_LOGS_DIR_NAME, log_filename)
    if not os.path.isdir(os.path.dirname(log_path)):
        os.makedirs(os.path.dirname(log_path))
    formatter = logging.Formatter('[%(asctime)s] %(levelname)s: %(message)s')
    handler = logging.FileHandler(log_path, mode='a')
    handler.setFormatter(formatter)
    logging.getLogger().addHandler(handler)
    logging.info('%s %s', '-' * 60,
                 common_util.GetCommandLineForLogging(sys.argv))
    try:
        with _ResumingFileBuilder(args) as resume_file_builder:
            for task_execute_id, task in enumerate(scenario):
                if task in tasks_to_skip:
                    continue
                logging.info('%s %s', '-' * 60, task.name)
                try:
                    task.Execute()
                except (MemoryError, SyntaxError):
                    raise
                except BaseException:
                    # The resuming file being incrementally generated by
                    # resume_file_builder.OnTaskSuccess() is automatically fsynced().
                    # But resume_file_builder.OnScenarioFinish() completely rewrite
                    # this file with the mininal subset of task to freeze, and in case
                    # of an ENOSPC, we don't want to touch the resuming file at all so
                    # that it remains uncorrupted.
                    if (sys.exc_info()[0] == IOError
                            and sys.exc_info()[1].errno == errno.ENOSPC):
                        raise
                    logging.exception('%s %s failed', '-' * 60, task.name)
                    failed_tasks.append(task)
                    if args.keep_going and sys.exc_info(
                    )[0] != KeyboardInterrupt:
                        MarkTaskNotToExecute(task)
                    else:
                        tasks_to_skip.update(set(scenario[task_execute_id:]))
                        break
                else:
                    resume_file_builder.OnTaskSuccess(task)
            if tasks_to_skip:
                assert failed_tasks
                resume_file_builder.OnScenarioFinish(scenario, final_tasks,
                                                     failed_tasks,
                                                     tasks_to_skip)
                if sys.exc_info()[0] == KeyboardInterrupt:
                    raise
                return 1
    finally:
        logging.getLogger().removeHandler(handler)
    assert not failed_tasks
    return 0