package net.certware.history.egit.handlers;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.certware.core.ICertWareConstants;
import net.certware.core.ui.log.CertWareLog;
import net.certware.measurement.sco.ArtifactCommit;
import net.certware.measurement.sco.ArtifactIdentifier;
import net.certware.measurement.sco.CommitHistory;
import net.certware.measurement.sco.ScoFactory;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IStorage;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.egit.core.GitProvider;
import org.eclipse.egit.core.project.RepositoryMapping;
import org.eclipse.jgit.lib.Constants;
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.revwalk.FooterLine;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
import org.eclipse.team.core.RepositoryProvider;
import org.eclipse.team.core.history.IFileHistory;
import org.eclipse.team.core.history.IFileHistoryProvider;
import org.eclipse.team.core.history.IFileRevision;
import org.eclipse.team.core.history.ITag;
/**
* Dump history collection to the console.
* @author mrb
* @since 1.1
*/
@SuppressWarnings("restriction")
public class DumpHistory implements ICertWareConstants {
/**
* Process a ref map.
* @param prefix reference prefix
* @param map map of strings and ref entries
*/
@SuppressWarnings("unused")
private void processRefMap(String prefix, Map<String,Ref> map) {
Set<String> keyset = map.keySet();
if ( keyset.isEmpty() )
return;
System.out.println(prefix);
Iterator<String> i = keyset.iterator();
while( i.hasNext() ) {
String key = i.next();
System.out.println("key " + key + " value " + map.get(key));
}
}
/**
* Process the EGit history associated with a given project.
* @param selectedProject selected project, presumably an object contribution selection
* @throws CoreException
* @throws IOException
*/
public void processHistory(IProject selectedProject,IProgressMonitor monitor) throws CoreException, IOException {
// find the repository mapping for the project
// if none found, return
RepositoryMapping repositoryMapping = RepositoryMapping.getMapping((IResource) selectedProject);
if ( repositoryMapping == null ) {
CertWareLog.logWarning(
String.format("%s %s","Missing repository for project",
selectedProject.getName()));
return;
}
Repository repo = repositoryMapping.getRepository();
//String branch = repo.getBranch();
//Ref head = repo.getRef("HEAD");
RevWalk revWalk = new RevWalk(repo);
ObjectId headObject = repo.resolve("HEAD");
revWalk.markStart(revWalk.parseCommit(headObject));
Set<String> authorEmails = new HashSet<String>();
final Set<String> repositoryPaths =
Collections.singleton(repositoryMapping.getRepoRelativePath(selectedProject));
revWalk.setTreeFilter(PathFilterGroup.createFromStrings(repositoryPaths));
final CommitHistory commitHistory = ScoFactory.eINSTANCE.createCommitHistory();
for ( RevCommit commit : revWalk ) {
String commitName = commit.getName();
ArtifactCommit artifactCommit = ScoFactory.eINSTANCE.createArtifactCommit();
artifactCommit.setCommitIdentifier( commitName );
commitHistory.getCommitRecord().add(artifactCommit);
}
// revision commit walk
for (RevCommit commit : revWalk) {
System.out.println(' ');
System.out.println("commit: " + commit);
PersonIdent author = commit.getAuthorIdent();
PersonIdent committer = commit.getCommitterIdent();
Date when = committer.getWhen();
String name = commit.getName();
int type = commit.getType();
int commitTime = commit.getCommitTime();
System.out.println("name " + name + " type " + type + " author " + author + " committer " + committer + " time " + commitTime + " when " + when);
int parentCount = commit.getParentCount();
List<FooterLine> footerLines = commit.getFooterLines();
String fullMessage = commit.getFullMessage();
String shortMessage = commit.getShortMessage();
System.out.println("parents " + parentCount + " full " + fullMessage + " short " + shortMessage);
System.out.println("footer lines:");
Iterator<FooterLine> i = footerLines.iterator();
while( i.hasNext() ) {
FooterLine fl = (FooterLine)i.next();
System.out.println("key " + fl.getKey() + " value " + fl.getValue() + " email " + fl.getEmailAddress());
}
// extract the commit fields you need, for example:
authorEmails.add(commit.getAuthorIdent().getEmailAddress());
RevTree revTree = commit.getTree();
int firstByte = revTree.getFirstByte();
ObjectId oi = revTree.getId();
String rtname = revTree.getName();
System.out.print("commit rev tree: ");
System.out.println("first byte " + firstByte + " id " + oi.getName() + " rev tree name " + rtname);
int rtype = revTree.getType();
switch( rtype ) {
case Constants.OBJ_BAD:
System.out.println("rev type bad");
break;
case Constants.OBJ_BLOB:
System.out.println("rev type blob");
break;
case Constants.OBJ_COMMIT:
System.out.println("rev type commit");
break;
case Constants.OBJ_OFS_DELTA :
System.out.println("rev type OFS delta");
break;
case Constants.OBJ_REF_DELTA:
System.out.println("rev type REF delta");
break;
case Constants.OBJ_TAG:
System.out.println("rev type tag");
break;
case Constants.OBJ_TREE:
System.out.println("rev type tree");
break;
case Constants.OBJ_TYPE_5:
System.out.println("rev type five");
break;
case Constants.OBJ_EXT:
System.out.println("rev type ext");
break;
} // switch
// commit.dispose();
// commit.reset();
}
// revWalk.dispose();
revWalk.close();
// use the Git provider to find the file history
GitProvider provider = (GitProvider)RepositoryProvider.getProvider(selectedProject);
IFileHistoryProvider fileHistoryProvider = provider.getFileHistoryProvider();
IResource[] projectMembers = selectedProject.members();
// process history
processHistory(selectedProject,monitor);
// process resources
monitor.beginTask("Processing project resources", projectMembers.length);
for ( IResource resource : projectMembers ) {
processResource(resource,fileHistoryProvider,commitHistory,monitor);
monitor.worked(1);
if ( monitor.isCanceled() ) {
return;
}
} // members
// report what was created
System.out.println("SCO model result");
for ( ArtifactCommit ac : commitHistory.getCommitRecord() ) {
System.out.println("artifact commit " + ac.getCommitIdentifier() );
for ( ArtifactIdentifier ai : ac.getArtifactIdentifiers() ) {
System.out.println("resource " + ai.getResourceName()
+ " current " + ai.getCurrentLineCount());
}
}
monitor.done();
}
/**
* Process a resource. For each revision find its commit and add to the new list.
* @param resource to recover historical record
* @param fileHistoryProvider
* @param commitHistory commit history records to populate
* @param monitor progress monitor
*/
private void processResource(IResource resource, IFileHistoryProvider fileHistoryProvider, CommitHistory commitHistory, IProgressMonitor monitor) {
IFileHistory fileHistory = fileHistoryProvider.getFileHistoryFor(resource,
IFileHistoryProvider.SINGLE_LINE_OF_DESCENT,
monitor);
// process file revisions
IFileRevision[] fileRevisions = fileHistory.getFileRevisions();
for ( IFileRevision fr : fileRevisions ) {
processFileRevision(fr,commitHistory,monitor);
IFileRevision[] contributors = fileHistory.getContributors(fr);
for ( IFileRevision c : contributors ) {
processContributor(fr,c,monitor);
}
} // revisions
}
/**
* Process branch tags.
* @param prefix
* @param tags
*/
@SuppressWarnings("unused")
private void processTags(String prefix, ITag[] tags) {
if ( tags.length < 1 )
return;
System.out.println(prefix);
for ( ITag t : tags ) {
System.out.println("tag " + t.getName() );
}
}
/**
* Process file revision contributors
* @param fr original revision
* @param c contributor to this revision
* @param monitor progress monitor
*/
private void processContributor(IFileRevision fr, IFileRevision c,IProgressMonitor monitor) {
String author = fr.getAuthor();
String comment = fr.getComment();
String identifier = fr.getContentIdentifier();
String name = fr.getName();
long timestamp = fr.getTimestamp();
SimpleDateFormat sdf = new SimpleDateFormat();
String date = sdf.format(new Date(timestamp));
System.out.println("file contributor: " + author + ";" +
comment + ";" +
identifier + ";" +
name + ";" +
timestamp + ";" + date);
}
/**
* Computes and results the line count for a file revision using its storage.
* Uses a line number reader to compute the line count.
* @param fr file revision
* @param monitor progress monitor for storage access
* @return line count or zero, exceptions caught and reported to log
*/
protected int getLineCount(IFileRevision fr, IProgressMonitor monitor) {
int lineCount = 0;
try {
IStorage storage = fr.getStorage(monitor);
InputStream is = storage.getContents();
LineNumberReader lineNumberReader = new LineNumberReader(new InputStreamReader(is));
while( lineNumberReader.ready() ) {
lineNumberReader.readLine();
lineCount++;
}
lineNumberReader.close();
is.close();
} catch (Exception e) {
CertWareLog.logError(String.format("%s %s",
"Gathering line count for revision",
fr.getName()), e);
}
return lineCount;
}
/**
* Computes and results the byte count for a file revision using its storage.
* Uses an input stream reader to count bytes read.
* @param fr file revision
* @param monitor progress monitor for storage access
* @return line count or zero, exceptions caught and reported to log
*/
protected int getByteCount(IFileRevision fr, IProgressMonitor monitor) {
int byteCount = 0;
try {
IStorage storage = fr.getStorage(monitor);
InputStream is = storage.getContents();
InputStreamReader isr = new InputStreamReader(is);
while( isr.read() != -1 ) {
byteCount++;
}
isr.close();
is.close();
} catch (Exception e) {
CertWareLog.logError(String.format("%s %s","Gathering byte count for revision",fr.getName()),e);
}
return byteCount;
}
/**
* Process file revision
* @param fr file revision
* @param ch commit history, already populated with artifact history records
* @param monitor progress monitor
*/
private void processFileRevision(IFileRevision fr, CommitHistory ch, IProgressMonitor monitor) {
String author = fr.getAuthor();
String comment = fr.getComment();
long timestamp = fr.getTimestamp();
String commitId = fr.getContentIdentifier();
String name = fr.getName();
int lineCount = getLineCount(fr,monitor);
SimpleDateFormat sdf = new SimpleDateFormat();
String date = sdf.format(new Date(timestamp));
System.out.println("Author " + author + " comment " + comment);
System.out.println("commit id: " + commitId);
System.out.println("Date " + date + " timestamp " + timestamp);
// create artifact identifier and add it to the existing commit
ArtifactIdentifier ai = ScoFactory.eINSTANCE.createArtifactIdentifier();
ai.setCurrentLineCount(lineCount);
ai.setResourceName(name);
// add the resource revision identifier to the corresponding commit record
ArtifactCommit ac = findCommit(ch, commitId);
if ( ac != null ) {
ac.getArtifactIdentifiers().add(ai);
} else {
CertWareLog.logWarning(String.format("%s %s","Could not find commit for file",fr.getName()));
}
}
/**
* Find the artifact commit list associated with a commit ID.
* @param ch commit history, already populated with commit ID records
* @param id commit identifier
* @return commit matching the given ID, or null
*/
private ArtifactCommit findCommit(CommitHistory ch, String id ) {
if ( ch != null ) {
for ( ArtifactCommit ac : ch.getCommitRecord() ) {
if ( ac.getCommitIdentifier().equals(id)) {
return ac;
}
}
}
return null;
}
}