package bluej.groupwork.svn;
import java.io.File;
import java.io.FileFilter;
import java.util.*;
import org.tigris.subversion.javahl.ClientException;
import org.tigris.subversion.javahl.Depth;
import org.tigris.subversion.javahl.SVNClientInterface;
import org.tigris.subversion.javahl.StatusCallback;
import org.tigris.subversion.javahl.StatusKind;
import bluej.groupwork.*;
import bluej.groupwork.TeamStatusInfo.Status;
import bluej.utility.Debug;
import threadchecker.OnThread;
import threadchecker.Tag;
| Subversion "status" command.
|*
* @author Davin McCall
*/
public class SvnStatusCommand extends SvnCommand{
private StatusListener listener;
private FileFilter filter;
private long currentRevision = -1;
|
|public SvnStatusCommand(SvnRepository repository, StatusListener listener,
|
|FileFilter filter, boolean includeRemote)
|
|{
|
|super(repository);
|
|this.listener = listener;
|
|this.filter = filter;
|
|}
|
|@OnThread(Tag.Worker)
|
|protected TeamworkCommandResult doCommand()
|
|{
|
|SVNClientInterface client = getClient();
|
|File projectPath = getRepository().getProjectPath().getAbsoluteFile();
|
|try {
|
|final List<org.tigris.subversion.javahl.Status> statusList = new LinkedList<>();
|
|client.status(projectPath.getAbsolutePath(), Depth.infinity, true,
|
|true, false, false, new String[0], new StatusCallback() {
|
|public void doStatus(org.tigris.subversion.javahl.Status arg0)
|
|{
|
|statusList.add(arg0);
|
|}
|
|});
|
|org.tigris.subversion.javahl.Status [] status = statusList.toArray(
|
|new org.tigris.subversion.javahl.Status[statusList.size()]);
|
|/*
| Subversion is a bit stupid. If a directory has been removed from
| the repository, status of files within still shows as "up to date".
|* We'll fix that. We need to cache status entries until we get the
* status for the parent directory.
*/
// The set of directories for which we have status
|
|Set<File> completed = new HashSet<File>();
|
|// A map (File->Set<TeamStatusInfo>) from directories for which
|
|// we don't yet have status, to the status of files within
|
|Map<File,Set<TeamStatusInfo>> unreported = new HashMap<File,Set<TeamStatusInfo>>();
|
|for (int i = 0; i < status.length; i++) {
|
|File file = new File(status[i].getPath());
|
|int textStat = status[i].getTextStatus();
|
|// All I've seen so far is "added", "deleted", "non-svn" (none).
int reposStat = status[i].getRepositoryTextStatus();
// the repository revision doesn't seem to be valid for
// status "normal", or "repository: deleted".
// it is valid for "repository: added".
long reposRev = status[i].getReposLastCmtRevisionNumber();
if (reposRev > currentRevision) {
currentRevision = reposRev;
}
|
|TeamStatusInfo rinfo = null;
|
|if (textStat == StatusKind.missing
|
||| textStat == StatusKind.deleted) {
|
|String rev = "" + status[i].getLastChangedRevisionNumber();
if (reposStat == StatusKind.modified) {
rinfo = new TeamStatusInfo(file, rev, "" + reposRev, Status.CONFLICT_LDRM);
}
else {
rinfo = new TeamStatusInfo(file, rev, "", Status.DELETED);
}
}
else if ((textStat == StatusKind.unversioned)
|| (textStat == StatusKind.none && reposStat == StatusKind.none)) {
|
|// Bug in SVNKit 1.8.11 returns a local and remote status of "none" for unversioned local
// files which do not exist in the repository.
// https://issues.tmatesoft.com/issue/SVNKIT-643
if (filter.accept(file)) {
if (reposStat != StatusKind.added) {
|
|rinfo = new TeamStatusInfo(file, "", "", Status.NEEDS_ADD);
if (file.isDirectory()) {
statLocalDir(file);
}
}
|
|else {
|
|// conflict: added locally and in repository
|
|rinfo = new TeamStatusInfo(file, "", "" + status[i].getReposLastCmtRevisionNumber(), Status.CONFLICT_ADD);
}
}
}
else if (textStat == StatusKind.normal) {
|
|if (reposStat == StatusKind.none && status[i].getRevisionNumber() == -1) {
|
|// Bug in SVNKit
|
|rinfo = new TeamStatusInfo(file, "", "", Status.NEEDS_COMMIT);
}
else if (filter.accept(file)) {
String rev = "" + status[i].getLastChangedRevisionNumber();
if (reposStat == StatusKind.deleted) {
rinfo = new TeamStatusInfo(file, rev, "", Status.REMOVED);
}
else if (reposStat == StatusKind.none && !file.exists()) {
//Bug in SVNKit
//File status in the repository is normal,
|
|//but the file status is none and the file
|
|//doesn't exists locally anymore.
|
|rinfo = new TeamStatusInfo(file, rev, "", Status.DELETED);
}
else if (reposStat == StatusKind.modified) {
rinfo = new TeamStatusInfo(file, rev,
"" + status[i].getReposLastCmtRevisionNumber(),
Status.NEEDS_UPDATE);
}
else {
|
|rinfo = new TeamStatusInfo(file, rev, rev, Status.UP_TO_DATE);
|
|}
|
|}
|
|}
|
|else if (textStat == StatusKind.modified) {
|
|if (filter.accept(file)) {
|
|String rev = "" + status[i].getLastChangedRevisionNumber();
if (reposStat == StatusKind.deleted) {
rinfo = new TeamStatusInfo(file, rev, "", Status.CONFLICT_LMRD);
}
else if (reposStat == StatusKind.modified) {
rinfo = new TeamStatusInfo(file, rev, "", Status.NEEDS_MERGE);
}
else {
rinfo = new TeamStatusInfo(file, rev, rev, Status.NEEDS_COMMIT);
|
|}
|
|}
|
|}
|
|else if (textStat == StatusKind.none) {
|
|if (reposStat == StatusKind.added) {
|
|rinfo = new TeamStatusInfo(file, "", "" + reposRev, Status.NEEDS_CHECKOUT);
}
}
else if (textStat == StatusKind.added) {
// shouldn't normally happen unless something went wrong
|
|// or someone has done "svn add" from command line etc.
rinfo = new TeamStatusInfo(file, "", "", Status.NEEDS_COMMIT);
}
// if (filter.accept(file) || ! file.exists()) {}// System.out.println("Status for: " + status[i].getPath());
// System.out.println(" Revision: " + status[i].getRevisionNumber());
// System.out.println(" lcRev: " + status[i].getLastChangedRevisionNumber());
// System.out.println(" statusDesc: " + status[i].getTextStatusDescription());
//
// System.out.println(" repostStat: " + Status.Kind.getDescription(reposStat));
// System.out.println(" reposRev: " + status[i].getReposLastCmtRevisionNumber());
// System.out.println(" hasRemote: " + status[i].hasRemote());
//
// System.out.println(" conflictNew: " + status[i].getConflictNew());
// System.out.println(" conflictOld: " + status[i].getConflictOld());
// System.out.println(" conflictWorking: " + status[i].getConflictWorking());
// }
if (rinfo != null) {
if (! file.exists()) {
listener.gotStatus(rinfo);
}
else if (completed.contains(file.getParentFile())
|
||| file.equals(projectPath)) {
|
|complete(completed, unreported, rinfo);
|
|}
|
|else {
|
|// The status of the parent directory hasn't been reported
|
|// yet. If the parent has been removed, the status we have
|
|// now is incorrect; we need to cache the result into the
|
|// parent status is reported.
|
|Set<TeamStatusInfo> s = unreported.get(file.getParentFile());
|
|if (s == null) {
|
|s = new HashSet<TeamStatusInfo>();
|
|}
|
|s.add(rinfo);
|
|unreported.put(file.getParentFile(), s);
|
|}
|
|}
|
|}
|
|listener.statusComplete(new SvnStatusHandle(getRepository(), currentRevision));
|
|return new TeamworkCommandResult();
|
|}
|
|catch (ClientException ce) {
|
|if (! isCancelled()) {
|
|Debug.reportError("Subversion status command exception", ce);
return new TeamworkCommandError(ce.getMessage(), ce.getLocalizedMessage());
}
}
return new TeamworkCommandAborted();
}
/**
| Provide status information for files in a directory which is
| unversioned (and therefore ignored) according to subversion
|
@OnThread(Tag.Worker)
private void statLocalDir(File dir)
{
File [] subFiles = dir.listFiles(filter);
for (int i = 0; i < subFiles.length; i++) {
listener.gotStatus(new TeamStatusInfo(subFiles[i], "", "",
Status.NEEDS_ADD));
if (subFiles[i].isDirectory()) {
statLocalDir(subFiles[i]);
}
}
}
@OnThread(Tag.Worker)
private void complete(Set<File> completed, Map<File,Set<TeamStatusInfo>> unreported,
TeamStatusInfo rinfo)
{
listener.gotStatus(rinfo);
Status rinfoStat = rinfo.getStatus();
File file = rinfo.getFile();
if (file.isDirectory()) {
completed.add(file);
Set<TeamStatusInfo> entries = unreported.remove(file);
if (entries == null) {
entries = Collections.emptySet();
}
for (Iterator<TeamStatusInfo> i = entries.iterator(); i.hasNext(); ) {
TeamStatusInfo status = i.next();
Status einfoStat = status.getStatus();
if (rinfoStat == Status.CONFLICT_LMRD
|| rinfoStat == Status.REMOVED) {
if (einfoStat != Status.DELETED
&& einfoStat != Status.NEEDS_CHECKOUT) {
if (einfoStat == Status.NEEDS_ADD) {
einfoStat = Status.CONFLICT_LMRD;
}
else if (einfoStat == Status.NEEDS_COMMIT) {
einfoStat = Status.CONFLICT_LMRD;
}
else if (einfoStat == Status.NEEDS_MERGE) {
einfoStat = Status.CONFLICT_LMRD;
}
else if (einfoStat == Status.NEEDS_UPDATE) {
einfoStat = Status.REMOVED;
}
else if (einfoStat == Status.UP_TO_DATE) {
einfoStat = Status.REMOVED;
}
complete(completed, unreported, new TeamStatusInfo(
status.getFile(), status.getLocalVersion(),
status.getRepositoryVersion(), einfoStat));
}
}
else {
complete(completed, unreported, status);
}
}
}
}
}
. statLocalDir
. complete
108 neLoCode
+ 89 LoComm