diff --git a/java/com/google/gerrit/httpd/init/WebAppInitializer.java b/java/com/google/gerrit/httpd/init/WebAppInitializer.java
index 769396eca7..05992d4b40 100644
--- a/java/com/google/gerrit/httpd/init/WebAppInitializer.java
+++ b/java/com/google/gerrit/httpd/init/WebAppInitializer.java
@@ -338,7 +338,7 @@ public class WebAppInitializer extends GuiceServletContextListener implements Fi
new AbstractModule() {
@Override
protected void configure() {
- bind(GerritOptions.class).toInstance(new GerritOptions(false, false, false));
+ bind(GerritOptions.class).toInstance(new GerritOptions(false, false, ""));
bind(GerritRuntime.class).toInstance(GerritRuntime.DAEMON);
}
});
diff --git a/java/com/google/gerrit/httpd/raw/BazelBuild.java b/java/com/google/gerrit/httpd/raw/BazelBuild.java
deleted file mode 100644
index 7677e97458..0000000000
--- a/java/com/google/gerrit/httpd/raw/BazelBuild.java
+++ /dev/null
@@ -1,160 +0,0 @@
-// Copyright (C) 2016 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 static com.google.common.base.MoreObjects.firstNonNull;
-import static java.nio.charset.StandardCharsets.UTF_8;
-
-import com.google.common.base.Joiner;
-import com.google.common.escape.Escaper;
-import com.google.common.flogger.FluentLogger;
-import com.google.common.html.HtmlEscapers;
-import com.google.common.io.ByteStreams;
-import com.google.gerrit.launcher.GerritLauncher;
-import com.google.gerrit.server.util.time.TimeUtil;
-import com.google.gerrit.util.http.CacheHeaders;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InterruptedIOException;
-import java.io.PrintWriter;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Properties;
-import javax.servlet.http.HttpServletResponse;
-import org.eclipse.jgit.util.RawParseUtils;
-
-public class BazelBuild {
- private static final FluentLogger logger = FluentLogger.forEnclosingClass();
-
- private final Path sourceRoot;
-
- public BazelBuild(Path sourceRoot) {
- this.sourceRoot = sourceRoot;
- }
-
- // builds the given label.
- public void build(Label label) throws IOException, BuildFailureException {
- ProcessBuilder proc = newBuildProcess(label);
- proc.directory(sourceRoot.toFile()).redirectErrorStream(true);
- logger.atInfo().log("building %s", label.fullName());
- long start = TimeUtil.nowMs();
- Process rebuild = proc.start();
- byte[] out;
- try (InputStream in = rebuild.getInputStream()) {
- out = ByteStreams.toByteArray(in);
- } finally {
- rebuild.getOutputStream().close();
- }
-
- int status;
- try {
- status = rebuild.waitFor();
- } catch (InterruptedException e) {
- String msg = "interrupted waiting for: " + Joiner.on(' ').join(proc.command());
- logger.atSevere().withCause(e).log(msg);
- throw new InterruptedIOException(msg);
- }
- if (status != 0) {
- logger.atWarning().log("build failed: %s", new String(out, UTF_8));
- throw new BuildFailureException(out);
- }
-
- long time = TimeUtil.nowMs() - start;
- logger.atInfo().log("UPDATED %s in %.3fs", label.fullName(), time / 1000.0);
- }
-
- // Represents a label in bazel.
- static class Label {
- protected final String pkg;
- protected final String name;
-
- public String fullName() {
- return "//" + pkg + ":" + name;
- }
-
- @Override
- public String toString() {
- return fullName();
- }
-
- // Label in Bazel style.
- Label(String pkg, String name) {
- this.name = name;
- this.pkg = pkg;
- }
- }
-
- static class BuildFailureException extends Exception {
- private static final long serialVersionUID = 1L;
-
- final byte[] why;
-
- BuildFailureException(byte[] why) {
- this.why = why;
- }
-
- public void display(String rule, HttpServletResponse res) throws IOException {
- res.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
- res.setContentType("text/html");
- res.setCharacterEncoding(UTF_8.name());
- CacheHeaders.setNotCacheable(res);
-
- Escaper html = HtmlEscapers.htmlEscaper();
- try (PrintWriter w = res.getWriter()) {
- w.write("
BUILD FAILED");
- w.format("%s FAILED
", html.escape(rule));
- w.write("");
- w.write(html.escape(RawParseUtils.decode(why)));
- w.write("
");
- w.write("");
- }
- }
- }
-
- private ProcessBuilder newBuildProcess(Label label) throws IOException {
- Properties properties = GerritLauncher.loadBuildProperties(sourceRoot.resolve(".bazel_path"));
- String bazel = firstNonNull(properties.getProperty("bazel"), "bazel");
- List cmd = new ArrayList<>();
- cmd.add(bazel);
- cmd.add("build");
- if (GerritLauncher.isJdk9OrLater()) {
- String v = GerritLauncher.getJdkVersionPostJdk8();
- cmd.add("--host_java_toolchain=@bazel_tools//tools/jdk:toolchain_java" + v);
- cmd.add("--java_toolchain=@bazel_tools//tools/jdk:toolchain_java" + v);
- }
- cmd.add(label.fullName());
- ProcessBuilder proc = new ProcessBuilder(cmd);
- if (properties.containsKey("PATH")) {
- proc.environment().put("PATH", properties.getProperty("PATH"));
- }
- return proc;
- }
-
- /** returns the root relative path to the artifact for the given label */
- public Path targetPath(Label l) {
- return sourceRoot.resolve("bazel-bin").resolve(l.pkg).resolve(l.name);
- }
-
- /** Label for the polygerrit component zip. */
- public Label polygerritComponents() {
- return new Label("polygerrit-ui", "polygerrit_components.bower_components.zip");
- }
-
- /** Label for the fonts zip file. */
- public Label fontZipLabel() {
- return new Label("polygerrit-ui", "fonts.zip");
- }
-}
diff --git a/java/com/google/gerrit/httpd/raw/BowerComponentsDevServlet.java b/java/com/google/gerrit/httpd/raw/BowerComponentsDevServlet.java
deleted file mode 100644
index 1be304590d..0000000000
--- a/java/com/google/gerrit/httpd/raw/BowerComponentsDevServlet.java
+++ /dev/null
@@ -1,49 +0,0 @@
-// 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 com.google.gerrit.launcher.GerritLauncher;
-import java.io.IOException;
-import java.nio.file.Path;
-import java.util.Objects;
-
-/* Bower component servlet only used in development mode */
-class BowerComponentsDevServlet extends ResourceServlet {
- private static final long serialVersionUID = 1L;
-
- private final Path bowerComponents;
- private final Path zip;
-
- BowerComponentsDevServlet(Cache cache, BazelBuild builder) throws IOException {
- super(cache, true);
-
- Objects.requireNonNull(builder);
- BazelBuild.Label label = builder.polygerritComponents();
- try {
- builder.build(label);
- } catch (BazelBuild.BuildFailureException e) {
- throw new IOException(e);
- }
-
- zip = builder.targetPath(label);
- bowerComponents = GerritLauncher.newZipFileSystem(zip).getPath("/");
- }
-
- @Override
- protected Path getResourcePath(String pathInfo) throws IOException {
- return bowerComponents.resolve(pathInfo);
- }
-}
diff --git a/java/com/google/gerrit/httpd/raw/FontsDevServlet.java b/java/com/google/gerrit/httpd/raw/FontsDevServlet.java
deleted file mode 100644
index 68b0d8ceb1..0000000000
--- a/java/com/google/gerrit/httpd/raw/FontsDevServlet.java
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright (C) 2016 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 com.google.gerrit.launcher.GerritLauncher;
-import java.io.IOException;
-import java.nio.file.Path;
-import java.util.Objects;
-
-/* Font servlet only used in development mode */
-class FontsDevServlet extends ResourceServlet {
- private static final long serialVersionUID = 1L;
-
- private final Path fonts;
-
- FontsDevServlet(Cache cache, BazelBuild builder) throws IOException {
- super(cache, true);
- Objects.requireNonNull(builder);
-
- BazelBuild.Label zipLabel = builder.fontZipLabel();
- try {
- builder.build(zipLabel);
- } catch (BazelBuild.BuildFailureException e) {
- throw new IOException(e);
- }
-
- Path zip = builder.targetPath(zipLabel);
- Objects.requireNonNull(zip);
-
- fonts = GerritLauncher.newZipFileSystem(zip).getPath("/");
- }
-
- @Override
- protected Path getResourcePath(String pathInfo) throws IOException {
- return fonts.resolve(pathInfo);
- }
-}
diff --git a/java/com/google/gerrit/httpd/raw/StaticModule.java b/java/com/google/gerrit/httpd/raw/StaticModule.java
index 0d4c67e8ee..c91048c91f 100644
--- a/java/com/google/gerrit/httpd/raw/StaticModule.java
+++ b/java/com/google/gerrit/httpd/raw/StaticModule.java
@@ -14,7 +14,6 @@
package com.google.gerrit.httpd.raw;
-import static com.google.common.base.Preconditions.checkArgument;
import static java.nio.file.Files.exists;
import static java.nio.file.Files.isReadable;
@@ -222,7 +221,8 @@ public class StaticModule extends ServletModule {
@CanonicalWebUrl @Nullable String canonicalUrl,
@GerritServerConfig Config cfg,
GerritApi gerritApi) {
- String cdnPath = cfg.getString("gerrit", null, "cdnPath");
+ String cdnPath =
+ options.useDevCdn() ? options.devCdn() : cfg.getString("gerrit", null, "cdnPath");
String faviconPath = cfg.getString("gerrit", null, "faviconPath");
return new IndexServlet(canonicalUrl, cdnPath, faviconPath, gerritApi);
}
@@ -233,29 +233,8 @@ public class StaticModule extends ServletModule {
return new PolyGerritUiServlet(cache, polyGerritBasePath());
}
- @Provides
- @Singleton
- BowerComponentsDevServlet getBowerComponentsServlet(@Named(CACHE) Cache cache)
- throws IOException {
- return getPaths().isDev() ? new BowerComponentsDevServlet(cache, getPaths().builder) : null;
- }
-
- @Provides
- @Singleton
- FontsDevServlet getFontsServlet(@Named(CACHE) Cache cache) throws IOException {
- return getPaths().isDev() ? new FontsDevServlet(cache, getPaths().builder) : null;
- }
-
private Path polyGerritBasePath() {
Paths p = getPaths();
- if (options.forcePolyGerritDev()) {
- checkArgument(
- p.sourceRoot != null, "no source root directory found for PolyGerrit developer mode");
- }
-
- if (p.isDev()) {
- return p.sourceRoot.resolve("polygerrit-ui").resolve("app");
- }
return p.warFs != null
? p.warFs.getPath("/polygerrit_ui")
@@ -265,7 +244,6 @@ public class StaticModule extends ServletModule {
private static class Paths {
private final FileSystem warFs;
- private final BazelBuild builder;
private final Path sourceRoot;
private final Path unpackedWar;
private final boolean development;
@@ -285,21 +263,19 @@ public class StaticModule extends ServletModule {
launcherLoadedFrom.getParentFile().getParentFile().getParentFile().toURI());
sourceRoot = null;
development = false;
- builder = null;
return;
}
warFs = getDistributionArchive(launcherLoadedFrom);
if (warFs == null) {
unpackedWar = makeWarTempDir();
development = true;
- } else if (options.forcePolyGerritDev()) {
+ } else if (options.useDevCdn()) {
unpackedWar = null;
development = true;
} else {
unpackedWar = null;
development = false;
sourceRoot = null;
- builder = null;
return;
}
} catch (IOException e) {
@@ -307,7 +283,6 @@ public class StaticModule extends ServletModule {
}
sourceRoot = getSourceRootOrNull();
- builder = new BazelBuild(sourceRoot);
}
private static Path getSourceRootOrNull() {
@@ -376,21 +351,15 @@ public class StaticModule extends ServletModule {
private final Paths paths;
private final HttpServlet polyGerritIndex;
private final PolyGerritUiServlet polygerritUI;
- private final BowerComponentsDevServlet bowerComponentServlet;
- private final FontsDevServlet fontServlet;
@Inject
PolyGerritFilter(
Paths paths,
@Named(POLYGERRIT_INDEX_SERVLET) HttpServlet polyGerritIndex,
- PolyGerritUiServlet polygerritUI,
- @Nullable BowerComponentsDevServlet bowerComponentServlet,
- @Nullable FontsDevServlet fontServlet) {
+ PolyGerritUiServlet polygerritUI) {
this.paths = paths;
this.polyGerritIndex = polyGerritIndex;
this.polygerritUI = polygerritUI;
- this.bowerComponentServlet = bowerComponentServlet;
- this.fontServlet = fontServlet;
}
@Override
@@ -408,22 +377,6 @@ public class StaticModule extends ServletModule {
GuiceFilterRequestWrapper reqWrapper = new GuiceFilterRequestWrapper(req);
String path = pathInfo(req);
- // Special case assets during development that are built by Bazel and not
- // served out of the source tree.
- //
- // In the war case, these are either inlined, or live under
- // /polygerrit_ui in the war file, so we can just treat them as normal
- // assets.
- if (paths.isDev()) {
- if (path.startsWith("/bower_components/")) {
- bowerComponentServlet.service(reqWrapper, res);
- return;
- } else if (path.startsWith("/fonts/")) {
- fontServlet.service(reqWrapper, res);
- return;
- }
- }
-
if (isPolyGerritIndex(path)) {
polyGerritIndex.service(reqWrapper, res);
return;
diff --git a/java/com/google/gerrit/pgm/Daemon.java b/java/com/google/gerrit/pgm/Daemon.java
index 2e9ef2f0b4..8905ee5ea1 100644
--- a/java/com/google/gerrit/pgm/Daemon.java
+++ b/java/com/google/gerrit/pgm/Daemon.java
@@ -168,8 +168,18 @@ public class Daemon extends SiteProgram {
@Option(name = "--headless", usage = "Don't start the UI frontend")
private boolean headless;
- @Option(name = "--polygerrit-dev", usage = "Force PolyGerrit UI for development")
- private boolean polyGerritDev;
+ private String devCdn = "";
+
+ @Option(name = "--dev-cdn", usage = "Use specified cdn for serving static content.")
+ private void setDevCdn(String cdn) {
+ if (cdn == null) {
+ cdn = "";
+ }
+ if (cdn.endsWith("/")) {
+ cdn = cdn.substring(0, cdn.length() - 1);
+ }
+ devCdn = cdn;
+ }
@Option(
name = "--init",
@@ -463,8 +473,7 @@ public class Daemon extends SiteProgram {
new AbstractModule() {
@Override
protected void configure() {
- bind(GerritOptions.class)
- .toInstance(new GerritOptions(headless, replica, polyGerritDev));
+ bind(GerritOptions.class).toInstance(new GerritOptions(headless, replica, devCdn));
if (inMemoryTest) {
bind(String.class)
.annotatedWith(SecureStoreClassName.class)
diff --git a/java/com/google/gerrit/server/config/GerritOptions.java b/java/com/google/gerrit/server/config/GerritOptions.java
index 17b65c9f21..d9edf23d27 100644
--- a/java/com/google/gerrit/server/config/GerritOptions.java
+++ b/java/com/google/gerrit/server/config/GerritOptions.java
@@ -17,12 +17,12 @@ package com.google.gerrit.server.config;
public class GerritOptions {
private final boolean headless;
private final boolean slave;
- private final boolean forcePolyGerritDev;
+ private final String devCdn;
- public GerritOptions(boolean headless, boolean slave, boolean forcePolyGerritDev) {
+ public GerritOptions(boolean headless, boolean slave, String devCdn) {
this.headless = headless;
this.slave = slave;
- this.forcePolyGerritDev = forcePolyGerritDev;
+ this.devCdn = devCdn;
}
public boolean headless() {
@@ -33,7 +33,11 @@ public class GerritOptions {
return !slave;
}
- public boolean forcePolyGerritDev() {
- return !headless && forcePolyGerritDev;
+ public String devCdn() {
+ return devCdn;
+ }
+
+ public boolean useDevCdn() {
+ return !headless && devCdn.length() > 0;
}
}
diff --git a/java/com/google/gerrit/testing/InMemoryModule.java b/java/com/google/gerrit/testing/InMemoryModule.java
index fa9685e7fd..af9d8c3925 100644
--- a/java/com/google/gerrit/testing/InMemoryModule.java
+++ b/java/com/google/gerrit/testing/InMemoryModule.java
@@ -181,7 +181,7 @@ public class InMemoryModule extends FactoryModule {
// support Path-based Configs, only FileBasedConfig.
bind(Path.class).annotatedWith(SitePath.class).toInstance(Paths.get("."));
bind(Config.class).annotatedWith(GerritServerConfig.class).toInstance(cfg);
- bind(GerritOptions.class).toInstance(new GerritOptions(false, false, false));
+ bind(GerritOptions.class).toInstance(new GerritOptions(false, false, ""));
bind(GitRepositoryManager.class).to(InMemoryRepositoryManager.class);
bind(InMemoryRepositoryManager.class).in(SINGLETON);
diff --git a/polygerrit-ui/README.md b/polygerrit-ui/README.md
index a1e960f1cb..acc5d0d445 100644
--- a/polygerrit-ui/README.md
+++ b/polygerrit-ui/README.md
@@ -39,12 +39,11 @@ npm install
It may complain about a missing `typescript@2.3.4` peer dependency, which is
harmless.
-## Running locally against production data
+## Serving files locally
#### Go server
-To test the local Polymer frontend against gerrit-review.googlesource.com
-simply execute:
+To test the local Polymer frontend against production data or a local test site execute:
```sh
./polygerrit-ui/run-server.sh
@@ -53,10 +52,7 @@ simply execute:
npm run start
```
-Then visit http://localhost:8081
-
-This method is based on a
-[simple hand-written Go webserver](https://gerrit.googlesource.com/gerrit/+/master/polygerrit-ui/server.go).
+These commands start the [simple hand-written Go webserver](https://gerrit.googlesource.com/gerrit/+/master/polygerrit-ui/server.go).
Mostly it just switches between serving files locally and proxying the real
server based on the file name. It also does some basic response rewriting, e.g.
it patches the `config/server/info` response with plugin information provided on
@@ -66,6 +62,12 @@ the command line:
./polygerrit-ui/run-server.sh --plugins=plugins/my_plugin/static/my_plugin.js,plugins/my_plugin/static/my_plugin.html
```
+## Running locally against production data
+
+### Local website
+
+Start [Go server](#go-server) and then visit http://localhost:8081
+
The biggest draw back of this method is that you cannot log in, so cannot test
scenarios that require it.
@@ -89,9 +91,11 @@ Set up a local test site once:
3. Optionally [populate](https://gerrit.googlesource.com/gerrit/+/master/contrib/populate-fixture-data.py) your test site with some test data.
For running a locally built Gerrit war against your test instance use
-[this command](https://gerrit-review.googlesource.com/Documentation/dev-readme.html#run_daemon),
-and add the `--polygerrit-dev` option, if you want to serve the Polymer frontend
-directly from the sources in `polygerrit_ui/app/` instead of from the war:
+[this command](https://gerrit-review.googlesource.com/Documentation/dev-readme.html#run_daemon).
+
+If you want to serve the Polymer frontend directly from the sources in `polygerrit_ui/app/` instead of from the war:
+1. Start [Go server](#go-server)
+2. Add the `--dev-cdn` option:
```sh
$(bazel info output_base)/external/local_jdk/bin/java \
@@ -99,9 +103,11 @@ $(bazel info output_base)/external/local_jdk/bin/java \
-jar bazel-bin/gerrit.war daemon \
-d $GERRIT_SITE \
--console-log \
- --polygerrit-dev
+ --dev-cdn http://localhost:8081
```
+*NOTE* You can use any other cdn here, for example: https://cdn.googlesource.com/polygerrit_ui/678.0
+
## Running Tests
This step requires the `web-component-tester` npm module.
diff --git a/polygerrit-ui/server.go b/polygerrit-ui/server.go
index ba52ce83c1..5b48785777 100644
--- a/polygerrit-ui/server.go
+++ b/polygerrit-ui/server.go
@@ -64,11 +64,12 @@ func main() {
log.Fatal(err)
}
- http.Handle("/", http.FileServer(http.Dir("app")))
+ http.Handle("/", addDevHeadersMiddleware(http.FileServer(http.Dir("app"))))
http.Handle("/bower_components/",
- http.FileServer(httpfs.New(zipfs.New(componentsArchive, "bower_components"))))
+ addDevHeadersMiddleware(
+ http.FileServer(httpfs.New(zipfs.New(componentsArchive, "bower_components")))))
http.Handle("/fonts/",
- http.FileServer(httpfs.New(zipfs.New(fontsArchive, "fonts"))))
+ addDevHeadersMiddleware(http.FileServer(httpfs.New(zipfs.New(fontsArchive, "fonts")))))
http.HandleFunc("/index.html", handleIndex)
http.HandleFunc("/changes/", handleProxy)
@@ -92,6 +93,14 @@ func main() {
log.Fatal(http.ListenAndServe(*port, &server{}))
}
+func addDevHeadersMiddleware(h http.Handler) http.Handler {
+ return http.HandlerFunc(func(writer http.ResponseWriter, req *http.Request) {
+ writer.Header().Set("Access-Control-Allow-Origin", "*")
+ writer.Header().Set("Cache-Control", "public, max-age=10, must-revalidate")
+ h.ServeHTTP(writer, req)
+ })
+}
+
func openDataArchive(path string) (*zip.ReadCloser, error) {
absBinPath, err := resourceBasePath()
if err != nil {