package org.tmatesoft.svn.core.internal.wc2.remote;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Date;
import java.util.Map;
import org.tmatesoft.svn.core.SVNAnnotationGenerator;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNProperties;
import org.tmatesoft.svn.core.SVNProperty;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import org.tmatesoft.svn.core.internal.wc.SVNFileUtil;
import org.tmatesoft.svn.core.internal.wc.admin.SVNTranslator;
import org.tmatesoft.svn.core.internal.wc.admin.SVNTranslatorInputStream;
import org.tmatesoft.svn.core.internal.wc17.SVNStatusEditor17;
import org.tmatesoft.svn.core.internal.wc17.db.Structure;
import org.tmatesoft.svn.core.internal.wc2.SvnRemoteOperationRunner;
import org.tmatesoft.svn.core.internal.wc2.SvnWcGeneration;
import org.tmatesoft.svn.core.internal.wc2.SvnRepositoryAccess.RepositoryInfo;
import org.tmatesoft.svn.core.internal.wc2.SvnRepositoryAccess.RevisionsPair;
import org.tmatesoft.svn.core.io.SVNFileRevision;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.wc.ISVNAnnotateHandler;
import org.tmatesoft.svn.core.wc.ISVNEventHandler;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc.SVNStatusType;
import org.tmatesoft.svn.core.wc2.*;
import org.tmatesoft.svn.util.SVNLogType;
public class SvnRemoteAnnotate extends SvnRemoteOperationRunner<SvnAnnotateItem, SvnAnnotate> implements ISVNAnnotateHandler {
@Override
public boolean isApplicable(SvnAnnotate operation, SvnWcGeneration wcGeneration) throws SVNException {
return (operation.hasRemoteTargets() || wcGeneration == SvnWcGeneration.V17);
}
@Override
protected SvnAnnotateItem run() throws SVNException {
if (getOperation().getEndRevision() == SVNRevision.UNDEFINED) {
if (getOperation().hasRemoteTargets()) {
getOperation().setEndRevision(SVNRevision.HEAD);
} else {
getOperation().setEndRevision(SVNRevision.WORKING);
}
}
if (getOperation().getStartRevision() == null || !getOperation().getStartRevision().isValid() ||
getOperation().getEndRevision() == null || !getOperation().getEndRevision().isValid()) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.CLIENT_BAD_REVISION);
SVNErrorManager.error(err, SVNLogType.WC);
}
Structure<RepositoryInfo> repositoryInfo = getRepositoryAccess().createRepositoryFor(
getOperation().getFirstTarget(), getOperation().getEndRevision(), getOperation().getFirstTarget().getResolvedPegRevision(),null);
SVNRepository repository = repositoryInfo.<SVNRepository>get(RepositoryInfo.repository);
repositoryInfo.release();
Structure<RevisionsPair> pair =
getRepositoryAccess().getRevisionNumber(repository, getOperation().getFirstTarget(), getOperation().getStartRevision(), null);
long startRev = pair.lng(RevisionsPair.revNumber);
pair = getRepositoryAccess().getRevisionNumber(repository, getOperation().getFirstTarget(), getOperation().getEndRevision(), pair);
long endRev = pair.lng(RevisionsPair.revNumber);
pair.release();
if (endRev < startRev) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.CLIENT_BAD_REVISION, "Start revision must precede end revision"), SVNLogType.DEFAULT);
}
if (!getOperation().isIgnoreMimeType()) {
SvnOperationFactory operationFactory = getOperation().getOperationFactory();
ISVNEventHandler oldEventHandler = operationFactory.getEventHandler();
operationFactory.setEventHandler(null);
SvnGetProperties getProperties = operationFactory.createGetProperties();
getProperties.setRevision(getOperation().getRevision());
getProperties.setSingleTarget(getOperation().getFirstTarget());
SVNProperties svnProperties = getProperties.run();
operationFactory.setEventHandler(oldEventHandler);
if (svnProperties != null) {
String mimeTypeString = svnProperties.getStringValue(SVNProperty.MIME_TYPE);
if (SVNProperty.isBinaryMimeType(mimeTypeString)) {
SVNErrorMessage errorMessage = SVNErrorMessage.create(SVNErrorCode.CLIENT_IS_BINARY_FILE, "Cannot calculate blame information for binary file ''{0}''", getOperation().getFirstTarget());
SVNErrorManager.error(errorMessage, SVNLogType.CLIENT);
}
}
}
String path;
File tmpFile;
if (getOperation().hasRemoteTargets()){
tmpFile = SVNFileUtil.createTempDirectory("annotate");
path = repository.getLocation().toString();
} else {
tmpFile = getWcContext().getDb().getWCRootTempDir(getOperation().getFirstTarget().getFile());
tmpFile = SVNFileUtil.createUniqueFile(tmpFile, "annotate", ".tmp", false);
SVNFileUtil.deleteAll(tmpFile, true);
SVNFileUtil.ensureDirectoryExists(tmpFile);
path = getOperation().getFirstTarget().getFile().getAbsolutePath();
}
SVNAnnotationGenerator generator = new SVNAnnotationGenerator(path, tmpFile, startRev,
getOperation().isIgnoreMimeType(), getOperation().isUseMergeHistory(), getOperation().getDiffOptions(), getOperation().getInputEncoding(), this, this);
try {
repository.getFileRevisions("", startRev > 0 ? startRev - 1 : startRev, endRev, getOperation().isUseMergeHistory(), generator);
if (getOperation().getEndRevision() == SVNRevision.WORKING) {
File target = getOperation().getFirstTarget().getFile();
SvnStatus status = SVNStatusEditor17.internalStatus(getWcContext(), target);
if (status.getTextStatus() != SVNStatusType.STATUS_NORMAL) {
SVNProperties properties = getWcContext().getActualProps(target);
String keywords = properties.getStringValue(SVNProperty.KEYWORDS);
InputStream source = null;
OutputStream dst = null;
try {
source = SVNFileUtil.openFileForReading(target);
Map<?,?> keywordsMap = keywords != null ?
SVNTranslator.computeKeywords(keywords, null, null, null, null, null, getOperation().getOptions()) : null;
source = new SVNTranslatorInputStream(source, new byte[] {'\n'}, false, keywordsMap, false);
SVNFileRevision localRevision = new SVNFileRevision(path, -1, new SVNProperties(), new SVNProperties());
generator.openRevision(localRevision);
generator.addFileBlame(source);
generator.closeRevision(null);
} finally {
SVNFileUtil.closeFile(dst);
SVNFileUtil.closeFile(source);
}
}
}
if (!generator.isLastRevisionReported()) {
generator.reportAnnotations(this, getOperation().getInputEncoding());
}
} finally {
generator.dispose();
SVNFileUtil.deleteAll(tmpFile, !"text-base".equals(tmpFile.getName()), null);
}
return getOperation().first();
}
public void handleLine(Date date, long revision, String author, String line, Date mergedDate,
long mergedRevision, String mergedAuthor, String mergedPath, int lineNumber) throws SVNException {
getOperation().receive(getOperation().getFirstTarget(),
new SvnAnnotateItem(date, revision, author, line, mergedDate, mergedRevision, mergedAuthor, mergedPath, lineNumber)
);
}
public boolean handleRevision(Date date, long revision, String author, File contents) throws SVNException{
SvnAnnotateItem item = new SvnAnnotateItem(date, revision, author, contents);
getOperation().receive(getOperation().getFirstTarget(), item);
return item.getReturnResult();
}
public void handleLine(Date date, long revision, String author, String line) throws SVNException {
}
public void handleEOF() {
try {
getOperation().receive(getOperation().getFirstTarget(), new SvnAnnotateItem(true));
} catch (SVNException e) {
}
}
}