ProjectConfig sections refactoring
Add a new class RefConfigSection to be superclass for some sections in project.config file. This is a preparation to include "Merge Strategy per branch" feature which will add another section to project.config file. Change-Id: I559aad8325358823471665b24186470a76aaf967
This commit is contained in:
committed by
Gustaf Lundh
parent
040834ffc4
commit
45fd656895
@@ -0,0 +1,124 @@
|
||||
// Copyright (C) 2011 The Android Open Source Project
|
||||
//
|
||||
// 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.google.gerrit.server.util;
|
||||
|
||||
import com.google.gerrit.common.data.RefConfigSection;
|
||||
import com.google.gerrit.server.project.RefControl;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
/**
|
||||
* Order the Ref Pattern by the most specific. This sort is done by:
|
||||
* <ul>
|
||||
* <li>1 - The minor value of Levenshtein string distance between the branch
|
||||
* name and the regex string shortest example. A shorter distance is a more
|
||||
* specific match.
|
||||
* <li>2 - Finites first, infinities after.
|
||||
* <li>3 - Number of transitions.
|
||||
* <li>4 - Length of the expression text.
|
||||
* </ul>
|
||||
*
|
||||
* Levenshtein distance is a measure of the similarity between two strings.
|
||||
* The distance is the number of deletions, insertions, or substitutions
|
||||
* required to transform one string into another.
|
||||
*
|
||||
* For example, if given refs/heads/m* and refs/heads/*, the distances are 5
|
||||
* and 6. It means that refs/heads/m* is more specific because it's closer to
|
||||
* refs/heads/master than refs/heads/*.
|
||||
*
|
||||
* Another example could be refs/heads/* and refs/heads/[a-zA-Z]*, the
|
||||
* distances are both 6. Both are infinite, but refs/heads/[a-zA-Z]* has more
|
||||
* transitions, which after all turns it more specific.
|
||||
*/
|
||||
public final class MostSpecificComparator implements
|
||||
Comparator<RefConfigSection> {
|
||||
private final String refName;
|
||||
|
||||
public MostSpecificComparator(String refName) {
|
||||
this.refName = refName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(RefConfigSection a, RefConfigSection b) {
|
||||
return compare(a.getName(), b.getName());
|
||||
}
|
||||
|
||||
public int compare(final String pattern1, final String pattern2) {
|
||||
int cmp = distance(pattern1) - distance(pattern2);
|
||||
if (cmp == 0) {
|
||||
boolean p1_finite = finite(pattern1);
|
||||
boolean p2_finite = finite(pattern2);
|
||||
|
||||
if (p1_finite && !p2_finite) {
|
||||
cmp = -1;
|
||||
} else if (!p1_finite && p2_finite) {
|
||||
cmp = 1;
|
||||
} else /* if (f1 == f2) */{
|
||||
cmp = 0;
|
||||
}
|
||||
}
|
||||
if (cmp == 0) {
|
||||
cmp = transitions(pattern1) - transitions(pattern2);
|
||||
}
|
||||
if (cmp == 0) {
|
||||
cmp = pattern2.length() - pattern1.length();
|
||||
}
|
||||
return cmp;
|
||||
}
|
||||
|
||||
private int distance(String pattern) {
|
||||
String example;
|
||||
if (RefControl.isRE(pattern)) {
|
||||
example = RefControl.shortestExample(pattern);
|
||||
|
||||
} else if (pattern.endsWith("/*")) {
|
||||
example = pattern.substring(0, pattern.length() - 1) + '1';
|
||||
|
||||
} else if (pattern.equals(refName)) {
|
||||
return 0;
|
||||
|
||||
} else {
|
||||
return Math.max(pattern.length(), refName.length());
|
||||
}
|
||||
return StringUtils.getLevenshteinDistance(example, refName);
|
||||
}
|
||||
|
||||
private boolean finite(String pattern) {
|
||||
if (RefControl.isRE(pattern)) {
|
||||
return RefControl.toRegExp(pattern).toAutomaton().isFinite();
|
||||
|
||||
} else if (pattern.endsWith("/*")) {
|
||||
return false;
|
||||
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private int transitions(String pattern) {
|
||||
if (RefControl.isRE(pattern)) {
|
||||
return RefControl.toRegExp(pattern).toAutomaton()
|
||||
.getNumberOfTransitions();
|
||||
|
||||
} else if (pattern.endsWith("/*")) {
|
||||
return pattern.length();
|
||||
|
||||
} else {
|
||||
return pattern.length();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user