blob: 6d49d4e44bf80989f1a92dfd1e6d1e16bb2b4537 [file] [log] [blame]
Dave Borowitz09ff62b2012-12-17 14:09:16 -08001// Copyright 2012 Google Inc. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package com.google.gitiles.dev;
16
Dave Borowitzc410f962014-09-23 10:49:26 -070017import static com.google.common.base.MoreObjects.firstNonNull;
Dave Borowitz03397692012-12-18 17:11:16 -080018import static com.google.gitiles.GitilesServlet.STATIC_PREFIX;
19
Dave Borowitz03397692012-12-18 17:11:16 -080020import com.google.gitiles.DebugRenderer;
Dave Borowitz09ff62b2012-12-17 14:09:16 -080021import com.google.gitiles.GitilesServlet;
Dave Borowitz03397692012-12-18 17:11:16 -080022import com.google.gitiles.PathServlet;
Dave Borowitz09ff62b2012-12-17 14:09:16 -080023
24import org.eclipse.jetty.server.Connector;
25import org.eclipse.jetty.server.Handler;
26import org.eclipse.jetty.server.Server;
Dave Borowitze1056bb2013-01-11 10:31:37 -080027import org.eclipse.jetty.server.bio.SocketConnector;
Dave Borowitz09ff62b2012-12-17 14:09:16 -080028import org.eclipse.jetty.server.handler.ContextHandler;
29import org.eclipse.jetty.server.handler.ContextHandlerCollection;
30import org.eclipse.jetty.server.handler.ResourceHandler;
Dave Borowitz09ff62b2012-12-17 14:09:16 -080031import org.eclipse.jetty.servlet.ServletContextHandler;
32import org.eclipse.jetty.servlet.ServletHolder;
33import org.eclipse.jetty.util.resource.FileResource;
34import org.eclipse.jetty.util.thread.QueuedThreadPool;
35import org.eclipse.jetty.util.thread.ThreadPool;
Dave Borowitz03397692012-12-18 17:11:16 -080036import org.eclipse.jgit.errors.ConfigInvalidException;
Dave Borowitz09ff62b2012-12-17 14:09:16 -080037import org.eclipse.jgit.lib.Config;
Dave Borowitz03397692012-12-18 17:11:16 -080038import org.eclipse.jgit.storage.file.FileBasedConfig;
39import org.eclipse.jgit.util.FS;
40import org.slf4j.Logger;
41import org.slf4j.LoggerFactory;
Dave Borowitz09ff62b2012-12-17 14:09:16 -080042
43import java.io.File;
44import java.io.FileNotFoundException;
45import java.io.IOException;
Dave Borowitz03397692012-12-18 17:11:16 -080046import java.net.InetAddress;
Dave Borowitz09ff62b2012-12-17 14:09:16 -080047import java.net.URI;
48import java.net.URISyntaxException;
Dave Borowitz03397692012-12-18 17:11:16 -080049import java.net.UnknownHostException;
Dave Borowitz76bbefd2014-03-11 16:57:45 -070050import java.util.Arrays;
Dave Borowitz09ff62b2012-12-17 14:09:16 -080051
52class DevServer {
Dave Borowitz03397692012-12-18 17:11:16 -080053 private static final Logger log = LoggerFactory.getLogger(PathServlet.class);
54
Dave Borowitz823724a2013-07-30 13:18:42 -070055 private static Config defaultConfig() {
Dave Borowitz03397692012-12-18 17:11:16 -080056 Config cfg = new Config();
57 String cwd = System.getProperty("user.dir");
58 cfg.setString("gitiles", null, "basePath", cwd);
59 cfg.setBoolean("gitiles", null, "exportAll", true);
60 cfg.setString("gitiles", null, "baseGitUrl", "file://" + cwd + "/");
Dave Borowitz823724a2013-07-30 13:18:42 -070061 String networkHostName;
62 try {
63 networkHostName = InetAddress.getLocalHost().getCanonicalHostName();
64 } catch (UnknownHostException e) {
65 networkHostName = "127.0.0.1";
66 }
Dave Borowitz03397692012-12-18 17:11:16 -080067 cfg.setString("gitiles", null, "siteTitle",
68 String.format("Gitiles - %s:%s", networkHostName, cwd));
69 cfg.setString("gitiles", null, "canonicalHostName", new File(cwd).getName());
70 return cfg;
71 }
72
73 private static FileNotFoundException badSourceRoot(URI u) {
74 return new FileNotFoundException("Cannot find source root from " + u);
75 }
76
77 private static FileNotFoundException badSourceRoot(URI u, Throwable cause) {
78 FileNotFoundException notFound = badSourceRoot(u);
79 notFound.initCause(cause);
80 return notFound;
81 }
82
83 private static File findSourceRoot() throws IOException {
84 URI u;
85 try {
86 u = DevServer.class.getResource(DevServer.class.getSimpleName() + ".class").toURI();
87 } catch (URISyntaxException e) {
88 u = null;
89 }
90 if (u == null) {
91 throw new FileNotFoundException("Cannot find Gitiles source directory");
92 }
93 if ("jar".equals(u.getScheme())) {
Dave Borowitzb2f4d562012-12-27 16:36:37 -080094 String path = u.getSchemeSpecificPart();
95 int jarEntry = path.indexOf("!/");
Dave Borowitz03397692012-12-18 17:11:16 -080096 if (jarEntry < 0) {
97 throw badSourceRoot(u);
98 }
99 try {
Dave Borowitzb2f4d562012-12-27 16:36:37 -0800100 return findSourceRoot(new URI(path.substring(0, jarEntry)));
Dave Borowitz03397692012-12-18 17:11:16 -0800101 } catch (URISyntaxException e) {
102 throw badSourceRoot(u, e);
103 }
104 } else {
105 return findSourceRoot(u);
106 }
107 }
108
109 private static File findSourceRoot(URI targetUri) throws IOException {
110 if (!"file".equals(targetUri.getScheme())) {
111 throw badSourceRoot(targetUri);
112 }
113 String targetPath = targetUri.getPath();
David Ostrovsky22c45b32014-02-23 22:22:26 +0100114 // targetPath is an arbitrary path under buck-out/ in our Buck package
115 // layout.
116 int targetIndex = targetPath.lastIndexOf("buck-out/");
Dave Borowitz03397692012-12-18 17:11:16 -0800117 if (targetIndex < 0) {
118 throw badSourceRoot(targetUri);
119 }
120 String path = targetPath.substring(0, targetIndex);
121 URI u;
122 try {
123 u = new URI("file", path, null).normalize();
124 } catch (URISyntaxException e) {
125 throw new IOException(e);
126 }
127 File root = new File(u);
128 if (!root.exists() || !root.isDirectory()) {
129 throw badSourceRoot(targetUri);
130 }
131 return root;
132 }
133
134 private final File sourceRoot;
135 private final Config cfg;
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800136 private final Server httpd;
137
Dave Borowitz03397692012-12-18 17:11:16 -0800138 DevServer(File cfgFile) throws IOException, ConfigInvalidException {
139 sourceRoot = findSourceRoot();
140
141 Config cfg = defaultConfig();
142 if (cfgFile.exists() && cfgFile.isFile()) {
143 FileBasedConfig fcfg = new FileBasedConfig(cfg, cfgFile, FS.DETECTED);
144 fcfg.load();
145 cfg = fcfg;
146 } else {
Dave Borowitzfd25c3a2013-01-11 14:37:11 -0800147 log.info("Config file {} not found, using defaults", cfgFile.getPath());
Dave Borowitz03397692012-12-18 17:11:16 -0800148 }
149 this.cfg = cfg;
150
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800151 httpd = new Server();
Dave Borowitz03397692012-12-18 17:11:16 -0800152 httpd.setConnectors(connectors());
153 httpd.setThreadPool(threadPool());
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800154 httpd.setHandler(handler());
155 }
156
157 void start() throws Exception {
158 httpd.start();
159 httpd.join();
160 }
161
Dave Borowitz03397692012-12-18 17:11:16 -0800162 private Connector[] connectors() {
Dave Borowitze1056bb2013-01-11 10:31:37 -0800163 Connector c = new SocketConnector();
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800164 c.setHost(null);
165 c.setPort(cfg.getInt("gitiles", null, "port", 8080));
166 c.setStatsOn(false);
167 return new Connector[]{c};
168 }
169
Dave Borowitz03397692012-12-18 17:11:16 -0800170 private ThreadPool threadPool() {
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800171 QueuedThreadPool pool = new QueuedThreadPool();
172 pool.setName("HTTP");
173 pool.setMinThreads(2);
174 pool.setMaxThreads(10);
175 pool.setMaxQueued(50);
176 return pool;
177 }
178
179 private Handler handler() throws IOException {
180 ContextHandlerCollection handlers = new ContextHandlerCollection();
181 handlers.addHandler(staticHandler());
182 handlers.addHandler(appHandler());
183 return handlers;
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800184 }
185
186 private Handler appHandler() {
Dave Borowitz03397692012-12-18 17:11:16 -0800187 GitilesServlet servlet = new GitilesServlet(
188 cfg,
189 new DebugRenderer(
190 STATIC_PREFIX,
Dave Borowitz76bbefd2014-03-11 16:57:45 -0700191 Arrays.asList(cfg.getStringList("gitiles", null, "customTemplates")),
Dave Borowitz03397692012-12-18 17:11:16 -0800192 new File(sourceRoot, "gitiles-servlet/src/main/resources/com/google/gitiles/templates")
193 .getPath(),
Dave Borowitzc410f962014-09-23 10:49:26 -0700194 firstNonNull(cfg.getString("gitiles", null, "siteTitle"), "Gitiles")),
Dave Borowitz86462df2014-02-03 14:23:57 -0800195 null, null, null, null, null, null, null);
Dave Borowitz03397692012-12-18 17:11:16 -0800196
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800197 ServletContextHandler handler = new ServletContextHandler();
198 handler.setContextPath("");
Dave Borowitz03397692012-12-18 17:11:16 -0800199 handler.addServlet(new ServletHolder(servlet), "/*");
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800200 return handler;
201 }
202
Dave Borowitz03397692012-12-18 17:11:16 -0800203 private Handler staticHandler() throws IOException {
204 File staticRoot = new File(sourceRoot,
205 "gitiles-servlet/src/main/resources/com/google/gitiles/static");
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800206 ResourceHandler rh = new ResourceHandler();
207 try {
Dave Borowitz03397692012-12-18 17:11:16 -0800208 rh.setBaseResource(new FileResource(staticRoot.toURI().toURL()));
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800209 } catch (URISyntaxException e) {
Dave Borowitz03397692012-12-18 17:11:16 -0800210 throw new IOException(e);
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800211 }
212 rh.setWelcomeFiles(new String[]{});
213 rh.setDirectoriesListed(false);
214 ContextHandler handler = new ContextHandler("/+static");
215 handler.setHandler(rh);
216 return handler;
217 }
Dave Borowitz09ff62b2012-12-17 14:09:16 -0800218}