GWT SuperDevMode: Spawn codeserver and Daemon in same process
Simplify SDM experience by embedding codeserver and daemon in one process: no multiple launch configurations must be started and the output must not be captured in different IDE console windows. Unfortunately, as is Codeserver implementation is based on outdated Jetty. Replace WebServer.java from GWT project (same license like Gerrit itself, preserving the license header) and adjust it to run against Jetty 9 that is used by Gerrit. This also removes the need to fetch outdated Jetty version that we have just wiped out from gwt-dev.jar during download from Central. Change-Id: I616a53eb080d49a2bdf7a2211067b821af9f85d7
This commit is contained in:
parent
430d50527a
commit
9adf60e96f
@ -69,12 +69,6 @@ Duplicate the existing launch configuration:
|
||||
|
||||
=== Running Super Dev Mode
|
||||
|
||||
Install dependencies:
|
||||
|
||||
----
|
||||
buck build codeserver
|
||||
----
|
||||
|
||||
Due to codeserver not correctly identifying user agent problem, that was
|
||||
already fixed upstream but not released yet, the used user agent must be
|
||||
explicitly set in `GerritGwtUI.gwt.xml` for SDM to work:
|
||||
@ -91,8 +85,7 @@ or
|
||||
<set-property name="user.agent" value="safari" />
|
||||
----
|
||||
|
||||
* Select in Eclipse Run -> Debug Configurations `gerrit_gwt_codeserver.launch`
|
||||
* Select in Eclipse Run -> Debug Configurations `gerrit_daemon.launch`
|
||||
* Select in Eclipse Run -> Debug Configurations `gerrit_gwt_sdm_debug.launch`
|
||||
* Only once: add bookmarks for `Dev Mode On/Off` from codeserver URL:
|
||||
`http://localhost:9876/` to your bookmark bar
|
||||
* Make sure to activate source maps feature in your browser
|
||||
|
@ -1,11 +1,18 @@
|
||||
java_library(
|
||||
name = 'gwtdebug',
|
||||
srcs = ['src/main/java/com/google/gerrit/gwtdebug/GerritDebugLauncher.java'],
|
||||
srcs = glob(['src/main/java/**/*.java']),
|
||||
deps = [
|
||||
'//gerrit-pgm:pgm',
|
||||
'//gerrit-pgm:util',
|
||||
'//gerrit-util-cli:cli',
|
||||
'//lib/gwt:dev',
|
||||
'//lib/gwt:codeserver',
|
||||
'//lib/jetty:server',
|
||||
'//lib/jetty:servlet',
|
||||
'//lib/jetty:servlets',
|
||||
'//lib/jetty:webapp',
|
||||
'//lib/log:api',
|
||||
'//lib/log:log4j',
|
||||
],
|
||||
visibility = ['//tools/eclipse:classpath'],
|
||||
)
|
||||
|
@ -0,0 +1,80 @@
|
||||
// Copyright (C) 2014 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package com.google.gerrit.gwtdebug;
|
||||
|
||||
import com.google.gerrit.pgm.Daemon;
|
||||
import com.google.gwt.dev.codeserver.CodeServer;
|
||||
import com.google.gwt.dev.codeserver.Options;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
class GerritSDMLauncher {
|
||||
private static final Logger log = LoggerFactory.getLogger(GerritSDMLauncher.class);
|
||||
|
||||
public static void main(String[] argv) throws Exception {
|
||||
GerritSDMLauncher launcher = new GerritSDMLauncher();
|
||||
launcher.mainImpl(argv);
|
||||
}
|
||||
|
||||
private int mainImpl(String[] argv) {
|
||||
List<String> sdmLauncherOptions = new ArrayList<>();
|
||||
List<String> daemonLauncherOptions = new ArrayList<>();
|
||||
|
||||
// Separator between Daemon and Codeserver parameters is "--"
|
||||
boolean daemonArgumentSeparator = false;
|
||||
int i = 0;
|
||||
for (; i < argv.length; i++) {
|
||||
if (!argv[i].equals("--")) {
|
||||
sdmLauncherOptions.add(argv[i]);
|
||||
} else {
|
||||
daemonArgumentSeparator = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (daemonArgumentSeparator) {
|
||||
++i;
|
||||
for (; i < argv.length; i++) {
|
||||
daemonLauncherOptions.add(argv[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Options options = new Options();
|
||||
if (!options.parseArgs(sdmLauncherOptions.toArray(
|
||||
new String[sdmLauncherOptions.size()]))) {
|
||||
log.error("Failed to parse codeserver arguments");
|
||||
return 1;
|
||||
}
|
||||
|
||||
CodeServer.main(options);
|
||||
|
||||
try {
|
||||
int r = new Daemon().main(daemonLauncherOptions.toArray(
|
||||
new String[daemonLauncherOptions.size()]));
|
||||
if (r != 0) {
|
||||
log.error("Daemon exited with return code: " + r);
|
||||
return 1;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Cannot start daemon", e);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
@ -0,0 +1,513 @@
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package com.google.gwt.dev.codeserver;
|
||||
|
||||
import com.google.gwt.core.ext.TreeLogger;
|
||||
import com.google.gwt.core.ext.UnableToCompleteException;
|
||||
import com.google.gwt.dev.json.JsonArray;
|
||||
import com.google.gwt.dev.json.JsonObject;
|
||||
import org.eclipse.jetty.http.MimeTypes;
|
||||
import org.eclipse.jetty.server.HttpConnection;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.servlets.GzipFilter;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* The web server for Super Dev Mode, also known as the code server. The URLs handled include:
|
||||
* <ul>
|
||||
* <li>HTML pages for the front page and module pages</li>
|
||||
* <li>JavaScript that implementing the bookmarklets</li>
|
||||
* <li>The web API for recompiling a GWT app</li>
|
||||
* <li>The output files and log files from the GWT compiler</li>
|
||||
* <li>Java source code (for source-level debugging)</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>EXPERIMENTAL. There is no authentication, encryption, or XSS protection, so this server is
|
||||
* only safe to run on localhost.</p>
|
||||
*/
|
||||
// This file was copied from GWT project and adjusted to run against
|
||||
// Jetty 9.2.2. The original diff can be found here:
|
||||
// https://gwt-review.googlesource.com/#/c/7857/13/dev/codeserver/java/com/google/gwt/dev/codeserver/WebServer.java
|
||||
public class WebServer {
|
||||
|
||||
private static final Pattern SAFE_DIRECTORY =
|
||||
Pattern.compile("([a-zA-Z0-9_-]+\\.)*[a-zA-Z0-9_-]+"); // no extension needed
|
||||
|
||||
private static final Pattern SAFE_FILENAME =
|
||||
Pattern.compile("([a-zA-Z0-9_-]+\\.)+[a-zA-Z0-9_-]+"); // an extension is required
|
||||
|
||||
private static final Pattern SAFE_MODULE_PATH =
|
||||
Pattern.compile("/(" + SAFE_DIRECTORY + ")/$");
|
||||
|
||||
static final Pattern SAFE_DIRECTORY_PATH =
|
||||
Pattern.compile("/(" + SAFE_DIRECTORY + "/)+$");
|
||||
|
||||
/* visible for testing */
|
||||
static final Pattern SAFE_FILE_PATH =
|
||||
Pattern.compile("/(" + SAFE_DIRECTORY + "/)+" + SAFE_FILENAME + "$");
|
||||
|
||||
private static final Pattern SAFE_CALLBACK =
|
||||
Pattern.compile("([a-zA-Z_][a-zA-Z0-9_]*\\.)*[a-zA-Z_][a-zA-Z0-9_]*");
|
||||
|
||||
private static final MimeTypes MIME_TYPES = new MimeTypes();
|
||||
|
||||
private final SourceHandler handler;
|
||||
|
||||
private final Modules modules;
|
||||
|
||||
private final String bindAddress;
|
||||
private final int port;
|
||||
private final TreeLogger logger;
|
||||
private Server server;
|
||||
|
||||
WebServer(SourceHandler handler, Modules modules, String bindAddress, int port,
|
||||
TreeLogger logger) {
|
||||
this.handler = handler;
|
||||
this.modules = modules;
|
||||
this.bindAddress = bindAddress;
|
||||
this.port = port;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public void start() throws UnableToCompleteException {
|
||||
|
||||
Server newServer = new Server();
|
||||
ServerConnector connector = new ServerConnector(newServer);
|
||||
connector.setHost(bindAddress);
|
||||
connector.setPort(port);
|
||||
connector.setReuseAddress(false);
|
||||
connector.setSoLingerTime(0);
|
||||
newServer.addConnector(connector);
|
||||
|
||||
ServletContextHandler handler = new ServletContextHandler(ServletContextHandler.SESSIONS);
|
||||
handler.setContextPath("/");
|
||||
handler.addServlet(new ServletHolder(new HttpServlet() {
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
handleRequest(request.getPathInfo(), request, response);
|
||||
}
|
||||
}), "/*");
|
||||
handler.addFilter(GzipFilter.class, "/*", EnumSet.allOf(DispatcherType.class));
|
||||
newServer.setHandler(handler);
|
||||
try {
|
||||
newServer.start();
|
||||
} catch (Exception e) {
|
||||
logger.log(TreeLogger.ERROR, "cannot start web server", e);
|
||||
throw new UnableToCompleteException();
|
||||
}
|
||||
this.server = newServer;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public void stop() throws Exception {
|
||||
server.stop();
|
||||
server = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the location of the compiler output. (Changes after every recompile.)
|
||||
*/
|
||||
public File getCurrentWarDir(String moduleName) {
|
||||
return modules.get(moduleName).getWarDir();
|
||||
}
|
||||
|
||||
private void handleRequest(String target, HttpServletRequest request,
|
||||
HttpServletResponse response)
|
||||
throws IOException {
|
||||
|
||||
if (request.getMethod().equalsIgnoreCase("get")) {
|
||||
doGet(target, request, response);
|
||||
}
|
||||
}
|
||||
|
||||
private void doGet(String target, HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException {
|
||||
|
||||
if (!target.endsWith(".cache.js")) {
|
||||
// Make sure IE9 doesn't cache any pages.
|
||||
// (Nearly all pages may change on server restart.)
|
||||
PageUtil.setNoCacheHeaders(response);
|
||||
}
|
||||
|
||||
if (target.equals("/")) {
|
||||
setHandled(request);
|
||||
JsonObject config = makeConfig();
|
||||
PageUtil.sendJsonAndHtml("config", config, "frontpage.html", response, logger);
|
||||
return;
|
||||
}
|
||||
|
||||
if (target.equals("/dev_mode_on.js")) {
|
||||
setHandled(request);
|
||||
JsonObject config = makeConfig();
|
||||
PageUtil
|
||||
.sendJsonAndJavaScript("__gwt_codeserver_config", config, "dev_mode_on.js", response,
|
||||
logger);
|
||||
return;
|
||||
}
|
||||
|
||||
// Recompile on request from the bookmarklet.
|
||||
// This is a GET because a bookmarklet can call it from a different origin (JSONP).
|
||||
if (target.startsWith("/recompile/")) {
|
||||
setHandled(request);
|
||||
String moduleName = target.substring("/recompile/".length());
|
||||
ModuleState moduleState = modules.get(moduleName);
|
||||
if (moduleState == null) {
|
||||
response.sendError(HttpServletResponse.SC_NOT_FOUND);
|
||||
logger.log(TreeLogger.WARN, "not found: " + target);
|
||||
return;
|
||||
}
|
||||
|
||||
// We are passing properties from an unauthenticated GET request directly to the compiler.
|
||||
// This should be safe, but only because these are binding properties. For each binding
|
||||
// property, you can only choose from a set of predefined values. So all an attacker can do is
|
||||
// cause a spurious recompile, resulting in an unexpected permutation being loaded later.
|
||||
//
|
||||
// It would be unsafe to allow a configuration property to be changed.
|
||||
boolean ok = moduleState.recompile(getBindingProperties(request));
|
||||
|
||||
JsonObject config = makeConfig();
|
||||
config.put("status", ok ? "ok" : "failed");
|
||||
sendJsonpPage(config, request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
if (target.startsWith("/log/")) {
|
||||
setHandled(request);
|
||||
String moduleName = target.substring("/log/".length());
|
||||
File file = modules.get(moduleName).getCompileLog();
|
||||
sendLogPage(moduleName, file, response);
|
||||
return;
|
||||
}
|
||||
|
||||
if (target.equals("/favicon.ico")) {
|
||||
InputStream faviconStream = getClass().getResourceAsStream("favicon.ico");
|
||||
if (faviconStream != null) {
|
||||
setHandled(request);
|
||||
// IE8 will not load the favicon in an img tag with the default MIME type,
|
||||
// so use "image/x-icon" instead.
|
||||
PageUtil.sendStream("image/x-icon", faviconStream, response);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (target.equals("/policies/")) {
|
||||
setHandled(request);
|
||||
sendPolicyIndex(response);
|
||||
return;
|
||||
}
|
||||
|
||||
Matcher matcher = SAFE_MODULE_PATH.matcher(target);
|
||||
if (matcher.matches()) {
|
||||
setHandled(request);
|
||||
sendModulePage(matcher.group(1), response);
|
||||
return;
|
||||
}
|
||||
|
||||
matcher = SAFE_DIRECTORY_PATH.matcher(target);
|
||||
if (matcher.matches() && handler.isSourceMapRequest(target)) {
|
||||
setHandled(request);
|
||||
handler.handle(target, request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
matcher = SAFE_FILE_PATH.matcher(target);
|
||||
if (matcher.matches()) {
|
||||
setHandled(request);
|
||||
if (handler.isSourceMapRequest(target)) {
|
||||
handler.handle(target, request, response);
|
||||
return;
|
||||
}
|
||||
if (target.startsWith("/policies/")) {
|
||||
sendPolicyFile(target, response);
|
||||
return;
|
||||
}
|
||||
sendOutputFile(target, request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
logger.log(TreeLogger.WARN, "ignored get request: " + target);
|
||||
}
|
||||
|
||||
private void sendOutputFile(String target, HttpServletRequest request,
|
||||
HttpServletResponse response) throws IOException {
|
||||
|
||||
int secondSlash = target.indexOf('/', 1);
|
||||
String moduleName = target.substring(1, secondSlash);
|
||||
ModuleState moduleState = modules.get(moduleName);
|
||||
|
||||
File file = moduleState.getOutputFile(target);
|
||||
if (!file.isFile()) {
|
||||
// perhaps it's compressed
|
||||
file = moduleState.getOutputFile(target + ".gz");
|
||||
if (!file.isFile()) {
|
||||
response.sendError(HttpServletResponse.SC_NOT_FOUND);
|
||||
logger.log(TreeLogger.WARN, "not found: " + file.toString());
|
||||
return;
|
||||
}
|
||||
if (!request.getHeader("Accept-Encoding").contains("gzip")) {
|
||||
response.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
|
||||
logger.log(TreeLogger.WARN, "client doesn't accept gzip; bailing");
|
||||
return;
|
||||
}
|
||||
response.setHeader("Content-Encoding", "gzip");
|
||||
}
|
||||
|
||||
if (target.endsWith(".cache.js")) {
|
||||
response.setHeader("X-SourceMap", sourceMapLocationForModule(moduleName));
|
||||
}
|
||||
response.setHeader("Access-Control-Allow-Origin", "*");
|
||||
String mimeType = guessMimeType(target);
|
||||
PageUtil.sendFile(mimeType, file, response);
|
||||
}
|
||||
|
||||
private void sendModulePage(String moduleName, HttpServletResponse response) throws IOException {
|
||||
ModuleState module = modules.get(moduleName);
|
||||
if (module == null) {
|
||||
response.sendError(HttpServletResponse.SC_NOT_FOUND);
|
||||
logger.log(TreeLogger.WARN, "module not found: " + moduleName);
|
||||
return;
|
||||
}
|
||||
PageUtil
|
||||
.sendJsonAndHtml("config", module.getTemplateVariables(), "modulepage.html", response,
|
||||
logger);
|
||||
}
|
||||
|
||||
private void sendPolicyIndex(HttpServletResponse response) throws IOException {
|
||||
|
||||
response.setContentType("text/html");
|
||||
|
||||
HtmlWriter out = new HtmlWriter(response.getWriter());
|
||||
|
||||
out.startTag("html").nl();
|
||||
out.startTag("head").nl();
|
||||
out.startTag("title").text("Policy Files").endTag("title").nl();
|
||||
out.endTag("head");
|
||||
out.startTag("body");
|
||||
|
||||
out.startTag("h1").text("Policy Files").endTag("h1").nl();
|
||||
|
||||
for (String moduleName : modules) {
|
||||
ModuleState module = modules.get(moduleName);
|
||||
File manifest = module.getExtraFile("rpcPolicyManifest/manifest.txt");
|
||||
if (manifest.isFile()) {
|
||||
out.startTag("h2").text(moduleName).endTag("h2").nl();
|
||||
|
||||
out.startTag("table").nl();
|
||||
String text = PageUtil.loadFile(manifest);
|
||||
for (String line : text.split("\n")) {
|
||||
line = line.trim();
|
||||
if (line.isEmpty() || line.startsWith("#")) {
|
||||
continue;
|
||||
}
|
||||
String[] fields = line.split(", ");
|
||||
if (fields.length < 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String serviceName = fields[0];
|
||||
String policyFileName = fields[1];
|
||||
|
||||
String serviceUrl = SourceHandler.SOURCEMAP_PATH + moduleName + "/" +
|
||||
serviceName.replace('.', '/') + ".java";
|
||||
String policyUrl = "/policies/" + policyFileName;
|
||||
|
||||
out.startTag("tr");
|
||||
|
||||
out.startTag("td");
|
||||
out.startTag("a", "href=", serviceUrl).text(serviceName).endTag("a");
|
||||
out.endTag("td");
|
||||
|
||||
out.startTag("td");
|
||||
out.startTag("a", "href=", policyUrl).text(policyFileName).endTag("a");
|
||||
out.endTag("td");
|
||||
|
||||
out.endTag("tr").nl();
|
||||
}
|
||||
out.endTag("table").nl();
|
||||
}
|
||||
}
|
||||
|
||||
out.endTag("body").nl();
|
||||
out.endTag("html").nl();
|
||||
}
|
||||
|
||||
private void sendPolicyFile(String target, HttpServletResponse response) throws IOException {
|
||||
int secondSlash = target.indexOf('/', 1);
|
||||
if (secondSlash < 1) {
|
||||
response.sendError(HttpServletResponse.SC_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
String rest = target.substring(secondSlash + 1);
|
||||
if (rest.contains("/") || !rest.endsWith(".gwt.rpc")) {
|
||||
response.sendError(HttpServletResponse.SC_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
for (String moduleName : modules) {
|
||||
ModuleState module = modules.get(moduleName);
|
||||
File policy = module.getOutputFile(moduleName + "/" + rest);
|
||||
if (policy.isFile()) {
|
||||
PageUtil.sendFile("text/plain", policy, response);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
logger.log(TreeLogger.Type.WARN, "policy file not found: " + rest);
|
||||
response.sendError(HttpServletResponse.SC_NOT_FOUND);
|
||||
}
|
||||
|
||||
private JsonObject makeConfig() {
|
||||
JsonArray moduleNames = new JsonArray();
|
||||
for (String module : modules) {
|
||||
moduleNames.add(module);
|
||||
}
|
||||
JsonObject config = JsonObject.create();
|
||||
config.put("moduleNames", moduleNames);
|
||||
return config;
|
||||
}
|
||||
|
||||
private void sendJsonpPage(JsonObject json, HttpServletRequest request,
|
||||
HttpServletResponse response) throws IOException {
|
||||
|
||||
response.setStatus(HttpServletResponse.SC_OK);
|
||||
response.setContentType("application/javascript");
|
||||
PrintWriter out = response.getWriter();
|
||||
|
||||
String callbackExpression = request.getParameter("_callback");
|
||||
if (callbackExpression == null || !SAFE_CALLBACK.matcher(callbackExpression).matches()) {
|
||||
logger.log(TreeLogger.ERROR, "invalid callback: " + callbackExpression);
|
||||
out.print("/* invalid callback parameter */");
|
||||
return;
|
||||
}
|
||||
|
||||
out.print(callbackExpression + "(");
|
||||
json.write(out);
|
||||
out.println(");");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the log file as html with errors highlighted in red.
|
||||
*/
|
||||
private void sendLogPage(String moduleName, File file, HttpServletResponse response)
|
||||
throws IOException {
|
||||
BufferedReader reader = new BufferedReader(new FileReader(file));
|
||||
|
||||
response.setStatus(HttpServletResponse.SC_OK);
|
||||
response.setContentType("text/html");
|
||||
response.setHeader("Content-Style-Type", "text/css");
|
||||
|
||||
HtmlWriter out = new HtmlWriter(response.getWriter());
|
||||
out.startTag("html").nl();
|
||||
out.startTag("head").nl();
|
||||
out.startTag("title").text(moduleName + " compile log").endTag("title").nl();
|
||||
out.startTag("style").nl();
|
||||
out.text(".error { color: red; font-weight: bold; }").nl();
|
||||
out.endTag("style").nl();
|
||||
out.endTag("head").nl();
|
||||
out.startTag("body").nl();
|
||||
sendLogAsHtml(reader, out);
|
||||
out.endTag("body").nl();
|
||||
out.endTag("html").nl();
|
||||
}
|
||||
|
||||
private static final Pattern ERROR_PATTERN = Pattern.compile("\\[ERROR\\]");
|
||||
|
||||
/**
|
||||
* Copies in to out line by line, escaping each line for html characters and highlighting
|
||||
* error lines. Closes <code>in</code> when done.
|
||||
*/
|
||||
private static void sendLogAsHtml(BufferedReader in, HtmlWriter out) throws IOException {
|
||||
try {
|
||||
out.startTag("pre").nl();
|
||||
String line = in.readLine();
|
||||
while (line != null) {
|
||||
Matcher m = ERROR_PATTERN.matcher(line);
|
||||
boolean error = m.find();
|
||||
if (error) {
|
||||
out.startTag("span", "class=", "error");
|
||||
}
|
||||
out.text(line);
|
||||
if (error) {
|
||||
out.endTag("span");
|
||||
}
|
||||
out.nl(); // the readLine doesn't include the newline.
|
||||
line = in.readLine();
|
||||
}
|
||||
out.endTag("pre").nl();
|
||||
} finally {
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
|
||||
/* visible for testing */
|
||||
static String guessMimeType(String filename) {
|
||||
String mimeType = MIME_TYPES.getMimeByExtension(filename);
|
||||
return mimeType != null ? mimeType : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the binding properties from the web page where dev mode is being used. (As passed in
|
||||
* by dev_mode_on.js in a JSONP request to "/recompile".)
|
||||
*/
|
||||
private Map<String, String> getBindingProperties(HttpServletRequest request) {
|
||||
Map<String, String> result = new HashMap<String, String>();
|
||||
for (Object key : request.getParameterMap().keySet()) {
|
||||
String propName = (String) key;
|
||||
if (!propName.equals("_callback")) {
|
||||
result.put(propName, request.getParameter(propName));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static String sourceMapLocationForModule(String moduleName) {
|
||||
return SourceHandler.SOURCEMAP_PATH + moduleName +
|
||||
"/gwtSourceMap.json";
|
||||
}
|
||||
|
||||
private static void setHandled(HttpServletRequest request) {
|
||||
Request baseRequest = (request instanceof Request) ? (Request) request :
|
||||
HttpConnection.getCurrentConnection().getHttpChannel().getRequest();
|
||||
baseRequest.setHandled(true);
|
||||
}
|
||||
}
|
@ -79,6 +79,7 @@ java_library(
|
||||
],
|
||||
visibility = [
|
||||
'//gerrit-acceptance-tests/...',
|
||||
'//gerrit-gwtdebug:gwtdebug',
|
||||
'//gerrit-war:',
|
||||
],
|
||||
)
|
||||
@ -133,6 +134,7 @@ java_library(
|
||||
visibility = [
|
||||
'//:',
|
||||
'//gerrit-acceptance-tests/...',
|
||||
'//gerrit-gwtdebug:gwtdebug',
|
||||
'//tools/eclipse:classpath',
|
||||
'//Documentation:licenses.txt',
|
||||
],
|
||||
|
20
lib/gwt/BUCK
20
lib/gwt/BUCK
@ -31,7 +31,6 @@ maven_jar(
|
||||
license = 'Apache2.0',
|
||||
deps = [
|
||||
':dev',
|
||||
':legacy-jetty-servlet-aggregate',
|
||||
],
|
||||
attach_source = False,
|
||||
)
|
||||
@ -72,22 +71,3 @@ maven_jar(
|
||||
license = 'Apache2.0',
|
||||
visibility = [],
|
||||
)
|
||||
|
||||
maven_jar(
|
||||
name = 'legacy-jetty-servlet-aggregate',
|
||||
id = 'org.eclipse.jetty.aggregate:jetty-servlet:8.1.12.v20130726',
|
||||
sha1 = '4d0f0cb6e5a54de01be46717a7ab48d0b45dcadd',
|
||||
license = 'Apache2.0',
|
||||
attach_source = False,
|
||||
deps = [':legacy-jetty-servlets'],
|
||||
visibility = [],
|
||||
)
|
||||
|
||||
maven_jar(
|
||||
name = 'legacy-jetty-servlets',
|
||||
id = 'org.eclipse.jetty:jetty-servlets:8.1.12.v20130726',
|
||||
sha1 = '4ebc6894b899fee0c3597697d11f255ce9214bbf',
|
||||
license = 'Apache2.0',
|
||||
attach_source = False,
|
||||
visibility = [],
|
||||
)
|
||||
|
@ -38,6 +38,18 @@ maven_jar(
|
||||
],
|
||||
)
|
||||
|
||||
maven_jar(
|
||||
name = 'servlets',
|
||||
id = 'org.eclipse.jetty:jetty-servlets:' + VERSION,
|
||||
sha1 = '36053479af8213a14d320845e5b5b1b595778f74',
|
||||
license = 'Apache2.0',
|
||||
exclude = EXCLUDE,
|
||||
visibility = [
|
||||
'//tools/eclipse:classpath',
|
||||
'//gerrit-gwtdebug:gwtdebug',
|
||||
],
|
||||
)
|
||||
|
||||
maven_jar(
|
||||
name = 'xml',
|
||||
id = 'org.eclipse.jetty:jetty-xml:' + VERSION,
|
||||
|
@ -19,6 +19,8 @@ java_library(
|
||||
'//lib/bouncycastle:bcprov',
|
||||
'//lib/bouncycastle:bcpg',
|
||||
'//lib/bouncycastle:bcpkix',
|
||||
'//lib/gwt:codeserver',
|
||||
'//lib/jetty:servlets',
|
||||
'//lib/jetty:webapp',
|
||||
'//lib/prolog:compiler_lib',
|
||||
'//Documentation:index_lib',
|
||||
|
@ -1,10 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
|
||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
|
||||
<listEntry value="/gerrit"/>
|
||||
<listEntry value="/gerrit/gerrit-gwtdebug/src/main/java/com/google/gerrit/gwtdebug/GerritSDMLauncher.java"/>
|
||||
</listAttribute>
|
||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
|
||||
<listEntry value="4"/>
|
||||
<listEntry value="1"/>
|
||||
</listAttribute>
|
||||
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
|
||||
<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
|
||||
@ -12,14 +12,12 @@
|
||||
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
|
||||
<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry containerPath="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7" javaProject="gerrit" path="1" type="4"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/gerrit/buck-out/gen/lib/gwt/legacy-jetty-servlet-aggregate/jetty-servlet-8.1.12.v20130726.jar" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/gerrit/buck-out/gen/lib/gwt/codeserver/gwt-codeserver-2.6.1.jar" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/gerrit/buck-out/gen/lib/gwt/legacy-jetty-servlets/jetty-servlets-8.1.12.v20130726.jar" path="3" type="2"/> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry id="org.eclipse.jdt.launching.classpathentry.defaultClasspath"> <memento exportedEntriesOnly="false" project="gerrit"/> </runtimeClasspathEntry> "/>
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/gerrit/buck-out/gen/lib/gwt/codeserver/gwt-codeserver-2.6.1.jar" path="3" type="2"/> "/>
|
||||
</listAttribute>
|
||||
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.codeserver.CodeServer"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-noprecompile -src ${resource_loc:/gerrit} -workDir ${resource_loc:/gerrit}/buck-out/gen/gerrit-gwtui com.google.gerrit.GerritGwtUI"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gerrit.gwtdebug.GerritSDMLauncher"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-noprecompile -src ${resource_loc:/gerrit} -workDir ${resource_loc:/gerrit}/buck-out/gen/gerrit-gwtui com.google.gerrit.GerritGwtUI -- --console-log --show-stack-trace -d ${resource_loc:/gerrit}/../gerrit_testsite"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="gerrit"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx1024M -XX:MaxPermSize=256M"/>
|
||||
</launchConfiguration>
|
Loading…
Reference in New Issue
Block a user