blob: 6bf0feb7764d68fd98a4ba1da2a6c02bf66330d7 [file] [log] [blame]
Shawn Pearce45e83752015-02-20 17:59:05 -08001// Copyright 2015 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 com.google.gitiles.doc.GitilesMarkdown;
18import com.google.gitiles.doc.ImageLoader;
19import com.google.gitiles.doc.MarkdownToHtml;
20import com.google.template.soy.data.SanitizedContent;
21
22import org.eclipse.jgit.errors.CorruptObjectException;
23import org.eclipse.jgit.errors.IncorrectObjectTypeException;
24import org.eclipse.jgit.errors.LargeObjectException;
25import org.eclipse.jgit.errors.MissingObjectException;
26import org.eclipse.jgit.lib.Config;
27import org.eclipse.jgit.lib.Constants;
28import org.eclipse.jgit.lib.FileMode;
29import org.eclipse.jgit.lib.ObjectId;
30import org.eclipse.jgit.lib.ObjectReader;
31import org.eclipse.jgit.revwalk.RevTree;
32import org.eclipse.jgit.treewalk.TreeWalk;
33import org.eclipse.jgit.util.RawParseUtils;
Shawn Pearce0e5fc542016-02-15 14:27:05 -080034import org.joda.time.Duration;
Shawn Pearce45e83752015-02-20 17:59:05 -080035import org.pegdown.ast.RootNode;
36import org.slf4j.Logger;
37import org.slf4j.LoggerFactory;
38
39import java.io.IOException;
40
41class ReadmeHelper {
42 private static final Logger log = LoggerFactory.getLogger(ReadmeHelper.class);
43
44 private final ObjectReader reader;
45 private final GitilesView view;
46 private final Config cfg;
47 private final RevTree rootTree;
48 private final boolean render;
49
50 private String readmePath;
51 private ObjectId readmeId;
52
Han-Wen Nienhuysc0200f62016-05-02 17:34:51 +020053 ReadmeHelper(ObjectReader reader, GitilesView view, Config cfg, RevTree rootTree) {
Shawn Pearce45e83752015-02-20 17:59:05 -080054 this.reader = reader;
55 this.view = view;
56 this.cfg = cfg;
57 this.rootTree = rootTree;
58 render = cfg.getBoolean("markdown", "render", true);
59 }
60
Han-Wen Nienhuysc0200f62016-05-02 17:34:51 +020061 void scanTree(RevTree tree)
62 throws MissingObjectException, IncorrectObjectTypeException, CorruptObjectException,
63 IOException {
Shawn Pearce45e83752015-02-20 17:59:05 -080064 if (render) {
65 TreeWalk tw = new TreeWalk(reader);
66 tw.setRecursive(false);
67 tw.addTree(tree);
68 while (tw.next() && !isPresent()) {
69 considerEntry(tw);
70 }
71 }
72 }
73
74 void considerEntry(TreeWalk tw) {
75 if (render
76 && FileMode.REGULAR_FILE.equals(tw.getRawMode(0))
77 && isReadmeFile(tw.getNameString())) {
78 readmePath = tw.getPathString();
79 readmeId = tw.getObjectId(0);
80 }
81 }
82
83 boolean isPresent() {
84 return readmeId != null;
85 }
86
87 String getPath() {
88 return readmePath;
89 }
90
91 SanitizedContent render() {
92 try {
Han-Wen Nienhuysc0200f62016-05-02 17:34:51 +020093 Duration parseTimeout =
94 ConfigUtil.getDuration(
95 cfg, "markdown", null, "parseTimeout", Duration.standardSeconds(2));
Shawn Pearce45e83752015-02-20 17:59:05 -080096 int inputLimit = cfg.getInt("markdown", "inputLimit", 5 << 20);
97 byte[] raw = reader.open(readmeId, Constants.OBJ_BLOB).getCachedBytes(inputLimit);
98 String md = RawParseUtils.decode(raw);
Han-Wen Nienhuysc0200f62016-05-02 17:34:51 +020099 RootNode root = GitilesMarkdown.parseFile(parseTimeout, view, readmePath, md);
Shawn Pearce45e83752015-02-20 17:59:05 -0800100 if (root == null) {
101 return null;
102 }
103
104 int imageLimit = cfg.getInt("markdown", "imageLimit", 256 << 10);
105 ImageLoader img = null;
106 if (imageLimit > 0) {
107 img = new ImageLoader(reader, view, rootTree, readmePath, imageLimit);
108 }
109
Han-Wen Nienhuysc0200f62016-05-02 17:34:51 +0200110 return new MarkdownToHtml(view, cfg).setImageLoader(img).setReadme(true).toSoyHtml(root);
Shawn Pearce45e83752015-02-20 17:59:05 -0800111 } catch (LargeObjectException | IOException e) {
Han-Wen Nienhuysc0200f62016-05-02 17:34:51 +0200112 log.error(String.format("error rendering %s/%s", view.getRepositoryName(), readmePath), e);
Shawn Pearce45e83752015-02-20 17:59:05 -0800113 return null;
114 }
115 }
116
117 /** True if the file is the default markdown file to render in tree view. */
118 private static boolean isReadmeFile(String name) {
119 return name.equalsIgnoreCase("README.md");
120 }
121}