Make skydb just a ctl-style helper (e.g. apachectl)
This makes it much easier to work with a device where we don't expect a persistent commandline session. Prompt no longer actually makes a prompt but rather just runs an http server. This is just a v1 patch. It doesn't work with android yet and it isn't smart enough to allow you to run more than one copy of prompt.cc at the same time (since you can't control the port it listens on). If you have a second copy of prompt runnning (or anything else bound to port 7777) it will just crash. We could make this a lot better, including splitting out the pid-file tracking for sky_server into sky_server instead of having skydb manage it. R=ojan@chromium.org, abarth@chromium.org BUG= Review URL: https://codereview.chromium.org/840973002
This commit is contained in:
parent
6d658c8c95
commit
5f587b2878
@ -16,6 +16,8 @@ mojo_native_application("prompt") {
|
|||||||
"//mojo/application",
|
"//mojo/application",
|
||||||
"//mojo/public/cpp/bindings",
|
"//mojo/public/cpp/bindings",
|
||||||
"//mojo/public/cpp/utility",
|
"//mojo/public/cpp/utility",
|
||||||
|
"//net",
|
||||||
|
"//net:http_server",
|
||||||
"//services/tracing:bindings",
|
"//services/tracing:bindings",
|
||||||
"//sky/tools/debugger:bindings",
|
"//sky/tools/debugger:bindings",
|
||||||
"//sky/viewer:bindings",
|
"//sky/viewer:bindings",
|
||||||
|
@ -8,29 +8,17 @@
|
|||||||
#include "mojo/public/c/system/main.h"
|
#include "mojo/public/c/system/main.h"
|
||||||
#include "mojo/public/cpp/application/application_delegate.h"
|
#include "mojo/public/cpp/application/application_delegate.h"
|
||||||
#include "mojo/public/cpp/application/application_impl.h"
|
#include "mojo/public/cpp/application/application_impl.h"
|
||||||
|
#include "net/server/http_server.h"
|
||||||
|
#include "net/server/http_server_request_info.h"
|
||||||
|
#include "net/socket/tcp_server_socket.h"
|
||||||
#include "services/tracing/tracing.mojom.h"
|
#include "services/tracing/tracing.mojom.h"
|
||||||
#include "sky/tools/debugger/debugger.mojom.h"
|
#include "sky/tools/debugger/debugger.mojom.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
namespace sky {
|
namespace sky {
|
||||||
namespace debugger {
|
namespace debugger {
|
||||||
namespace {
|
|
||||||
|
|
||||||
std::string GetCommand() {
|
class Prompt : public mojo::ApplicationDelegate, public net::HttpServer::Delegate {
|
||||||
std::cout << "(skydb) ";
|
|
||||||
std::cout.flush();
|
|
||||||
|
|
||||||
std::string command;
|
|
||||||
std::getline(std::cin, command);
|
|
||||||
// Any errors (including eof) just quit the debugger:
|
|
||||||
if (!std::cin.good())
|
|
||||||
command = 'q';
|
|
||||||
return command;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class Prompt : public mojo::ApplicationDelegate {
|
|
||||||
public:
|
public:
|
||||||
Prompt()
|
Prompt()
|
||||||
: is_tracing_(false),
|
: is_tracing_(false),
|
||||||
@ -49,6 +37,12 @@ class Prompt : public mojo::ApplicationDelegate {
|
|||||||
url_ = "https://raw.githubusercontent.com/domokit/mojo/master/sky/"
|
url_ = "https://raw.githubusercontent.com/domokit/mojo/master/sky/"
|
||||||
"examples/home.sky";
|
"examples/home.sky";
|
||||||
}
|
}
|
||||||
|
scoped_ptr<net::ServerSocket> server_socket(
|
||||||
|
new net::TCPServerSocket(NULL, net::NetLog::Source()));
|
||||||
|
// FIXME: This port needs to be configurable, as-is we can only run
|
||||||
|
// one copy of mojo_shell with sky at a time!
|
||||||
|
server_socket->ListenWithAddressAndPort("0.0.0.0", 7777, 1);
|
||||||
|
web_server_.reset(new net::HttpServer(server_socket.Pass(), this));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool ConfigureIncomingConnection(
|
virtual bool ConfigureIncomingConnection(
|
||||||
@ -56,93 +50,86 @@ class Prompt : public mojo::ApplicationDelegate {
|
|||||||
connection->ConnectToService(&debugger_);
|
connection->ConnectToService(&debugger_);
|
||||||
std::cout << "Loading " << url_ << std::endl;
|
std::cout << "Loading " << url_ << std::endl;
|
||||||
Reload();
|
Reload();
|
||||||
#if !defined(OS_ANDROID)
|
|
||||||
// FIXME: To support device-centric development we need to re-write
|
|
||||||
// prompt.cc to just be a server and have all the command handling move
|
|
||||||
// to python (skydb). prompt.cc would just run until told to quit.
|
|
||||||
// If we don't comment this out then prompt.cc just quits when run headless
|
|
||||||
// as it immediately recieves EOF which it treats as quit.
|
|
||||||
ScheduleWaitForInput();
|
|
||||||
#endif
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ExecuteCommand(const std::string& command) {
|
// net::HttpServer::Delegate
|
||||||
if (command == "help" || command == "h") {
|
void OnConnect(int connection_id) override {
|
||||||
PrintHelp();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (command == "trace") {
|
|
||||||
ToggleTracing();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (command == "reload" || command == "r") {
|
|
||||||
Reload();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (command == "inspect") {
|
|
||||||
Inspect();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (command == "quit" || command == "q") {
|
|
||||||
Quit();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (command.size() == 1) {
|
|
||||||
std::cout << "Unknown command: " << command << std::endl;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaitForInput() {
|
void OnClose(int connection_id) override {
|
||||||
std::string command = GetCommand();
|
}
|
||||||
|
|
||||||
if (!ExecuteCommand(command)) {
|
void OnHttpRequest(
|
||||||
if (command.size() > 0) {
|
int connection_id, const net::HttpServerRequestInfo& info) override {
|
||||||
url_ = command;
|
|
||||||
Reload();
|
// FIXME: We should use use a fancier lookup system more like what
|
||||||
}
|
// services/http_server/http_server.cc does with AddHandler.
|
||||||
|
if (info.path == "/trace")
|
||||||
|
ToggleTracing(connection_id);
|
||||||
|
else if (info.path == "/reload")
|
||||||
|
Load(connection_id, url_);
|
||||||
|
else if (info.path == "/inspect")
|
||||||
|
Inspect(connection_id);
|
||||||
|
else if (info.path == "/quit")
|
||||||
|
Quit(connection_id);
|
||||||
|
else if (info.path == "/load")
|
||||||
|
Load(connection_id, info.data);
|
||||||
|
else {
|
||||||
|
Help(info.path, connection_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
ScheduleWaitForInput();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScheduleWaitForInput() {
|
void OnWebSocketRequest(
|
||||||
base::MessageLoop::current()->PostTask(FROM_HERE,
|
int connection_id, const net::HttpServerRequestInfo& info) override {
|
||||||
base::Bind(&Prompt::WaitForInput, weak_ptr_factory_.GetWeakPtr()));
|
web_server_->Send500(connection_id, "http only");
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrintHelp() {
|
void OnWebSocketMessage(
|
||||||
std::cout
|
int connection_id, const std::string& data) override {
|
||||||
<< "Sky Debugger" << std::endl
|
web_server_->Send500(connection_id, "http only");
|
||||||
<< "============" << std::endl
|
}
|
||||||
<< "Type a URL to load in the debugger, enter to reload." << std::endl
|
|
||||||
<< "Commands: help -- Help" << std::endl
|
void Respond(int connection_id, std::string response) {
|
||||||
<< " trace -- Capture a trace" << std::endl
|
web_server_->Send200(connection_id, response, "text/plain");
|
||||||
<< " reload -- Reload the current page" << std::endl
|
}
|
||||||
<< " inspect -- Inspect the current page" << std::endl
|
|
||||||
<< " quit -- Quit" << std::endl;
|
void Help(std::string path, int connection_id) {
|
||||||
|
std::string help = "Sky Debugger\n"
|
||||||
|
"Supported URLs:\n"
|
||||||
|
"/toggle_tracing -- Start/stop tracing\n"
|
||||||
|
"/reload -- Reload the current page\n"
|
||||||
|
"/inspect -- Start inspector server for current page\n"
|
||||||
|
"/quit -- Quit\n"
|
||||||
|
"/load -- Load a new URL, url in POST body.\n";
|
||||||
|
if (path != "/")
|
||||||
|
help = "Unknown path: " + path + "\n\n" + help;
|
||||||
|
Respond(connection_id, help);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Load(int connection_id, std::string url) {
|
||||||
|
url_ = url;
|
||||||
|
Reload();
|
||||||
|
Respond(connection_id, "OK\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Reload() {
|
void Reload() {
|
||||||
debugger_->NavigateToURL(url_);
|
debugger_->NavigateToURL(url_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Inspect() {
|
void Inspect(int connection_id) {
|
||||||
debugger_->InjectInspector();
|
debugger_->InjectInspector();
|
||||||
std::cout
|
Respond(connection_id,
|
||||||
<< "Open the following URL in Chrome:" << std::endl
|
"Open the following URL in Chrome:\n"
|
||||||
<< "chrome-devtools://devtools/bundled/devtools.html?ws=localhost:9898"
|
"chrome-devtools://devtools/bundled/devtools.html?ws=localhost:9898\n");
|
||||||
<< std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Quit() {
|
void Quit(int connection_id) {
|
||||||
std::cout << "quitting" << std::endl;
|
std::cout << "quitting" << std::endl;
|
||||||
debugger_->Shutdown();
|
debugger_->Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ToggleTracing() {
|
void ToggleTracing(int connection_id) {
|
||||||
if (is_tracing_) {
|
if (is_tracing_) {
|
||||||
std::cout << "Stopping trace (writing to sky_viewer.trace)" << std::endl;
|
std::cout << "Stopping trace (writing to sky_viewer.trace)" << std::endl;
|
||||||
tracing_->StopAndFlush();
|
tracing_->StopAndFlush();
|
||||||
@ -151,6 +138,7 @@ class Prompt : public mojo::ApplicationDelegate {
|
|||||||
tracing_->Start(mojo::String("sky_viewer"), mojo::String("*"));
|
tracing_->Start(mojo::String("sky_viewer"), mojo::String("*"));
|
||||||
}
|
}
|
||||||
is_tracing_ = !is_tracing_;
|
is_tracing_ = !is_tracing_;
|
||||||
|
Respond(connection_id, "OK\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_tracing_;
|
bool is_tracing_;
|
||||||
@ -158,6 +146,7 @@ class Prompt : public mojo::ApplicationDelegate {
|
|||||||
tracing::TraceCoordinatorPtr tracing_;
|
tracing::TraceCoordinatorPtr tracing_;
|
||||||
std::string url_;
|
std::string url_;
|
||||||
base::WeakPtrFactory<Prompt> weak_ptr_factory_;
|
base::WeakPtrFactory<Prompt> weak_ptr_factory_;
|
||||||
|
scoped_ptr<net::HttpServer> web_server_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(Prompt);
|
DISALLOW_COPY_AND_ASSIGN(Prompt);
|
||||||
};
|
};
|
||||||
@ -167,5 +156,6 @@ class Prompt : public mojo::ApplicationDelegate {
|
|||||||
|
|
||||||
MojoResult MojoMain(MojoHandle shell_handle) {
|
MojoResult MojoMain(MojoHandle shell_handle) {
|
||||||
mojo::ApplicationRunnerChromium runner(new sky::debugger::Prompt);
|
mojo::ApplicationRunnerChromium runner(new sky::debugger::Prompt);
|
||||||
|
runner.set_message_loop_type(base::MessageLoop::TYPE_IO);
|
||||||
return runner.Run(shell_handle);
|
return runner.Run(shell_handle);
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,11 @@
|
|||||||
from skypy.paths import Paths
|
from skypy.paths import Paths
|
||||||
from skypy.skyserver import SkyServer
|
from skypy.skyserver import SkyServer
|
||||||
import argparse
|
import argparse
|
||||||
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
import requests
|
||||||
|
import signal
|
||||||
import skypy.configuration as configuration
|
import skypy.configuration as configuration
|
||||||
import subprocess
|
import subprocess
|
||||||
import urlparse
|
import urlparse
|
||||||
@ -19,13 +22,17 @@ SUPPORTED_MIME_TYPES = [
|
|||||||
'text/plain',
|
'text/plain',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
HTTP_PORT = 9999
|
HTTP_PORT = 9999
|
||||||
|
PID_FILE_PATH = "/tmp/skydb.pids"
|
||||||
|
|
||||||
|
|
||||||
class SkyDebugger(object):
|
class SkyDebugger(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.paths = None
|
self.paths = None
|
||||||
|
self.pids = {}
|
||||||
|
# FIXME: This is not android aware nor aware of the port
|
||||||
|
# skyserver is listening on.
|
||||||
|
self.base_url = 'http://localhost:7777'
|
||||||
|
|
||||||
def _server_root_and_url_from_path_arg(self, url_or_path):
|
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.
|
# This is already a valid url we don't need a local server.
|
||||||
@ -46,19 +53,8 @@ class SkyDebugger(object):
|
|||||||
def _in_chromoting(self):
|
def _in_chromoting(self):
|
||||||
return os.environ.get('CHROME_REMOTE_DESKTOP_SESSION', False)
|
return os.environ.get('CHROME_REMOTE_DESKTOP_SESSION', False)
|
||||||
|
|
||||||
def main(self):
|
def _build_mojo_shell_command(self, args):
|
||||||
logging.basicConfig(level=logging.INFO)
|
sky_server = None
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description='Sky launcher/debugger')
|
|
||||||
parser.add_argument('--gdb', action='store_true')
|
|
||||||
parser.add_argument('--use-osmesa', action='store_true',
|
|
||||||
default=self._in_chromoting())
|
|
||||||
parser.add_argument('url_or_path', nargs='?', type=str)
|
|
||||||
parser.add_argument('--show-command', action='store_true',
|
|
||||||
help='Display the shell command and exit')
|
|
||||||
configuration.add_arguments(parser)
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
self.paths = Paths(os.path.join('out', args.configuration))
|
self.paths = Paths(os.path.join('out', args.configuration))
|
||||||
|
|
||||||
content_handlers = ['%s,%s' % (mime_type, 'mojo:sky_viewer')
|
content_handlers = ['%s,%s' % (mime_type, 'mojo:sky_viewer')
|
||||||
@ -73,33 +69,126 @@ class SkyDebugger(object):
|
|||||||
if args.use_osmesa:
|
if args.use_osmesa:
|
||||||
shell_command.append('--args-for=mojo:native_viewport_service --use-osmesa')
|
shell_command.append('--args-for=mojo:native_viewport_service --use-osmesa')
|
||||||
|
|
||||||
server_root = None
|
|
||||||
|
|
||||||
if args.url_or_path:
|
if args.url_or_path:
|
||||||
# Check if we need a local server for the url/path arg:
|
# Check if we need a local server for the url/path arg:
|
||||||
server_root, url = \
|
server_root, url = \
|
||||||
self._server_root_and_url_from_path_arg(args.url_or_path)
|
self._server_root_and_url_from_path_arg(args.url_or_path)
|
||||||
|
sky_server = SkyServer(self.paths, HTTP_PORT, args.configuration,
|
||||||
|
server_root)
|
||||||
|
|
||||||
prompt_args = '--args-for=mojo:sky_debugger_prompt %s' % url
|
prompt_args = '--args-for=mojo:sky_debugger_prompt %s' % url
|
||||||
shell_command.append(prompt_args)
|
shell_command.append(prompt_args)
|
||||||
|
|
||||||
if args.gdb:
|
if args.gdb:
|
||||||
shell_command = ['gdb', '--args'] + shell_command
|
shell_command = ['gdb', '--args'] + shell_command
|
||||||
|
|
||||||
if server_root:
|
return shell_command, sky_server
|
||||||
with SkyServer(self.paths, HTTP_PORT, args.configuration,
|
|
||||||
server_root):
|
def start_command(self, args):
|
||||||
subprocess.check_call(shell_command)
|
shell_command, sky_server = self._build_mojo_shell_command(args)
|
||||||
else:
|
|
||||||
subprocess.check_call(shell_command)
|
|
||||||
if args.show_command:
|
if args.show_command:
|
||||||
print " ".join(shell_command)
|
print " ".join(shell_command)
|
||||||
else:
|
return
|
||||||
subprocess.check_call(shell_command)
|
|
||||||
|
|
||||||
def shutdown(self):
|
self.stop_command([]) # Quit any existing process.
|
||||||
print "Quitting"
|
|
||||||
if self._sky_server:
|
if sky_server:
|
||||||
self._sky_server.terminate()
|
self.pids['sky_server_pid'] = sky_server.start()
|
||||||
|
# self.pids['sky_server_port'] = sky_server.port
|
||||||
|
# self.pids['sky_server_root'] = sky_server.root
|
||||||
|
self.pids['mojo_shell_pid'] = subprocess.Popen(shell_command).pid
|
||||||
|
|
||||||
|
def _kill_if_exists(self, key, name):
|
||||||
|
pid = self.pids.pop(key, None)
|
||||||
|
if not pid:
|
||||||
|
logging.info('No pid for %s, nothing to do.' % name)
|
||||||
|
return
|
||||||
|
logging.info('Killing %s (%s).' % (name, pid))
|
||||||
|
try:
|
||||||
|
os.kill(pid, signal.SIGTERM)
|
||||||
|
except OSError:
|
||||||
|
logging.info('%s (%s) already gone.' % (name, pid))
|
||||||
|
|
||||||
|
def stop_command(self, args):
|
||||||
|
# FIXME: Send /quit to sky prompt instead of killing.
|
||||||
|
# self._send_command_to_sky('/quit')
|
||||||
|
self._kill_if_exists('mojo_shell_pid', 'mojo_shell')
|
||||||
|
self._kill_if_exists('sky_server_pid', 'sky_server')
|
||||||
|
|
||||||
|
def load_command(self, args):
|
||||||
|
# Should resolve paths to relative urls like start does.
|
||||||
|
# self.pids['sky_server_root'] and port should help.
|
||||||
|
self._send_command_to_sky('/load', args.url_or_path)
|
||||||
|
|
||||||
|
def _send_command_to_sky(self, command_path, payload=None):
|
||||||
|
url = self.base_url + command_path
|
||||||
|
if payload:
|
||||||
|
response = requests.post(url, payload)
|
||||||
|
else:
|
||||||
|
response = requests.get(url)
|
||||||
|
print response.text
|
||||||
|
|
||||||
|
# FIXME: These could be made into a context object with __enter__/__exit__.
|
||||||
|
def _load_pid_file(self, path):
|
||||||
|
try:
|
||||||
|
with open(path, 'r') as pid_file:
|
||||||
|
return json.load(pid_file)
|
||||||
|
except:
|
||||||
|
if os.path.exists(path):
|
||||||
|
logging.warn('Failed to read pid file: %s' % path)
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def _write_pid_file(self, path, pids):
|
||||||
|
try:
|
||||||
|
with open(path, 'w') as pid_file:
|
||||||
|
json.dump(pids, pid_file)
|
||||||
|
except:
|
||||||
|
logging.warn('Failed to write pid file: %s' % path)
|
||||||
|
|
||||||
|
def _add_basic_command(self, subparsers, name, url_path, help_text):
|
||||||
|
parser = subparsers.add_parser(name, help=help_text)
|
||||||
|
command = lambda args: self._send_command_to_sky(url_path)
|
||||||
|
parser.set_defaults(func=command)
|
||||||
|
|
||||||
|
def main(self):
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
|
||||||
|
self.pids = self._load_pid_file(PID_FILE_PATH)
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description='Sky launcher/debugger')
|
||||||
|
subparsers = parser.add_subparsers(help='sub-command help')
|
||||||
|
|
||||||
|
start_parser = subparsers.add_parser('start',
|
||||||
|
help='launch a new mojo_shell with sky')
|
||||||
|
configuration.add_arguments(start_parser)
|
||||||
|
start_parser.add_argument('--gdb', action='store_true')
|
||||||
|
start_parser.add_argument('--use-osmesa', action='store_true',
|
||||||
|
default=self._in_chromoting())
|
||||||
|
start_parser.add_argument('url_or_path', nargs='?', type=str)
|
||||||
|
start_parser.add_argument('--show-command', action='store_true',
|
||||||
|
help='Display the shell command and exit')
|
||||||
|
start_parser.set_defaults(func=self.start_command)
|
||||||
|
|
||||||
|
stop_parser = subparsers.add_parser('stop',
|
||||||
|
help=('stop sky (as listed in %s)' % PID_FILE_PATH))
|
||||||
|
stop_parser.set_defaults(func=self.stop_command)
|
||||||
|
|
||||||
|
self._add_basic_command(subparsers, 'trace', '/trace',
|
||||||
|
'toggle tracing')
|
||||||
|
self._add_basic_command(subparsers, 'reload', '/reload',
|
||||||
|
'reload the current page')
|
||||||
|
self._add_basic_command(subparsers, 'inspect', '/inspect',
|
||||||
|
'stop the running sky instance')
|
||||||
|
|
||||||
|
load_parser = subparsers.add_parser('load',
|
||||||
|
help='load a new page in the currently running sky')
|
||||||
|
load_parser.add_argument('url_or_path', type=str)
|
||||||
|
load_parser.set_defaults(func=self.load_command)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
args.func(args)
|
||||||
|
|
||||||
|
self._write_pid_file(PID_FILE_PATH, self.pids)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
@ -26,7 +26,7 @@ class SkyServer(object):
|
|||||||
'download_sky_server'))
|
'download_sky_server'))
|
||||||
return os.path.join(paths.src_root, 'out', 'downloads', 'sky_server')
|
return os.path.join(paths.src_root, 'out', 'downloads', 'sky_server')
|
||||||
|
|
||||||
def __enter__(self):
|
def start(self):
|
||||||
if self._port_in_use(self.port):
|
if self._port_in_use(self.port):
|
||||||
logging.warn(
|
logging.warn(
|
||||||
'Port %s already in use, assuming custom sky_server started.' %
|
'Port %s already in use, assuming custom sky_server started.' %
|
||||||
@ -41,11 +41,18 @@ class SkyServer(object):
|
|||||||
str(self.port),
|
str(self.port),
|
||||||
]
|
]
|
||||||
self.server = subprocess.Popen(server_command)
|
self.server = subprocess.Popen(server_command)
|
||||||
|
return self.server.pid
|
||||||
|
|
||||||
def __exit__(self, exc_type, exc_value, traceback):
|
def stop(self):
|
||||||
if self.server:
|
if self.server:
|
||||||
self.server.terminate()
|
self.server.terminate()
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
self.start()
|
||||||
|
|
||||||
|
def __exit__(self, exc_type, exc_value, traceback):
|
||||||
|
self.stop()
|
||||||
|
|
||||||
def path_as_url(self, path):
|
def path_as_url(self, path):
|
||||||
return self.url_for_path(self.port, self.root, path)
|
return self.url_for_path(self.port, self.root, path)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user