blob: 9887195ecd31002100edd24d2bf9c03beca72a47 [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;
18import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
19import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
20import static org.eclipse.jgit.lib.Constants.OBJ_COMMIT;
21import static org.eclipse.jgit.lib.Constants.OBJ_TAG;
22import static org.eclipse.jgit.lib.Constants.OBJ_TREE;
23
24import com.google.common.collect.ImmutableMap;
Dave Borowitz01551272014-03-16 13:43:16 -070025import com.google.common.collect.ImmutableSet;
Dave Borowitz9de65952012-08-13 16:09:45 -070026import com.google.common.collect.Lists;
Robert Iannucci5d93b852014-09-27 19:48:44 -070027import com.google.common.io.BaseEncoding;
Dave Borowitz01551272014-03-16 13:43:16 -070028import com.google.gitiles.CommitData.Field;
Dave Borowitz90d1db92014-03-16 14:16:15 -070029import com.google.gitiles.CommitJsonData.Commit;
Dave Borowitz2b2f34b2014-04-29 16:47:20 -070030import com.google.gitiles.DateFormatter.Format;
Dave Borowitz9de65952012-08-13 16:09:45 -070031
32import org.eclipse.jgit.errors.IncorrectObjectTypeException;
33import org.eclipse.jgit.errors.MissingObjectException;
34import org.eclipse.jgit.http.server.ServletUtils;
Shawn Pearce73e34532015-02-12 16:27:54 -080035import org.eclipse.jgit.lib.Config;
Dave Borowitz9de65952012-08-13 16:09:45 -070036import org.eclipse.jgit.lib.Constants;
37import org.eclipse.jgit.lib.ObjectId;
Robert Iannucci5d93b852014-09-27 19:48:44 -070038import org.eclipse.jgit.lib.ObjectLoader;
Dave Borowitzfe8fdab2014-11-04 16:19:33 -080039import org.eclipse.jgit.lib.ObjectReader;
Dave Borowitz9de65952012-08-13 16:09:45 -070040import org.eclipse.jgit.lib.Repository;
41import org.eclipse.jgit.revwalk.RevCommit;
42import org.eclipse.jgit.revwalk.RevObject;
43import org.eclipse.jgit.revwalk.RevTag;
Shawn Pearce73e34532015-02-12 16:27:54 -080044import org.eclipse.jgit.revwalk.RevTree;
Dave Borowitz9de65952012-08-13 16:09:45 -070045import org.eclipse.jgit.revwalk.RevWalk;
46import org.slf4j.Logger;
47import org.slf4j.LoggerFactory;
48
49import java.io.IOException;
Robert Iannucci5d93b852014-09-27 19:48:44 -070050import java.io.OutputStream;
51import java.io.Writer;
Dave Borowitz9de65952012-08-13 16:09:45 -070052import java.util.List;
53import java.util.Map;
54
55import javax.servlet.http.HttpServletRequest;
56import javax.servlet.http.HttpServletResponse;
57
58/** Serves an HTML page with detailed information about a ref. */
59public class RevisionServlet extends BaseServlet {
Dave Borowitz90d1db92014-03-16 14:16:15 -070060 private static final ImmutableSet<Field> COMMIT_SOY_FIELDS =
61 Field.setOf(CommitSoyData.DEFAULT_FIELDS, Field.DIFF_TREE);
62 private static final ImmutableSet<Field> COMMIT_JSON_FIELDS =
63 Field.setOf(CommitJsonData.DEFAULT_FIELDS, Field.DIFF_TREE);
Dave Borowitz01551272014-03-16 13:43:16 -070064
Chad Horohoead23f142012-11-12 09:45:39 -080065 private static final long serialVersionUID = 1L;
Dave Borowitz9de65952012-08-13 16:09:45 -070066 private static final Logger log = LoggerFactory.getLogger(RevisionServlet.class);
67
68 private final Linkifier linkifier;
69
Dave Borowitzded109a2014-03-03 15:25:39 -050070 public RevisionServlet(GitilesAccess.Factory accessFactory, Renderer renderer,
Dave Borowitz2b2f34b2014-04-29 16:47:20 -070071 Linkifier linkifier) {
Dave Borowitz8d6d6872014-03-16 15:18:14 -070072 super(renderer, accessFactory);
Dave Borowitz9de65952012-08-13 16:09:45 -070073 this.linkifier = checkNotNull(linkifier, "linkifier");
74 }
75
76 @Override
Dave Borowitz90d1db92014-03-16 14:16:15 -070077 protected void doGetHtml(HttpServletRequest req, HttpServletResponse res) throws IOException {
Dave Borowitz9de65952012-08-13 16:09:45 -070078 GitilesView view = ViewFilter.getView(req);
79 Repository repo = ServletUtils.getRepository(req);
Dave Borowitz2b2f34b2014-04-29 16:47:20 -070080 GitilesAccess access = getAccess(req);
Shawn Pearce73e34532015-02-12 16:27:54 -080081 Config cfg = getAccess(req).getConfig();
Dave Borowitz9de65952012-08-13 16:09:45 -070082
Shawn Pearceb5ad0a02015-05-24 20:33:17 -070083 try (RevWalk walk = new RevWalk(repo)) {
Dave Borowitz2b2f34b2014-04-29 16:47:20 -070084 DateFormatter df = new DateFormatter(access, Format.DEFAULT);
Dave Borowitz558005d2012-12-20 15:48:08 -080085 List<RevObject> objects = listObjects(walk, view.getRevision());
Dave Borowitz9de65952012-08-13 16:09:45 -070086 List<Map<String, ?>> soyObjects = Lists.newArrayListWithCapacity(objects.size());
87 boolean hasBlob = false;
Shawn Pearce73e34532015-02-12 16:27:54 -080088 boolean hasReadme = false;
Dave Borowitz9de65952012-08-13 16:09:45 -070089
90 // TODO(sop): Allow caching commits by SHA-1 when no S cookie is sent.
91 for (RevObject obj : objects) {
92 try {
93 switch (obj.getType()) {
94 case OBJ_COMMIT:
95 soyObjects.add(ImmutableMap.of(
96 "type", Constants.TYPE_COMMIT,
Dave Borowitz3b086a72013-07-02 15:03:03 -070097 "data", new CommitSoyData()
98 .setLinkifier(linkifier)
99 .setRevWalk(walk)
Dave Borowitz2b2f34b2014-04-29 16:47:20 -0700100 .setArchiveFormat(getArchiveFormat(access))
Dave Borowitz90d1db92014-03-16 14:16:15 -0700101 .toSoyData(req, (RevCommit) obj, COMMIT_SOY_FIELDS, df)));
Dave Borowitz9de65952012-08-13 16:09:45 -0700102 break;
103 case OBJ_TREE:
Shawn Pearce73e34532015-02-12 16:27:54 -0800104 Map<String, Object> tree =
105 new TreeSoyData(walk.getObjectReader(), view, cfg, (RevTree) obj)
106 .toSoyData(obj);
Dave Borowitz9de65952012-08-13 16:09:45 -0700107 soyObjects.add(ImmutableMap.of(
108 "type", Constants.TYPE_TREE,
Shawn Pearce73e34532015-02-12 16:27:54 -0800109 "data", tree));
110 hasReadme = tree.containsKey("readmeHtml");
Dave Borowitz9de65952012-08-13 16:09:45 -0700111 break;
112 case OBJ_BLOB:
113 soyObjects.add(ImmutableMap.of(
114 "type", Constants.TYPE_BLOB,
Dave Borowitz6e797482014-05-01 11:10:01 -0700115 "data", new BlobSoyData(walk.getObjectReader(), view).toSoyData(obj)));
Dave Borowitz9de65952012-08-13 16:09:45 -0700116 hasBlob = true;
117 break;
118 case OBJ_TAG:
119 soyObjects.add(ImmutableMap.of(
120 "type", Constants.TYPE_TAG,
Dave Borowitza03760a2014-01-29 16:17:28 -0800121 "data", new TagSoyData(linkifier, req).toSoyData((RevTag) obj, df)));
Dave Borowitz9de65952012-08-13 16:09:45 -0700122 break;
123 default:
Dave Borowitzfd25c3a2013-01-11 14:37:11 -0800124 log.warn("Bad object type for {}: {}", ObjectId.toString(obj.getId()), obj.getType());
Dave Borowitz9de65952012-08-13 16:09:45 -0700125 res.setStatus(SC_NOT_FOUND);
126 return;
127 }
128 } catch (MissingObjectException e) {
129 log.warn("Missing object " + ObjectId.toString(obj.getId()), e);
130 res.setStatus(SC_NOT_FOUND);
131 return;
132 } catch (IncorrectObjectTypeException e) {
133 log.warn("Incorrect object type for " + ObjectId.toString(obj.getId()), e);
134 res.setStatus(SC_NOT_FOUND);
135 return;
136 }
137 }
138
Dave Borowitzb1c628f2013-01-11 11:28:20 -0800139 renderHtml(req, res, "gitiles.revisionDetail", ImmutableMap.of(
Dave Borowitz9de65952012-08-13 16:09:45 -0700140 "title", view.getRevision().getName(),
141 "objects", soyObjects,
Shawn Pearce73e34532015-02-12 16:27:54 -0800142 "hasBlob", hasBlob,
143 "hasReadme", hasReadme));
Dave Borowitz9de65952012-08-13 16:09:45 -0700144 }
145 }
146
Dave Borowitz90d1db92014-03-16 14:16:15 -0700147 @Override
Robert Iannucci5d93b852014-09-27 19:48:44 -0700148 protected void doGetText(HttpServletRequest req, HttpServletResponse res) throws IOException {
149 GitilesView view = ViewFilter.getView(req);
150 Repository repo = ServletUtils.getRepository(req);
Shawn Pearceb5ad0a02015-05-24 20:33:17 -0700151 try (ObjectReader reader = repo.newObjectReader()) {
Robert Iannucci5d93b852014-09-27 19:48:44 -0700152 ObjectLoader loader = reader.open(view.getRevision().getId());
153 if (loader.getType() != OBJ_COMMIT) {
154 res.setStatus(SC_NOT_FOUND);
155 } else {
Robert Iannuccie6dafdf2014-10-10 20:54:30 -0700156 PathServlet.setTypeHeader(res, loader.getType());
Robert Iannucci5d93b852014-09-27 19:48:44 -0700157 try (Writer writer = startRenderText(req, res);
158 OutputStream out = BaseEncoding.base64().encodingStream(writer)) {
159 loader.copyTo(out);
160 }
161 }
Robert Iannucci5d93b852014-09-27 19:48:44 -0700162 }
163 }
164
165 @Override
Dave Borowitz90d1db92014-03-16 14:16:15 -0700166 protected void doGetJson(HttpServletRequest req, HttpServletResponse res) throws IOException {
167 GitilesView view = ViewFilter.getView(req);
168 Repository repo = ServletUtils.getRepository(req);
169
Shawn Pearceb5ad0a02015-05-24 20:33:17 -0700170 try (RevWalk walk = new RevWalk(repo)) {
Dave Borowitz2b2f34b2014-04-29 16:47:20 -0700171 DateFormatter df = new DateFormatter(getAccess(req), Format.DEFAULT);
Dave Borowitz90d1db92014-03-16 14:16:15 -0700172 RevObject obj = walk.parseAny(view.getRevision().getId());
173 switch (obj.getType()) {
174 case OBJ_COMMIT:
175 renderJson(req, res, new CommitJsonData()
176 .setRevWalk(walk)
177 .toJsonData(req, (RevCommit) obj, COMMIT_JSON_FIELDS, df),
178 Commit.class);
179 break;
180 default:
181 // TODO(dborowitz): Support showing other types.
182 res.setStatus(SC_NOT_FOUND);
183 break;
184 }
Dave Borowitz90d1db92014-03-16 14:16:15 -0700185 }
186 }
187
Dave Borowitz9de65952012-08-13 16:09:45 -0700188 // TODO(dborowitz): Extract this.
Dave Borowitz558005d2012-12-20 15:48:08 -0800189 static List<RevObject> listObjects(RevWalk walk, Revision rev)
Dave Borowitz9de65952012-08-13 16:09:45 -0700190 throws MissingObjectException, IOException {
191 List<RevObject> objects = Lists.newArrayListWithExpectedSize(1);
Dave Borowitz558005d2012-12-20 15:48:08 -0800192 ObjectId id = rev.getId();
193 RevObject cur;
Dave Borowitz9de65952012-08-13 16:09:45 -0700194 while (true) {
Dave Borowitz558005d2012-12-20 15:48:08 -0800195 cur = walk.parseAny(id);
Dave Borowitz9de65952012-08-13 16:09:45 -0700196 objects.add(cur);
Dave Borowitz558005d2012-12-20 15:48:08 -0800197 if (cur.getType() != Constants.OBJ_TAG) {
Dave Borowitz9de65952012-08-13 16:09:45 -0700198 break;
199 }
Dave Borowitz558005d2012-12-20 15:48:08 -0800200 id = ((RevTag) cur).getObject();
201 }
202 if (cur.getType() == Constants.OBJ_COMMIT) {
203 objects.add(walk.parseTree(((RevCommit) cur).getTree()));
Dave Borowitz9de65952012-08-13 16:09:45 -0700204 }
205 return objects;
206 }
207}