package org.tmatesoft.svn.core.internal.wc2.ng;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.tmatesoft.svn.core.SVNDepth;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNLock;
import org.tmatesoft.svn.core.SVNNodeKind;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.internal.util.SVNDate;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import org.tmatesoft.svn.core.internal.wc.SVNFileUtil;
import org.tmatesoft.svn.core.internal.wc17.SVNWCContext;
import org.tmatesoft.svn.core.internal.wc17.SVNWCContext.ISVNWCNodeHandler;
import org.tmatesoft.svn.core.internal.wc17.SVNWCContext.SVNWCNodeReposInfo;
import org.tmatesoft.svn.core.internal.wc17.SVNWCContext.SVNWCSchedule;
import org.tmatesoft.svn.core.internal.wc17.SVNWCContext.ScheduleInternalInfo;
import org.tmatesoft.svn.core.internal.wc17.SVNWCUtils;
import org.tmatesoft.svn.core.internal.wc17.db.ISVNWCDb;
import org.tmatesoft.svn.core.internal.wc17.db.ISVNWCDb.SVNWCDbKind;
import org.tmatesoft.svn.core.internal.wc17.db.ISVNWCDb.SVNWCDbStatus;
import org.tmatesoft.svn.core.internal.wc17.db.ISVNWCDb.WCDbBaseInfo;
import org.tmatesoft.svn.core.internal.wc17.db.ISVNWCDb.WCDbBaseInfo.BaseInfoField;
import org.tmatesoft.svn.core.internal.wc17.db.ISVNWCDb.WCDbInfo;
import org.tmatesoft.svn.core.internal.wc17.db.ISVNWCDb.WCDbInfo.InfoField;
import org.tmatesoft.svn.core.internal.wc17.db.SVNWCDb;
import org.tmatesoft.svn.core.internal.wc17.db.Structure;
import org.tmatesoft.svn.core.internal.wc17.db.StructureFields.AdditionInfo;
import org.tmatesoft.svn.core.internal.wc17.db.StructureFields.DeletionInfo;
import org.tmatesoft.svn.core.internal.wc17.db.StructureFields.MovedInfo;
import org.tmatesoft.svn.core.internal.wc17.db.StructureFields.NodeOriginInfo;
import org.tmatesoft.svn.core.internal.wc17.db.StructureFields.PristineInfo;
import org.tmatesoft.svn.core.internal.wc17.db.SvnWcDbShared;
import org.tmatesoft.svn.core.internal.wc2.SvnWcGeneration;
import org.tmatesoft.svn.core.wc.SVNConflictDescription;
import org.tmatesoft.svn.core.wc.SVNTreeConflictDescription;
import org.tmatesoft.svn.core.wc2.SvnChecksum;
import org.tmatesoft.svn.core.wc2.SvnGetInfo;
import org.tmatesoft.svn.core.wc2.SvnInfo;
import org.tmatesoft.svn.core.wc2.SvnSchedule;
import org.tmatesoft.svn.core.wc2.SvnTarget;
import org.tmatesoft.svn.core.wc2.SvnWorkingCopyInfo;
import org.tmatesoft.svn.util.SVNLogType;
public class SvnNgGetInfo extends SvnNgOperationRunner<SvnInfo, SvnGetInfo> implements ISVNWCNodeHandler {
private boolean hasRootTreeConflict;
private boolean isFirstInfo;
private Map<File, SVNTreeConflictDescription> treeConflicts;
public void reset(SvnWcGeneration wcGeneration) {
super.reset(wcGeneration);
hasRootTreeConflict = false;
isFirstInfo = false;
treeConflicts = null;
}
@Override
protected SvnInfo run(SVNWCContext context) throws SVNException {
hasRootTreeConflict = false;
isFirstInfo = true;
getTreeConflicts().clear();
if (getOperation().isFetchActualOnly()) {
SVNTreeConflictDescription treeConflict = context.getDb().opReadTreeConflict(getFirstTarget());
if (treeConflict != null) {
hasRootTreeConflict = true;
getTreeConflicts().put(getFirstTarget(), treeConflict);
}
}
try {
context.nodeWalkChildren(getFirstTarget(), this, getOperation().isFetchExcluded(), getOperation().getDepth(), getOperation().getApplicableChangelists());
} catch (SVNException e) {
if (!(e.getErrorMessage().getErrorCode() == SVNErrorCode.WC_PATH_NOT_FOUND && hasRootTreeConflict)) {
throw e;
}
}
SVNWCNodeReposInfo reposInfo = null;
if (!getTreeConflicts().isEmpty()) {
reposInfo = getWcContext().getNodeReposInfo(getFirstTarget());
if (reposInfo.reposRootUrl == null) {
reposInfo = null;
}
}
for (File target: getTreeConflicts().keySet()) {
SVNTreeConflictDescription treeConflict = getTreeConflicts().get(target);
if (isDepthIncludes(getFirstTarget(), getOperation().getDepth(), target, treeConflict.getNodeKind())) {
SvnInfo unversionedInfo = buildUnversionedInfo(target);
Collection<SVNConflictDescription> conflicts = new ArrayList<SVNConflictDescription>(1);
conflicts.add(treeConflict);
unversionedInfo.getWcInfo().setConflicts(conflicts);
if (reposInfo != null) {
unversionedInfo.setRepositoryRootURL(reposInfo.reposRootUrl);
unversionedInfo.setRepositoryUuid(reposInfo.reposUuid);
}
getOperation().receive(SvnTarget.fromFile(target), unversionedInfo);
}
}
return getOperation().first();
}
public void nodeFound(File localAbspath, SVNWCDbKind kind) throws SVNException {
SvnInfo info = buildInfo(localAbspath, kind);
if (info == null && isFirstInfo) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.WC_PATH_NOT_FOUND, "The node ''{0}'' was not found", localAbspath),
SVNLogType.WC);
}
isFirstInfo = false;
if (info != null) {
getOperation().receive(SvnTarget.fromFile(localAbspath), info);
}
if (getOperation().isFetchActualOnly() && kind == SVNWCDbKind.Dir) {
Map<String,SVNTreeConflictDescription> treeConflicts = getWcContext().getDb().opReadAllTreeConflicts(localAbspath);
for (String name : treeConflicts.keySet()) {
getTreeConflicts().put(SVNFileUtil.createFilePath(localAbspath, name), treeConflicts.get(name));
}
}
getTreeConflicts().remove(localAbspath);
}
private SvnInfo buildUnversionedInfo(File localAbspath) throws SVNException {
SvnWorkingCopyInfo wcInfo = new SvnWorkingCopyInfo();
wcInfo.setPath(localAbspath);
SvnInfo info = new SvnInfo();
info.setWcInfo(wcInfo);
info.setRevision(SVNWCContext.INVALID_REVNUM);
info.setLastChangedRevision(SVNWCContext.INVALID_REVNUM);
info.setSize(ISVNWCDb.INVALID_FILESIZE);
info.setLastChangedDate(SVNDate.NULL);
info.setKind(SVNNodeKind.NONE);
wcInfo.setDepth(SVNDepth.UNKNOWN);
wcInfo.setRecordedSize(ISVNWCDb.INVALID_FILESIZE);
wcInfo.setCopyFromRevision(SVNWCContext.INVALID_REVNUM);
wcInfo.setSchedule(SvnSchedule.NORMAL);
return info;
}
private SvnInfo buildInfo(File localAbspath, SVNWCDbKind kind) throws SVNException {
SvnInfo info = new SvnInfo();
SvnWorkingCopyInfo wcInfo = new SvnWorkingCopyInfo();
wcInfo.setPath(localAbspath);
info.setWcInfo(wcInfo);
info.setKind(kind.toNodeKind());
wcInfo.setCopyFromRevision(SVNWCContext.INVALID_REVNUM);
WCDbInfo readInfo = getWcContext().getDb().readInfo(localAbspath,
InfoField.status, InfoField.kind, InfoField.revision, InfoField.reposRelPath, InfoField.reposRootUrl,
InfoField.reposUuid,
InfoField.changedRev, InfoField.changedDate, InfoField.changedAuthor,
InfoField.depth, InfoField.checksum,
InfoField.originalReposRelpath, InfoField.originalRootUrl, InfoField.originalUuid, InfoField.originalRevision,
InfoField.lock, InfoField.translatedSize, InfoField.lastModTime, InfoField.changelist,
InfoField.conflicted, InfoField.opRoot, InfoField.haveBase, InfoField.movedHere, InfoField.movedTo);
info.setRevision(readInfo.revision);
info.setRepositoryRootURL(readInfo.reposRootUrl);
info.setRepositoryUuid(readInfo.reposUuid);
info.setLastChangedDate(readInfo.changedDate);
info.setLastChangedAuthor(readInfo.changedAuthor);
info.setLastChangedRevision(readInfo.changedRev);
wcInfo.setDepth(readInfo.depth);
wcInfo.setChecksum(readInfo.checksum);
wcInfo.setRecordedSize(readInfo.translatedSize);
wcInfo.setRecordedTime(readInfo.lastModTime);
wcInfo.setChangelist(readInfo.changelist);
wcInfo.setMovedTo(readInfo.movedToAbsPath);
if (readInfo.opRoot && readInfo.movedHere) {
final Structure<MovedInfo> movedInfo = SvnWcDbShared.scanMoved((SVNWCDb) getWcContext().getDb(), localAbspath);
wcInfo.setMovedFrom(movedInfo.<File>get(MovedInfo.movedFromAbsPath));
}
File reposRelPath = readInfo.reposRelPath;
if (readInfo.originalRootUrl != null) {
info.setRepositoryRootURL(readInfo.originalRootUrl);
info.setRepositoryUuid(readInfo.originalUuid);
}
if (readInfo.status == SVNWCDbStatus.Added) {
if (readInfo.originalReposRelpath != null) {
info.setRevision(readInfo.originalRevision);
reposRelPath = readInfo.originalReposRelpath;
if (readInfo.opRoot) {
wcInfo.setCopyFromUrl(SVNWCUtils.join(info.getRepositoryRootUrl(), readInfo.originalReposRelpath));
wcInfo.setCopyFromRevision(readInfo.originalRevision);
}
} else if (readInfo.opRoot) {
Structure<AdditionInfo> additionInfo =
SvnWcDbShared.scanAddition((SVNWCDb) getWcContext().getDb(), localAbspath);
info.setRepositoryRootURL(additionInfo.<SVNURL>get(AdditionInfo.reposRootUrl));
info.setRepositoryUuid(additionInfo.<String>get(AdditionInfo.reposUuid));
if (readInfo.haveBase) {
long baseRev = getWcContext().getDb().getBaseInfo(localAbspath, BaseInfoField.revision).revision;
info.setRevision(baseRev);
}
additionInfo.release();
} else {
Structure<NodeOriginInfo> nodeOrigin = getWcContext().getNodeOrigin(localAbspath, true);
info.setRepositoryRootURL(nodeOrigin.<SVNURL>get(NodeOriginInfo.reposRootUrl));
info.setRepositoryUuid(nodeOrigin.text(NodeOriginInfo.reposUuid));
info.setRevision(nodeOrigin.lng(NodeOriginInfo.revision));
nodeOrigin.release();
}
ScheduleInternalInfo scheduleInfo = getWcContext().getNodeScheduleInternal(localAbspath, true, false);
wcInfo.setSchedule(toSchedule(scheduleInfo.schedule));
info.setUrl(getWcContext().getNodeUrl(localAbspath));
} else if (readInfo.status == SVNWCDbStatus.Deleted) {
Structure<PristineInfo> pristineInfo = getWcContext().getDb().readPristineInfo(localAbspath);
info.setLastChangedRevision(pristineInfo.lng(PristineInfo.changed_rev));
info.setLastChangedDate(pristineInfo.<SVNDate>get(PristineInfo.changed_date));
info.setLastChangedAuthor(pristineInfo.text(PristineInfo.changed_author));
wcInfo.setDepth(pristineInfo.<SVNDepth>get(PristineInfo.depth));
wcInfo.setChecksum(pristineInfo.<SvnChecksum>get(PristineInfo.checksum));
pristineInfo.release();
Structure<DeletionInfo> delInfo = SvnWcDbShared.scanDeletion((SVNWCDb) getWcContext().getDb(), localAbspath);
File workDelAbsPath = delInfo.<File>get(DeletionInfo.workDelAbsPath);
delInfo.release();
if (workDelAbsPath != null) {
File addedAbsPath = SVNFileUtil.getFileDir(workDelAbsPath);
Structure<AdditionInfo> additionInfo =
SvnWcDbShared.scanAddition((SVNWCDb) getWcContext().getDb(), addedAbsPath
);
reposRelPath = additionInfo.<File>get(AdditionInfo.reposRelPath);
info.setRepositoryRootURL(additionInfo.<SVNURL>get(AdditionInfo.reposRootUrl));
info.setRepositoryUuid(additionInfo.<String>get(AdditionInfo.reposUuid));
info.setRevision(additionInfo.lng(AdditionInfo.originalRevision));
additionInfo.release();
File p = SVNFileUtil.createFilePath(reposRelPath, SVNWCUtils.skipAncestor(addedAbsPath, localAbspath));
info.setUrl(SVNWCUtils.join(info.getRepositoryRootUrl(), p));
} else {
WCDbBaseInfo baseInfo = getWcContext().getDb().getBaseInfo(localAbspath, BaseInfoField.revision, BaseInfoField.reposRelPath, BaseInfoField.reposRootUrl, BaseInfoField.reposUuid);
reposRelPath = baseInfo.reposRelPath;
info.setRevision(baseInfo.revision);
info.setRepositoryRootURL(baseInfo.reposRootUrl);
info.setRepositoryUuid(baseInfo.reposUuid);
info.setUrl(SVNWCUtils.join(info.getRepositoryRootUrl(), reposRelPath));
}
wcInfo.setSchedule(SvnSchedule.DELETE);
} else if (readInfo.status == SVNWCDbStatus.NotPresent || readInfo.status == SVNWCDbStatus.ServerExcluded) {
return null;
} else {
if (info.getRepositoryRootUrl() != null) {
if (reposRelPath != null) {
info.setUrl(SVNWCUtils.join(info.getRepositoryRootUrl(), reposRelPath));
} else {
info.setUrl(info.getRepositoryRootUrl());
}
}
wcInfo.setSchedule(SvnSchedule.NORMAL);
}
if (readInfo.status == SVNWCDbStatus.Excluded) {
wcInfo.setDepth(SVNDepth.EXCLUDE);
}
info.setSize(ISVNWCDb.INVALID_FILESIZE);
wcInfo.setWcRoot(getWcContext().getDb().getWCRoot(localAbspath));
if (readInfo.conflicted) {
wcInfo.setConflicts(getWcContext().getDb().readConflicts(localAbspath));
}
if (readInfo.lock != null) {
SVNLock lock = new SVNLock(null, readInfo.lock.token, readInfo.lock.owner, readInfo.lock.comment, readInfo.lock.date, null);
info.setLock(lock);
}
return info;
}
private SvnSchedule toSchedule(SVNWCSchedule schedule) {
if (schedule == SVNWCSchedule.add) {
return SvnSchedule.ADD;
} else if (schedule == SVNWCSchedule.delete) {
return SvnSchedule.DELETE;
} else if (schedule == SVNWCSchedule.normal) {
return SvnSchedule.NORMAL;
} else if (schedule == SVNWCSchedule.replace) {
return SvnSchedule.REPLACE;
}
return null;
}
private boolean isDepthIncludes(File rootPath, SVNDepth depth, File childPath, SVNNodeKind childKind) {
if (depth == SVNDepth.INFINITY) {
return true;
}
File childParentPath = SVNFileUtil.getParentFile(childPath);
if (depth == SVNDepth.IMMEDIATES) {
return rootPath.equals(childParentPath);
} else if (depth == SVNDepth.FILES) {
return childKind == SVNNodeKind.FILE && rootPath.equals(childParentPath);
}
return rootPath.equals(childPath);
}
private Map<File, SVNTreeConflictDescription> getTreeConflicts() {
if (treeConflicts == null) {
treeConflicts = new HashMap<File, SVNTreeConflictDescription>();
}
return treeConflicts;
}
}