| OLD | NEW |
| 1 # Copyright 2015 The Chromium Authors. All rights reserved. | 1 # Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 """Functions that configure the shell before it is run manipulating its argument | 5 """Functions that configure the shell before it is run manipulating its argument |
| 6 list. | 6 list. |
| 7 """ | 7 """ |
| 8 | 8 |
| 9 import os.path | 9 import os.path |
| 10 import sys | 10 import sys |
| 11 import urlparse | 11 import urlparse |
| 12 | 12 |
| 13 from devtoolslib.android_shell import AndroidShell | 13 from devtoolslib.android_shell import AndroidShell |
| 14 from devtoolslib.linux_shell import LinuxShell | 14 from devtoolslib.linux_shell import LinuxShell |
| 15 | 15 |
| 16 # When spinning up servers for local origins, we want to use predictable ports | 16 # When spinning up servers for local origins, we want to use predictable ports |
| 17 # so that caching works between subsequent runs with the same command line. | 17 # so that caching works between subsequent runs with the same command line. |
| 18 _LOCAL_ORIGIN_PORT = 31840 | 18 _LOCAL_ORIGIN_PORT = 31840 |
| 19 _MAPPINGS_BASE_PORT = 31841 | 19 _MAPPINGS_BASE_PORT = 31841 |
| 20 | |
| 21 _SKY_SERVER_PORT = 9998 | 20 _SKY_SERVER_PORT = 9998 |
| 22 | 21 |
| 23 | 22 |
| 24 def _IsWebUrl(dest): | 23 def _is_web_url(dest): |
| 25 return True if urlparse.urlparse(dest).scheme else False | 24 return True if urlparse.urlparse(dest).scheme else False |
| 26 | 25 |
| 27 | 26 |
| 28 def _HostLocalUrlDestination(shell, dest_file, port): | 27 def _host_local_url_destination(shell, dest_file, port): |
| 29 """Starts a local server to host |dest_file|. | 28 """Starts a local server to host |dest_file|. |
| 30 | 29 |
| 31 Returns: | 30 Returns: |
| 32 Url of the hosted file. | 31 Url of the hosted file. |
| 33 """ | 32 """ |
| 34 directory = os.path.dirname(dest_file) | 33 directory = os.path.dirname(dest_file) |
| 35 if not os.path.exists(directory): | 34 if not os.path.exists(directory): |
| 36 raise ValueError('local path passed as --map-url destination ' | 35 raise ValueError('local path passed as --map-url destination ' |
| 37 'does not exist') | 36 'does not exist') |
| 38 server_url = shell.ServeLocalDirectory(directory, port) | 37 server_url = shell.ServeLocalDirectory(directory, port) |
| 39 return server_url + os.path.relpath(dest_file, directory) | 38 return server_url + os.path.relpath(dest_file, directory) |
| 40 | 39 |
| 41 | 40 |
| 42 def _HostLocalOriginDestination(shell, dest_dir, port): | 41 def _host_local_origin_destination(shell, dest_dir, port): |
| 43 """Starts a local server to host |dest_dir|. | 42 """Starts a local server to host |dest_dir|. |
| 44 | 43 |
| 45 Returns: | 44 Returns: |
| 46 Url of the hosted directory. | 45 Url of the hosted directory. |
| 47 """ | 46 """ |
| 48 return shell.ServeLocalDirectory(dest_dir, port) | 47 return shell.ServeLocalDirectory(dest_dir, port) |
| 49 | 48 |
| 50 | 49 |
| 51 def _Rewrite(mapping, host_destination_functon, shell, port): | 50 def _rewrite(mapping, host_destination_functon, shell, port): |
| 52 """Takes a mapping given as <src>=<dest> and rewrites the <dest> part to be | 51 """Takes a mapping given as <src>=<dest> and rewrites the <dest> part to be |
| 53 hosted locally using the given function if <dest> is not a web url. | 52 hosted locally using the given function if <dest> is not a web url. |
| 54 """ | 53 """ |
| 55 parts = mapping.split('=') | 54 parts = mapping.split('=') |
| 56 if len(parts) != 2: | 55 if len(parts) != 2: |
| 57 raise ValueError('each mapping value should be in format ' | 56 raise ValueError('each mapping value should be in format ' |
| 58 '"<url>=<url-or-local-path>"') | 57 '"<url>=<url-or-local-path>"') |
| 59 if _IsWebUrl(parts[1]): | 58 if _is_web_url(parts[1]): |
| 60 # The destination is a web url, do nothing. | 59 # The destination is a web url, do nothing. |
| 61 return mapping | 60 return mapping |
| 62 | 61 |
| 63 src = parts[0] | 62 src = parts[0] |
| 64 dest = host_destination_functon(shell, parts[1], port) | 63 dest = host_destination_functon(shell, parts[1], port) |
| 65 return src + '=' + dest | 64 return src + '=' + dest |
| 66 | 65 |
| 67 | 66 |
| 68 def _ApplyMappings(shell, original_arguments, map_urls, map_origins): | 67 def _apply_appings(shell, original_arguments, map_urls, map_origins): |
| 69 """Applies mappings for specified urls and origins. For each local path | 68 """Applies mappings for specified urls and origins. For each local path |
| 70 specified as destination a local server will be spawned and the mapping will | 69 specified as destination a local server will be spawned and the mapping will |
| 71 be rewritten accordingly. | 70 be rewritten accordingly. |
| 72 | 71 |
| 73 Args: | 72 Args: |
| 74 shell: The shell that is being configured. | 73 shell: The shell that is being configured. |
| 75 original_arguments: Current list of shell arguments. | 74 original_arguments: Current list of shell arguments. |
| 76 map_urls: List of url mappings, each in the form of | 75 map_urls: List of url mappings, each in the form of |
| 77 <url>=<url-or-local-path>. | 76 <url>=<url-or-local-path>. |
| 78 map_origins: List of origin mappings, each in the form of | 77 map_origins: List of origin mappings, each in the form of |
| 79 <origin>=<url-or-local-path>. | 78 <origin>=<url-or-local-path>. |
| 80 | 79 |
| 81 Returns: | 80 Returns: |
| 82 The updated argument list. | 81 The updated argument list. |
| 83 """ | 82 """ |
| 84 next_port = _MAPPINGS_BASE_PORT | 83 next_port = _MAPPINGS_BASE_PORT |
| 85 args = original_arguments | 84 args = original_arguments |
| 86 if map_urls: | 85 if map_urls: |
| 87 # Sort the mappings to preserve caching regardless of argument order. | 86 # Sort the mappings to preserve caching regardless of argument order. |
| 88 for map_url in sorted(map_urls): | 87 for map_url in sorted(map_urls): |
| 89 mapping = _Rewrite(map_url, _HostLocalUrlDestination, shell, next_port) | 88 mapping = _rewrite(map_url, _host_local_url_destination, shell, next_port) |
| 90 next_port += 1 | 89 next_port += 1 |
| 91 # All url mappings need to be coalesced into one shell argument. | 90 # All url mappings need to be coalesced into one shell argument. |
| 92 args = AppendToArgument(args, '--url-mappings=', mapping) | 91 args = append_to_argument(args, '--url-mappings=', mapping) |
| 93 | 92 |
| 94 if map_origins: | 93 if map_origins: |
| 95 for map_origin in sorted(map_origins): | 94 for map_origin in sorted(map_origins): |
| 96 mapping = _Rewrite(map_origin, _HostLocalOriginDestination, shell, | 95 mapping = _rewrite(map_origin, _host_local_origin_destination, shell, |
| 97 next_port) | 96 next_port) |
| 98 next_port += 1 | 97 next_port += 1 |
| 99 # Origin mappings are specified as separate, repeated shell arguments. | 98 # Origin mappings are specified as separate, repeated shell arguments. |
| 100 args.append('--map-origin=' + mapping) | 99 args.append('--map-origin=' + mapping) |
| 101 return args | 100 return args |
| 102 | 101 |
| 103 | 102 |
| 104 def ConfigureSky(shell, root_path, sky_packages_path, sky_target): | 103 def _configure_sky(shell, root_path, sky_packages_path, sky_target): |
| 105 """Configures additional mappings and a server needed to run the given Sky | 104 """Configures additional mappings and a server needed to run the given Sky |
| 106 app. | 105 app. |
| 107 | 106 |
| 108 Args: | 107 Args: |
| 109 root_path: Local path to the root from which Sky apps will be served. | 108 root_path: Local path to the root from which Sky apps will be served. |
| 110 sky_packages_path: Local path to the root from which Sky packages will be | 109 sky_packages_path: Local path to the root from which Sky packages will be |
| 111 served. | 110 served. |
| 112 sky_target: Path to the Sky app to be run, relative to |root_path|. | 111 sky_target: Path to the Sky app to be run, relative to |root_path|. |
| 113 | 112 |
| 114 Returns: | 113 Returns: |
| 115 Arguments that need to be appended to the shell argument list. | 114 Arguments that need to be appended to the shell argument list. |
| 116 """ | 115 """ |
| 117 # Configure a server to serve the checkout root at / (so that Sky examples | 116 # Configure a server to serve the checkout root at / (so that Sky examples |
| 118 # are accessible using a root-relative path) and Sky packages at /packages. | 117 # are accessible using a root-relative path) and Sky packages at /packages. |
| 119 # This is independent from the server that potentially serves the origin | 118 # This is independent from the server that potentially serves the origin |
| 120 # directory containing the mojo: apps. | 119 # directory containing the mojo: apps. |
| 121 additional_mappings = [ | 120 additional_mappings = [ |
| 122 ('packages/', sky_packages_path), | 121 ('packages/', sky_packages_path), |
| 123 ] | 122 ] |
| 124 server_url = shell.ServeLocalDirectory(root_path, port=_SKY_SERVER_PORT, | 123 server_url = shell.ServeLocalDirectory(root_path, port=_SKY_SERVER_PORT, |
| 125 additional_mappings=additional_mappings) | 124 additional_mappings=additional_mappings) |
| 126 | 125 |
| 127 args = [] | 126 args = [] |
| 128 # Configure the content type mappings for the sky_viewer. This is needed | 127 # Configure the content type mappings for the sky_viewer. This is needed |
| 129 # only for the Sky apps that do not declare mojo:sky_viewer in a shebang, | 128 # only for the Sky apps that do not declare mojo:sky_viewer in a shebang, |
| 130 # and it is unfortunate as it configures the shell to map all items of the | 129 # and it is unfortunate as it configures the shell to map all items of the |
| 131 # application/dart content-type as Sky apps. | 130 # application/dart content-type as Sky apps. |
| 132 # TODO(ppi): drop this part once we can rely on the Sky files declaring | 131 # TODO(ppi): drop this part once we can rely on the Sky files declaring |
| 133 # correct shebang. | 132 # correct shebang. |
| 134 args = AppendToArgument(args, '--content-handlers=', | 133 args = append_to_argument(args, '--content-handlers=', |
| 135 'text/sky,mojo:sky_viewer') | 134 'text/sky,mojo:sky_viewer') |
| 136 args = AppendToArgument(args, '--content-handlers=', | 135 args = append_to_argument(args, '--content-handlers=', |
| 137 'application/dart,mojo:sky_viewer') | 136 'application/dart,mojo:sky_viewer') |
| 138 | 137 |
| 139 # Configure the window manager to embed the sky_viewer. | 138 # Configure the window manager to embed the sky_viewer. |
| 140 sky_url = server_url + sky_target | 139 sky_url = server_url + sky_target |
| 141 args.append('mojo:window_manager %s' % sky_url) | 140 args.append('mojo:window_manager %s' % sky_url) |
| 142 return args | 141 return args |
| 143 | 142 |
| 144 | 143 |
| 145 def ConfigureLocalOrigin(shell, local_dir, fixed_port=True): | 144 def configure_local_origin(shell, local_dir, fixed_port=True): |
| 146 """Sets up a local http server to serve files in |local_dir| along with | 145 """Sets up a local http server to serve files in |local_dir| along with |
| 147 device port forwarding if needed. | 146 device port forwarding if needed. |
| 148 | 147 |
| 149 Returns: | 148 Returns: |
| 150 The list of arguments to be appended to the shell argument list. | 149 The list of arguments to be appended to the shell argument list. |
| 151 """ | 150 """ |
| 152 | 151 |
| 153 origin_url = shell.ServeLocalDirectory( | 152 origin_url = shell.ServeLocalDirectory( |
| 154 local_dir, _LOCAL_ORIGIN_PORT if fixed_port else 0) | 153 local_dir, _LOCAL_ORIGIN_PORT if fixed_port else 0) |
| 155 return ["--origin=" + origin_url] | 154 return ["--origin=" + origin_url] |
| 156 | 155 |
| 157 | 156 |
| 158 def AppendToArgument(arguments, key, value, delimiter=","): | 157 def append_to_argument(arguments, key, value, delimiter=","): |
| 159 """Looks for an argument of the form "key=val1,val2" within |arguments| and | 158 """Looks for an argument of the form "key=val1,val2" within |arguments| and |
| 160 appends |value| to it. | 159 appends |value| to it. |
| 161 | 160 |
| 162 If the argument is not present in |arguments| it is added. | 161 If the argument is not present in |arguments| it is added. |
| 163 | 162 |
| 164 Args: | 163 Args: |
| 165 arguments: List of arguments for the shell. | 164 arguments: List of arguments for the shell. |
| 166 key: Identifier of the argument, including the equal sign, eg. | 165 key: Identifier of the argument, including the equal sign, eg. |
| 167 "--content-handlers=". | 166 "--content-handlers=". |
| 168 value: The value to be appended, after |delimeter|, to the argument. | 167 value: The value to be appended, after |delimeter|, to the argument. |
| 169 delimiter: The string used to separate values within the argument. | 168 delimiter: The string used to separate values within the argument. |
| 170 | 169 |
| 171 Returns: | 170 Returns: |
| 172 The updated argument list. | 171 The updated argument list. |
| 173 """ | 172 """ |
| 174 assert key and key.endswith('=') | 173 assert key and key.endswith('=') |
| 175 assert value | 174 assert value |
| 176 | 175 |
| 177 for i, argument in enumerate(arguments): | 176 for i, argument in enumerate(arguments): |
| 178 if not argument.startswith(key): | 177 if not argument.startswith(key): |
| 179 continue | 178 continue |
| 180 arguments[i] = argument + delimiter + value | 179 arguments[i] = argument + delimiter + value |
| 181 break | 180 break |
| 182 else: | 181 else: |
| 183 arguments.append(key + value) | 182 arguments.append(key + value) |
| 184 | 183 |
| 185 return arguments | 184 return arguments |
| 186 | 185 |
| 187 | 186 |
| 188 def AddShellArguments(parser): | 187 def add_shell_arguments(parser): |
| 189 """Adds argparse arguments allowing to configure shell abstraction using | 188 """Adds argparse arguments allowing to configure shell abstraction using |
| 190 ConfigureShell() below. | 189 configure_shell() below. |
| 191 """ | 190 """ |
| 192 # Arguments indicating paths to binaries and tools. | 191 # Arguments indicating paths to binaries and tools. |
| 193 parser.add_argument('--adb-path', help='Path of the adb binary.') | 192 parser.add_argument('--adb-path', help='Path of the adb binary.') |
| 194 parser.add_argument('--shell-path', help='Path of the Mojo shell binary.') | 193 parser.add_argument('--shell-path', help='Path of the Mojo shell binary.') |
| 195 | 194 |
| 196 # Arguments configuring the shell run. | 195 # Arguments configuring the shell run. |
| 197 parser.add_argument('--android', help='Run on Android', | 196 parser.add_argument('--android', help='Run on Android', |
| 198 action='store_true') | 197 action='store_true') |
| 199 parser.add_argument('--origin', help='Origin for mojo: URLs. This can be a ' | 198 parser.add_argument('--origin', help='Origin for mojo: URLs. This can be a ' |
| 200 'web url or a local directory path.') | 199 'web url or a local directory path.') |
| (...skipping 19 matching lines...) Expand all Loading... |
| 220 # Other configuration. | 219 # Other configuration. |
| 221 parser.add_argument('-v', '--verbose', action="store_true", | 220 parser.add_argument('-v', '--verbose', action="store_true", |
| 222 help="Increase output verbosity") | 221 help="Increase output verbosity") |
| 223 | 222 |
| 224 | 223 |
| 225 class ShellConfigurationException(Exception): | 224 class ShellConfigurationException(Exception): |
| 226 """Represents an error preventing creating a functional shell abstraction.""" | 225 """Represents an error preventing creating a functional shell abstraction.""" |
| 227 pass | 226 pass |
| 228 | 227 |
| 229 | 228 |
| 230 def ConfigureShell(config_args, shell_args): | 229 def configure_shell(config_args, shell_args): |
| 231 """ | 230 """ |
| 232 Produces a shell abstraction configured using the parsed arguments defined in | 231 Produces a shell abstraction configured using the parsed arguments defined in |
| 233 AddShellArguments(). | 232 add_shell_arguments(). |
| 234 | 233 |
| 235 Args: | 234 Args: |
| 236 config_args: Parsed arguments added using AddShellArguments(). | 235 config_args: Parsed arguments added using add_shell_arguments(). |
| 237 shell_args: Additional raw shell arguments to be passed to the shell. We | 236 shell_args: Additional raw shell arguments to be passed to the shell. We |
| 238 need to take these into account as some parameters need to appear only | 237 need to take these into account as some parameters need to appear only |
| 239 once on the argument list (e.g. url-mappings) so we need to coalesce any | 238 once on the argument list (e.g. url-mappings) so we need to coalesce any |
| 240 overrides and the existing value into just one argument. | 239 overrides and the existing value into just one argument. |
| 241 | 240 |
| 242 Returns: | 241 Returns: |
| 243 A tuple of (shell, shell_args). | 242 A tuple of (shell, shell_args). |
| 244 | 243 |
| 245 Throws: | 244 Throws: |
| 246 ShellConfigurationException if shell abstraction could not be configured. | 245 ShellConfigurationException if shell abstraction could not be configured. |
| 247 """ | 246 """ |
| 248 if config_args.android: | 247 if config_args.android: |
| 249 verbose_pipe = sys.stdout if config_args.verbose else None | 248 verbose_pipe = sys.stdout if config_args.verbose else None |
| 250 | 249 |
| 251 shell = AndroidShell(config_args.adb_path, config_args.target_device, | 250 shell = AndroidShell(config_args.adb_path, config_args.target_device, |
| 252 logcat_tags=config_args.logcat_tags, | 251 logcat_tags=config_args.logcat_tags, |
| 253 verbose_pipe=verbose_pipe) | 252 verbose_pipe=verbose_pipe) |
| 254 device_status, error = shell.CheckDevice() | 253 device_status, error = shell.CheckDevice() |
| 255 if not device_status: | 254 if not device_status: |
| 256 raise ShellConfigurationException('Device check failed: ' + error) | 255 raise ShellConfigurationException('Device check failed: ' + error) |
| 257 if config_args.shell_path: | 256 if config_args.shell_path: |
| 258 shell.InstallApk(config_args.shell_path) | 257 shell.InstallApk(config_args.shell_path) |
| 259 | 258 |
| 260 shell_args = _ApplyMappings(shell, shell_args, config_args.map_url, | 259 shell_args = _apply_appings(shell, shell_args, config_args.map_url, |
| 261 config_args.map_origin) | 260 config_args.map_origin) |
| 262 else: | 261 else: |
| 263 if not config_args.shell_path: | 262 if not config_args.shell_path: |
| 264 raise ShellConfigurationException('Can not run without a shell binary. ' | 263 raise ShellConfigurationException('Can not run without a shell binary. ' |
| 265 'Please pass --shell-path.') | 264 'Please pass --shell-path.') |
| 266 shell = LinuxShell(config_args.shell_path) | 265 shell = LinuxShell(config_args.shell_path) |
| 267 if config_args.use_osmesa: | 266 if config_args.use_osmesa: |
| 268 shell_args.append('--args-for=mojo:native_viewport_service --use-osmesa') | 267 shell_args.append('--args-for=mojo:native_viewport_service --use-osmesa') |
| 269 | 268 |
| 270 if config_args.origin: | 269 if config_args.origin: |
| 271 if _IsWebUrl(config_args.origin): | 270 if _is_web_url(config_args.origin): |
| 272 shell_args.append('--origin=' + config_args.origin) | 271 shell_args.append('--origin=' + config_args.origin) |
| 273 else: | 272 else: |
| 274 shell_args.extend(ConfigureLocalOrigin(shell, config_args.origin, | 273 shell_args.extend(configure_local_origin(shell, config_args.origin, |
| 275 fixed_port=True)) | 274 fixed_port=True)) |
| 276 | 275 |
| 277 return shell, shell_args | 276 return shell, shell_args |
| OLD | NEW |