// Copyright 2012 Google Inc. All Rights Reserved. // // 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.collide.server.shared.merge; import com.google.common.collect.Lists; import org.eclipse.jgit.diff.RawText; import org.eclipse.jgit.diff.RawTextComparator; import org.eclipse.jgit.merge.MergeAlgorithm; import org.eclipse.jgit.merge.MergeChunk.ConflictState; import java.util.List; /** * Merger for performing a 3-way-merge using JGit. * */ public class JGitMerger { private static MergeAlgorithm mergeAlgorithm = new MergeAlgorithm(); public static MergeResult merge(String base, String child, String parent) { // Jgit Merge org.eclipse.jgit.merge.MergeResult<RawText> jgitMergeResult = mergeAlgorithm.merge(RawTextComparator.DEFAULT, new RawText(base.getBytes()), new RawText(child.getBytes()), new RawText(parent.getBytes())); return formatMerge(jgitMergeResult); } public static MergeResult formatMerge(org.eclipse.jgit.merge.MergeResult<RawText> results) { int runningIndex = 0; int numLines = 0; List<MergeChunk> mergeChunks = Lists.newArrayList(); MergeChunk currentMergeChunk = null; StringBuilder fileContent = new StringBuilder(); int conflictIndex = 0; for (org.eclipse.jgit.merge.MergeChunk chunk : results) { RawText seq = results.getSequences().get(chunk.getSequenceIndex()); String chunkContent = seq.getString(chunk.getBegin(), chunk.getEnd(), false); if (chunk.getConflictState() == ConflictState.NO_CONFLICT || chunk.getConflictState() == ConflictState.FIRST_CONFLICTING_RANGE) { if (currentMergeChunk != null) { mergeChunks.add(currentMergeChunk); } currentMergeChunk = new MergeChunk(); } switch (chunk.getConflictState()) { case NO_CONFLICT: currentMergeChunk.setHasConflict(false); currentMergeChunk.setMergedData(chunkContent); fileContent.append(chunkContent); numLines = chunk.getEnd() - chunk.getBegin(); runningIndex = setRanges(currentMergeChunk, runningIndex, numLines); break; case FIRST_CONFLICTING_RANGE: currentMergeChunk.setHasConflict(true); currentMergeChunk.setChildData(chunkContent); fileContent.append(chunkContent); numLines = chunk.getEnd() - chunk.getBegin(); runningIndex = setRanges(currentMergeChunk, runningIndex, numLines); break; case NEXT_CONFLICTING_RANGE: currentMergeChunk.setParentData(chunkContent); break; } } mergeChunks.add(currentMergeChunk); MergeResult mergeResult = new MergeResult(mergeChunks, (conflictIndex > 0) ? "" : fileContent.toString()); return mergeResult; } private static int setRanges(MergeChunk mergeChunk, int runningChildIndex, int numLines) { mergeChunk.setStartLine(runningChildIndex); // JGit end index is exclusive, Collide's is inclusive. numLines can be 0. int endLine = runningChildIndex + numLines; if (numLines > 0) { endLine--; } mergeChunk.setEndLine(endLine); runningChildIndex += numLines; return runningChildIndex; } }