mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
244 lines
8.3 KiB
Python
244 lines
8.3 KiB
Python
# 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.
|
|
|
|
"""Produces configured shell abstractions.
|
|
|
|
This module knows how to produce a configured shell abstraction based on
|
|
shell_config.ShellConfig.
|
|
"""
|
|
|
|
import os.path
|
|
import sys
|
|
import urlparse
|
|
|
|
from devtoolslib.android_shell import AndroidShell
|
|
from devtoolslib.linux_shell import LinuxShell
|
|
from devtoolslib.shell_config import ShellConfigurationException
|
|
|
|
# When spinning up servers for local origins, we want to use predictable ports
|
|
# so that caching works between subsequent runs with the same command line.
|
|
_LOCAL_ORIGIN_PORT = 31840
|
|
_MAPPINGS_BASE_PORT = 31841
|
|
|
|
|
|
def _is_web_url(dest):
|
|
return True if urlparse.urlparse(dest).scheme else False
|
|
|
|
|
|
def _host_local_url_destination(shell, dest_file, port):
|
|
"""Starts a local server to host |dest_file|.
|
|
|
|
Returns:
|
|
Url of the hosted file.
|
|
"""
|
|
directory = os.path.dirname(dest_file)
|
|
if not os.path.exists(directory):
|
|
raise ValueError('local path passed as --map-url destination '
|
|
'does not exist')
|
|
server_url = shell.serve_local_directory(directory, port)
|
|
return server_url + os.path.relpath(dest_file, directory)
|
|
|
|
|
|
def _host_local_origin_destination(shell, dest_dir, port):
|
|
"""Starts a local server to host |dest_dir|.
|
|
|
|
Returns:
|
|
Url of the hosted directory.
|
|
"""
|
|
return shell.serve_local_directory(dest_dir, port)
|
|
|
|
|
|
def _rewrite(mapping, host_destination_functon, shell, port):
|
|
"""Takes a mapping given as <src>=<dest> and rewrites the <dest> part to be
|
|
hosted locally using the given function if <dest> is not a web url.
|
|
"""
|
|
parts = mapping.split('=')
|
|
if len(parts) != 2:
|
|
raise ValueError('each mapping value should be in format '
|
|
'"<url>=<url-or-local-path>"')
|
|
if _is_web_url(parts[1]):
|
|
# The destination is a web url, do nothing.
|
|
return mapping
|
|
|
|
src = parts[0]
|
|
dest = host_destination_functon(shell, parts[1], port)
|
|
return src + '=' + dest
|
|
|
|
|
|
def _apply_mappings(shell, original_arguments, map_urls, map_origins):
|
|
"""Applies mappings for specified urls and origins. For each local path
|
|
specified as destination a local server will be spawned and the mapping will
|
|
be rewritten accordingly.
|
|
|
|
Args:
|
|
shell: The shell that is being configured.
|
|
original_arguments: Current list of shell arguments.
|
|
map_urls: List of url mappings, each in the form of
|
|
<url>=<url-or-local-path>.
|
|
map_origins: List of origin mappings, each in the form of
|
|
<origin>=<url-or-local-path>.
|
|
|
|
Returns:
|
|
The updated argument list.
|
|
"""
|
|
next_port = _MAPPINGS_BASE_PORT
|
|
args = original_arguments
|
|
if map_urls:
|
|
# Sort the mappings to preserve caching regardless of argument order.
|
|
for map_url in sorted(map_urls):
|
|
mapping = _rewrite(map_url, _host_local_url_destination, shell, next_port)
|
|
next_port += 1
|
|
# All url mappings need to be coalesced into one shell argument.
|
|
args = append_to_argument(args, '--url-mappings=', mapping)
|
|
|
|
if map_origins:
|
|
for map_origin in sorted(map_origins):
|
|
mapping = _rewrite(map_origin, _host_local_origin_destination, shell,
|
|
next_port)
|
|
next_port += 1
|
|
# Origin mappings are specified as separate, repeated shell arguments.
|
|
args.append('--map-origin=' + mapping)
|
|
return args
|
|
|
|
|
|
def _configure_sky(shell_args):
|
|
"""Maps mojo:sky_viewer as a content handler for dart applications.
|
|
app.
|
|
|
|
Args:
|
|
shell_args: Current list of shell arguments.
|
|
|
|
Returns:
|
|
Updated list of shell arguments.
|
|
"""
|
|
# Configure the content type mappings for the sky_viewer. This is needed
|
|
# only for the Sky apps that do not declare mojo:sky_viewer in a shebang.
|
|
# TODO(ppi): drop this part once we can rely on the Sky files declaring
|
|
# correct shebang.
|
|
shell_args = append_to_argument(shell_args, '--content-handlers=',
|
|
'text/sky,mojo:sky_viewer')
|
|
shell_args = append_to_argument(shell_args, '--content-handlers=',
|
|
'application/dart,mojo:sky_viewer')
|
|
return shell_args
|
|
|
|
|
|
def configure_local_origin(shell, local_dir, fixed_port=True):
|
|
"""Sets up a local http server to serve files in |local_dir| along with
|
|
device port forwarding if needed.
|
|
|
|
Returns:
|
|
The list of arguments to be appended to the shell argument list.
|
|
"""
|
|
|
|
origin_url = shell.serve_local_directory(
|
|
local_dir, _LOCAL_ORIGIN_PORT if fixed_port else 0)
|
|
return ["--origin=" + origin_url]
|
|
|
|
|
|
def append_to_argument(arguments, key, value, delimiter=","):
|
|
"""Looks for an argument of the form "key=val1,val2" within |arguments| and
|
|
appends |value| to it.
|
|
|
|
If the argument is not present in |arguments| it is added.
|
|
|
|
Args:
|
|
arguments: List of arguments for the shell.
|
|
key: Identifier of the argument, including the equal sign, eg.
|
|
"--content-handlers=".
|
|
value: The value to be appended, after |delimeter|, to the argument.
|
|
delimiter: The string used to separate values within the argument.
|
|
|
|
Returns:
|
|
The updated argument list.
|
|
"""
|
|
assert key and key.endswith('=')
|
|
assert value
|
|
|
|
for i, argument in enumerate(arguments):
|
|
if not argument.startswith(key):
|
|
continue
|
|
arguments[i] = argument + delimiter + value
|
|
break
|
|
else:
|
|
arguments.append(key + value)
|
|
|
|
return arguments
|
|
|
|
|
|
def _configure_dev_server(shell, shell_args, dev_server_config):
|
|
"""Sets up a dev server on the host according to |dev_server_config|.
|
|
|
|
Args:
|
|
shell: The shell that is being configured.
|
|
shell_arguments: Current list of shell arguments.
|
|
dev_server_config: Instance of shell_config.DevServerConfig describing the
|
|
dev server to be set up.
|
|
|
|
Returns:
|
|
The updated argument list.
|
|
"""
|
|
server_url = shell.serve_local_directories(dev_server_config.mappings)
|
|
shell_args.append('--map-origin=%s=%s' % (dev_server_config.host, server_url))
|
|
print "Configured %s locally to serve:" % (dev_server_config.host)
|
|
for mapping_prefix, mapping_path in dev_server_config.mappings:
|
|
print " /%s -> %s" % (mapping_prefix, mapping_path)
|
|
return shell_args
|
|
|
|
|
|
def get_shell(shell_config, shell_args):
|
|
"""
|
|
Produces a shell abstraction configured according to |shell_config|.
|
|
|
|
Args:
|
|
shell_config: Instance of shell_config.ShellConfig.
|
|
shell_args: Additional raw shell arguments to be passed to the shell. We
|
|
need to take these into account as some parameters need to appear only
|
|
once on the argument list (e.g. url-mappings) so we need to coalesce any
|
|
overrides and the existing value into just one argument.
|
|
|
|
Returns:
|
|
A tuple of (shell, shell_args). |shell| is the configured shell abstraction,
|
|
|shell_args| is updated list of shell arguments.
|
|
|
|
Throws:
|
|
ShellConfigurationException if shell abstraction could not be configured.
|
|
"""
|
|
if shell_config.android:
|
|
verbose_pipe = sys.stdout if shell_config.verbose else None
|
|
|
|
shell = AndroidShell(shell_config.adb_path, shell_config.target_device,
|
|
logcat_tags=shell_config.logcat_tags,
|
|
verbose_pipe=verbose_pipe)
|
|
|
|
device_status, error = shell.check_device()
|
|
if not device_status:
|
|
raise ShellConfigurationException('Device check failed: ' + error)
|
|
if shell_config.shell_path:
|
|
shell.install_apk(shell_config.shell_path)
|
|
else:
|
|
if not shell_config.shell_path:
|
|
raise ShellConfigurationException('Can not run without a shell binary. '
|
|
'Please pass --shell-path.')
|
|
shell = LinuxShell(shell_config.shell_path)
|
|
if shell_config.use_osmesa:
|
|
shell_args.append('--args-for=mojo:native_viewport_service --use-osmesa')
|
|
|
|
shell_args = _apply_mappings(shell, shell_args, shell_config.map_url_list,
|
|
shell_config.map_origin_list)
|
|
|
|
if shell_config.origin:
|
|
if _is_web_url(shell_config.origin):
|
|
shell_args.append('--origin=' + shell_config.origin)
|
|
else:
|
|
shell_args.extend(configure_local_origin(shell, shell_config.origin,
|
|
fixed_port=True))
|
|
|
|
if shell_config.sky:
|
|
shell_args = _configure_sky(shell_args)
|
|
|
|
for dev_server_config in shell_config.dev_servers:
|
|
shell_args = _configure_dev_server(shell, shell_args, dev_server_config)
|
|
|
|
return shell, shell_args
|