| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 1 | // 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 | |
| 15 | package com.google.gitiles.dev; |
| 16 | |
| Dave Borowitz | c410f96 | 2014-09-23 10:49:26 -0700 | [diff] [blame] | 17 | import static com.google.common.base.MoreObjects.firstNonNull; |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 18 | import static com.google.gitiles.GitilesServlet.STATIC_PREFIX; |
| 19 | |
| Shawn Pearce | 68311c7 | 2015-06-09 17:01:34 -0700 | [diff] [blame] | 20 | import com.google.common.base.Strings; |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 21 | import com.google.gitiles.DebugRenderer; |
| Shawn Pearce | 68311c7 | 2015-06-09 17:01:34 -0700 | [diff] [blame] | 22 | import com.google.gitiles.GitilesAccess; |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 23 | import com.google.gitiles.GitilesServlet; |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 24 | import com.google.gitiles.PathServlet; |
| Shawn Pearce | 68311c7 | 2015-06-09 17:01:34 -0700 | [diff] [blame] | 25 | import com.google.gitiles.RepositoryDescription; |
| 26 | import com.google.gitiles.RootedDocServlet; |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 27 | |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 28 | import org.eclipse.jetty.server.Handler; |
| 29 | import org.eclipse.jetty.server.Server; |
| 30 | import org.eclipse.jetty.server.handler.ContextHandler; |
| 31 | import org.eclipse.jetty.server.handler.ContextHandlerCollection; |
| 32 | import org.eclipse.jetty.server.handler.ResourceHandler; |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 33 | import org.eclipse.jetty.servlet.ServletContextHandler; |
| 34 | import org.eclipse.jetty.servlet.ServletHolder; |
| 35 | import org.eclipse.jetty.util.resource.FileResource; |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 36 | import org.eclipse.jgit.errors.ConfigInvalidException; |
| Shawn Pearce | 68311c7 | 2015-06-09 17:01:34 -0700 | [diff] [blame] | 37 | import org.eclipse.jgit.errors.RepositoryNotFoundException; |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 38 | import org.eclipse.jgit.lib.Config; |
| Shawn Pearce | 68311c7 | 2015-06-09 17:01:34 -0700 | [diff] [blame] | 39 | import org.eclipse.jgit.lib.Constants; |
| 40 | import org.eclipse.jgit.lib.Repository; |
| 41 | import org.eclipse.jgit.lib.RepositoryCache; |
| 42 | import org.eclipse.jgit.lib.RepositoryCache.FileKey; |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 43 | import org.eclipse.jgit.storage.file.FileBasedConfig; |
| Shawn Pearce | 68311c7 | 2015-06-09 17:01:34 -0700 | [diff] [blame] | 44 | import org.eclipse.jgit.transport.resolver.RepositoryResolver; |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 45 | import org.eclipse.jgit.util.FS; |
| 46 | import org.slf4j.Logger; |
| 47 | import org.slf4j.LoggerFactory; |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 48 | |
| 49 | import java.io.File; |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 50 | import java.io.IOException; |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 51 | import java.net.InetAddress; |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 52 | import java.net.URISyntaxException; |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 53 | import java.net.UnknownHostException; |
| Dave Borowitz | 197d3ec | 2015-12-07 10:02:33 -0500 | [diff] [blame] | 54 | import java.nio.file.NoSuchFileException; |
| 55 | import java.nio.file.Path; |
| 56 | import java.nio.file.Paths; |
| Dave Borowitz | 76bbefd | 2014-03-11 16:57:45 -0700 | [diff] [blame] | 57 | import java.util.Arrays; |
| Shawn Pearce | 68311c7 | 2015-06-09 17:01:34 -0700 | [diff] [blame] | 58 | import java.util.Collections; |
| 59 | import java.util.Map; |
| 60 | import java.util.Set; |
| 61 | |
| 62 | import javax.servlet.Servlet; |
| 63 | import javax.servlet.http.HttpServletRequest; |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 64 | |
| 65 | class DevServer { |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 66 | private static final Logger log = LoggerFactory.getLogger(PathServlet.class); |
| 67 | |
| Dave Borowitz | 823724a | 2013-07-30 13:18:42 -0700 | [diff] [blame] | 68 | private static Config defaultConfig() { |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 69 | Config cfg = new Config(); |
| 70 | String cwd = System.getProperty("user.dir"); |
| 71 | cfg.setString("gitiles", null, "basePath", cwd); |
| 72 | cfg.setBoolean("gitiles", null, "exportAll", true); |
| 73 | cfg.setString("gitiles", null, "baseGitUrl", "file://" + cwd + "/"); |
| Dave Borowitz | 823724a | 2013-07-30 13:18:42 -0700 | [diff] [blame] | 74 | String networkHostName; |
| 75 | try { |
| 76 | networkHostName = InetAddress.getLocalHost().getCanonicalHostName(); |
| 77 | } catch (UnknownHostException e) { |
| 78 | networkHostName = "127.0.0.1"; |
| 79 | } |
| Dave Borowitz | cf38c03 | 2016-05-02 11:06:23 -0400 | [diff] [blame] | 80 | cfg.setString( |
| 81 | "gitiles", null, "siteTitle", String.format("Gitiles - %s:%s", networkHostName, cwd)); |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 82 | cfg.setString("gitiles", null, "canonicalHostName", new File(cwd).getName()); |
| 83 | return cfg; |
| 84 | } |
| 85 | |
| Dave Borowitz | 197d3ec | 2015-12-07 10:02:33 -0500 | [diff] [blame] | 86 | private static Path findSourceRoot() throws IOException { |
| Han-Wen Nienhuys | ad16092 | 2016-03-30 13:22:27 +0200 | [diff] [blame] | 87 | String prop = "com.google.gitiles.sourcePath"; |
| 88 | String sourceRoot = System.getProperty(prop); |
| 89 | if (sourceRoot == null) { |
| 90 | throw new NoSuchFileException( |
| Dave Borowitz | cf38c03 | 2016-05-02 11:06:23 -0400 | [diff] [blame] | 91 | String.format("Must set system property %s to top of source directory", prop)); |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 92 | } |
| Han-Wen Nienhuys | ad16092 | 2016-03-30 13:22:27 +0200 | [diff] [blame] | 93 | return Paths.get(sourceRoot); |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 94 | } |
| 95 | |
| Han-Wen Nienhuys | 5ca8002 | 2016-03-30 12:58:27 +0200 | [diff] [blame] | 96 | private final Path sourceRoot; |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 97 | private final Config cfg; |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 98 | private final Server httpd; |
| 99 | |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 100 | DevServer(File cfgFile) throws IOException, ConfigInvalidException { |
| Han-Wen Nienhuys | ad16092 | 2016-03-30 13:22:27 +0200 | [diff] [blame] | 101 | // Jetty doesn't doesn't allow symlinks, so canonicalize. |
| 102 | sourceRoot = findSourceRoot().toRealPath(); |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 103 | |
| 104 | Config cfg = defaultConfig(); |
| 105 | if (cfgFile.exists() && cfgFile.isFile()) { |
| 106 | FileBasedConfig fcfg = new FileBasedConfig(cfg, cfgFile, FS.DETECTED); |
| 107 | fcfg.load(); |
| 108 | cfg = fcfg; |
| 109 | } else { |
| Dave Borowitz | fd25c3a | 2013-01-11 14:37:11 -0800 | [diff] [blame] | 110 | log.info("Config file {} not found, using defaults", cfgFile.getPath()); |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 111 | } |
| 112 | this.cfg = cfg; |
| 113 | |
| David Pursehouse | 6e7b58f | 2015-12-07 19:37:21 +0900 | [diff] [blame] | 114 | httpd = new Server(cfg.getInt("gitiles", null, "port", 8080)); |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 115 | httpd.setHandler(handler()); |
| 116 | } |
| 117 | |
| 118 | void start() throws Exception { |
| 119 | httpd.start(); |
| 120 | httpd.join(); |
| 121 | } |
| 122 | |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 123 | private Handler handler() throws IOException { |
| 124 | ContextHandlerCollection handlers = new ContextHandlerCollection(); |
| 125 | handlers.addHandler(staticHandler()); |
| 126 | handlers.addHandler(appHandler()); |
| 127 | return handlers; |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 128 | } |
| 129 | |
| 130 | private Handler appHandler() { |
| Dave Borowitz | cf38c03 | 2016-05-02 11:06:23 -0400 | [diff] [blame] | 131 | DebugRenderer renderer = |
| 132 | new DebugRenderer( |
| 133 | STATIC_PREFIX, |
| 134 | Arrays.asList(cfg.getStringList("gitiles", null, "customTemplates")), |
| 135 | sourceRoot |
| 136 | .resolve("gitiles-servlet/src/main/resources/com/google/gitiles/templates") |
| 137 | .toString(), |
| 138 | firstNonNull(cfg.getString("gitiles", null, "siteTitle"), "Gitiles")); |
| Shawn Pearce | 68311c7 | 2015-06-09 17:01:34 -0700 | [diff] [blame] | 139 | |
| 140 | String docRoot = cfg.getString("gitiles", null, "docroot"); |
| 141 | Servlet servlet; |
| 142 | if (!Strings.isNullOrEmpty(docRoot)) { |
| 143 | servlet = createRootedDocServlet(renderer, docRoot); |
| 144 | } else { |
| Dave Borowitz | cf38c03 | 2016-05-02 11:06:23 -0400 | [diff] [blame] | 145 | servlet = new GitilesServlet(cfg, renderer, null, null, null, null, null, null, null); |
| Shawn Pearce | 68311c7 | 2015-06-09 17:01:34 -0700 | [diff] [blame] | 146 | } |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 147 | |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 148 | ServletContextHandler handler = new ServletContextHandler(); |
| 149 | handler.setContextPath(""); |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 150 | handler.addServlet(new ServletHolder(servlet), "/*"); |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 151 | return handler; |
| 152 | } |
| 153 | |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 154 | private Handler staticHandler() throws IOException { |
| Dave Borowitz | cf38c03 | 2016-05-02 11:06:23 -0400 | [diff] [blame] | 155 | Path staticRoot = |
| 156 | sourceRoot.resolve("gitiles-servlet/src/main/resources/com/google/gitiles/static"); |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 157 | ResourceHandler rh = new ResourceHandler(); |
| 158 | try { |
| Han-Wen Nienhuys | 5ca8002 | 2016-03-30 12:58:27 +0200 | [diff] [blame] | 159 | rh.setBaseResource(new FileResource(staticRoot.toUri().toURL())); |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 160 | } catch (URISyntaxException e) { |
| Dave Borowitz | 0339769 | 2012-12-18 17:11:16 -0800 | [diff] [blame] | 161 | throw new IOException(e); |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 162 | } |
| Dave Borowitz | cf38c03 | 2016-05-02 11:06:23 -0400 | [diff] [blame] | 163 | rh.setWelcomeFiles(new String[] {}); |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 164 | rh.setDirectoriesListed(false); |
| 165 | ContextHandler handler = new ContextHandler("/+static"); |
| 166 | handler.setHandler(rh); |
| 167 | return handler; |
| 168 | } |
| Shawn Pearce | 68311c7 | 2015-06-09 17:01:34 -0700 | [diff] [blame] | 169 | |
| 170 | private Servlet createRootedDocServlet(DebugRenderer renderer, String docRoot) { |
| 171 | File docRepo = new File(docRoot); |
| 172 | final FileKey repoKey = FileKey.exact(docRepo, FS.DETECTED); |
| 173 | |
| Dave Borowitz | cf38c03 | 2016-05-02 11:06:23 -0400 | [diff] [blame] | 174 | RepositoryResolver<HttpServletRequest> resolver = |
| 175 | new RepositoryResolver<HttpServletRequest>() { |
| 176 | @Override |
| 177 | public Repository open(HttpServletRequest req, String name) |
| 178 | throws RepositoryNotFoundException { |
| 179 | try { |
| 180 | return RepositoryCache.open(repoKey, true); |
| 181 | } catch (IOException e) { |
| 182 | throw new RepositoryNotFoundException(repoKey.getFile(), e); |
| 183 | } |
| 184 | } |
| 185 | }; |
| Shawn Pearce | 68311c7 | 2015-06-09 17:01:34 -0700 | [diff] [blame] | 186 | |
| Dave Borowitz | cf38c03 | 2016-05-02 11:06:23 -0400 | [diff] [blame] | 187 | return new RootedDocServlet(resolver, new RootedDocAccess(docRepo), renderer); |
| Shawn Pearce | 68311c7 | 2015-06-09 17:01:34 -0700 | [diff] [blame] | 188 | } |
| 189 | |
| 190 | private class RootedDocAccess implements GitilesAccess.Factory { |
| 191 | private final String repoName; |
| 192 | |
| 193 | RootedDocAccess(File docRepo) { |
| 194 | if (Constants.DOT_GIT.equals(docRepo.getName())) { |
| 195 | repoName = docRepo.getParentFile().getName(); |
| 196 | } else { |
| 197 | repoName = docRepo.getName(); |
| 198 | } |
| 199 | } |
| 200 | |
| 201 | @Override |
| 202 | public GitilesAccess forRequest(HttpServletRequest req) { |
| 203 | return new GitilesAccess() { |
| 204 | @Override |
| Shawn Pearce | c709c4c | 2015-08-28 15:30:42 -0700 | [diff] [blame] | 205 | public Map<String, RepositoryDescription> listRepositories( |
| 206 | String prefix, Set<String> branches) { |
| Shawn Pearce | 68311c7 | 2015-06-09 17:01:34 -0700 | [diff] [blame] | 207 | return Collections.emptyMap(); |
| 208 | } |
| 209 | |
| 210 | @Override |
| 211 | public Object getUserKey() { |
| 212 | return null; |
| 213 | } |
| 214 | |
| 215 | @Override |
| 216 | public String getRepositoryName() { |
| 217 | return repoName; |
| 218 | } |
| 219 | |
| 220 | @Override |
| 221 | public RepositoryDescription getRepositoryDescription() { |
| 222 | RepositoryDescription d = new RepositoryDescription(); |
| 223 | d.name = getRepositoryName(); |
| 224 | return d; |
| 225 | } |
| 226 | |
| 227 | @Override |
| 228 | public Config getConfig() { |
| 229 | return cfg; |
| 230 | } |
| 231 | }; |
| 232 | } |
| 233 | } |
| Dave Borowitz | 09ff62b | 2012-12-17 14:09:16 -0800 | [diff] [blame] | 234 | } |