Search in sources :

Example 1 with MergeFormatter

use of org.eclipse.jgit.merge.MergeFormatter in project gerrit by GerritCodeReview.

the class AutoMerger method merge.

/**
   * Perform an auto-merge of the parents of the given merge commit.
   *
   * @return auto-merge commit or {@code null} if an auto-merge commit couldn't be created. Headers
   *     of the returned RevCommit are parsed.
   */
public RevCommit merge(Repository repo, RevWalk rw, final ObjectInserter ins, RevCommit merge, ThreeWayMergeStrategy mergeStrategy) throws IOException {
    checkArgument(rw.getObjectReader().getCreatedFromInserter() == ins);
    InMemoryInserter tmpIns = null;
    if (ins instanceof InMemoryInserter) {
        // Caller gave us an in-memory inserter, so ensure anything we write from
        // this method is visible to them.
        tmpIns = (InMemoryInserter) ins;
    } else if (!save) {
        // If we don't plan on saving results, use a fully in-memory inserter.
        // Using just a non-flushing wrapper is not sufficient, since in
        // particular DfsInserter might try to write to storage after exceeding an
        // internal buffer size.
        tmpIns = new InMemoryInserter(rw.getObjectReader());
    }
    rw.parseHeaders(merge);
    String refName = RefNames.refsCacheAutomerge(merge.name());
    Ref ref = repo.getRefDatabase().exactRef(refName);
    if (ref != null && ref.getObjectId() != null) {
        RevObject obj = rw.parseAny(ref.getObjectId());
        if (obj instanceof RevCommit) {
            return (RevCommit) obj;
        }
        return commit(repo, rw, tmpIns, ins, refName, obj, merge);
    }
    ResolveMerger m = (ResolveMerger) mergeStrategy.newMerger(repo, true);
    DirCache dc = DirCache.newInCore();
    m.setDirCache(dc);
    m.setObjectInserter(tmpIns == null ? new NonFlushingWrapper(ins) : tmpIns);
    boolean couldMerge;
    try {
        couldMerge = m.merge(merge.getParents());
    } catch (IOException e) {
        // It is not safe to continue further down in this method as throwing
        // an exception most likely means that the merge tree was not created
        // and m.getMergeResults() is empty. This would mean that all paths are
        // unmerged and Gerrit UI would show all paths in the patch list.
        log.warn("Error attempting automerge " + refName, e);
        return null;
    }
    ObjectId treeId;
    if (couldMerge) {
        treeId = m.getResultTreeId();
    } else {
        RevCommit ours = merge.getParent(0);
        RevCommit theirs = merge.getParent(1);
        rw.parseBody(ours);
        rw.parseBody(theirs);
        String oursMsg = ours.getShortMessage();
        String theirsMsg = theirs.getShortMessage();
        String oursName = String.format("HEAD   (%s %s)", ours.abbreviate(6).name(), oursMsg.substring(0, Math.min(oursMsg.length(), 60)));
        String theirsName = String.format("BRANCH (%s %s)", theirs.abbreviate(6).name(), theirsMsg.substring(0, Math.min(theirsMsg.length(), 60)));
        MergeFormatter fmt = new MergeFormatter();
        Map<String, MergeResult<? extends Sequence>> r = m.getMergeResults();
        Map<String, ObjectId> resolved = new HashMap<>();
        for (Map.Entry<String, MergeResult<? extends Sequence>> entry : r.entrySet()) {
            MergeResult<? extends Sequence> p = entry.getValue();
            try (TemporaryBuffer buf = new TemporaryBuffer.LocalFile(null, 10 * 1024 * 1024)) {
                fmt.formatMerge(buf, p, "BASE", oursName, theirsName, UTF_8.name());
                buf.close();
                try (InputStream in = buf.openInputStream()) {
                    resolved.put(entry.getKey(), ins.insert(Constants.OBJ_BLOB, buf.length(), in));
                }
            }
        }
        DirCacheBuilder builder = dc.builder();
        int cnt = dc.getEntryCount();
        for (int i = 0; i < cnt; ) {
            DirCacheEntry entry = dc.getEntry(i);
            if (entry.getStage() == 0) {
                builder.add(entry);
                i++;
                continue;
            }
            int next = dc.nextEntry(i);
            String path = entry.getPathString();
            DirCacheEntry res = new DirCacheEntry(path);
            if (resolved.containsKey(path)) {
                // For a file with content merge conflict that we produced a result
                // above on, collapse the file down to a single stage 0 with just
                // the blob content, and a randomly selected mode (the lowest stage,
                // which should be the merge base, or ours).
                res.setFileMode(entry.getFileMode());
                res.setObjectId(resolved.get(path));
            } else if (next == i + 1) {
                // If there is exactly one stage present, shouldn't be a conflict...
                res.setFileMode(entry.getFileMode());
                res.setObjectId(entry.getObjectId());
            } else if (next == i + 2) {
                // Two stages suggests a delete/modify conflict. Pick the higher
                // stage as the automatic result.
                entry = dc.getEntry(i + 1);
                res.setFileMode(entry.getFileMode());
                res.setObjectId(entry.getObjectId());
            } else {
                // 3 stage conflict, no resolve above
                // Punt on the 3-stage conflict and show the base, for now.
                res.setFileMode(entry.getFileMode());
                res.setObjectId(entry.getObjectId());
            }
            builder.add(res);
            i = next;
        }
        builder.finish();
        treeId = dc.writeTree(ins);
    }
    return commit(repo, rw, tmpIns, ins, refName, treeId, merge);
}
Also used : DirCacheBuilder(org.eclipse.jgit.dircache.DirCacheBuilder) DirCacheEntry(org.eclipse.jgit.dircache.DirCacheEntry) HashMap(java.util.HashMap) MergeResult(org.eclipse.jgit.merge.MergeResult) RevCommit(org.eclipse.jgit.revwalk.RevCommit) RevObject(org.eclipse.jgit.revwalk.RevObject) ObjectId(org.eclipse.jgit.lib.ObjectId) InputStream(java.io.InputStream) InMemoryInserter(com.google.gerrit.server.git.InMemoryInserter) IOException(java.io.IOException) Sequence(org.eclipse.jgit.diff.Sequence) ResolveMerger(org.eclipse.jgit.merge.ResolveMerger) DirCache(org.eclipse.jgit.dircache.DirCache) Ref(org.eclipse.jgit.lib.Ref) TemporaryBuffer(org.eclipse.jgit.util.TemporaryBuffer) HashMap(java.util.HashMap) Map(java.util.Map) MergeFormatter(org.eclipse.jgit.merge.MergeFormatter)

Example 2 with MergeFormatter

use of org.eclipse.jgit.merge.MergeFormatter in project gerrit by GerritCodeReview.

the class MergeUtil method mergeWithConflicts.

// TemporaryBuffer requires calling close before reading.
@SuppressWarnings("resource")
public static ObjectId mergeWithConflicts(RevWalk rw, ObjectInserter ins, DirCache dc, String oursName, RevCommit ours, String theirsName, RevCommit theirs, Map<String, MergeResult<? extends Sequence>> mergeResults) throws IOException {
    rw.parseBody(ours);
    rw.parseBody(theirs);
    String oursMsg = ours.getShortMessage();
    String theirsMsg = theirs.getShortMessage();
    int nameLength = Math.max(oursName.length(), theirsName.length());
    String oursNameFormatted = String.format("%-" + nameLength + "s (%s %s)", oursName, abbreviateName(ours, NAME_ABBREV_LEN), oursMsg.substring(0, Math.min(oursMsg.length(), 60)));
    String theirsNameFormatted = String.format("%-" + nameLength + "s (%s %s)", theirsName, abbreviateName(theirs, NAME_ABBREV_LEN), theirsMsg.substring(0, Math.min(theirsMsg.length(), 60)));
    MergeFormatter fmt = new MergeFormatter();
    Map<String, ObjectId> resolved = new HashMap<>();
    for (Map.Entry<String, MergeResult<? extends Sequence>> entry : mergeResults.entrySet()) {
        MergeResult<? extends Sequence> p = entry.getValue();
        TemporaryBuffer buf = null;
        try {
            // TODO(dborowitz): Respect inCoreLimit here.
            buf = new TemporaryBuffer.LocalFile(null, 10 * 1024 * 1024);
            fmt.formatMerge(buf, p, "BASE", oursNameFormatted, theirsNameFormatted, UTF_8);
            // Flush file and close for writes, but leave available for reading.
            buf.close();
            try (InputStream in = buf.openInputStream()) {
                resolved.put(entry.getKey(), ins.insert(Constants.OBJ_BLOB, buf.length(), in));
            }
        } finally {
            if (buf != null) {
                buf.destroy();
            }
        }
    }
    DirCacheBuilder builder = dc.builder();
    int cnt = dc.getEntryCount();
    for (int i = 0; i < cnt; ) {
        DirCacheEntry entry = dc.getEntry(i);
        if (entry.getStage() == 0) {
            builder.add(entry);
            i++;
            continue;
        }
        int next = dc.nextEntry(i);
        String path = entry.getPathString();
        DirCacheEntry res = new DirCacheEntry(path);
        if (resolved.containsKey(path)) {
            // For a file with content merge conflict that we produced a result
            // above on, collapse the file down to a single stage 0 with just
            // the blob content, and a randomly selected mode (the lowest stage,
            // which should be the merge base, or ours).
            res.setFileMode(entry.getFileMode());
            res.setObjectId(resolved.get(path));
        } else if (next == i + 1) {
            // If there is exactly one stage present, shouldn't be a conflict...
            res.setFileMode(entry.getFileMode());
            res.setObjectId(entry.getObjectId());
        } else if (next == i + 2) {
            // Two stages suggests a delete/modify conflict. Pick the higher
            // stage as the automatic result.
            entry = dc.getEntry(i + 1);
            res.setFileMode(entry.getFileMode());
            res.setObjectId(entry.getObjectId());
        } else {
            // 3 stage conflict, no resolve above
            // Punt on the 3-stage conflict and show the base, for now.
            res.setFileMode(entry.getFileMode());
            res.setObjectId(entry.getObjectId());
        }
        builder.add(res);
        i = next;
    }
    builder.finish();
    return dc.writeTree(ins);
}
Also used : DirCacheBuilder(org.eclipse.jgit.dircache.DirCacheBuilder) DirCacheEntry(org.eclipse.jgit.dircache.DirCacheEntry) ObjectId(org.eclipse.jgit.lib.ObjectId) HashMap(java.util.HashMap) InputStream(java.io.InputStream) MergeResult(org.eclipse.jgit.merge.MergeResult) Sequence(org.eclipse.jgit.diff.Sequence) TemporaryBuffer(org.eclipse.jgit.util.TemporaryBuffer) Map(java.util.Map) HashMap(java.util.HashMap) MergeFormatter(org.eclipse.jgit.merge.MergeFormatter)

Aggregations

InputStream (java.io.InputStream)2 HashMap (java.util.HashMap)2 Map (java.util.Map)2 Sequence (org.eclipse.jgit.diff.Sequence)2 DirCacheBuilder (org.eclipse.jgit.dircache.DirCacheBuilder)2 DirCacheEntry (org.eclipse.jgit.dircache.DirCacheEntry)2 ObjectId (org.eclipse.jgit.lib.ObjectId)2 MergeFormatter (org.eclipse.jgit.merge.MergeFormatter)2 MergeResult (org.eclipse.jgit.merge.MergeResult)2 TemporaryBuffer (org.eclipse.jgit.util.TemporaryBuffer)2 InMemoryInserter (com.google.gerrit.server.git.InMemoryInserter)1 IOException (java.io.IOException)1 DirCache (org.eclipse.jgit.dircache.DirCache)1 Ref (org.eclipse.jgit.lib.Ref)1 ResolveMerger (org.eclipse.jgit.merge.ResolveMerger)1 RevCommit (org.eclipse.jgit.revwalk.RevCommit)1 RevObject (org.eclipse.jgit.revwalk.RevObject)1