io.github.svndump_to_git.git.model.SvnMergeInfoUtils Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2014 The Kuali Foundation Licensed under the
* Educational Community 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.osedu.org/licenses/ECL-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 io.github.svndump_to_git.git.model;
import io.github.svndump_to_git.branch.model.BranchData;
import io.github.svndump_to_git.common.io.IOUtils;
import io.github.svndump_to_git.git.model.branch.BranchDetector;
import io.github.svndump_to_git.git.model.branch.exceptions.VetoBranchException;
import io.github.svndump_to_git.git.model.branch.utils.GitBranchUtils;
import io.github.svndump_to_git.git.model.branch.utils.GitBranchUtils.ILargeBranchNameProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
/**
* @author Kuali Student Team
*
*/
public class SvnMergeInfoUtils {
private static final Logger log = LoggerFactory.getLogger(SvnMergeInfoUtils.class);
/**
* Consume the full content of the input stream and parse out the svn:mergeinfo property content found.
*
* You should use a bounded input stream sized for only the length of the svn:mergeinfo data to be consumed.
*
* @param inputStream
* @return the list of brance merge info
* @throws IOException
*/
public static ListextractBranchMergeInfoFromInputStream (BranchDetector branchDetector, InputStream inputStream) throws IOException {
StringBuilder builder = new StringBuilder();
while (true) {
String line = IOUtils.readLine(inputStream, "UTF-8");
if (line == null)
break;
if (line.isEmpty())
continue;
builder.append(line).append("\n");
}
return extractBranchMergeInfoFromString(branchDetector, builder.toString());
}
public static ListextractBranchMergeInfoFromString (BranchDetector branchDetector, String inputString) {
ListbmiList = new LinkedList<>();
String lines[] = inputString.split("\\n");
for (String line : lines) {
if (line.isEmpty())
continue; // skip to the next line
String [] parts = line.split(":");
if (parts.length != 2)
continue; // skip to the next line
String branchPath = parts[0].trim();
if (branchPath.startsWith("/")) {
// trim the leading slash if it exists.
branchPath = branchPath.substring(1);
}
BranchData bd = null;
try {
bd = branchDetector.parseBranch(0L, branchPath);
} catch (VetoBranchException e) {
log.warn("failed to detect a branch on " + branchPath);
continue; // skip to the next line
}
BranchMergeInfo bmi = new BranchMergeInfo(bd.getBranchPath());
String revisions = parts[1].trim();
String revParts[] = revisions.split(",");
/*
* A star (*) suffix on a number is used to indicate that the revision was record only merged.
*
* We strip the value and treat all merged revisions the same.
*
*/
for (String revString : revParts) {
if (revString.contains("-")) {
// a range
String rangeParts[] = revString.split("-");
long rangeStart = Long.parseLong(rangeParts[0].trim().replaceAll("\\*", ""));
long rangeEndInclusive = Long.parseLong(rangeParts[1].trim().replaceAll("\\*", ""));
long low = rangeStart;
long highInclusive = rangeEndInclusive;
if (rangeEndInclusive < rangeStart) {
// reverse the high and low
low = rangeEndInclusive;
highInclusive = rangeStart;
}
for(long i = low; i <= highInclusive; i++) {
bmi.addMergeRevision(i);
}
}
else {
// a single value
bmi.addMergeRevision(Long.valueOf(revString.replaceAll("\\*", "")));
}
}
bmiList.add(bmi);
}
return bmiList;
}
public static interface BranchRangeDataProvider {
public boolean areCommitsAdjacent(String branchName, long firstRevision, long secondRevision);
}
public static void consolidateConsecutiveRanges(BranchRangeDataProvider rangeDataProvider, BranchDetector branchDetector,
ILargeBranchNameProvider provider, List deltas) {
for (BranchMergeInfo delta : deltas) {
ListorderedRevisions = new ArrayList<>(delta.getMergedRevisions());
if (orderedRevisions.size() < 2)
continue;
delta.clearMergedRevisions();
Collections.sort(orderedRevisions);
long previousRevision = orderedRevisions.get(0);
for (int i = 1; i < orderedRevisions.size(); i++) {
Long rev = orderedRevisions.get(i);
String branchName = GitBranchUtils.getCanonicalBranchName(delta.getBranchName(), 1L, provider);
if (!rangeDataProvider.areCommitsAdjacent(branchName, previousRevision, rev)) {
// range ends
delta.addMergeRevision(previousRevision);
}
else {
// range continues
}
previousRevision = rev;
}
// always store the last revision
delta.addMergeRevision(previousRevision);
}
}
/**
* Computes the difference, what has been added to the target that is not in the source, between the two sets of merge info and returns the difference out.
* @param sourceData
* @param targetData
* @return the delta between the target and the source data.
*/
public static ListcomputeDifference (ListsourceData, ListtargetData) {
Listdifference = new ArrayList<>();
// branch name to bmi
HashMap sourceBmiMap = new HashMap();
for (BranchMergeInfo sourceBmi : sourceData) {
sourceBmiMap.put(sourceBmi.getBranchName(), sourceBmi);
}
for (BranchMergeInfo targetBmi : targetData) {
BranchMergeInfo sourceBmi = sourceBmiMap.get(targetBmi.getBranchName());
if (sourceBmi == null) {
// add the entire target bmi to the result
difference.add(targetBmi);
}
else {
BranchMergeInfo differenceBMI = new BranchMergeInfo (targetBmi.getBranchName());
LinkedHashSet revsDifference = new LinkedHashSet(targetBmi.getMergedRevisions());
revsDifference.removeAll(sourceBmi.getMergedRevisions());
differenceBMI.setMergedRevisions(revsDifference);
difference.add(differenceBMI);
}
}
return difference;
}
}