From 9adf60e96fdce8c62cd33e0b6dd8fa6a45846932 Mon Sep 17 00:00:00 2001 From: David Ostrovsky Date: Mon, 18 Aug 2014 08:46:13 +0200 Subject: [PATCH] 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 --- Documentation/dev-eclipse.txt | 9 +- gerrit-gwtdebug/BUCK | 9 +- .../gerrit/gwtdebug/GerritSDMLauncher.java | 80 +++ .../google/gwt/dev/codeserver/WebServer.java | 513 ++++++++++++++++++ gerrit-pgm/BUCK | 2 + lib/gwt/BUCK | 20 - lib/jetty/BUCK | 12 + tools/eclipse/BUCK | 2 + ...ver.launch => gerrit_gwt_sdm_debug.launch} | 12 +- 9 files changed, 623 insertions(+), 36 deletions(-) create mode 100644 gerrit-gwtdebug/src/main/java/com/google/gerrit/gwtdebug/GerritSDMLauncher.java create mode 100644 gerrit-gwtdebug/src/main/java/com/google/gwt/dev/codeserver/WebServer.java rename tools/eclipse/{gerrit_gwt_codeserver.launch => gerrit_gwt_sdm_debug.launch} (69%) diff --git a/Documentation/dev-eclipse.txt b/Documentation/dev-eclipse.txt index d8db555909..ba55268b43 100644 --- a/Documentation/dev-eclipse.txt +++ b/Documentation/dev-eclipse.txt @@ -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 ---- -* 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 diff --git a/gerrit-gwtdebug/BUCK b/gerrit-gwtdebug/BUCK index a926773a1a..2e8949b0d1 100644 --- a/gerrit-gwtdebug/BUCK +++ b/gerrit-gwtdebug/BUCK @@ -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'], ) diff --git a/gerrit-gwtdebug/src/main/java/com/google/gerrit/gwtdebug/GerritSDMLauncher.java b/gerrit-gwtdebug/src/main/java/com/google/gerrit/gwtdebug/GerritSDMLauncher.java new file mode 100644 index 0000000000..bc26330a12 --- /dev/null +++ b/gerrit-gwtdebug/src/main/java/com/google/gerrit/gwtdebug/GerritSDMLauncher.java @@ -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 sdmLauncherOptions = new ArrayList<>(); + List 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; + } +} diff --git a/gerrit-gwtdebug/src/main/java/com/google/gwt/dev/codeserver/WebServer.java b/gerrit-gwtdebug/src/main/java/com/google/gwt/dev/codeserver/WebServer.java new file mode 100644 index 0000000000..8eb1300f75 --- /dev/null +++ b/gerrit-gwtdebug/src/main/java/com/google/gwt/dev/codeserver/WebServer.java @@ -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: + *
    + *
  • HTML pages for the front page and module pages
  • + *
  • JavaScript that implementing the bookmarklets
  • + *
  • The web API for recompiling a GWT app
  • + *
  • The output files and log files from the GWT compiler
  • + *
  • Java source code (for source-level debugging)
  • + *
+ * + *

EXPERIMENTAL. There is no authentication, encryption, or XSS protection, so this server is + * only safe to run on localhost.

+ */ +// 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 in 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 getBindingProperties(HttpServletRequest request) { + Map result = new HashMap(); + 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); + } +} diff --git a/gerrit-pgm/BUCK b/gerrit-pgm/BUCK index cffc0c1616..3de5a2ac91 100644 --- a/gerrit-pgm/BUCK +++ b/gerrit-pgm/BUCK @@ -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', ], diff --git a/lib/gwt/BUCK b/lib/gwt/BUCK index 3bf514d346..3e9908b3a4 100644 --- a/lib/gwt/BUCK +++ b/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 = [], -) diff --git a/lib/jetty/BUCK b/lib/jetty/BUCK index 13e977457b..2e3d84dbec 100644 --- a/lib/jetty/BUCK +++ b/lib/jetty/BUCK @@ -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, diff --git a/tools/eclipse/BUCK b/tools/eclipse/BUCK index 2cc66a08e7..598f727567 100644 --- a/tools/eclipse/BUCK +++ b/tools/eclipse/BUCK @@ -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', diff --git a/tools/eclipse/gerrit_gwt_codeserver.launch b/tools/eclipse/gerrit_gwt_sdm_debug.launch similarity index 69% rename from tools/eclipse/gerrit_gwt_codeserver.launch rename to tools/eclipse/gerrit_gwt_sdm_debug.launch index e7f5206eef..cd5313a2d2 100644 --- a/tools/eclipse/gerrit_gwt_codeserver.launch +++ b/tools/eclipse/gerrit_gwt_sdm_debug.launch @@ -1,10 +1,10 @@ - + - + @@ -12,14 +12,12 @@ - - - + - - + +