blob: d64a19f130231408b6e897cc103f0b447c3edf2f [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
Dave Borowitz9de65952012-08-13 16:09:45 -070017import static com.google.common.base.Preconditions.checkNotNull;
18import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
19import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
20
Dave Borowitz80334b22013-01-11 14:19:11 -080021import com.google.common.base.Optional;
22import com.google.common.base.Strings;
23import com.google.common.collect.Iterables;
24import com.google.common.collect.ListMultimap;
25import com.google.common.collect.Lists;
26import com.google.gitiles.CommitSoyData.KeySet;
Dave Borowitz9de65952012-08-13 16:09:45 -070027
28import org.eclipse.jgit.errors.IncorrectObjectTypeException;
29import org.eclipse.jgit.errors.MissingObjectException;
30import org.eclipse.jgit.errors.RevWalkException;
31import org.eclipse.jgit.http.server.ServletUtils;
32import org.eclipse.jgit.lib.AbbreviatedObjectId;
33import org.eclipse.jgit.lib.AnyObjectId;
Dave Borowitz80334b22013-01-11 14:19:11 -080034import org.eclipse.jgit.lib.Constants;
Dave Borowitz9de65952012-08-13 16:09:45 -070035import org.eclipse.jgit.lib.ObjectId;
36import org.eclipse.jgit.lib.ObjectReader;
37import org.eclipse.jgit.lib.Ref;
38import org.eclipse.jgit.lib.Repository;
39import org.eclipse.jgit.revwalk.FollowFilter;
40import org.eclipse.jgit.revwalk.RevCommit;
41import org.eclipse.jgit.revwalk.RevObject;
42import org.eclipse.jgit.revwalk.RevTag;
43import org.eclipse.jgit.revwalk.RevWalk;
44import org.slf4j.Logger;
45import org.slf4j.LoggerFactory;
46
Dave Borowitz80334b22013-01-11 14:19:11 -080047import java.io.IOException;
48import java.util.Collection;
49import java.util.List;
50import java.util.Map;
51import java.util.Set;
52
53import javax.servlet.http.HttpServletRequest;
54import javax.servlet.http.HttpServletResponse;
Dave Borowitz9de65952012-08-13 16:09:45 -070055
56/** Serves an HTML page with a shortlog for commits and paths. */
57public class LogServlet extends BaseServlet {
Chad Horohoead23f142012-11-12 09:45:39 -080058 private static final long serialVersionUID = 1L;
Dave Borowitz9de65952012-08-13 16:09:45 -070059 private static final Logger log = LoggerFactory.getLogger(LogServlet.class);
60
Dave Borowitzb772cce2012-12-28 13:57:22 -080061 static final String START_PARAM = "s";
62 private static final int LIMIT = 100;
Dave Borowitz9de65952012-08-13 16:09:45 -070063
64 private final Linkifier linkifier;
Dave Borowitz9de65952012-08-13 16:09:45 -070065
66 public LogServlet(Renderer renderer, Linkifier linkifier) {
Dave Borowitz9de65952012-08-13 16:09:45 -070067 super(renderer);
68 this.linkifier = checkNotNull(linkifier, "linkifier");
Dave Borowitz9de65952012-08-13 16:09:45 -070069 }
70
71 @Override
Dave Borowitz80334b22013-01-11 14:19:11 -080072 protected void doGetHtml(HttpServletRequest req, HttpServletResponse res) throws IOException {
Dave Borowitz9de65952012-08-13 16:09:45 -070073 Repository repo = ServletUtils.getRepository(req);
Dave Borowitz80334b22013-01-11 14:19:11 -080074 GitilesView view = getView(req, repo);
75 if (view == null) {
76 res.setStatus(SC_NOT_FOUND);
77 return;
78 }
79
Dave Borowitz9de65952012-08-13 16:09:45 -070080 RevWalk walk = null;
81 try {
82 try {
83 walk = newWalk(repo, view);
84 } catch (IncorrectObjectTypeException e) {
85 res.setStatus(SC_NOT_FOUND);
86 return;
87 }
88
89 Optional<ObjectId> start = getStart(view.getParameters(), walk.getObjectReader());
90 if (start == null) {
91 res.setStatus(SC_NOT_FOUND);
92 return;
93 }
94
Dave Borowitzb772cce2012-12-28 13:57:22 -080095 Map<String, Object> data = new LogSoyData(req, repo, view)
96 .toSoyData(walk, LIMIT, null, start.orNull());
Dave Borowitz9de65952012-08-13 16:09:45 -070097
98 if (!view.getRevision().nameIsId()) {
99 List<Map<String, Object>> tags = Lists.newArrayListWithExpectedSize(1);
Dave Borowitz558005d2012-12-20 15:48:08 -0800100 for (RevObject o : RevisionServlet.listObjects(walk, view.getRevision())) {
Dave Borowitz9de65952012-08-13 16:09:45 -0700101 if (o instanceof RevTag) {
102 tags.add(new TagSoyData(linkifier, req).toSoyData((RevTag) o));
103 }
104 }
105 if (!tags.isEmpty()) {
106 data.put("tags", tags);
107 }
108 }
109
Dave Borowitzb772cce2012-12-28 13:57:22 -0800110 Paginator paginator = new Paginator(walk, LIMIT, start.orNull());
Dave Borowitz9de65952012-08-13 16:09:45 -0700111 Map<AnyObjectId, Set<Ref>> refsById = repo.getAllRefsByPeeledObjectId();
Dave Borowitzb772cce2012-12-28 13:57:22 -0800112 List<Map<String, Object>> entries = Lists.newArrayListWithCapacity(LIMIT);
Dave Borowitz9de65952012-08-13 16:09:45 -0700113 for (RevCommit c : paginator) {
114 entries.add(new CommitSoyData(null, req, repo, walk, view, refsById)
115 .toSoyData(c, KeySet.SHORTLOG));
116 }
117
118 String title = "Log - ";
119 if (view.getOldRevision() != Revision.NULL) {
120 title += view.getRevisionRange();
121 } else {
122 title += view.getRevision().getName();
123 }
124
125 data.put("title", title);
Dave Borowitz9de65952012-08-13 16:09:45 -0700126
Dave Borowitzb1c628f2013-01-11 11:28:20 -0800127 renderHtml(req, res, "gitiles.logDetail", data);
Dave Borowitz9de65952012-08-13 16:09:45 -0700128 } catch (RevWalkException e) {
129 log.warn("Error in rev walk", e);
130 res.setStatus(SC_INTERNAL_SERVER_ERROR);
131 return;
132 } finally {
133 if (walk != null) {
134 walk.release();
135 }
136 }
137 }
138
Dave Borowitz80334b22013-01-11 14:19:11 -0800139 private static GitilesView getView(HttpServletRequest req, Repository repo) throws IOException {
140 GitilesView view = ViewFilter.getView(req);
141 if (view.getRevision() != Revision.NULL) {
142 return view;
143 }
144 Ref headRef = repo.getRef(Constants.HEAD);
145 if (headRef == null) {
146 return null;
147 }
148 RevWalk walk = new RevWalk(repo);
149 try {
150 return GitilesView.log()
151 .copyFrom(view)
Dave Borowitz48ca6702013-04-09 11:52:41 -0700152 .setRevision(Revision.peel(Constants.HEAD, walk.parseAny(headRef.getObjectId()), walk))
Dave Borowitz80334b22013-01-11 14:19:11 -0800153 .build();
154 } finally {
155 walk.release();
156 }
157 }
158
Dave Borowitz9de65952012-08-13 16:09:45 -0700159 private static Optional<ObjectId> getStart(ListMultimap<String, String> params,
160 ObjectReader reader) throws IOException {
161 List<String> values = params.get(START_PARAM);
162 switch (values.size()) {
163 case 0:
164 return Optional.absent();
165 case 1:
166 Collection<ObjectId> ids = reader.resolve(AbbreviatedObjectId.fromString(values.get(0)));
167 if (ids.size() != 1) {
168 return null;
169 }
170 return Optional.of(Iterables.getOnlyElement(ids));
171 default:
172 return null;
173 }
174 }
175
176 private static RevWalk newWalk(Repository repo, GitilesView view)
177 throws MissingObjectException, IncorrectObjectTypeException, IOException {
178 RevWalk walk = new RevWalk(repo);
179 walk.markStart(walk.parseCommit(view.getRevision().getId()));
180 if (view.getOldRevision() != Revision.NULL) {
181 walk.markUninteresting(walk.parseCommit(view.getOldRevision().getId()));
182 }
Dave Borowitzdd3c3d92013-03-11 16:38:41 -0700183 if (!Strings.isNullOrEmpty(view.getPathPart())) {
184 walk.setTreeFilter(FollowFilter.create(view.getPathPart()));
Dave Borowitz9de65952012-08-13 16:09:45 -0700185 }
186 return walk;
187 }
188}