| // Copyright 2012 Google Inc. All Rights Reserved. | |
| // | |
| // 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.gitiles; | |
| import static com.google.common.base.Preconditions.checkNotNull; | |
| import com.google.common.base.Strings; | |
| import com.google.common.collect.ImmutableList; | |
| import com.google.common.collect.ImmutableMap; | |
| import com.google.common.collect.Sets; | |
| import com.google.gitiles.GitilesRequestFailureException.FailureReason; | |
| import com.google.gson.reflect.TypeToken; | |
| import com.google.template.soy.data.restricted.NullData; | |
| import java.io.IOException; | |
| import java.io.Writer; | |
| import java.util.Collections; | |
| import java.util.LinkedHashMap; | |
| import java.util.List; | |
| import java.util.Map; | |
| import java.util.Optional; | |
| import java.util.Set; | |
| import javax.annotation.Nullable; | |
| import javax.servlet.http.HttpServletRequest; | |
| import javax.servlet.http.HttpServletResponse; | |
| import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException; | |
| import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException; | |
| /** Serves the top level index page for a Gitiles host. */ | |
| public class HostIndexServlet extends BaseServlet { | |
| private static final long serialVersionUID = 1L; | |
| protected final GitilesUrls urls; | |
| public HostIndexServlet( | |
| GitilesAccess.Factory accessFactory, Renderer renderer, GitilesUrls urls) { | |
| super(renderer, accessFactory); | |
| this.urls = checkNotNull(urls, "urls"); | |
| } | |
| private Map<String, RepositoryDescription> list( | |
| HttpServletRequest req, String prefix, Set<String> branches) throws IOException { | |
| Map<String, RepositoryDescription> descs; | |
| try { | |
| descs = getAccess(req).listRepositories(prefix, branches); | |
| } catch (ServiceNotEnabledException e) { | |
| throw new GitilesRequestFailureException(FailureReason.SERVICE_NOT_ENABLED, e); | |
| } catch (ServiceNotAuthorizedException e) { | |
| throw new GitilesRequestFailureException(FailureReason.NOT_AUTHORIZED, e); | |
| } | |
| if (prefix != null && descs.isEmpty()) { | |
| throw new GitilesRequestFailureException(FailureReason.REPOSITORY_NOT_FOUND); | |
| } | |
| return descs; | |
| } | |
| private Map<String, Object> toMapData( | |
| RepositoryDescription desc, @Nullable String prefix, GitilesView view) { | |
| return ImmutableMap.<String, Object>builder() | |
| .put("name", stripPrefix(prefix, desc.name)) | |
| .put("description", Strings.nullToEmpty(desc.description)) | |
| .put( | |
| "url", | |
| GitilesView.repositoryIndex().copyFrom(view).setRepositoryName(desc.name).toUrl()) | |
| .build(); | |
| } | |
| @Override | |
| protected void doHead(HttpServletRequest req, HttpServletResponse res) throws IOException { | |
| Optional<FormatType> format = getFormat(req); | |
| if (!format.isPresent()) { | |
| throw new GitilesRequestFailureException(FailureReason.UNSUPPORTED_RESPONSE_FORMAT); | |
| } | |
| GitilesView view = ViewFilter.getView(req); | |
| String prefix = view.getRepositoryPrefix(); | |
| if (prefix != null) { | |
| Map<String, RepositoryDescription> descs = list(req, prefix, Collections.emptySet()); | |
| if (descs == null) { | |
| return; | |
| } | |
| } | |
| switch (format.get()) { | |
| case HTML: | |
| case JSON: | |
| case TEXT: | |
| res.setStatus(HttpServletResponse.SC_OK); | |
| res.setContentType(format.get().getMimeType()); | |
| break; | |
| case DEFAULT: | |
| default: | |
| throw new GitilesRequestFailureException(FailureReason.UNSUPPORTED_RESPONSE_FORMAT); | |
| } | |
| } | |
| @Override | |
| protected void doGetHtml(HttpServletRequest req, HttpServletResponse res) throws IOException { | |
| GitilesView view = ViewFilter.getView(req); | |
| String prefix = view.getRepositoryPrefix(); | |
| Map<String, RepositoryDescription> descs = list(req, prefix, parseShowBranch(req)); | |
| if (descs == null) { | |
| return; | |
| } | |
| ImmutableList.Builder<Map<String, Object>> repos = ImmutableList.builder(); | |
| for (RepositoryDescription desc : descs.values()) { | |
| if (prefix == null || desc.name.startsWith(prefix)) { | |
| repos.add(toMapData(desc, prefix, view)); | |
| } | |
| } | |
| String hostName = urls.getHostName(req); | |
| List<Map<String, String>> breadcrumbs = null; | |
| if (prefix != null) { | |
| hostName = hostName + '/' + prefix; | |
| breadcrumbs = view.getBreadcrumbs(); | |
| } | |
| renderHtml( | |
| req, | |
| res, | |
| "com.google.gitiles.templates.HostIndex.hostIndex", | |
| ImmutableMap.of( | |
| "hostName", | |
| hostName, | |
| "breadcrumbs", | |
| breadcrumbs != null ? breadcrumbs : NullData.INSTANCE, | |
| "prefix", | |
| prefix != null ? prefix + '/' : "", | |
| "repositories", | |
| repos.build())); | |
| } | |
| @Override | |
| protected void doGetText(HttpServletRequest req, HttpServletResponse res) throws IOException { | |
| String prefix = ViewFilter.getView(req).getRepositoryPrefix(); | |
| Set<String> branches = parseShowBranch(req); | |
| Map<String, RepositoryDescription> descs = list(req, prefix, branches); | |
| if (descs == null) { | |
| return; | |
| } | |
| try (Writer writer = startRenderText(req, res)) { | |
| for (RepositoryDescription repo : descs.values()) { | |
| for (String name : branches) { | |
| String ref = repo.branches.get(name); | |
| if (ref == null) { | |
| // Print stub (forty '-' symbols) | |
| ref = "----------------------------------------"; | |
| } | |
| writer.write(ref); | |
| writer.write(' '); | |
| } | |
| writer.write(GitilesUrls.escapeName(stripPrefix(prefix, repo.name))); | |
| writer.write('\n'); | |
| } | |
| } | |
| } | |
| @Override | |
| protected void doGetJson(HttpServletRequest req, HttpServletResponse res) throws IOException { | |
| String prefix = ViewFilter.getView(req).getRepositoryPrefix(); | |
| Map<String, RepositoryDescription> descs = list(req, prefix, parseShowBranch(req)); | |
| if (descs == null) { | |
| return; | |
| } | |
| if (prefix != null) { | |
| Map<String, RepositoryDescription> r = new LinkedHashMap<>(); | |
| for (Map.Entry<String, RepositoryDescription> e : descs.entrySet()) { | |
| r.put(stripPrefix(prefix, e.getKey()), e.getValue()); | |
| } | |
| descs = r; | |
| } | |
| renderJson(req, res, descs, new TypeToken<Map<String, RepositoryDescription>>() {}.getType()); | |
| } | |
| private static String stripPrefix(@Nullable String prefix, String name) { | |
| if (prefix != null && name.startsWith(prefix)) { | |
| return name.substring(prefix.length() + 1); | |
| } | |
| return name; | |
| } | |
| private static Set<String> parseShowBranch(HttpServletRequest req) { | |
| // Roughly match Gerrit Code Review's /projects/ API by supporting | |
| // both show-branch and b as query parameters. | |
| Set<String> branches = Sets.newLinkedHashSet(); | |
| String[] values = req.getParameterValues("show-branch"); | |
| if (values != null) { | |
| Collections.addAll(branches, values); | |
| } | |
| values = req.getParameterValues("b"); | |
| if (values != null) { | |
| Collections.addAll(branches, values); | |
| } | |
| return branches; | |
| } | |
| } |