Add POC for diff against temporary merge result

This fails for files with merge conflicts, because results for these
files are not added to git and therefore there is no blob the diff
formatter can use to render. This has somehow to be fixed by making
jgit use the version from the file system. Taking a look at the
implementation of Git.clone() might help here.
This commit is contained in:
Rene Pfeuffer
2019-11-06 17:30:02 +01:00
parent c51118f575
commit df144e298c
8 changed files with 172 additions and 32 deletions

View File

@@ -151,6 +151,32 @@ class AbstractGitCommand
}
}
<R, W extends GitCloneWorker<R>> R inCloneWithPostponedClose(Function<Git, W> workerSupplier, GitWorkdirFactory workdirFactory, String initialBranch, WorkingCopyCloser closer) {
try {
WorkingCopy<Repository, Repository> workingCopy = workdirFactory.createWorkingCopy(context, initialBranch);
closer.setWorkingCopy(workingCopy);
Repository repository = workingCopy.getWorkingRepository();
logger.debug("cloned repository to folder {}", repository.getWorkTree());
return workerSupplier.apply(new Git(repository)).run();
} catch (IOException e) {
throw new InternalRepositoryException(context.getRepository(), "could not clone repository", e);
}
}
static class WorkingCopyCloser {
private WorkingCopy<?, ?> workingCopy;
private void setWorkingCopy(WorkingCopy<?, ?> workingCopy) {
this.workingCopy = workingCopy;
}
public void close() {
if (workingCopy != null) {
workingCopy.close();
}
}
}
ObjectId resolveRevisionOrThrowNotFound(Repository repository, String revision) throws IOException {
ObjectId resolved = repository.resolve(revision);
if (resolved == null) {

View File

@@ -8,6 +8,7 @@ import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.EmptyTreeIterator;
import org.eclipse.jgit.treewalk.FileTreeIterator;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.filter.PathFilter;
import sonia.scm.repository.GitUtil;
@@ -37,6 +38,17 @@ final class Differ implements AutoCloseable {
private static Differ create(Repository repository, DiffCommandRequest request) throws IOException {
RevWalk walk = new RevWalk(repository);
if (!Strings.isNullOrEmpty(request.getMergeChangeset()))
{
ObjectId otherRevision = repository.resolve(request.getMergeChangeset());
RevTree tree = walk.parseCommit(otherRevision).getTree();
TreeWalk treeWalk = new TreeWalk(repository);
treeWalk.addTree(tree);
treeWalk.addTree(new FileTreeIterator( repository ));
return new Differ(null, walk, treeWalk);
} else {
ObjectId revision = repository.resolve(request.getRevision());
RevCommit commit = walk.parseCommit(revision);
@@ -46,40 +58,32 @@ final class Differ implements AutoCloseable {
treeWalk.reset();
treeWalk.setRecursive(true);
if (Util.isNotEmpty(request.getPath()))
{
if (Util.isNotEmpty(request.getPath())) {
treeWalk.setFilter(PathFilter.create(request.getPath()));
}
if (!Strings.isNullOrEmpty(request.getAncestorChangeset()))
{
if (!Strings.isNullOrEmpty(request.getAncestorChangeset())) {
ObjectId otherRevision = repository.resolve(request.getAncestorChangeset());
ObjectId ancestorId = GitUtil.computeCommonAncestor(repository, revision, otherRevision);
RevTree tree = walk.parseCommit(ancestorId).getTree();
treeWalk.addTree(tree);
}
else if (commit.getParentCount() > 0)
{
} else if (commit.getParentCount() > 0) {
RevTree tree = commit.getParent(0).getTree();
if (tree != null)
{
if (tree != null) {
treeWalk.addTree(tree);
}
else
{
} else {
treeWalk.addTree(new EmptyTreeIterator());
}
}
else
{
} else {
treeWalk.addTree(new EmptyTreeIterator());
}
treeWalk.addTree(commit.getTree());
return new Differ(commit, walk, treeWalk);
return new Differ(commit, walk, treeWalk);
}
}
private Diff diff() throws IOException {

View File

@@ -31,8 +31,14 @@
package sonia.scm.repository.spi;
import com.google.common.base.Strings;
import org.eclipse.jgit.api.MergeCommand;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.diff.DiffEntry;
import org.eclipse.jgit.diff.DiffFormatter;
import org.eclipse.jgit.lib.ObjectId;
import sonia.scm.repository.GitWorkdirFactory;
import sonia.scm.repository.InternalRepositoryException;
import sonia.scm.repository.Repository;
import sonia.scm.repository.api.DiffCommandBuilder;
@@ -44,15 +50,42 @@ import java.io.IOException;
*/
public class GitDiffCommand extends AbstractGitCommand implements DiffCommand {
GitDiffCommand(GitContext context, Repository repository) {
private final GitWorkdirFactory workdirFactory;
GitDiffCommand(GitContext context, Repository repository, GitWorkdirFactory workdirFactory) {
super(context, repository);
this.workdirFactory = workdirFactory;
}
@Override
public DiffCommandBuilder.OutputStreamConsumer getDiffResult(DiffCommandRequest request) throws IOException {
@SuppressWarnings("squid:S2095") // repository will be closed with the RepositoryService
org.eclipse.jgit.lib.Repository repository = open();
WorkingCopyCloser closer = new WorkingCopyCloser();
if (Strings.isNullOrEmpty(request.getMergeChangeset())) {
return computeDiff(request, open(), closer);
} else {
return inCloneWithPostponedClose(git -> new GitCloneWorker<DiffCommandBuilder.OutputStreamConsumer>(git) {
@Override
DiffCommandBuilder.OutputStreamConsumer run() throws IOException {
ObjectId sourceRevision = resolveRevision(request.getRevision());
try {
getClone().merge()
.setFastForward(MergeCommand.FastForwardMode.NO_FF)
.setCommit(false) // we want to set the author manually
.include(request.getRevision(), sourceRevision)
.call();
} catch (GitAPIException e) {
throw new InternalRepositoryException(context.getRepository(), "could not merge branch " + request.getRevision() + " into " + request.getMergeChangeset(), e);
}
DiffCommandRequest clone = request.clone();
clone.setRevision(sourceRevision.name());
return computeDiff(request, getClone().getRepository(), closer);
}
}, workdirFactory, request.getMergeChangeset(), closer);
}
}
private DiffCommandBuilder.OutputStreamConsumer computeDiff(DiffCommandRequest request, org.eclipse.jgit.lib.Repository repository, WorkingCopyCloser closer) throws IOException {
Differ.Diff diff = Differ.diff(repository, request);
return output -> {
@@ -66,8 +99,9 @@ public class GitDiffCommand extends AbstractGitCommand implements DiffCommand {
}
formatter.flush();
} finally {
closer.close();
}
};
}
}

View File

@@ -169,7 +169,7 @@ public class GitRepositoryServiceProvider extends RepositoryServiceProvider
@Override
public DiffCommand getDiffCommand()
{
return new GitDiffCommand(context, repository);
return new GitDiffCommand(context, repository, handler.getWorkdirFactory());
}
@Override