# 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. """Functions that configure the shell before it is run manipulating its argument list. """ import os.path import urlparse # 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 # Port on which the mojo:debugger http server will be available on the host # machine. _MOJO_DEBUGGER_PORT = 7777 _SKY_SERVER_PORT = 9998 def _HostLocalUrlDestination(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.ServeLocalDirectory(directory, port) return server_url + os.path.relpath(dest_file, directory) def _HostLocalOriginDestination(shell, dest_dir, port): """Starts a local server to host |dest_dir|. Returns: Url of the hosted directory. """ return shell.ServeLocalDirectory(dest_dir, port) def _Rewrite(mapping, host_destination_functon, shell, port): """Takes a mapping given as = and rewrites the part to be hosted locally using the given function if is not a web url. """ parts = mapping.split('=') if len(parts) != 2: raise ValueError('each mapping value should be in format ' '"="') if urlparse.urlparse(parts[1])[0]: # 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 ApplyMappings(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 =. map_origins: List of origin mappings, each in the form of =. 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, _HostLocalUrlDestination, shell, next_port) next_port += 1 # All url mappings need to be coalesced into one shell argument. args = AppendToArgument(args, '--url-mappings=', mapping) if map_origins: for map_origin in sorted(map_origins): mapping = _Rewrite(map_origin, _HostLocalOriginDestination, shell, next_port) next_port += 1 # Origin mappings are specified as separate, repeated shell arguments. args.append('--map-origin=' + mapping) return args def ConfigureDebugger(shell): """Configures mojo:debugger to run and sets up port forwarding for its http server if the shell is running on a device. Returns: Arguments that need to be appended to the shell argument list in order to run with the debugger. """ shell.ForwardHostPortToShell(_MOJO_DEBUGGER_PORT) return ['mojo:debugger %d' % _MOJO_DEBUGGER_PORT] def ConfigureSky(shell, root_path, sky_packages_path, sky_target): """Configures additional mappings and a server needed to run the given Sky app. Args: root_path: Local path to the root from which Sky apps will be served. sky_packages_path: Local path to the root from which Sky packages will be served. sky_target: Path to the Sky app to be run, relative to |root_path|. Returns: Arguments that need to be appended to the shell argument list. """ # Configure a server to serve the checkout root at / (so that Sky examples # are accessible using a root-relative path) and Sky packages at /packages. # This is independent from the server that potentially serves the origin # directory containing the mojo: apps. additional_mappings = [ ('packages/', sky_packages_path), ] server_url = shell.ServeLocalDirectory(root_path, port=_SKY_SERVER_PORT, additional_mappings=additional_mappings) args = [] # 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, # and it is unfortunate as it configures the shell to map all items of the # application/dart content-type as Sky apps. # TODO(ppi): drop this part once we can rely on the Sky files declaring # correct shebang. args = AppendToArgument(args, '--content-handlers=', 'text/sky,mojo:sky_viewer') args = AppendToArgument(args, '--content-handlers=', 'application/dart,mojo:sky_viewer') # Configure the window manager to embed the sky_viewer. sky_url = server_url + sky_target args.append('mojo:window_manager %s' % sky_url) return args def ConfigureLocalOrigin(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.ServeLocalDirectory( local_dir, _LOCAL_ORIGIN_PORT if fixed_port else 0) return ["--origin=" + origin_url] def AppendToArgument(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