blob: c4087a6edc54810a78c948f89c6cc3b4def4d3ae [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.checkState;
Dave Borowitzd6184a62013-01-10 11:53:54 -080018import static org.eclipse.jgit.diff.DiffEntry.ChangeType.COPY;
19import static org.eclipse.jgit.diff.DiffEntry.ChangeType.DELETE;
20import static org.eclipse.jgit.diff.DiffEntry.ChangeType.RENAME;
21
Dave Borowitz9de65952012-08-13 16:09:45 -070022import com.google.common.collect.ImmutableMap;
23import com.google.common.collect.ImmutableSet;
24import com.google.common.collect.Lists;
25import com.google.common.collect.Maps;
Dave Borowitz75a78322014-03-16 12:13:08 -070026import com.google.common.collect.Sets;
Dave Borowitz01551272014-03-16 13:43:16 -070027import com.google.gitiles.CommitData.DiffList;
28import com.google.gitiles.CommitData.Field;
Dave Borowitz9de65952012-08-13 16:09:45 -070029import com.google.template.soy.data.restricted.NullData;
Dave Borowitz3b744b12016-08-19 16:11:10 -040030import java.io.IOException;
31import java.util.List;
32import java.util.Map;
33import java.util.Set;
34import javax.annotation.Nullable;
35import javax.servlet.http.HttpServletRequest;
Dave Borowitz9de65952012-08-13 16:09:45 -070036import org.eclipse.jgit.diff.DiffEntry;
37import org.eclipse.jgit.diff.DiffEntry.ChangeType;
Dave Borowitz9de65952012-08-13 16:09:45 -070038import org.eclipse.jgit.lib.Constants;
Dave Borowitz9de65952012-08-13 16:09:45 -070039import org.eclipse.jgit.lib.PersonIdent;
40import org.eclipse.jgit.lib.Ref;
Dave Borowitz9de65952012-08-13 16:09:45 -070041import org.eclipse.jgit.revwalk.RevCommit;
42import org.eclipse.jgit.revwalk.RevWalk;
Dave Borowitz9de65952012-08-13 16:09:45 -070043import org.eclipse.jgit.util.RelativeDateFormatter;
Dave Borowitz9de65952012-08-13 16:09:45 -070044
Dave Borowitz9de65952012-08-13 16:09:45 -070045/** Soy data converter for git commits. */
Dave Borowitz6ed598f2014-04-17 10:09:50 -070046public class CommitSoyData {
Han-Wen Nienhuysc0200f62016-05-02 17:34:51 +020047 static final ImmutableSet<Field> DEFAULT_FIELDS =
48 Sets.immutableEnumSet(
49 Field.AUTHOR,
50 Field.COMMITTER,
51 Field.SHA,
52 Field.TREE,
53 Field.TREE_URL,
54 Field.PARENTS,
55 Field.MESSAGE,
56 Field.LOG_URL,
57 Field.ARCHIVE_URL,
58 Field.ARCHIVE_TYPE);
Dave Borowitz9de65952012-08-13 16:09:45 -070059
Han-Wen Nienhuysc0200f62016-05-02 17:34:51 +020060 private static final ImmutableSet<Field> NESTED_FIELDS =
61 Sets.immutableEnumSet(Field.PARENT_BLAME_URL);
Dave Borowitzf03fcea2014-04-21 17:20:33 -070062
Dave Borowitz3b086a72013-07-02 15:03:03 -070063 private Linkifier linkifier;
Gustaf Lundh06a98702015-08-17 17:29:11 +020064 private CommitData.Builder cdb;
Dave Borowitzc8a15682013-07-02 14:33:08 -070065 private ArchiveFormat archiveFormat;
Dave Borowitz9de65952012-08-13 16:09:45 -070066
Dave Borowitz01551272014-03-16 13:43:16 -070067 CommitSoyData setLinkifier(@Nullable Linkifier linkifier) {
68 this.linkifier = linkifier;
Dave Borowitz3b086a72013-07-02 15:03:03 -070069 return this;
Dave Borowitz9de65952012-08-13 16:09:45 -070070 }
71
Dave Borowitz01551272014-03-16 13:43:16 -070072 CommitSoyData setArchiveFormat(@Nullable ArchiveFormat archiveFormat) {
73 this.archiveFormat = archiveFormat;
Dave Borowitzc8a15682013-07-02 14:33:08 -070074 return this;
75 }
76
Han-Wen Nienhuysc0200f62016-05-02 17:34:51 +020077 Map<String, Object> toSoyData(
Jonathan Niederb49306a2019-03-07 14:10:57 -080078 HttpServletRequest req, RevWalk walk, RevCommit c, Set<Field> fs, DateFormatter df)
79 throws IOException {
Dave Borowitz01551272014-03-16 13:43:16 -070080 GitilesView view = ViewFilter.getView(req);
Gustaf Lundh06a98702015-08-17 17:29:11 +020081 if (cdb == null) {
82 cdb = new CommitData.Builder();
83 }
84
Jonathan Niederb49306a2019-03-07 14:10:57 -080085 CommitData cd = cdb.setArchiveFormat(archiveFormat).build(req, walk, c, fs);
Dave Borowitz3b086a72013-07-02 15:03:03 -070086
Dave Borowitz01551272014-03-16 13:43:16 -070087 Map<String, Object> data = Maps.newHashMapWithExpectedSize(fs.size());
88 if (cd.author != null) {
89 data.put("author", toSoyData(cd.author, df));
Dave Borowitz9de65952012-08-13 16:09:45 -070090 }
Dave Borowitz01551272014-03-16 13:43:16 -070091 if (cd.committer != null) {
92 data.put("committer", toSoyData(cd.committer, df));
Dave Borowitz9de65952012-08-13 16:09:45 -070093 }
Dave Borowitz01551272014-03-16 13:43:16 -070094 if (cd.sha != null) {
95 data.put("sha", cd.sha.name());
Dave Borowitz9de65952012-08-13 16:09:45 -070096 }
Dave Borowitz01551272014-03-16 13:43:16 -070097 if (cd.abbrev != null) {
98 data.put("abbrevSha", cd.abbrev.name());
Dave Borowitz9de65952012-08-13 16:09:45 -070099 }
Dave Borowitz01551272014-03-16 13:43:16 -0700100 if (cd.url != null) {
101 data.put("url", cd.url);
Dave Borowitz9de65952012-08-13 16:09:45 -0700102 }
Dave Borowitz01551272014-03-16 13:43:16 -0700103 if (cd.logUrl != null) {
104 data.put("logUrl", cd.logUrl);
Dave Borowitzc222cce2013-06-19 10:47:06 -0700105 }
Dave Borowitz01551272014-03-16 13:43:16 -0700106 if (cd.archiveUrl != null) {
107 data.put("archiveUrl", cd.archiveUrl);
Dave Borowitzc8a15682013-07-02 14:33:08 -0700108 }
Dave Borowitz01551272014-03-16 13:43:16 -0700109 if (cd.archiveType != null) {
110 data.put("archiveType", cd.archiveType.getShortName());
Dave Borowitz9de65952012-08-13 16:09:45 -0700111 }
Dave Borowitz01551272014-03-16 13:43:16 -0700112 if (cd.tree != null) {
113 data.put("tree", cd.tree.name());
Dave Borowitz9de65952012-08-13 16:09:45 -0700114 }
Dave Borowitz01551272014-03-16 13:43:16 -0700115 if (cd.treeUrl != null) {
116 data.put("treeUrl", cd.treeUrl);
Dave Borowitz9de65952012-08-13 16:09:45 -0700117 }
Dave Borowitz01551272014-03-16 13:43:16 -0700118 if (cd.parents != null) {
Dave Borowitzf03fcea2014-04-21 17:20:33 -0700119 data.put("parents", toSoyData(view, fs, cd.parents));
Dave Borowitz9de65952012-08-13 16:09:45 -0700120 }
Dave Borowitz01551272014-03-16 13:43:16 -0700121 if (cd.shortMessage != null) {
122 data.put("shortMessage", cd.shortMessage);
Dave Borowitz9de65952012-08-13 16:09:45 -0700123 }
Dave Borowitz01551272014-03-16 13:43:16 -0700124 if (cd.branches != null) {
125 data.put("branches", toSoyData(view, cd.branches, Constants.R_HEADS));
Dave Borowitz9de65952012-08-13 16:09:45 -0700126 }
Dave Borowitz01551272014-03-16 13:43:16 -0700127 if (cd.tags != null) {
128 data.put("tags", toSoyData(view, cd.tags, Constants.R_TAGS));
Dave Borowitz9de65952012-08-13 16:09:45 -0700129 }
Dave Borowitz01551272014-03-16 13:43:16 -0700130 if (cd.message != null) {
Dave Borowitz9de65952012-08-13 16:09:45 -0700131 if (linkifier != null) {
Dave Borowitz01551272014-03-16 13:43:16 -0700132 data.put("message", linkifier.linkify(req, cd.message));
Dave Borowitz9de65952012-08-13 16:09:45 -0700133 } else {
Dave Borowitz01551272014-03-16 13:43:16 -0700134 data.put("message", cd.message);
Dave Borowitz9de65952012-08-13 16:09:45 -0700135 }
136 }
Dave Borowitz01551272014-03-16 13:43:16 -0700137 if (cd.diffEntries != null) {
138 data.put("diffTree", toSoyData(view, cd.diffEntries));
Dave Borowitz9de65952012-08-13 16:09:45 -0700139 }
Han-Wen Nienhuysc0200f62016-05-02 17:34:51 +0200140 checkState(
141 Sets.difference(fs, NESTED_FIELDS).size() == data.size(),
142 "bad commit data fields: %s != %s",
143 fs,
144 data.keySet());
Michael Moss92bb12f2014-05-09 10:55:35 -0700145 return data;
Dave Borowitz9de65952012-08-13 16:09:45 -0700146 }
147
Jonathan Niederb49306a2019-03-07 14:10:57 -0800148 Map<String, Object> toSoyData(
149 HttpServletRequest req, RevWalk walk, RevCommit commit, DateFormatter df) throws IOException {
150 return toSoyData(req, walk, commit, DEFAULT_FIELDS, df);
Dave Borowitz9de65952012-08-13 16:09:45 -0700151 }
152
153 // TODO(dborowitz): Extract this.
Dave Borowitz97a70312014-04-28 15:50:23 -0700154 public static Map<String, String> toSoyData(PersonIdent ident, DateFormatter df) {
Dave Borowitz9de65952012-08-13 16:09:45 -0700155 return ImmutableMap.of(
156 "name", ident.getName(),
157 "email", ident.getEmailAddress(),
Dave Borowitz97a70312014-04-28 15:50:23 -0700158 "time", df.format(ident),
Dave Borowitz9de65952012-08-13 16:09:45 -0700159 // TODO(dborowitz): Switch from relative to absolute at some threshold.
160 "relativeTime", RelativeDateFormatter.format(ident.getWhen()));
161 }
162
Han-Wen Nienhuysc0200f62016-05-02 17:34:51 +0200163 private List<Map<String, String>> toSoyData(
164 GitilesView view, Set<Field> fs, List<RevCommit> parents) {
Dave Borowitz01551272014-03-16 13:43:16 -0700165 List<Map<String, String>> result = Lists.newArrayListWithCapacity(parents.size());
Dave Borowitz9de65952012-08-13 16:09:45 -0700166 int i = 1;
167 // TODO(dborowitz): Render something slightly different when we're actively
168 // viewing a diff against one of the parents.
169 for (RevCommit parent : parents) {
170 String name = parent.name();
Dave Borowitz359ad6d2014-04-21 16:07:59 -0700171 // Clear path on parent diff view, since this parent may not have a diff
172 // for the path in question.
Dave Borowitzdd3c3d92013-03-11 16:38:41 -0700173 GitilesView.Builder diff = GitilesView.diff().copyFrom(view).setPathPart("");
Dave Borowitz9de65952012-08-13 16:09:45 -0700174 String parentName;
Dave Borowitz01551272014-03-16 13:43:16 -0700175 if (parents.size() == 1) {
Dave Borowitz9de65952012-08-13 16:09:45 -0700176 parentName = view.getRevision().getName() + "^";
177 } else {
178 parentName = view.getRevision().getName() + "^" + (i++);
179 }
Dave Borowitz8d11fb72014-09-23 10:27:31 -0700180 diff.setOldRevision(parentName, parent);
181
Dave Borowitzf03fcea2014-04-21 17:20:33 -0700182 Map<String, String> e = Maps.newHashMapWithExpectedSize(4);
183 e.put("sha", name);
Han-Wen Nienhuysc0200f62016-05-02 17:34:51 +0200184 e.put("url", GitilesView.revision().copyFrom(view).setRevision(parentName, parent).toUrl());
Dave Borowitz8d11fb72014-09-23 10:27:31 -0700185 e.put("diffUrl", diff.toUrl());
Dave Borowitzf03fcea2014-04-21 17:20:33 -0700186 if (fs.contains(Field.PARENT_BLAME_URL)) {
187 // Assumes caller has ensured path is a file.
Han-Wen Nienhuysc0200f62016-05-02 17:34:51 +0200188 e.put(
189 "blameUrl",
190 GitilesView.blame()
191 .copyFrom(view)
192 .setRevision(Revision.peeled(parentName, parent))
193 .toUrl());
Dave Borowitzf03fcea2014-04-21 17:20:33 -0700194 }
195 result.add(e);
Dave Borowitz9de65952012-08-13 16:09:45 -0700196 }
197 return result;
198 }
199
Dave Borowitz01551272014-03-16 13:43:16 -0700200 private static Object toSoyData(GitilesView view, DiffList dl) {
201 if (dl.oldRevision == null) {
202 return NullData.INSTANCE;
203 }
Han-Wen Nienhuysc0200f62016-05-02 17:34:51 +0200204 GitilesView.Builder diffUrl =
205 GitilesView.diff()
206 .copyFrom(view)
207 .setOldRevision(dl.oldRevision)
208 .setRevision(dl.revision)
209 .setPathPart("");
Dave Borowitz9de65952012-08-13 16:09:45 -0700210
Dave Borowitz01551272014-03-16 13:43:16 -0700211 List<Object> result = Lists.newArrayListWithCapacity(dl.entries.size());
212 for (DiffEntry e : dl.entries) {
213 Map<String, Object> entry = Maps.newHashMapWithExpectedSize(5);
214 ChangeType type = e.getChangeType();
215 if (type != DELETE) {
216 entry.put("path", e.getNewPath());
Han-Wen Nienhuysc0200f62016-05-02 17:34:51 +0200217 entry.put(
218 "url",
219 GitilesView.path()
220 .copyFrom(view)
221 .setRevision(dl.revision)
222 .setPathPart(e.getNewPath())
223 .toUrl());
Dave Borowitz01551272014-03-16 13:43:16 -0700224 } else {
225 entry.put("path", e.getOldPath());
Han-Wen Nienhuysc0200f62016-05-02 17:34:51 +0200226 entry.put(
227 "url",
228 GitilesView.path()
229 .copyFrom(view)
230 .setRevision(dl.oldRevision)
231 .setPathPart(e.getOldPath())
232 .toUrl());
Dave Borowitz9de65952012-08-13 16:09:45 -0700233 }
Dave Borowitz01551272014-03-16 13:43:16 -0700234 entry.put("diffUrl", diffUrl.setAnchor("F" + result.size()).toUrl());
235 entry.put("changeType", e.getChangeType().toString());
236 if (type == COPY || type == RENAME) {
237 entry.put("oldPath", e.getOldPath());
238 }
239 result.add(entry);
Dave Borowitz9de65952012-08-13 16:09:45 -0700240 }
Dave Borowitz01551272014-03-16 13:43:16 -0700241 return result;
Dave Borowitz9de65952012-08-13 16:09:45 -0700242 }
243
Han-Wen Nienhuysc0200f62016-05-02 17:34:51 +0200244 private static List<Map<String, String>> toSoyData(
245 GitilesView view, List<Ref> refs, String prefix) {
Dave Borowitz9de65952012-08-13 16:09:45 -0700246 List<Map<String, String>> result = Lists.newArrayListWithCapacity(refs.size());
247 for (Ref ref : refs) {
248 if (ref.getName().startsWith(prefix)) {
Han-Wen Nienhuysc0200f62016-05-02 17:34:51 +0200249 result.add(
250 ImmutableMap.of(
251 "name", ref.getName().substring(prefix.length()),
252 "url",
253 GitilesView.revision()
254 .copyFrom(view)
255 .setRevision(Revision.unpeeled(ref.getName(), ref.getObjectId()))
256 .toUrl()));
Dave Borowitz9de65952012-08-13 16:09:45 -0700257 }
258 }
Dave Borowitz9de65952012-08-13 16:09:45 -0700259 return result;
260 }
Dave Borowitz9de65952012-08-13 16:09:45 -0700261}