CloneGit.java
/*
* @copyright defined in LICENSE.txt
*/
package ship.command;
import static org.eclipse.jgit.lib.Constants.HEAD;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.stream.Stream;
import lombok.Getter;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectLoader;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.transport.FetchResult;
import org.eclipse.jgit.transport.URIish;
import org.eclipse.jgit.treewalk.TreeWalk;
import ship.FileContent;
import ship.FileSet;
public class CloneGit extends AbstractCommand {
protected static final String URI_PATTERN = "https://github.com/{0}.git";
@Getter
protected FileSet fileSet = new FileSet();
@Override
public void execute() throws Exception {
final String packageName = getArgument(0);
final String branch = getOptionalArgument(1).orElse("master");
logger.debug("Package name: {}, Branch: {}", packageName, branch);
final String remoteUri = MessageFormat.format(URI_PATTERN, packageName);
final InMemoryRepository repository = new InMemoryRepository(new DfsRepositoryDescription());
final Git git = new Git(repository);
git.remoteAdd().setName("origin").setUri(new URIish(remoteUri)).call();
logger.trace("Git: {}", git);
final FetchResult fetchResult = git.fetch()
.setRemote("origin")
.setRefSpecs("+refs/heads/" + branch + ":refs/remotes/origin/" + branch)
.call();
logger.debug("Fetch result: {}", fetchResult);
logger.debug("Refs: {}", fetchResult.getAdvertisedRefs());
final Ref fetchHead = fetchResult.getAdvertisedRef(HEAD);
final ObjectId commitId = fetchHead.getObjectId();
logger.debug("Commit id: {}", commitId);
try (final RevWalk revWalk = new RevWalk(repository)) {
visit(repository, revWalk, commitId);
}
logger.debug("FileSet: {}", fileSet);
}
protected void visit(final Repository repository, final RevWalk revWalk,
final ObjectId commitId) throws IOException {
final RevCommit revCommit = revWalk.parseCommit(commitId);
final RevTree revTree = revCommit.getTree();
logger.debug("Having tree: " + revTree);
// now try to find a specific file
try (final TreeWalk treeWalk = new TreeWalk(repository)) {
treeWalk.addTree(revTree);
treeWalk.setRecursive(true);
while (treeWalk.next()) {
visit(repository, treeWalk);
}
}
revWalk.dispose();
}
protected void visit(final Repository repository, final TreeWalk treeWalk) throws IOException {
final String path = treeWalk.getPathString();
logger.debug("Path: {}", path);
logger.trace("Subtree: {}", treeWalk.isSubtree());
if (treeWalk.isSubtree()) {
treeWalk.enterSubtree();
} else {
final ObjectId objectId = treeWalk.getObjectId(0);
final FileContent file = new FileContent(path, () -> {
try {
final ObjectLoader loader = repository.open(objectId);
final ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
loader.copyTo(byteOut);
return new ByteArrayInputStream(byteOut.toByteArray());
} catch (final IOException e) {
throw new IllegalStateException(e);
}
});
fileSet.add(file);
logger.debug("{} added", file);
}
}
public Stream<FileContent> stream() {
return fileSet.stream();
}
}