Move wm_flow off of views and onto Sky
This is a proof of concept for replacing ui/views code with Sky instead. erg says this will allow him to delete 10s of thousands of LOC from mojo. Mojo does not yet expose the current binary's URL: https://docs.google.com/a/chromium.org/document/d/1AQ2y6ekzvbdaMF5WrUQmneyXJnke-MnYYL4Gz1AKDos So I've worked around that by passing the url of the binary via the helper script. I discovered several bugs in the wm_flow code including that it doesn't handle view resizes (during embiggen). Related, I discovered that every time a new window is made it drops the connections to the embedded.cc app from the previous window, since the ViewManagerDelegate is incorrectly implemented as part of the ApplicationDelegate on both app.cc and embedded.cc. We'd need to split out a separate per-view object in both of those apps to handle the ViewManagerDelegate calls. There are some changes to logging during loading as well as the CopyToFile helper to have better error reporting. I hit several issues early on trying to get mojo to load the http: urls correctly, including eventually running out of disk space on my /tmp and mojo then silently failing to launch the app (due to mojo never clearing its caches crbug.com/446302). I had to re-write the mojo_demo.sh script in python as well as split the sky_server handling code out of skydb into a separate python module in order to cleanly launch sky_server. We could use a separate server if we wanted to but the primary benefit of sky_server is that it sets up the proper url->disk mappings into the generated file directories, etc. BUG=443439 R=abarth@chromium.org Review URL: https://codereview.chromium.org/817573003
This commit is contained in:
parent
7ce7206df7
commit
5096b17cc6
@ -3,14 +3,13 @@
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
from skypy.paths import Paths
|
||||
from skypy.skyserver import SkyServer
|
||||
import argparse
|
||||
import logging
|
||||
import os
|
||||
from skypy.paths import Paths
|
||||
import skypy.configuration as configuration
|
||||
import socket;
|
||||
import subprocess
|
||||
import sys
|
||||
import urlparse
|
||||
|
||||
|
||||
@ -21,21 +20,19 @@ SUPPORTED_MIME_TYPES = [
|
||||
]
|
||||
|
||||
|
||||
HTTP_PORT = 9999
|
||||
|
||||
|
||||
class SkyDebugger(object):
|
||||
def __init__(self):
|
||||
self._sky_server = None
|
||||
self.paths = None
|
||||
|
||||
@staticmethod
|
||||
def _port_in_use(port):
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
return sock.connect_ex(('localhost', port)) == 0
|
||||
def _server_root_and_url_from_path_arg(self, url_or_path):
|
||||
# This is already a valid url we don't need a local server.
|
||||
if urlparse.urlparse(url_or_path).scheme:
|
||||
return None, url_or_path
|
||||
|
||||
def _start_http_server_for_file(self, path, configuration):
|
||||
HTTP_PORT = 9999
|
||||
|
||||
|
||||
path = os.path.abspath(path)
|
||||
path = os.path.abspath(url_or_path)
|
||||
if os.path.commonprefix([path, self.paths.src_root]) == self.paths.src_root:
|
||||
server_root = self.paths.src_root
|
||||
else:
|
||||
@ -43,23 +40,8 @@ class SkyDebugger(object):
|
||||
logging.warn(
|
||||
'%s is outside of mojo root, using %s as server root' %
|
||||
(path, server_root))
|
||||
relative_path = os.path.relpath(path, server_root)
|
||||
|
||||
if self._port_in_use(HTTP_PORT):
|
||||
logging.warn(
|
||||
'Port %s already in use, assuming custom sky_server started.' %
|
||||
HTTP_PORT)
|
||||
else:
|
||||
subprocess.call(os.path.join(self.paths.sky_tools_directory,
|
||||
'download_sky_server'))
|
||||
server_command = [
|
||||
os.path.join(self.paths.src_root, 'out', 'downloads', 'sky_server'),
|
||||
'-t', configuration,
|
||||
server_root,
|
||||
str(HTTP_PORT),
|
||||
]
|
||||
self._sky_server = subprocess.Popen(server_command)
|
||||
return 'http://localhost:%s/%s' % (HTTP_PORT, relative_path)
|
||||
local_url = SkyServer.url_for_path(HTTP_PORT, server_root, path)
|
||||
return server_root, local_url
|
||||
|
||||
def _in_chromoting(self):
|
||||
return os.environ.get('CHROME_REMOTE_DESKTOP_SESSION', False)
|
||||
@ -71,7 +53,7 @@ class SkyDebugger(object):
|
||||
parser.add_argument('--gdb', action='store_true')
|
||||
parser.add_argument('--use-osmesa', action='store_true',
|
||||
default=self._in_chromoting())
|
||||
parser.add_argument('url', nargs='?', type=str)
|
||||
parser.add_argument('url_or_path', nargs='?', type=str)
|
||||
configuration.add_arguments(parser)
|
||||
args = parser.parse_args()
|
||||
|
||||
@ -86,31 +68,28 @@ class SkyDebugger(object):
|
||||
'--url-mappings=mojo:window_manager=mojo:sky_debugger',
|
||||
'mojo:window_manager',
|
||||
]
|
||||
if args.url:
|
||||
url = args.url
|
||||
if not urlparse.urlparse(url).scheme:
|
||||
url = self._start_http_server_for_file(url, args.configuration)
|
||||
|
||||
prompt_args = '--args-for=mojo:sky_debugger_prompt %s' % url
|
||||
shell_command.append(prompt_args)
|
||||
if args.use_osmesa:
|
||||
shell_command.append('--args-for=mojo:native_viewport_service --use-osmesa')
|
||||
|
||||
server_root = None
|
||||
|
||||
if args.url_or_path:
|
||||
# Check if we need a local server for the url/path arg:
|
||||
server_root, url = \
|
||||
self._server_root_and_url_from_path_arg(args.url_or_path)
|
||||
prompt_args = '--args-for=mojo:sky_debugger_prompt %s' % url
|
||||
shell_command.append(prompt_args)
|
||||
|
||||
if args.gdb:
|
||||
shell_command = ['gdb', '--args'] + shell_command
|
||||
|
||||
subprocess.check_call(shell_command)
|
||||
|
||||
def shutdown(self):
|
||||
print "Quitting"
|
||||
if self._sky_server:
|
||||
self._sky_server.terminate()
|
||||
if server_root:
|
||||
with SkyServer(self.paths, HTTP_PORT, args.configuration,
|
||||
server_root):
|
||||
subprocess.check_call(shell_command)
|
||||
else:
|
||||
subprocess.check_call(shell_command)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
skydb = SkyDebugger()
|
||||
try:
|
||||
skydb.main()
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
pass
|
||||
finally:
|
||||
skydb.shutdown()
|
||||
SkyDebugger().main()
|
||||
|
@ -6,9 +6,12 @@ package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@ -28,25 +31,59 @@ func (handler *skyHandlerRoot) ServeHTTP(w http.ResponseWriter, r *http.Request)
|
||||
http.ServeFile(w, r, path)
|
||||
}
|
||||
|
||||
func usage() {
|
||||
fmt.Fprintf(os.Stderr, "Usage: sky_server [flags] MOJO_SRC_ROOT PORT\n\n")
|
||||
fmt.Fprintf(os.Stderr, "launches a basic http server with mappings into the\n")
|
||||
fmt.Fprintf(os.Stderr, "mojo repository for framework/service paths.\n")
|
||||
fmt.Fprintf(os.Stderr, "[flags] MUST be before arguments, because go:flag.\n\n")
|
||||
flag.PrintDefaults()
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
func addMapping(from_path string, to_path string) {
|
||||
// Print to stderr to it's more obvious what this binary does.
|
||||
fmt.Fprintf(os.Stderr, " %s -> %s\n", from_path, to_path)
|
||||
http.Handle(from_path, http.StripPrefix(from_path, skyHandler(to_path)))
|
||||
}
|
||||
|
||||
func main() {
|
||||
var configuration = flag.String("t", "Release", "The target configuration (i.e. Release or Debug)")
|
||||
flag.Parse()
|
||||
|
||||
args := flag.Args()
|
||||
root := args[0]
|
||||
port := args[1]
|
||||
flag.Parse()
|
||||
flag.Usage = usage
|
||||
// The built-in go:flag is awful. It only allows short-name arguments
|
||||
// and they *must* be before any unnamed arguments. There are better ones:
|
||||
// https://godoc.org/github.com/jessevdk/go-flags
|
||||
// but for now we're using raw-go.
|
||||
if flag.NArg() != 2 {
|
||||
usage()
|
||||
}
|
||||
|
||||
root, _ := filepath.Abs(flag.Arg(0))
|
||||
port := flag.Arg(1)
|
||||
|
||||
genRoot := path.Join(root, "out", *configuration, "gen")
|
||||
|
||||
fmt.Fprintf(os.Stderr, "Mappings for localhost:%s:\n", port)
|
||||
|
||||
fmt.Fprintf(os.Stderr, " / -> %s\n", root)
|
||||
http.Handle("/", skyHandler(root))
|
||||
|
||||
fmt.Fprintf(os.Stderr, " /echo_post -> custom echo handler\n")
|
||||
http.HandleFunc("/echo_post", func(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
body, _ := ioutil.ReadAll(r.Body)
|
||||
w.Write(body)
|
||||
})
|
||||
http.Handle("/mojo/public/", http.StripPrefix("/mojo/public/", skyHandler(path.Join(genRoot, "mojo", "public"))))
|
||||
http.Handle("/mojo/services/", http.StripPrefix("/mojo/services/", skyHandler(path.Join(genRoot, "mojo", "services"))))
|
||||
http.Handle("/sky/services/", http.StripPrefix("/sky/services/", skyHandler(path.Join(genRoot, "sky", "services"))))
|
||||
|
||||
addMapping("/gen/", genRoot)
|
||||
|
||||
// FIXME: Unclear if these are correct now that we have /gen.
|
||||
// /gen is more explicit, but also is less like how a 3rd party might
|
||||
// deploy a sky app.
|
||||
addMapping("/mojo/public/", path.Join(genRoot, "mojo", "public"))
|
||||
addMapping("/mojo/services/", path.Join(genRoot, "mojo", "services"))
|
||||
addMapping("/sky/services/", path.Join(genRoot, "sky", "services"))
|
||||
|
||||
http.ListenAndServe(":" + port, nil)
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
f6b808791e8ab0290cb18bc8b444159074c395ae
|
||||
7d2cceb778d3bfd4a710915de8721d10cc89b155
|
55
engine/src/flutter/tools/skypy/skyserver.py
Normal file
55
engine/src/flutter/tools/skypy/skyserver.py
Normal file
@ -0,0 +1,55 @@
|
||||
# Copyright 2014 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.
|
||||
|
||||
import socket
|
||||
import subprocess
|
||||
import logging
|
||||
import os.path
|
||||
|
||||
class SkyServer(object):
|
||||
def __init__(self, paths, port, configuration, root):
|
||||
self.paths = paths
|
||||
self.port = port
|
||||
self.configuration = configuration
|
||||
self.root = root
|
||||
self.server = None
|
||||
|
||||
@staticmethod
|
||||
def _port_in_use(port):
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
return sock.connect_ex(('localhost', port)) == 0
|
||||
|
||||
@staticmethod
|
||||
def _download_server_if_necessary(paths):
|
||||
subprocess.call(os.path.join(paths.sky_tools_directory,
|
||||
'download_sky_server'))
|
||||
return os.path.join(paths.src_root, 'out', 'downloads', 'sky_server')
|
||||
|
||||
def __enter__(self):
|
||||
if self._port_in_use(self.port):
|
||||
logging.warn(
|
||||
'Port %s already in use, assuming custom sky_server started.' %
|
||||
self.port)
|
||||
return
|
||||
|
||||
server_path = self._download_server_if_necessary(self.paths)
|
||||
server_command = [
|
||||
server_path,
|
||||
'-t', self.configuration,
|
||||
self.root,
|
||||
str(self.port),
|
||||
]
|
||||
self.server = subprocess.Popen(server_command)
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
if self.server:
|
||||
self.server.terminate()
|
||||
|
||||
def path_as_url(self, path):
|
||||
return self.url_for_path(self.port, self.root, path)
|
||||
|
||||
@staticmethod
|
||||
def url_for_path(port, root, path):
|
||||
relative_path = os.path.relpath(path, root)
|
||||
return 'http://localhost:%s/%s' % (port, relative_path)
|
Loading…
x
Reference in New Issue
Block a user