blob: 32359db34f5716e1af2c7cd7323f521e4d502163 [file] [log] [blame]
Dave Borowitz9de65952012-08-13 16:09:45 -07001// 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;
16
17import static com.google.common.base.Preconditions.checkNotNull;
18
Dave Borowitz9de65952012-08-13 16:09:45 -070019import com.google.common.base.Strings;
Dave Borowitz5db0eed2012-12-28 15:08:39 -080020import com.google.common.collect.ImmutableList;
Shawn Pearce45e83752015-02-20 17:59:05 -080021import com.google.common.collect.ImmutableMap;
Dave Borowitz209d0aa2012-12-28 14:28:53 -080022import com.google.common.collect.Maps;
Dave Borowitz2b2f34b2014-04-29 16:47:20 -070023import com.google.gitiles.DateFormatter.Format;
Kevin Graney77dbea92014-07-08 14:07:40 -040024import com.google.gson.reflect.TypeToken;
Dave Borowitz9de65952012-08-13 16:09:45 -070025
Shawn Pearce45e83752015-02-20 17:59:05 -080026import org.eclipse.jgit.errors.IncorrectObjectTypeException;
Dave Borowitz9de65952012-08-13 16:09:45 -070027import org.eclipse.jgit.http.server.ServletUtils;
Shawn Pearce45e83752015-02-20 17:59:05 -080028import org.eclipse.jgit.lib.Config;
Dave Borowitz9de65952012-08-13 16:09:45 -070029import org.eclipse.jgit.lib.Constants;
Dave Borowitz209d0aa2012-12-28 14:28:53 -080030import org.eclipse.jgit.lib.ObjectId;
31import org.eclipse.jgit.lib.Repository;
32import org.eclipse.jgit.revwalk.RevCommit;
33import org.eclipse.jgit.revwalk.RevObject;
Shawn Pearce45e83752015-02-20 17:59:05 -080034import org.eclipse.jgit.revwalk.RevTree;
Dave Borowitz14ce8282012-12-20 14:08:25 -080035import org.eclipse.jgit.revwalk.RevWalk;
Dave Borowitz9de65952012-08-13 16:09:45 -070036
37import java.io.IOException;
Dave Borowitzf6dcf7a2014-07-30 10:26:58 -070038import java.io.OutputStream;
Dave Borowitzf6dcf7a2014-07-30 10:26:58 -070039import java.io.Writer;
Dave Borowitz9de65952012-08-13 16:09:45 -070040import java.util.List;
41import java.util.Map;
42
43import javax.servlet.http.HttpServletRequest;
44import javax.servlet.http.HttpServletResponse;
45
46/** Serves the index page for a repository, if accessed directly by a browser. */
47public class RepositoryIndexServlet extends BaseServlet {
Chad Horohoead23f142012-11-12 09:45:39 -080048 private static final long serialVersionUID = 1L;
Dave Borowitz9de65952012-08-13 16:09:45 -070049
Dave Borowitz209d0aa2012-12-28 14:28:53 -080050 static final int REF_LIMIT = 10;
51 private static final int LOG_LIMIT = 20;
Shawn Pearce45e83752015-02-20 17:59:05 -080052 private static final int LOG_WITH_README_LIMIT = 5;
Dave Borowitz209d0aa2012-12-28 14:28:53 -080053
Dave Borowitz14ce8282012-12-20 14:08:25 -080054 private final TimeCache timeCache;
55
Dave Borowitz8d6d6872014-03-16 15:18:14 -070056 public RepositoryIndexServlet(GitilesAccess.Factory accessFactory, Renderer renderer,
Dave Borowitz2b2f34b2014-04-29 16:47:20 -070057 TimeCache timeCache) {
Dave Borowitz8d6d6872014-03-16 15:18:14 -070058 super(renderer, accessFactory);
Dave Borowitz14ce8282012-12-20 14:08:25 -080059 this.timeCache = checkNotNull(timeCache, "timeCache");
Dave Borowitz9de65952012-08-13 16:09:45 -070060 }
61
62 @Override
Kevin Graney77dbea92014-07-08 14:07:40 -040063 protected void doGetHtml(HttpServletRequest req, HttpServletResponse res) throws IOException {
Dave Borowitzf6dcf7a2014-07-30 10:26:58 -070064 GitilesView view = ViewFilter.getView(req);
65 Repository repo = ServletUtils.getRepository(req);
66 GitilesAccess access = getAccess(req);
67 RepositoryDescription desc = access.getRepositoryDescription();
68
Shawn Pearceb5ad0a02015-05-24 20:33:17 -070069 try (RevWalk walk = new RevWalk(repo)) {
70 Paginator paginator = null;
Dave Borowitzf6dcf7a2014-07-30 10:26:58 -070071 Map<String, Object> data = Maps.newHashMapWithExpectedSize(7);
72 List<Map<String, Object>> tags = RefServlet.getTagsSoyData(req, timeCache, walk, REF_LIMIT);
73 ObjectId headId = repo.resolve(Constants.HEAD);
74 if (headId != null) {
75 RevObject head = walk.parseAny(headId);
Shawn Pearce45e83752015-02-20 17:59:05 -080076 int limit = LOG_LIMIT;
77 Map<String, Object> readme = renderReadme(walk, view, access.getConfig(), head);
78 if (readme != null) {
79 data.putAll(readme);
80 limit = LOG_WITH_README_LIMIT;
81 }
Dave Borowitzf6dcf7a2014-07-30 10:26:58 -070082 // TODO(dborowitz): Handle non-commit or missing HEAD?
83 if (head.getType() == Constants.OBJ_COMMIT) {
84 walk.reset();
85 walk.markStart((RevCommit) head);
Shawn Pearce45e83752015-02-20 17:59:05 -080086 paginator = new Paginator(walk, limit, null);
Dave Borowitzf6dcf7a2014-07-30 10:26:58 -070087 }
88 }
89 if (!data.containsKey("entries")) {
90 data.put("entries", ImmutableList.of());
91 }
92 List<Map<String, Object>> branches = RefServlet.getBranchesSoyData(req, REF_LIMIT);
93
94 data.put("cloneUrl", desc.cloneUrl);
95 data.put("mirroredFromUrl", Strings.nullToEmpty(desc.mirroredFromUrl));
96 data.put("description", Strings.nullToEmpty(desc.description));
97 data.put("branches", trim(branches));
98 if (branches.size() > REF_LIMIT) {
99 data.put("moreBranchesUrl", GitilesView.refs().copyFrom(view).toUrl());
100 }
101 data.put("tags", trim(tags));
102 data.put("hasLog", paginator != null);
103 if (tags.size() > REF_LIMIT) {
104 data.put("moreTagsUrl", GitilesView.refs().copyFrom(view).toUrl());
105 }
106 GitilesConfig.putVariant(getAccess(req).getConfig(), "logEntry", "logEntryVariant", data);
107
108 if (paginator != null) {
109 DateFormatter df = new DateFormatter(access, Format.DEFAULT);
Shawn Pearce4c2eb852014-08-26 15:35:33 -0700110 try (OutputStream out = startRenderStreamingHtml(req, res, "gitiles.repositoryIndex", data)) {
111 Writer w = newWriter(out, res);
Dave Borowitzf6dcf7a2014-07-30 10:26:58 -0700112 new LogSoyData(req, access, "oneline")
113 .renderStreaming(paginator, "HEAD", renderer, w, df);
Shawn Pearce4c2eb852014-08-26 15:35:33 -0700114 w.flush();
Dave Borowitzf6dcf7a2014-07-30 10:26:58 -0700115 }
116 } else {
117 renderHtml(req, res, "gitiles.repositoryIndex", data);
118 }
Dave Borowitzf6dcf7a2014-07-30 10:26:58 -0700119 }
Dave Borowitz9de65952012-08-13 16:09:45 -0700120 }
121
Kevin Graney77dbea92014-07-08 14:07:40 -0400122 @Override
123 protected void doGetJson(HttpServletRequest req, HttpServletResponse res) throws IOException {
124 GitilesAccess access = getAccess(req);
125 RepositoryDescription desc = access.getRepositoryDescription();
126 renderJson(req, res, desc, new TypeToken<RepositoryDescription>() {}.getType());
127 }
128
Dave Borowitz209d0aa2012-12-28 14:28:53 -0800129 private static <T> List<T> trim(List<T> list) {
130 return list.size() > REF_LIMIT ? list.subList(0, REF_LIMIT) : list;
Dave Borowitz14ce8282012-12-20 14:08:25 -0800131 }
Shawn Pearce45e83752015-02-20 17:59:05 -0800132
David Ostrovsky412b3862015-06-11 08:59:15 +0200133 private static Map<String, Object> renderReadme(RevWalk walk,
134 GitilesView view, Config cfg, RevObject head) throws IOException {
Shawn Pearce45e83752015-02-20 17:59:05 -0800135 RevTree rootTree;
136 try {
137 rootTree = walk.parseTree(head);
138 } catch (IncorrectObjectTypeException notTreeish) {
139 return null;
140 }
141
Shawn Pearce978fe8e2015-03-25 16:49:41 -0700142 ReadmeHelper readme = new ReadmeHelper(
143 walk.getObjectReader(),
144 GitilesView.path().copyFrom(view).setRevision(Revision.HEAD).setPathPart("/").build(),
145 cfg, rootTree);
Shawn Pearce45e83752015-02-20 17:59:05 -0800146 readme.scanTree(rootTree);
147 if (readme.isPresent()) {
148 return ImmutableMap.<String, Object> of("readmeHtml", readme.render());
149 }
150 return null;
151 }
Dave Borowitz9de65952012-08-13 16:09:45 -0700152}