blob: c77d95037770cdfb1fff7119bd99d1da499d6473 [file] [log] [blame]
/*
* Copyright (C) 2021, Tencent.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
* https://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
package org.eclipse.jgit.internal.storage.commitgraph;
import java.io.IOException;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.eclipse.jgit.annotations.NonNull;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectIdOwnerMap;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.ProgressMonitor;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevObject;
import org.eclipse.jgit.revwalk.RevSort;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.util.BlockList;
/**
* The commits which are used by the commit-graph writer to:
* <ul>
* <li>List commits in SHA1 order.</li>
* <li>Get the position of a specific SHA1 in the list.</li>
* </ul>
*
* @since 6.5
*/
public class GraphCommits implements Iterable<RevCommit> {
/**
* Prepare and create the commits for
* {@link org.eclipse.jgit.internal.storage.commitgraph.CommitGraphWriter}
* from the RevWalk.
*
* @param pm
* progress monitor.
* @param wants
* the list of wanted objects, writer walks commits starting at
* these. Must not be {@code null}.
* @param walk
* the RevWalk to use. Must not be {@code null}.
* @return the commits' collection which are used by the commit-graph
* writer. Never null.
* @throws IOException
* if an error occurred
*/
public static GraphCommits fromWalk(ProgressMonitor pm,
@NonNull Set<? extends ObjectId> wants, @NonNull RevWalk walk)
throws IOException {
walk.reset();
walk.sort(RevSort.NONE);
walk.setRetainBody(false);
for (ObjectId id : wants) {
RevObject o = walk.parseAny(id);
if (o instanceof RevCommit) {
walk.markStart((RevCommit) o);
}
}
List<RevCommit> commits = new BlockList<>();
RevCommit c;
pm.beginTask(JGitText.get().findingCommitsForCommitGraph,
ProgressMonitor.UNKNOWN);
while ((c = walk.next()) != null) {
pm.update(1);
commits.add(c);
}
pm.endTask();
return new GraphCommits(commits, walk.getObjectReader());
}
private final List<RevCommit> sortedCommits;
private final ObjectIdOwnerMap<CommitWithPosition> commitPosMap;
private final int extraEdgeCnt;
private final ObjectReader objectReader;
/**
* Initialize the GraphCommits.
*
* @param commits
* list of commits with their headers already parsed.
* @param objectReader
* object reader
*/
private GraphCommits(List<RevCommit> commits, ObjectReader objectReader) {
Collections.sort(commits); // sorted by name
sortedCommits = commits;
commitPosMap = new ObjectIdOwnerMap<>();
int cnt = 0;
for (int i = 0; i < commits.size(); i++) {
RevCommit c = sortedCommits.get(i);
if (c.getParentCount() > 2) {
cnt += c.getParentCount() - 1;
}
commitPosMap.add(new CommitWithPosition(c, i));
}
this.extraEdgeCnt = cnt;
this.objectReader = objectReader;
}
int getOidPosition(RevCommit c) throws MissingObjectException {
CommitWithPosition commitWithPosition = commitPosMap.get(c);
if (commitWithPosition == null) {
throw new MissingObjectException(c, Constants.OBJ_COMMIT);
}
return commitWithPosition.position;
}
int getExtraEdgeCnt() {
return extraEdgeCnt;
}
int size() {
return sortedCommits.size();
}
ObjectReader getObjectReader() {
return objectReader;
}
@Override
public Iterator<RevCommit> iterator() {
return sortedCommits.iterator();
}
private static class CommitWithPosition extends ObjectIdOwnerMap.Entry {
final int position;
CommitWithPosition(AnyObjectId id, int position) {
super(id);
this.position = position;
}
}
}