blob: b3afa0438bbd995d4385728468eaab7931ff7ee2 [file] [log] [blame]
Dave Borowitzb772cce2012-12-28 13:57:22 -08001// 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 Borowitzc410f962014-09-23 10:49:26 -070017import static com.google.common.base.MoreObjects.firstNonNull;
Dave Borowitzba1bd222014-07-30 09:50:29 -070018import static com.google.common.base.Preconditions.checkNotNull;
19
Dave Borowitzf6dcf7a2014-07-30 10:26:58 -070020import com.google.common.collect.ImmutableMap;
Dave Borowitz01551272014-03-16 13:43:16 -070021import com.google.common.collect.ImmutableSet;
Dave Borowitz209d0aa2012-12-28 14:28:53 -080022import com.google.common.collect.Maps;
Dave Borowitz01551272014-03-16 13:43:16 -070023import com.google.common.collect.Sets;
24import com.google.gitiles.CommitData.Field;
David Pursehouse28726042019-06-27 09:09:30 +090025import com.google.template.soy.jbcsrc.api.SoySauce;
Dave Borowitz3b744b12016-08-19 16:11:10 -040026import java.io.IOException;
27import java.io.Writer;
28import java.util.Map;
29import java.util.Set;
30import javax.annotation.Nullable;
31import javax.servlet.http.HttpServletRequest;
Dave Borowitzcb88d4d2015-10-26 13:58:17 -040032import org.eclipse.jgit.diff.DiffEntry;
33import org.eclipse.jgit.diff.DiffEntry.ChangeType;
Dave Borowitzba1bd222014-07-30 09:50:29 -070034import org.eclipse.jgit.lib.Config;
Dave Borowitzb772cce2012-12-28 13:57:22 -080035import org.eclipse.jgit.lib.ObjectId;
Dave Borowitzb772cce2012-12-28 13:57:22 -080036import org.eclipse.jgit.revwalk.RevCommit;
Dave Borowitzb772cce2012-12-28 13:57:22 -080037
Dave Borowitzb772cce2012-12-28 13:57:22 -080038public class LogSoyData {
Han-Wen Nienhuysc0200f62016-05-02 17:34:51 +020039 private static final ImmutableSet<Field> FIELDS =
40 Sets.immutableEnumSet(
41 Field.ABBREV_SHA,
42 Field.SHA,
43 Field.URL,
44 Field.SHORT_MESSAGE,
45 Field.MESSAGE,
46 Field.AUTHOR,
47 Field.COMMITTER,
48 Field.BRANCHES,
Jonathan Niederb911eb32023-08-16 00:42:59 +000049 Field.TAGS);
Michael Moss558f8642014-04-15 09:29:21 -070050 private static final ImmutableSet<Field> VERBOSE_FIELDS = Field.setOf(FIELDS, Field.DIFF_TREE);
Dave Borowitz01551272014-03-16 13:43:16 -070051
Dave Borowitz571b7a02018-02-09 15:18:10 -050052 /** Behavior for the footer link when rendering streaming log data. */
53 public enum FooterBehavior {
54 /** "Next" link that skips commits in the current view. */
55 NEXT,
56
57 /** "More" link that starts from HEAD. */
58 LOG_HEAD;
59 }
60
Dave Borowitzb772cce2012-12-28 13:57:22 -080061 private final HttpServletRequest req;
Dave Borowitzf6dcf7a2014-07-30 10:26:58 -070062 private final GitilesView view;
Dave Borowitzba1bd222014-07-30 09:50:29 -070063 private final Set<Field> fields;
Dave Borowitzba1bd222014-07-30 09:50:29 -070064 private final String variant;
Gustaf Lundh06a98702015-08-17 17:29:11 +020065 private CommitSoyData csd;
Dave Borowitzb772cce2012-12-28 13:57:22 -080066
Dave Borowitzba1bd222014-07-30 09:50:29 -070067 public LogSoyData(HttpServletRequest req, GitilesAccess access, String pretty)
68 throws IOException {
69 this.req = checkNotNull(req);
Dave Borowitzf6dcf7a2014-07-30 10:26:58 -070070 this.view = checkNotNull(ViewFilter.getView(req));
Dave Borowitzb15a5862015-09-16 15:14:56 -040071 checkNotNull(pretty);
Dave Borowitzba1bd222014-07-30 09:50:29 -070072 Config config = access.getConfig();
Sam Delmericoe4ae3592024-01-31 14:44:58 -080073 fields =
74 config.getBoolean("logFormat", pretty, "verbose", false) || pretty.equals("fuller")
75 ? VERBOSE_FIELDS
76 : FIELDS;
Dave Borowitzc410f962014-09-23 10:49:26 -070077 variant = firstNonNull(config.getString("logFormat", pretty, "variant"), pretty);
Dave Borowitzb772cce2012-12-28 13:57:22 -080078 }
79
JiaYan Lin3cc31b22024-09-25 08:26:14 +000080 private void renderHtml(SoySauce.Renderer renderer, Appendable out) throws IOException {
David Pursehouse28726042019-06-27 09:09:30 +090081 if (!renderer.renderHtml(out).result().isDone()) {
82 throw new IOException("failed to render HTML");
83 }
84 }
85
Han-Wen Nienhuysc0200f62016-05-02 17:34:51 +020086 public void renderStreaming(
87 Paginator paginator,
88 @Nullable String revision,
89 Renderer renderer,
David Pursehouse28726042019-06-27 09:09:30 +090090 Writer writer,
Dave Borowitz571b7a02018-02-09 15:18:10 -050091 DateFormatter df,
92 FooterBehavior footerBehavior)
Han-Wen Nienhuysc0200f62016-05-02 17:34:51 +020093 throws IOException {
David Pursehouse28726042019-06-27 09:09:30 +090094 renderHtml(
95 renderer
Sven Selbergd99004c2022-01-31 10:24:08 +010096 .newRenderer("com.google.gitiles.templates.LogDetail.logEntriesHeader")
David Pursehouse28726042019-06-27 09:09:30 +090097 .setData(toHeaderSoyData(paginator, revision)),
JiaYan Lin3cc31b22024-09-25 08:26:14 +000098 writer);
Dave Borowitzf6dcf7a2014-07-30 10:26:58 -070099
Sven Selbergd99004c2022-01-31 10:24:08 +0100100 SoySauce.Renderer entryRenderer =
101 renderer.newRenderer("com.google.gitiles.templates.LogDetail.logEntryWrapper");
Andrew Bonventreb33426e2015-09-09 18:28:28 -0400102 boolean renderedEntries = false;
Dave Borowitzf6dcf7a2014-07-30 10:26:58 -0700103 for (RevCommit c : paginator) {
JiaYan Lin3cc31b22024-09-25 08:26:14 +0000104 renderHtml(entryRenderer.setData(toEntrySoyData(paginator, c, df)), writer);
Andrew Bonventreb33426e2015-09-09 18:28:28 -0400105 renderedEntries = true;
Dave Borowitzf6dcf7a2014-07-30 10:26:58 -0700106 }
Andrew Bonventreb33426e2015-09-09 18:28:28 -0400107 if (!renderedEntries) {
JiaYan Lin3cc31b22024-09-25 08:26:14 +0000108 renderHtml(renderer.newRenderer("com.google.gitiles.templates.LogDetail.emptyLog"), writer);
Dave Borowitzf6dcf7a2014-07-30 10:26:58 -0700109 }
110
David Pursehouse28726042019-06-27 09:09:30 +0900111 renderHtml(
112 renderer
Sven Selbergd99004c2022-01-31 10:24:08 +0100113 .newRenderer("com.google.gitiles.templates.LogDetail.logEntriesFooter")
David Pursehouse28726042019-06-27 09:09:30 +0900114 .setData(toFooterSoyData(paginator, revision, footerBehavior)),
JiaYan Lin3cc31b22024-09-25 08:26:14 +0000115 writer);
Dave Borowitz27fada42013-11-01 11:09:49 -0700116 }
117
Dave Borowitzf6dcf7a2014-07-30 10:26:58 -0700118 private Map<String, Object> toHeaderSoyData(Paginator paginator, @Nullable String revision) {
Andrew Bonventreb33426e2015-09-09 18:28:28 -0400119 Map<String, Object> data = Maps.newHashMapWithExpectedSize(1);
Dave Borowitzb772cce2012-12-28 13:57:22 -0800120 ObjectId prev = paginator.getPreviousStart();
121 if (prev != null) {
Dave Borowitzf6dcf7a2014-07-30 10:26:58 -0700122 GitilesView.Builder prevView = copyAndCanonicalizeView(revision);
Sam Delmericoe4ae3592024-01-31 14:44:58 -0800123 if (prevView.getRevision().getId().equals(prev)) {
124 prevView.removeParam(LogServlet.START_PARAM);
125 } else {
Dave Borowitzb772cce2012-12-28 13:57:22 -0800126 prevView.replaceParam(LogServlet.START_PARAM, prev.name());
127 }
128 data.put("previousUrl", prevView.toUrl());
129 }
130 return data;
131 }
132
Andrew Bonventreb33426e2015-09-09 18:28:28 -0400133 private Map<String, Object> toEntrySoyData(Paginator paginator, RevCommit c, DateFormatter df)
134 throws IOException {
Gustaf Lundh06a98702015-08-17 17:29:11 +0200135 if (csd == null) {
136 csd = new CommitSoyData();
137 }
138
Jonathan Niederb49306a2019-03-07 14:10:57 -0800139 Map<String, Object> entry = csd.toSoyData(req, paginator.getWalk(), c, fields, df);
Dave Borowitzcb88d4d2015-10-26 13:58:17 -0400140 DiffEntry rename = paginator.getRename(c);
141 if (rename != null) {
142 entry.put("rename", toRenameSoyData(rename));
143 }
Dave Borowitzf6dcf7a2014-07-30 10:26:58 -0700144 return ImmutableMap.of(
Dave Borowitzf6dcf7a2014-07-30 10:26:58 -0700145 "variant", variant,
146 "entry", entry);
147 }
148
Matthias Sohnc156c962023-09-30 22:15:23 +0200149 private @Nullable Map<String, Object> toRenameSoyData(DiffEntry entry) {
Dave Borowitzcb88d4d2015-10-26 13:58:17 -0400150 if (entry == null) {
151 return null;
152 }
153 ChangeType type = entry.getChangeType();
154 if (type != ChangeType.RENAME && type != ChangeType.COPY) {
155 return null;
156 }
Han-Wen Nienhuysc0200f62016-05-02 17:34:51 +0200157 return ImmutableMap.<String, Object>of(
Dave Borowitzcb88d4d2015-10-26 13:58:17 -0400158 "changeType", type.toString(),
159 "oldPath", entry.getOldPath(),
160 "newPath", entry.getNewPath(),
161 "score", entry.getScore());
162 }
163
Dave Borowitz571b7a02018-02-09 15:18:10 -0500164 private Map<String, Object> toFooterSoyData(
165 Paginator paginator, @Nullable String revision, FooterBehavior behavior) {
166 switch (behavior) {
167 case NEXT:
168 ObjectId next = paginator.getNextStart();
169 if (next == null) {
170 return ImmutableMap.of();
171 }
172 return ImmutableMap.of(
173 "nextUrl",
174 copyAndCanonicalizeView(revision)
175 .replaceParam(LogServlet.START_PARAM, next.name())
176 .toUrl(),
177 "nextText",
178 "Next");
179
180 case LOG_HEAD:
181 return ImmutableMap.of(
182 "nextUrl", GitilesView.log().copyFrom(view).toUrl(), "nextText", "More");
183 default:
184 throw new IllegalStateException("unknown footer behavior: " + behavior);
Dave Borowitzf6dcf7a2014-07-30 10:26:58 -0700185 }
Dave Borowitzf6dcf7a2014-07-30 10:26:58 -0700186 }
187
188 private GitilesView.Builder copyAndCanonicalizeView(String revision) {
Dave Borowitzb772cce2012-12-28 13:57:22 -0800189 // Canonicalize the view by using full SHAs.
190 GitilesView.Builder copy = GitilesView.log().copyFrom(view);
David Pursehousec53de2b2019-06-01 15:27:25 +0900191 if (!Revision.isNull(view.getRevision())) {
Dave Borowitzb772cce2012-12-28 13:57:22 -0800192 copy.setRevision(view.getRevision());
Dave Borowitzfa80a6a2018-02-09 15:31:49 -0500193 } else if (revision != null) {
Dave Borowitzb772cce2012-12-28 13:57:22 -0800194 copy.setRevision(Revision.named(revision));
Dave Borowitzfa80a6a2018-02-09 15:31:49 -0500195 } else {
196 copy.setRevision(Revision.NULL);
Dave Borowitzb772cce2012-12-28 13:57:22 -0800197 }
David Pursehousec53de2b2019-06-01 15:27:25 +0900198 if (!Revision.isNull(view.getOldRevision())) {
Dave Borowitzb772cce2012-12-28 13:57:22 -0800199 copy.setOldRevision(view.getOldRevision());
200 }
201 return copy;
202 }
203}