/*
* ModeShape (http://www.modeshape.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.modeshape.connector.git;
import java.io.ByteArrayOutputStream;
import java.io.File;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.ListBranchCommand;
import org.eclipse.jgit.api.ListBranchCommand.ListMode;
import org.eclipse.jgit.api.ListTagCommand;
import org.eclipse.jgit.api.LogCommand;
import org.eclipse.jgit.diff.DiffEntry;
import org.eclipse.jgit.diff.DiffEntry.ChangeType;
import org.eclipse.jgit.diff.DiffFormatter;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryBuilder;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.filter.PathFilter;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.modeshape.jcr.ExecutionContext;
public class GitFunctionalTest {
private static Git git;
private static Repository repository;
private static ExecutionContext context;
private static Values values;
private boolean print = false;
@BeforeClass
public static void beforeAll() throws Exception {
File gitDir = new File("../../.git");
RepositoryBuilder builder = new RepositoryBuilder();
repository = builder.setGitDir(gitDir).readEnvironment().findGitDir().build();
git = new Git(repository);
context = new ExecutionContext();
values = new Values(context.getValueFactories(), context.getBinaryStore());
}
@Before
public void beforeEach() {
print = false;
}
protected void print( String message ) {
if (!print) return;
System.out.println(message);
}
protected void print( String prefix,
Object obj ) {
if (!print) return;
System.out.println(prefix + obj.toString());
}
protected void print( String prefix,
Object... objects ) {
if (!print) return;
System.out.print(prefix + ": ");
for (Object obj : objects) {
System.out.print(obj.toString());
}
System.out.println();
}
protected void print( RevCommit commit ) {
if (!print) return;
System.out.println(commit.getId().name());
PersonIdent committer = commit.getCommitterIdent();
PersonIdent author = commit.getAuthorIdent();
System.out.println(" Author = " + author);
System.out.println(" Committer = " + committer);
System.out.println(" Committed = " + values.dateFrom(commit.getCommitTime()));
System.out.println(" Title = " + commit.getShortMessage());
System.out.println(" Message = " + commit.getFullMessage().trim());
System.out.println(" Parents = " + commit.getParents());
}
@Test
public void shouldGetBranchesWithLocalMode() throws Exception {
// print = true;
ListMode mode = null;
ListBranchCommand command = git.branchList();
command.setListMode(mode);
for (Ref ref : command.call()) {
String fullName = ref.getName();
String name = fullName.replaceFirst("refs/heads/", "");
print(fullName + " \t--> " + name);
}
}
@Test
public void shouldGetBranchesWithAllMode() throws Exception {
// print = true;
ListMode mode = ListMode.ALL;
ListBranchCommand command = git.branchList();
command.setListMode(mode);
for (Ref ref : command.call()) {
print(ref.getName());
}
}
@Test
public void shouldGetTags() throws Exception {
// print = true;
ListTagCommand command = git.tagList();
for (Ref ref : command.call()) {
String fullName = ref.getName();
String name = fullName.replaceFirst("refs/tags/", "");
print(fullName + " \t--> " + name);
}
}
@Test
public void shouldGetFirstDozenCommitsInHistoryForTag() throws Exception {
Ref ref = repository.getRef("modeshape-3.0.0.Final");
ref = repository.peel(ref);
RevWalk walker = new RevWalk(repository);
walker.setRetainBody(true);
try {
RevCommit commit = walker.parseCommit(ref.getObjectId());
LogCommand command = git.log();
command.add(commit.getId());
command.setMaxCount(12);
for (RevCommit rev : command.call()) {
commit = walker.parseCommit(rev);
print(commit);
}
} finally {
walker.dispose();
}
}
@Test
public void shouldComputeTheDiffOfACommit() throws Exception {
// print = true;
// Find the commit ...
Ref ref = repository.getRef("modeshape-3.0.0.Final");
ref = repository.peel(ref);
RevWalk walker = new RevWalk(repository);
walker.setRetainBody(true);
try {
RevCommit commit = walker.parseCommit(ref.getObjectId());
// Set up the tree walk to obtain the difference between the commit and it's parent(s) ...
TreeWalk tw = new TreeWalk(repository);
tw.setRecursive(true);
tw.addTree(commit.getTree());
for (RevCommit parent : commit.getParents()) {
RevCommit parentCommit = walker.parseCommit(parent);
tw.addTree(parentCommit.getTree());
}
// Now process the diff of each file ...
for (DiffEntry fileDiff : DiffEntry.scan(tw)) {
ChangeType type = fileDiff.getChangeType();
switch (type) {
case ADD:
String newPath = fileDiff.getNewPath();
print("ADD ", newPath);
break;
case COPY:
newPath = fileDiff.getNewPath();
String origPath = fileDiff.getOldPath();
print("COPY ", origPath, " -> ", newPath);
break;
case DELETE:
origPath = fileDiff.getOldPath();
print("DELETE ", origPath);
break;
case MODIFY:
newPath = fileDiff.getNewPath();
print("MODIFY ", newPath);
break;
case RENAME:
newPath = fileDiff.getNewPath();
origPath = fileDiff.getOldPath();
print("RENAME ", origPath, " -> ", newPath);
break;
default:
// skip
break;
}
ByteArrayOutputStream output = new ByteArrayOutputStream();
DiffFormatter formatter = new DiffFormatter(output);
formatter.setRepository(repository);
formatter.format(fileDiff);
String diff = output.toString("UTF-8");
print(diff);
}
} finally {
walker.dispose();
}
}
@Test
public void shouldGetTopLevelDirectoryContentForCommit() throws Exception {
printTreeContent("modeshape-3.0.0.Final", "", true);
}
@Test
public void shouldGetDirectoryContentsAtPathForCommit() throws Exception {
printTreeContent("modeshape-3.0.0.Final", "modeshape-jcr/src", true);
}
@Test
public void shouldGetFileInfoAtPathInContent() throws Exception {
printTreeContent("modeshape-3.0.0.Final", "modeshape-jcr/src/main/java/org/modeshape/jcr/XmlNodeTypeReader.java", false);
}
protected void printTreeContent( String tagOrBranchOrCommit,
String parentPath,
boolean showCommitInfo ) throws Exception {
// Find the commit ...
ObjectId objId = repository.resolve("modeshape-3.0.0.Final");
RevWalk walker = new RevWalk(repository);
if (showCommitInfo) {
walker.setRetainBody(true);
}
try {
RevCommit commit = walker.parseCommit(objId);
if (showCommitInfo) print(commit);
final TreeWalk tw = new TreeWalk(repository);
tw.addTree(commit.getTree());
if ("".equals(parentPath) || "/".equals(parentPath)) {
// We're already at the top-level
tw.setRecursive(false);
print("Getting contents of path ...");
while (tw.next()) {
print(tw.getPathString());
}
} else {
PathFilter filter = PathFilter.create(parentPath);
tw.setFilter(filter);
print("Finding path ...");
while (tw.next()) {
print(tw.getPathString());
if (filter.isDone(tw)) {
break;
} else if (tw.isSubtree()) {
tw.enterSubtree();
}
}
if (tw.isSubtree()) {
print("Getting contents of path ...");
tw.enterSubtree();
while (tw.next()) {
print(tw.getPathString());
}
} else {
print("File: " + tw.getPathString());
// Find the commit that last modified this file ...
// Is this the most efficient way to do this, 'cuz it's expensive?
RevCommit lastCommit = git.log().addPath(parentPath).call().iterator().next();
print("commitMessage", lastCommit.getShortMessage());
PersonIdent authorIdent = lastCommit.getAuthorIdent();
if (authorIdent != null) {
print("commiter", authorIdent.getName());
}
}
}
} finally {
walker.dispose();
}
}
}