Serve PolyGerrit static paths
PolyGerrit is a purely static web app. This means all UI-related endpoints just serve static content. In the developer case, the mapping looks like: / => polygerrit-ui/app/index.html /bower_components/* => polygerrit-ui/bower_components/* /* => polygerrit-ui/app/* In addition, PolyGerrit uses the HTML5 history API, which among other things replaces fragments used by GWT (#/c/1234) with actual paths (/c/1234). This means all paths formerly dispatched in Dispatcher.java have to be served as app/index.html, except for a few that are currently overlapping with the REST API (/projects and /groups/). We are still using PolyGerrit's native build system, which means the build steps in README.md need to be run on setup and any time dependencies change. This is the step that is responsible for setting up polygerrit-ui/bower_components/. In the compiled WAR case, lots of minification and inlining happens, so we just need to serve static content out of /polygerrit_ui/* in the WAR file. Note that WAR file integration is not implemented yet, since a) we need to tweak the buck build to allow this, and b) we need to do license auditing before inlining a bunch of code into the UI. Change-Id: I9d000f6fa1ae75e966593c174f43c9f366f7dcff
This commit is contained in:
@@ -14,20 +14,28 @@
|
||||
|
||||
package com.google.gerrit.httpd;
|
||||
|
||||
import org.eclipse.jgit.lib.Config;
|
||||
|
||||
public class GerritOptions {
|
||||
private final boolean headless;
|
||||
private final boolean slave;
|
||||
private final boolean polyGerrit;
|
||||
|
||||
public GerritOptions(boolean headless, boolean slave) {
|
||||
public GerritOptions(Config cfg, boolean headless, boolean slave) {
|
||||
this.headless = headless;
|
||||
this.slave = slave;
|
||||
this.polyGerrit = cfg.getBoolean("gerrit", null, "enablePolyGerrit", false);
|
||||
}
|
||||
|
||||
public boolean enableDefaultUi() {
|
||||
return !headless;
|
||||
return !headless && !polyGerrit;
|
||||
}
|
||||
|
||||
public boolean enableMasterFeatures() {
|
||||
return !slave;
|
||||
}
|
||||
|
||||
public boolean enablePolyGerrit() {
|
||||
return !headless && polyGerrit;
|
||||
}
|
||||
}
|
||||
|
@@ -107,7 +107,8 @@ class UrlModule extends ServletModule {
|
||||
|
||||
serve("/robots.txt").with(RobotsServlet.class);
|
||||
|
||||
install(new StaticModule());
|
||||
// Static paths are bound last, since they may include a wildcard for /*.
|
||||
install(new StaticModule(options));
|
||||
}
|
||||
|
||||
private Key<HttpServlet> notFound() {
|
||||
|
@@ -0,0 +1,35 @@
|
||||
// Copyright (C) 2015 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.httpd.raw;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
class PolyGerritUiIndexServlet extends ResourceServlet {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final Path index;
|
||||
|
||||
PolyGerritUiIndexServlet(Cache<Path, Resource> cache, Path ui) {
|
||||
super(cache, true);
|
||||
index = ui.resolve("index.html");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Path getResourcePath(String pathInfo) {
|
||||
return index;
|
||||
}
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
// Copyright (C) 2015 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.httpd.raw;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
class PolyGerritUiServlet extends ResourceServlet {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final Path ui;
|
||||
|
||||
PolyGerritUiServlet(Cache<Path, Resource> cache, Path ui) {
|
||||
super(cache, true);
|
||||
this.ui = ui;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Path getResourcePath(String pathInfo) {
|
||||
return ui.resolve(pathInfo);
|
||||
}
|
||||
}
|
@@ -118,7 +118,12 @@ public abstract class ResourceServlet extends HttpServlet {
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse rsp)
|
||||
throws IOException {
|
||||
String name = CharMatcher.is('/').trimFrom(req.getPathInfo());
|
||||
String name;
|
||||
if (req.getPathInfo() == null) {
|
||||
name = "/";
|
||||
} else {
|
||||
name = CharMatcher.is('/').trimFrom(req.getPathInfo());
|
||||
}
|
||||
if (isUnreasonableName(name)) {
|
||||
notFound(rsp);
|
||||
return;
|
||||
|
@@ -15,6 +15,7 @@
|
||||
package com.google.gerrit.httpd.raw;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.gerrit.httpd.GerritOptions;
|
||||
import com.google.gerrit.httpd.raw.ResourceServlet.Resource;
|
||||
import com.google.gerrit.launcher.GerritLauncher;
|
||||
import com.google.gerrit.server.cache.CacheModule;
|
||||
@@ -36,13 +37,16 @@ import javax.servlet.http.HttpServlet;
|
||||
|
||||
public class StaticModule extends ServletModule {
|
||||
private static final String GWT_UI_SERVLET = "GwtUiServlet";
|
||||
private static final String BOWER_SERVLET = "BowerServlet";
|
||||
static final String CACHE = "static_content";
|
||||
|
||||
private final GerritOptions options;
|
||||
private final FileSystem warFs;
|
||||
private final Path buckOut;
|
||||
private final Path unpackedWar;
|
||||
|
||||
public StaticModule() {
|
||||
public StaticModule(GerritOptions options) {
|
||||
this.options = options;
|
||||
warFs = getDistributionArchive();
|
||||
if (warFs == null) {
|
||||
buckOut = getDeveloperBuckOut();
|
||||
@@ -56,7 +60,6 @@ public class StaticModule extends ServletModule {
|
||||
@Override
|
||||
protected void configureServlets() {
|
||||
serve("/static/*").with(SiteStaticDirectoryServlet.class);
|
||||
serveGwtUi();
|
||||
install(new CacheModule() {
|
||||
@Override
|
||||
protected void configure() {
|
||||
@@ -65,6 +68,11 @@ public class StaticModule extends ServletModule {
|
||||
.weigher(ResourceServlet.Weigher.class);
|
||||
}
|
||||
});
|
||||
if (options.enablePolyGerrit()) {
|
||||
servePolyGerritUi();
|
||||
} else if (options.enableDefaultUi()) {
|
||||
serveGwtUi();
|
||||
}
|
||||
}
|
||||
|
||||
private void serveGwtUi() {
|
||||
@@ -75,6 +83,26 @@ public class StaticModule extends ServletModule {
|
||||
}
|
||||
}
|
||||
|
||||
private void servePolyGerritUi() {
|
||||
serve("/").with(PolyGerritUiIndexServlet.class);
|
||||
serve("/c/*").with(PolyGerritUiIndexServlet.class);
|
||||
serve("/q/*").with(PolyGerritUiIndexServlet.class);
|
||||
serve("/x/*").with(PolyGerritUiIndexServlet.class);
|
||||
serve("/admin/*").with(PolyGerritUiIndexServlet.class);
|
||||
serve("/dashboard/*").with(PolyGerritUiIndexServlet.class);
|
||||
serve("/settings/*").with(PolyGerritUiIndexServlet.class);
|
||||
// TODO(dborowitz): These fragments conflict with the REST API namespace, so
|
||||
// they will need to use a different path.
|
||||
//serve("/groups/*").with(PolyGerritUiIndexServlet.class);
|
||||
//serve("/projects/*").with(PolyGerritUiIndexServlet.class);
|
||||
|
||||
if (warFs == null) {
|
||||
serve("/bower_components/*")
|
||||
.with(Key.get(PolyGerritUiServlet.class, Names.named(BOWER_SERVLET)));
|
||||
}
|
||||
serve("/*").with(PolyGerritUiServlet.class);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@Named(GWT_UI_SERVLET)
|
||||
@@ -87,6 +115,35 @@ public class StaticModule extends ServletModule {
|
||||
}
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
PolyGerritUiIndexServlet getPolyGerritUiIndexServlet(
|
||||
@Named(CACHE) Cache<Path, Resource> cache) {
|
||||
return new PolyGerritUiIndexServlet(cache, polyGerritBasePath());
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
PolyGerritUiServlet getPolyGerritUiServlet(
|
||||
@Named(CACHE) Cache<Path, Resource> cache) {
|
||||
return new PolyGerritUiServlet(cache, polyGerritBasePath());
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@Named(BOWER_SERVLET)
|
||||
PolyGerritUiServlet getPolyGerritUiBowerServlet(
|
||||
@Named(CACHE) Cache<Path, Resource> cache) {
|
||||
return new PolyGerritUiServlet(cache,
|
||||
polyGerritBasePath().resolveSibling("bower_components"));
|
||||
}
|
||||
|
||||
private Path polyGerritBasePath() {
|
||||
return warFs != null
|
||||
? warFs.getPath("/polygerrit_ui")
|
||||
: buckOut.getParent().resolve("polygerrit-ui").resolve("app");
|
||||
}
|
||||
|
||||
private static FileSystem getDistributionArchive() {
|
||||
try {
|
||||
return GerritLauncher.getDistributionArchiveFileSystem();
|
||||
|
@@ -370,7 +370,8 @@ public class Daemon extends SiteProgram {
|
||||
modules.add(new AbstractModule() {
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(GerritOptions.class).toInstance(new GerritOptions(headless, slave));
|
||||
bind(GerritOptions.class)
|
||||
.toInstance(new GerritOptions(config, headless, slave));
|
||||
if (test) {
|
||||
bind(String.class).annotatedWith(SecureStoreClassName.class)
|
||||
.toInstance(DefaultSecureStore.class.getName());
|
||||
|
@@ -322,7 +322,8 @@ public class WebAppInitializer extends GuiceServletContextListener
|
||||
modules.add(new AbstractModule() {
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(GerritOptions.class).toInstance(new GerritOptions(false, false));
|
||||
bind(GerritOptions.class)
|
||||
.toInstance(new GerritOptions(config, false, false));
|
||||
}
|
||||
});
|
||||
modules.add(new GarbageCollectionModule());
|
||||
|
Reference in New Issue
Block a user