# Copyright 2015 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. """Configuration for the shell abstraction. This module declares ShellConfig and knows how to compute it from command-line arguments, applying any default paths inferred from the checkout, configuration file, etc. """ import ast from devtoolslib import paths class ShellConfigurationException(Exception): """Represents an error preventing creating a functional shell abstraction.""" pass class ShellConfig(object): """Configuration for the shell abstraction.""" def __init__(self): self.android = None self.shell_path = None self.origin = None self.map_url_list = [] self.map_origin_list = [] self.dev_servers = [] self.sky = None self.verbose = None # Android-only. self.adb_path = None self.target_device = None self.logcat_tags = None # Desktop-only. self.use_osmesa = None class DevServerConfig(object): """Configuration for a development server running on a host and available to the shell. """ def __init__(self): self.host = None self.mappings = None def add_shell_arguments(parser): """Adds argparse arguments allowing to configure shell abstraction using configure_shell() below. """ # Arguments configuring the shell run. parser.add_argument('--android', help='Run on Android', action='store_true') parser.add_argument('--shell-path', help='Path of the Mojo shell binary.') parser.add_argument('--origin', help='Origin for mojo: URLs. This can be a ' 'web url or a local directory path.') parser.add_argument('--map-url', action='append', help='Define a mapping for a url in the format ' '=') parser.add_argument('--map-origin', action='append', help='Define a mapping for a url origin in the format ' '=') parser.add_argument('--sky', action='store_true', help='Maps mojo:sky_viewer as the content handler for ' 'dart apps.') parser.add_argument('-v', '--verbose', action="store_true", help="Increase output verbosity") android_group = parser.add_argument_group('Android-only', 'These arguments apply only when --android is passed.') android_group.add_argument('--adb-path', help='Path of the adb binary.') android_group.add_argument('--target-device', help='Device to run on.') android_group.add_argument('--logcat-tags', help='Comma-separated list of ' 'additional logcat tags to display.') desktop_group = parser.add_argument_group('Desktop-only', 'These arguments apply only when running on desktop.') desktop_group.add_argument('--use-osmesa', action='store_true', help='Configure the native viewport service ' 'for off-screen rendering.') config_file_group = parser.add_argument_group('Configuration file', 'These arguments allow to modify the behavior regarding the mojoconfig ' 'file.') config_file_group.add_argument('--config-file', type=file, help='Path of the configuration file to use.') config_file_group.add_argument('--no-config-file', action='store_true', help='Pass to skip automatic discovery of the ' 'mojoconfig file.') # Arguments allowing to indicate the build directory we are targeting when # running within a Chromium-like checkout (e.g. Mojo checkout). These will go # away once we have devtools config files, see # https://github.com/domokit/devtools/issues/28. chromium_checkout_group = parser.add_argument_group( 'Chromium-like checkout configuration', 'These arguments allow to infer paths to tools and build results ' 'when running within a Chromium-like checkout') debug_group = chromium_checkout_group.add_mutually_exclusive_group() debug_group.add_argument('--debug', help='Debug build (default)', default=True, action='store_true') debug_group.add_argument('--release', help='Release build', default=False, dest='debug', action='store_false') chromium_checkout_group.add_argument('--target-cpu', help='CPU architecture to run for.', choices=['x64', 'x86', 'arm']) def _discover_config_file(): config_file_path = paths.find_within_ancestors('mojoconfig') if not config_file_path: return None return open(config_file_path, 'r') def _read_config_file(config_file, aliases): spec = config_file.read() for alias_pattern, alias_value in aliases: spec = spec.replace(alias_pattern, alias_value) return ast.literal_eval(spec) def get_shell_config(script_args): """Processes command-line options defined in add_shell_arguments(), applying any inferred default paths and produces an instance of ShellConfig. Returns: An instance of ShellConfig. """ # Infer paths based on the Chromium configuration options # (--debug/--release, etc.), if running within a Chromium-like checkout. inferred_paths = paths.infer_paths(script_args.android, script_args.debug, script_args.target_cpu) shell_config = ShellConfig() shell_config.android = script_args.android shell_config.shell_path = (script_args.shell_path or inferred_paths['shell_path']) shell_config.origin = script_args.origin shell_config.map_url_list = script_args.map_url shell_config.map_origin_list = script_args.map_origin shell_config.sky = script_args.sky shell_config.verbose = script_args.verbose # Android-only. shell_config.adb_path = (script_args.adb_path or inferred_paths['adb_path']) shell_config.target_device = script_args.target_device shell_config.logcat_tags = script_args.logcat_tags # Desktop-only. shell_config.use_osmesa = script_args.use_osmesa if (shell_config.android and not shell_config.origin and inferred_paths['build_dir_path']): shell_config.origin = inferred_paths['build_dir_path'] # Read the mojoconfig file. config_file = script_args.config_file if not script_args.no_config_file: config_file = config_file or _discover_config_file() if config_file: with config_file: config_file_aliases = [] if inferred_paths['build_dir_path']: config_file_aliases.append(('@{BUILD_DIR}', inferred_paths['build_dir_path'])) config = None try: if script_args.verbose: print 'Reading config file from: ' + config_file.name config = _read_config_file(config_file, config_file_aliases) except SyntaxError: raise ShellConfigurationException('Failed to parse the mojoconfig ' 'file.') if 'dev_servers' in config: try: for dev_server_spec in config['dev_servers']: dev_server_config = DevServerConfig() dev_server_config.host = dev_server_spec['host'] dev_server_config.mappings = [] for prefix, path in dev_server_spec['mappings']: dev_server_config.mappings.append((prefix, path)) shell_config.dev_servers.append(dev_server_config) except (ValueError, KeyError): raise ShellConfigurationException('Failed to parse dev_servers in ' 'the mojoconfig file.') return shell_config