Search in sources :

Example 1 with InMemoryInserter

use of com.google.gerrit.server.git.InMemoryInserter in project gerrit by GerritCodeReview.

the class CheckMergeability method apply.

@Override
public MergeableInfo apply(BranchResource resource) throws IOException, BadRequestException, ResourceNotFoundException {
    if (!(submitType.equals(SubmitType.MERGE_ALWAYS) || submitType.equals(SubmitType.MERGE_IF_NECESSARY))) {
        throw new BadRequestException("Submit type: " + submitType + " is not supported");
    }
    MergeableInfo result = new MergeableInfo();
    result.submitType = submitType;
    result.strategy = strategy;
    try (Repository git = gitManager.openRepository(resource.getNameKey());
        RevWalk rw = new RevWalk(git);
        ObjectInserter inserter = new InMemoryInserter(git)) {
        Merger m = MergeUtil.newMerger(inserter, git.getConfig(), strategy);
        Ref destRef = git.getRefDatabase().exactRef(resource.getRef());
        if (destRef == null) {
            throw new ResourceNotFoundException(resource.getRef());
        }
        RevCommit targetCommit = rw.parseCommit(destRef.getObjectId());
        RevCommit sourceCommit = MergeUtil.resolveCommit(git, rw, source);
        if (!resource.getControl().canReadCommit(db.get(), git, sourceCommit)) {
            throw new BadRequestException("do not have read permission for: " + source);
        }
        if (rw.isMergedInto(sourceCommit, targetCommit)) {
            result.mergeable = true;
            result.commitMerged = true;
            result.contentMerged = true;
            return result;
        }
        if (m.merge(false, targetCommit, sourceCommit)) {
            result.mergeable = true;
            result.commitMerged = false;
            result.contentMerged = m.getResultTreeId().equals(targetCommit.getTree());
        } else {
            result.mergeable = false;
            if (m instanceof ResolveMerger) {
                result.conflicts = ((ResolveMerger) m).getUnmergedPaths();
            }
        }
    } catch (IllegalArgumentException e) {
        throw new BadRequestException(e.getMessage());
    }
    return result;
}
Also used : Repository(org.eclipse.jgit.lib.Repository) Ref(org.eclipse.jgit.lib.Ref) Merger(org.eclipse.jgit.merge.Merger) ResolveMerger(org.eclipse.jgit.merge.ResolveMerger) ObjectInserter(org.eclipse.jgit.lib.ObjectInserter) MergeableInfo(com.google.gerrit.extensions.common.MergeableInfo) BadRequestException(com.google.gerrit.extensions.restapi.BadRequestException) InMemoryInserter(com.google.gerrit.server.git.InMemoryInserter) RevWalk(org.eclipse.jgit.revwalk.RevWalk) ResourceNotFoundException(com.google.gerrit.extensions.restapi.ResourceNotFoundException) ResolveMerger(org.eclipse.jgit.merge.ResolveMerger) RevCommit(org.eclipse.jgit.revwalk.RevCommit)

Example 2 with InMemoryInserter

use of com.google.gerrit.server.git.InMemoryInserter in project gerrit by GerritCodeReview.

the class AutoMerger method commit.

private RevCommit commit(Repository repo, RevWalk rw, @Nullable InMemoryInserter tmpIns, ObjectInserter ins, String refName, ObjectId tree, RevCommit merge) throws IOException {
    rw.parseHeaders(merge);
    // For maximum stability, choose a single ident using the committer time of
    // the input commit, using the server name and timezone.
    PersonIdent ident = new PersonIdent(gerritIdent, merge.getCommitterIdent().getWhen(), gerritIdent.getTimeZone());
    CommitBuilder cb = new CommitBuilder();
    cb.setAuthor(ident);
    cb.setCommitter(ident);
    cb.setTreeId(tree);
    cb.setMessage("Auto-merge of " + merge.name() + '\n');
    for (RevCommit p : merge.getParents()) {
        cb.addParentId(p);
    }
    if (!save) {
        checkArgument(tmpIns != null);
        try (ObjectReader tmpReader = tmpIns.newReader();
            RevWalk tmpRw = new RevWalk(tmpReader)) {
            return tmpRw.parseCommit(tmpIns.insert(cb));
        }
    }
    checkArgument(tmpIns == null);
    checkArgument(!(ins instanceof InMemoryInserter));
    ObjectId commitId = ins.insert(cb);
    ins.flush();
    RefUpdate ru = repo.updateRef(refName);
    ru.setNewObjectId(commitId);
    ru.disableRefLog();
    ru.forceUpdate();
    return rw.parseCommit(commitId);
}
Also used : PersonIdent(org.eclipse.jgit.lib.PersonIdent) GerritPersonIdent(com.google.gerrit.server.GerritPersonIdent) ObjectId(org.eclipse.jgit.lib.ObjectId) CommitBuilder(org.eclipse.jgit.lib.CommitBuilder) ObjectReader(org.eclipse.jgit.lib.ObjectReader) InMemoryInserter(com.google.gerrit.server.git.InMemoryInserter) RevWalk(org.eclipse.jgit.revwalk.RevWalk) RevCommit(org.eclipse.jgit.revwalk.RevCommit) RefUpdate(org.eclipse.jgit.lib.RefUpdate)

Example 3 with InMemoryInserter

use of com.google.gerrit.server.git.InMemoryInserter 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 4 with InMemoryInserter

use of com.google.gerrit.server.git.InMemoryInserter in project gerrit by GerritCodeReview.

the class ChangeNotesCommit method newStagedRevWalk.

public static ChangeNotesRevWalk newStagedRevWalk(Repository repo, Iterable<InsertedObject> stagedObjs) {
    final InMemoryInserter ins = new InMemoryInserter(repo);
    for (InsertedObject obj : stagedObjs) {
        ins.insert(obj);
    }
    return new ChangeNotesRevWalk(ins.newReader()) {

        @Override
        public void close() {
            ins.close();
            super.close();
        }
    };
}
Also used : InsertedObject(com.google.gerrit.server.git.InsertedObject) InMemoryInserter(com.google.gerrit.server.git.InMemoryInserter)

Aggregations

InMemoryInserter (com.google.gerrit.server.git.InMemoryInserter)4 RevCommit (org.eclipse.jgit.revwalk.RevCommit)3 ObjectId (org.eclipse.jgit.lib.ObjectId)2 Ref (org.eclipse.jgit.lib.Ref)2 ResolveMerger (org.eclipse.jgit.merge.ResolveMerger)2 RevWalk (org.eclipse.jgit.revwalk.RevWalk)2 MergeableInfo (com.google.gerrit.extensions.common.MergeableInfo)1 BadRequestException (com.google.gerrit.extensions.restapi.BadRequestException)1 ResourceNotFoundException (com.google.gerrit.extensions.restapi.ResourceNotFoundException)1 GerritPersonIdent (com.google.gerrit.server.GerritPersonIdent)1 InsertedObject (com.google.gerrit.server.git.InsertedObject)1 IOException (java.io.IOException)1 InputStream (java.io.InputStream)1 HashMap (java.util.HashMap)1 Map (java.util.Map)1 Sequence (org.eclipse.jgit.diff.Sequence)1 DirCache (org.eclipse.jgit.dircache.DirCache)1 DirCacheBuilder (org.eclipse.jgit.dircache.DirCacheBuilder)1 DirCacheEntry (org.eclipse.jgit.dircache.DirCacheEntry)1 CommitBuilder (org.eclipse.jgit.lib.CommitBuilder)1