Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import java.util.stream.Collectors;

Expand All @@ -60,6 +59,8 @@
import org.opengrok.indexer.history.RepositoryInfo;
import org.opengrok.indexer.logger.LoggerFactory;

import static org.opengrok.indexer.configuration.PatternUtil.compilePattern;


/**
* Placeholder class for all configuration variables. Due to the multi-threaded
Expand All @@ -76,20 +77,6 @@ public final class Configuration {
private static final Logger LOGGER = LoggerFactory.getLogger(Configuration.class);
public static final String PLUGIN_DIRECTORY_DEFAULT = "plugins";

/**
* A check if a pattern contains at least one pair of parentheses meaning
* that there is at least one capture group. This group must not be empty.
*/
private static final String PATTERN_SINGLE_GROUP = ".*\\([^\\)]+\\).*";
/**
* Error string for invalid patterns without a single group. This is passed
* as a first argument to the constructor of PatternSyntaxException and in
* the output it is followed by the invalid pattern.
*
* @see PatternSyntaxException
* @see #PATTERN_SINGLE_GROUP
*/
private static final String PATTERN_MUST_CONTAIN_GROUP = "The pattern must contain at least one non-empty group -";
/**
* Error string for negative numbers (could be int, double, long, ...).
* First argument is the name of the property, second argument is the actual
Expand Down Expand Up @@ -1057,10 +1044,7 @@ public String getBugPage() {
* contain a single character
*/
public void setBugPattern(String bugPattern) throws PatternSyntaxException {
if (!bugPattern.matches(PATTERN_SINGLE_GROUP)) {
throw new PatternSyntaxException(PATTERN_MUST_CONTAIN_GROUP, bugPattern, 0);
}
this.bugPattern = Pattern.compile(bugPattern).toString();
this.bugPattern = compilePattern(bugPattern);
}

public String getBugPattern() {
Expand Down Expand Up @@ -1088,10 +1072,7 @@ public String getReviewPattern() {
* contain a single character
*/
public void setReviewPattern(String reviewPattern) throws PatternSyntaxException {
if (!reviewPattern.matches(PATTERN_SINGLE_GROUP)) {
throw new PatternSyntaxException(PATTERN_MUST_CONTAIN_GROUP, reviewPattern, 0);
}
this.reviewPattern = Pattern.compile(reviewPattern).toString();
this.reviewPattern = compilePattern(reviewPattern);
}

public String getWebappLAF() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* See LICENSE.txt included in this distribution for the specific
* language governing permissions and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at LICENSE.txt.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/

/*
* Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved.
*/
package org.opengrok.indexer.configuration;

import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

public class PatternUtil {
private PatternUtil() {
// private to enforce static
}

/**
* A check if a pattern contains at least one pair of parentheses meaning
* that there is at least one capture group. This group must not be empty.
*/
static final String PATTERN_SINGLE_GROUP = ".*\\([^\\)]+\\).*";
/**
* Error string for invalid patterns without a single group. This is passed
* as a first argument to the constructor of PatternSyntaxException and in
* the output it is followed by the invalid pattern.
*
* @see PatternSyntaxException
* @see #PATTERN_SINGLE_GROUP
*/
static final String PATTERN_MUST_CONTAIN_GROUP = "The pattern must contain at least one non-empty group -";

/**
* Check and compile the bug pattern.
*
* @param pattern the new pattern
* @throws PatternSyntaxException when the pattern is not a valid regexp or
* does not contain at least one capture group and the group does not
* contain a single character
*/
public static String compilePattern(String pattern) throws PatternSyntaxException {
if (!pattern.matches(PATTERN_SINGLE_GROUP)) {
throw new PatternSyntaxException(PATTERN_MUST_CONTAIN_GROUP, pattern, 0);
}
return Pattern.compile(pattern).toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,15 @@
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.PatternSyntaxException;

import org.opengrok.indexer.logger.LoggerFactory;
import org.opengrok.indexer.util.ClassUtil;
import org.opengrok.indexer.util.ForbiddenSymlinkException;
import org.opengrok.indexer.web.Util;

import static org.opengrok.indexer.configuration.PatternUtil.compilePattern;

/**
* Placeholder for the information that builds up a project.
*/
Expand Down Expand Up @@ -100,6 +104,14 @@ public class Project implements Comparable<Project>, Nameable, Serializable {
*/
private transient Set<Group> groups = new TreeSet<>();

/**
* These properties override global settings, if set.
*/
private String bugPage;
private String bugPattern;
private String reviewPage;
private String reviewPattern;

// This empty constructor is needed for serialization.
public Project() {
}
Expand Down Expand Up @@ -302,6 +314,70 @@ public void addGroup(Group group) {
}
}

public void setBugPage(String bugPage) {
this.bugPage = bugPage;
}

public String getBugPage() {
if (bugPage != null) {
return bugPage;
} else {
return RuntimeEnvironment.getInstance().getBugPage();
}
}

/**
* Set the bug pattern to a new value.
*
* @param bugPattern the new pattern
* @throws PatternSyntaxException when the pattern is not a valid regexp or
* does not contain at least one capture group and the group does not
* contain a single character
*/
public void setBugPattern(String bugPattern) throws PatternSyntaxException {
this.bugPattern = compilePattern(bugPattern);
}

public String getBugPattern() {
if (bugPattern != null) {
return bugPattern;
} else {
return RuntimeEnvironment.getInstance().getBugPattern();
}
}

public String getReviewPage() {
if (reviewPage != null) {
return reviewPage;
} else {
return RuntimeEnvironment.getInstance().getReviewPage();
}
}

public void setReviewPage(String reviewPage) {
this.reviewPage = reviewPage;
}

public String getReviewPattern() {
if (reviewPattern != null) {
return reviewPattern;
} else {
return RuntimeEnvironment.getInstance().getReviewPattern();
}
}

/**
* Set the review pattern to a new value.
*
* @param reviewPattern the new pattern
* @throws PatternSyntaxException when the pattern is not a valid regexp or
* does not contain at least one capture group and the group does not
* contain a single character
*/
public void setReviewPattern(String reviewPattern) throws PatternSyntaxException {
this.reviewPattern = compilePattern(reviewPattern);
}

/**
* Fill the project with the current configuration where the applicable
* project property has a default value.
Expand All @@ -310,7 +386,7 @@ public final void completeWithDefaults() {
Configuration defaultCfg = new Configuration();
final RuntimeEnvironment env = RuntimeEnvironment.getInstance();

/**
/*
* Choosing strategy for properties (tabSize used as example here):
* <pre>
* this cfg defaultCfg chosen value
Expand Down Expand Up @@ -346,6 +422,20 @@ public final void completeWithDefaults() {
if (mergeCommitsEnabled == null) {
setMergeCommitsEnabled(env.isMergeCommitsEnabled());
}

if (bugPage == null) {
setBugPage(env.getBugPage());
}
if (bugPattern == null) {
setBugPattern(env.getBugPattern());
}

if (reviewPage == null) {
setReviewPage(env.getReviewPage());
}
if (reviewPattern == null) {
setReviewPattern(env.getReviewPattern());
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ public void testMergeProjects1() {
RuntimeEnvironment env = RuntimeEnvironment.getInstance();
env.setTabSize(new Configuration().getTabSize() + 3731);
env.setNavigateWindowEnabled(!new Configuration().isNavigateWindowEnabled());
env.setBugPage("http://example.com/bugPage");
env.setBugPattern("([1-9][0-9]{6,7})");
env.setReviewPage("http://example.com/reviewPage");
env.setReviewPattern("([A-Z]{2}ARC[ \\\\/]\\\\d{4}/\\\\d{3})");

Project p1 = new Project();
assertNotNull(p1);
Expand All @@ -143,6 +147,10 @@ public void testMergeProjects1() {

assertEquals(env.getTabSize(), p1.getTabSize());
assertEquals(env.isNavigateWindowEnabled(), p1.isNavigateWindowEnabled());
assertEquals(env.getBugPage(), p1.getBugPage());
assertEquals(env.getBugPattern(), p1.getBugPattern());
assertEquals(env.getReviewPage(), p1.getReviewPage());
assertEquals(env.getReviewPattern(), p1.getReviewPattern());
}

/**
Expand All @@ -157,13 +165,25 @@ public void testMergeProjects2() {
p1.setTabSize(new Project().getTabSize() + 9737);
p1.setNavigateWindowEnabled(true);
p1.setHandleRenamedFiles(true);
final String customBugPage = "http://example.com/bugPage";
p1.setBugPage(customBugPage);
final String customBugPattern = "([1-9][0-1]{6,7})";
p1.setBugPattern(customBugPattern);
final String customReviewPage = "http://example.com/reviewPage";
p1.setReviewPage(customReviewPage);
final String customReviewPattern = "([A-Z]{2}XYZ[ \\\\/]\\\\d{4}/\\\\d{3})";
p1.setReviewPattern(customReviewPattern);

p1.completeWithDefaults();

assertNotNull(p1);
assertTrue(p1.isNavigateWindowEnabled(), "Navigate window should be turned on");
assertTrue(p1.isHandleRenamedFiles(), "Renamed file handling should be true");
assertEquals(new Project().getTabSize() + 9737, p1.getTabSize());
assertEquals(p1.getBugPage(), customBugPage);
assertEquals(p1.getBugPattern(), customBugPattern);
assertEquals(p1.getReviewPage(), customReviewPage);
assertEquals(p1.getReviewPattern(), customReviewPattern);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -791,6 +791,7 @@ public String[] getSearchOnlyIn() {
*
* @return {@code null} if not available, the project otherwise.
*/
@Nullable
public Project getProject() {
return Project.getProject(getResourceFile());
}
Expand Down
23 changes: 15 additions & 8 deletions opengrok-web/src/main/webapp/history.jsp
Original file line number Diff line number Diff line change
Expand Up @@ -171,16 +171,23 @@ include file="minisearch.jspf"
if ((hist = (History) request.getAttribute("history.jsp-hist")) != null) {
RuntimeEnvironment env = cfg.getEnv();
String uriEncodedName = cfg.getUriEncodedPath();
Project project = cfg.getProject();

boolean striked = false;
String userPage = env.getUserPage();
String userPageSuffix = env.getUserPageSuffix();
String bugPage = env.getBugPage();
String bugRegex = env.getBugPattern();
Pattern bugPattern = Pattern.compile(bugRegex);
String reviewPage = env.getReviewPage();
String reviewRegex = env.getReviewPattern();
Pattern reviewPattern = Pattern.compile(reviewRegex);
String bugPage = project != null ? project.getBugPage() : env.getBugPage();
String bugRegex = project != null ? project.getBugPattern() : env.getBugPattern();
Pattern bugPattern = null;
if (bugRegex != null) {
bugPattern = Pattern.compile(bugRegex);
}
String reviewPage = project != null ? project.getReviewPage() : env.getReviewPage();
String reviewRegex = project != null ? project.getReviewPattern() : env.getReviewPattern();
Pattern reviewPattern = null;
if (reviewRegex != null) {
reviewPattern = Pattern.compile(reviewRegex);
}

Format df = new SimpleDateFormat("dd-MMM-yyyy");

Expand Down Expand Up @@ -352,10 +359,10 @@ document.domReady.push(function() {domReadyHistory();});
int summaryLength = Math.max(10, cfg.getRevisionMessageCollapseThreshold());
String cout = Util.htmlize(entry.getMessage());

if (bugPage != null && bugPage.length() > 0) {
if (bugPage != null && bugPage.length() > 0 && bugPattern != null) {
cout = Util.linkifyPattern(cout, bugPattern, "$1", Util.completeUrl(bugPage + "$1", request));
}
if (reviewPage != null && reviewPage.length() > 0) {
if (reviewPage != null && reviewPage.length() > 0 && reviewPattern != null) {
cout = Util.linkifyPattern(cout, reviewPattern, "$1", Util.completeUrl(reviewPage + "$1", request));
}

Expand Down