blob: 84cfdb21580f22d64c31551d6701aa4a2aa63f50 [file] [log] [blame] [raw]
// 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 static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
import static javax.servlet.http.HttpServletResponse.SC_SERVICE_UNAVAILABLE;
import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
import com.google.gson.reflect.TypeToken;
import com.google.template.soy.data.SoyListData;
import com.google.template.soy.data.SoyMapData;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.transport.ServiceMayNotContinueException;
import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/** Serves the top level index page for a Gitiles host. */
public class HostIndexServlet extends BaseServlet {
private static final long serialVersionUID = 1L;
private static final Logger log = LoggerFactory.getLogger(HostIndexServlet.class);
protected final GitilesUrls urls;
private final GitilesAccess.Factory accessFactory;
public HostIndexServlet(Renderer renderer, GitilesUrls urls,
GitilesAccess.Factory accessFactory) {
super(renderer);
this.urls = checkNotNull(urls, "urls");
this.accessFactory = checkNotNull(accessFactory, "accessFactory");
}
private Map<String, RepositoryDescription> getDescriptions(HttpServletRequest req,
HttpServletResponse res) throws IOException {
return getDescriptions(req, res, parseShowBranch(req));
}
private Map<String, RepositoryDescription> getDescriptions(HttpServletRequest req,
HttpServletResponse res, Set<String> branches) throws IOException {
Map<String, RepositoryDescription> descs;
try {
descs = accessFactory.forRequest(req).listRepositories(branches);
} catch (RepositoryNotFoundException e) {
res.sendError(SC_NOT_FOUND);
return null;
} catch (ServiceNotEnabledException e) {
res.sendError(SC_FORBIDDEN);
return null;
} catch (ServiceNotAuthorizedException e) {
res.sendError(SC_UNAUTHORIZED);
return null;
} catch (ServiceMayNotContinueException e) {
// TODO(dborowitz): Show the error message to the user.
res.sendError(SC_FORBIDDEN);
return null;
} catch (IOException err) {
String name = urls.getHostName(req);
log.warn("Cannot scan repositories" + (name != null ? "for " + name : ""), err);
res.sendError(SC_SERVICE_UNAVAILABLE);
return null;
}
return descs;
}
private SoyMapData toSoyMapData(RepositoryDescription desc, GitilesView view) {
return new SoyMapData(
"name", desc.name,
"description", Strings.nullToEmpty(desc.description),
"url", GitilesView.repositoryIndex()
.copyFrom(view)
.setRepositoryName(desc.name)
.toUrl());
}
@Override
protected void doGetHtml(HttpServletRequest req, HttpServletResponse res) throws IOException {
Map<String, RepositoryDescription> descs = getDescriptions(req, res);
if (descs == null) {
return;
}
SoyListData repos = new SoyListData();
for (RepositoryDescription desc : descs.values()) {
repos.add(toSoyMapData(desc, ViewFilter.getView(req)));
}
renderHtml(req, res, "gitiles.hostIndex", ImmutableMap.of(
"hostName", urls.getHostName(req),
"baseUrl", urls.getBaseGitUrl(req),
"repositories", repos));
}
@Override
protected void doGetText(HttpServletRequest req, HttpServletResponse res) throws IOException {
Set<String> branches = parseShowBranch(req);
Map<String, RepositoryDescription> descs = getDescriptions(req, res, branches);
if (descs == null) {
return;
}
PrintWriter 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.print(ref);
writer.print(' ');
}
writer.print(GitilesUrls.NAME_ESCAPER.apply(repo.name));
writer.print('\n');
}
writer.flush();
writer.close();
}
@Override
protected void doGetJson(HttpServletRequest req, HttpServletResponse res) throws IOException {
Map<String, RepositoryDescription> descs = getDescriptions(req, res);
if (descs == null) {
return;
}
renderJson(req, res, descs, new TypeToken<Map<String, RepositoryDescription>>() {}.getType());
}
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) {
branches.addAll(Arrays.asList(values));
}
values = req.getParameterValues("b");
if (values != null) {
branches.addAll(Arrays.asList(values));
}
return branches;
}
}