/* * Copyright 2013 gitblit.com. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.gitblit.utils; import java.io.IOException; import java.text.MessageFormat; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.eclipse.jgit.errors.ConfigInvalidException; import org.eclipse.jgit.lib.Repository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.gitblit.IStoredSettings; import com.gitblit.Keys; import com.gitblit.models.RepositoryModel; import com.syntevo.bugtraq.BugtraqConfig; import com.syntevo.bugtraq.BugtraqFormatter; import com.syntevo.bugtraq.BugtraqFormatter.OutputHandler; public class BugtraqProcessor { private final Logger logger = LoggerFactory.getLogger(getClass()); private final IStoredSettings settings; public BugtraqProcessor(IStoredSettings settings) { this.settings = settings; } /** * Returns an html version of the commit message with any global or * repository-specific regular expression substitution applied. * * This method uses the preferred renderer to transform the commit message. * * @param repository * @param model * @param text * @return html version of the commit message */ public String processCommitMessage(Repository repository, RepositoryModel model, String text) { switch (model.commitMessageRenderer) { case MARKDOWN: try { String prepared = processTextRegex(repository, model.name, text); return MarkdownUtils.transformMarkdown(prepared); } catch (Exception e) { logger.error("Failed to render commit message as markdown", e); } break; default: // noop break; } return processPlainCommitMessage(repository, model.name, text); } /** * Returns an html version of the commit message with any global or * repository-specific regular expression substitution applied. * * This method assumes the commit message is plain text. * * @param repository * @param repositoryName * @param text * @return html version of the commit message */ public String processPlainCommitMessage(Repository repository, String repositoryName, String text) { String html = StringUtils.escapeForHtml(text, false); html = processTextRegex(repository, repositoryName, html); return StringUtils.breakLinesForHtml(html); } /** * Returns an processed version of the text with any global or * repository-specific regular expression substitution applied. * * @param repository * @param repositoryName * @param text * @return processed version of the text */ public String processText(Repository repository, String repositoryName, String text) { String html = processTextRegex(repository, repositoryName, text); return html; } /** * Apply globally or per-repository specified regex substitutions to the * text. * * @param repository * @param repositoryName * @param text * @return the processed text */ protected String processTextRegex(Repository repository, String repositoryName, String text) { Map<String, String> map = new HashMap<String, String>(); // global regex keys if (settings.getBoolean(Keys.regex.global, false)) { for (String key : settings.getAllKeys(Keys.regex.global)) { if (!key.equals(Keys.regex.global)) { String subKey = key.substring(key.lastIndexOf('.') + 1); map.put(subKey, settings.getString(key, "")); } } } // repository-specific regex keys List<String> keys = settings.getAllKeys(Keys.regex._ROOT + "." + repositoryName.toLowerCase()); for (String key : keys) { String subKey = key.substring(key.lastIndexOf('.') + 1); map.put(subKey, settings.getString(key, "")); } for (Entry<String, String> entry : map.entrySet()) { String definition = entry.getValue().trim(); String[] chunks = definition.split("!!!"); if (chunks.length == 2) { text = text.replaceAll(chunks[0], chunks[1]); } else { logger.warn(entry.getKey() + " improperly formatted. Use !!! to separate match from replacement: " + definition); } } try { // parse bugtraq repo config BugtraqConfig config = BugtraqConfig.read(repository); if (config != null) { BugtraqFormatter formatter = new BugtraqFormatter(config); StringBuilder sb = new StringBuilder(); formatter.formatLogMessage(text, new BugtraqOutputHandler(sb)); text = sb.toString(); } } catch (IOException e) { logger.error(MessageFormat.format("Bugtraq config for {0} is invalid!", repositoryName), e); } catch (ConfigInvalidException e) { logger.error(MessageFormat.format("Bugtraq config for {0} is invalid!", repositoryName), e); } return text; } private class BugtraqOutputHandler implements OutputHandler { final StringBuilder sb; BugtraqOutputHandler(StringBuilder sb) { this.sb = sb; } @Override public void appendText(String text) { sb.append(text); } @Override public void appendLink(String name, String target) { sb.append(MessageFormat.format("<a class=\"bugtraq\" href=\"{1}\" target=\"_blank\">{0}</a>", name, target)); } } }