blob: ef3289a42d5d0b10e214a21779c2c99340abf598 [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
David Pletcherd7bdaf32014-08-27 14:50:32 -070017import static java.nio.charset.StandardCharsets.UTF_8;
Dave Borowitz9de65952012-08-13 16:09:45 -070018import static org.eclipse.jgit.lib.Constants.OBJ_COMMIT;
19
20import com.google.common.annotations.VisibleForTesting;
Dave Borowitz73269892013-11-13 14:23:50 -080021import com.google.common.base.Strings;
Dave Borowitz9de65952012-08-13 16:09:45 -070022import com.google.common.collect.Lists;
23import com.google.common.collect.Maps;
Dave Borowitz9de65952012-08-13 16:09:45 -070024import com.google.gitiles.PathServlet.FileType;
Shawn Pearce47fd6562016-05-28 14:15:15 -070025import com.google.gitiles.doc.MarkdownConfig;
Dave Borowitz9de65952012-08-13 16:09:45 -070026
27import org.eclipse.jgit.errors.MissingObjectException;
Shawn Pearce73e34532015-02-12 16:27:54 -080028import org.eclipse.jgit.lib.Config;
Dave Borowitz9de65952012-08-13 16:09:45 -070029import org.eclipse.jgit.lib.ObjectId;
Dave Borowitz7c0a8332014-05-01 11:07:04 -070030import org.eclipse.jgit.lib.ObjectReader;
Shawn Pearce73e34532015-02-12 16:27:54 -080031import org.eclipse.jgit.revwalk.RevTree;
Dave Borowitz9de65952012-08-13 16:09:45 -070032import org.eclipse.jgit.treewalk.TreeWalk;
33
34import java.io.IOException;
35import java.util.List;
36import java.util.Map;
Dave Borowitz9de65952012-08-13 16:09:45 -070037
38/** Soy data converter for git trees. */
39public class TreeSoyData {
40 /**
41 * Number of characters to display for a symlink target. Targets longer than
42 * this are abbreviated for display in a tree listing.
43 */
44 private static final int MAX_SYMLINK_TARGET_LENGTH = 72;
45
46 /**
47 * Maximum number of bytes to load from a blob that claims to be a symlink. If
48 * the blob is larger than this byte limit it will be displayed as a binary
49 * file instead of as a symlink.
50 */
51 static final int MAX_SYMLINK_SIZE = 16 << 10;
52
53 static String resolveTargetUrl(GitilesView view, String target) {
Dave Borowitzcfc1c532015-02-18 13:41:19 -080054 String resolved = PathUtil.simplifyPathUpToRoot(target, view.getPathPart());
Dave Borowitzbcd753d2013-02-08 11:10:19 -080055 if (resolved == null) {
Dave Borowitz9de65952012-08-13 16:09:45 -070056 return null;
57 }
Han-Wen Nienhuysc0200f62016-05-02 17:34:51 +020058 return GitilesView.path().copyFrom(view).setPathPart(resolved).toUrl();
Dave Borowitz9de65952012-08-13 16:09:45 -070059 }
60
61 @VisibleForTesting
62 static String getTargetDisplayName(String target) {
63 if (target.length() <= MAX_SYMLINK_TARGET_LENGTH) {
64 return target;
Dave Borowitz9de65952012-08-13 16:09:45 -070065 }
David Pursehouseb3b630f2016-06-15 21:51:18 +090066 int lastSlash = target.lastIndexOf('/');
67 // TODO(dborowitz): Doesn't abbreviate a long last path component.
68 return lastSlash >= 0 ? "..." + target.substring(lastSlash) : target;
Dave Borowitz9de65952012-08-13 16:09:45 -070069 }
70
Dave Borowitz7c0a8332014-05-01 11:07:04 -070071 private final ObjectReader reader;
Dave Borowitz9de65952012-08-13 16:09:45 -070072 private final GitilesView view;
Shawn Pearce73e34532015-02-12 16:27:54 -080073 private final Config cfg;
74 private final RevTree rootTree;
Shawn Pearcec68ad0b2016-05-28 16:52:47 -070075 private final String requestUri;
Dave Borowitzc782ebe2013-11-11 11:43:29 -080076 private ArchiveFormat archiveFormat;
Dave Borowitz9de65952012-08-13 16:09:45 -070077
Shawn Pearcec68ad0b2016-05-28 16:52:47 -070078 public TreeSoyData(
79 ObjectReader reader, GitilesView view, Config cfg, RevTree rootTree, String requestUri) {
Dave Borowitz7c0a8332014-05-01 11:07:04 -070080 this.reader = reader;
Dave Borowitz9de65952012-08-13 16:09:45 -070081 this.view = view;
Shawn Pearce73e34532015-02-12 16:27:54 -080082 this.cfg = cfg;
83 this.rootTree = rootTree;
Shawn Pearcec68ad0b2016-05-28 16:52:47 -070084 this.requestUri = requestUri;
Dave Borowitz9de65952012-08-13 16:09:45 -070085 }
86
Dave Borowitzc782ebe2013-11-11 11:43:29 -080087 public TreeSoyData setArchiveFormat(ArchiveFormat archiveFormat) {
88 this.archiveFormat = archiveFormat;
89 return this;
90 }
91
Han-Wen Nienhuysc0200f62016-05-02 17:34:51 +020092 public Map<String, Object> toSoyData(ObjectId treeId, TreeWalk tw)
93 throws MissingObjectException, IOException {
Shawn Pearcec68ad0b2016-05-28 16:52:47 -070094 ReadmeHelper readme =
95 new ReadmeHelper(reader, view, MarkdownConfig.get(cfg), rootTree, requestUri);
Dave Borowitz9de65952012-08-13 16:09:45 -070096 List<Object> entries = Lists.newArrayList();
97 GitilesView.Builder urlBuilder = GitilesView.path().copyFrom(view);
98 while (tw.next()) {
99 FileType type = FileType.forEntry(tw);
100 String name = tw.getNameString();
101
102 switch (view.getType()) {
103 case PATH:
Dave Borowitzdd3c3d92013-03-11 16:38:41 -0700104 urlBuilder.setPathPart(view.getPathPart() + "/" + name);
Dave Borowitz9de65952012-08-13 16:09:45 -0700105 break;
106 case REVISION:
107 // Got here from a tag pointing at a tree.
Dave Borowitzdd3c3d92013-03-11 16:38:41 -0700108 urlBuilder.setPathPart(name);
Dave Borowitz9de65952012-08-13 16:09:45 -0700109 break;
110 default:
Han-Wen Nienhuysc0200f62016-05-02 17:34:51 +0200111 throw new IllegalStateException(
112 String.format("Cannot render TreeSoyData from %s view", view.getType()));
Dave Borowitz9de65952012-08-13 16:09:45 -0700113 }
114
115 String url = urlBuilder.toUrl();
116 if (type == FileType.TREE) {
117 name += "/";
118 url += "/";
119 }
120 Map<String, String> entry = Maps.newHashMapWithExpectedSize(4);
121 entry.put("type", type.toString());
122 entry.put("name", name);
123 entry.put("url", url);
124 if (type == FileType.SYMLINK) {
Han-Wen Nienhuysc0200f62016-05-02 17:34:51 +0200125 String target = new String(reader.open(tw.getObjectId(0)).getCachedBytes(), UTF_8);
Dave Borowitz9de65952012-08-13 16:09:45 -0700126 entry.put("targetName", getTargetDisplayName(target));
127 String targetUrl = resolveTargetUrl(view, target);
128 if (targetUrl != null) {
129 entry.put("targetUrl", targetUrl);
130 }
Shawn Pearce45e83752015-02-20 17:59:05 -0800131 } else {
132 readme.considerEntry(tw);
Dave Borowitz9de65952012-08-13 16:09:45 -0700133 }
134 entries.add(entry);
135 }
136
137 Map<String, Object> data = Maps.newHashMapWithExpectedSize(3);
138 data.put("sha", treeId.name());
139 data.put("entries", entries);
140
141 if (view.getType() == GitilesView.Type.PATH
142 && view.getRevision().getPeeledType() == OBJ_COMMIT) {
143 data.put("logUrl", GitilesView.log().copyFrom(view).toUrl());
Han-Wen Nienhuysc0200f62016-05-02 17:34:51 +0200144 data.put(
145 "archiveUrl",
146 GitilesView.archive()
147 .copyFrom(view)
148 .setPathPart(Strings.emptyToNull(view.getPathPart()))
149 .setExtension(archiveFormat.getDefaultSuffix())
150 .toUrl());
Dave Borowitzc782ebe2013-11-11 11:43:29 -0800151 data.put("archiveType", archiveFormat.getShortName());
Dave Borowitz9de65952012-08-13 16:09:45 -0700152 }
153
Shawn Pearce45e83752015-02-20 17:59:05 -0800154 if (readme.isPresent()) {
155 data.put("readmePath", readme.getPath());
156 data.put("readmeHtml", readme.render());
Shawn Pearce73e34532015-02-12 16:27:54 -0800157 }
158
Dave Borowitz9de65952012-08-13 16:09:45 -0700159 return data;
160 }
161
162 public Map<String, Object> toSoyData(ObjectId treeId) throws MissingObjectException, IOException {
Dave Borowitz7c0a8332014-05-01 11:07:04 -0700163 TreeWalk tw = new TreeWalk(reader);
Dave Borowitz9de65952012-08-13 16:09:45 -0700164 tw.addTree(treeId);
165 tw.setRecursive(false);
166 return toSoyData(treeId, tw);
167 }
Dave Borowitz9de65952012-08-13 16:09:45 -0700168}