blob: e87c55dc447dbd57d036b585cfa653a057e0a36f [file] [log] [blame]
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* 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.jetbrains.idea.svn;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.vcs.impl.VcsRootIterator;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.commandLine.SvnBindException;
import org.jetbrains.idea.svn.info.Info;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.wc.SVNRevision;
import java.io.File;
import java.util.LinkedList;
import java.util.List;
public class ForNestedRootChecker {
@NotNull private final SvnVcs myVcs;
@NotNull private final VcsRootIterator myRootIterator;
public ForNestedRootChecker(@NotNull SvnVcs vcs) {
myVcs = vcs;
myRootIterator = new VcsRootIterator(vcs.getProject(), vcs);
}
public List<Node> getAllNestedWorkingCopies(@NotNull final VirtualFile root, final boolean goIntoNested) {
final LinkedList<WorkItem> workItems = new LinkedList<WorkItem>();
final LinkedList<Node> result = new LinkedList<Node>();
workItems.add(new WorkItem(root));
while (!workItems.isEmpty()) {
final WorkItem item = workItems.removeFirst();
checkCancelled();
// check self
final Node vcsElement = new VcsFileResolver(myVcs, item.file).resolve();
// TODO: actually goIntoNested = false always => item.url will be always null when this line is reached
if (vcsElement != null && (item.url == null || vcsElement.onUrl(item.url))) {
result.add(vcsElement);
if (!goIntoNested) {
continue;
}
}
// for next step
final VirtualFile file = item.file;
if (file.isDirectory() && (! SvnUtil.isAdminDirectory(file))) {
// TODO: Only directory children should be checked.
for (VirtualFile child : file.getChildren()) {
checkCancelled();
if (myRootIterator.acceptFolderUnderVcs(root, child)) {
// TODO: actually goIntoNested = false always => we could reach this line only when vcsElement is null
workItems.add(WorkItem.create(vcsElement, child));
}
}
}
}
return result;
}
private void checkCancelled() {
if (myVcs.getProject().isDisposed()) {
throw new ProcessCanceledException();
}
}
private static class WorkItem {
@NotNull private final VirtualFile file;
@Nullable private final SVNURL url;
private WorkItem(@NotNull VirtualFile file) {
this(file, null);
}
private WorkItem(@NotNull VirtualFile file, @Nullable SVNURL url) {
this.file = file;
this.url = url;
}
@NotNull
private static WorkItem create(@Nullable Node node, @NotNull VirtualFile child) {
return node == null ? new WorkItem(child) : new WorkItem(child, SvnUtil.append(node.getUrl(), child.getName()));
}
}
private static class VcsFileResolver {
@NotNull private final SvnVcs myVcs;
@NotNull private final VirtualFile myFile;
@NotNull private final File myIoFile;
@Nullable private Info myInfo;
@Nullable private SvnBindException myError;
private VcsFileResolver(@NotNull SvnVcs vcs, @NotNull VirtualFile file) {
myVcs = vcs;
myFile = file;
myIoFile = VfsUtilCore.virtualToIoFile(file);
}
@Nullable
public Node resolve() {
runInfo();
return processInfo();
}
private void runInfo() {
try {
myInfo = myVcs.getFactory(myIoFile, false).createInfoClient().doInfo(myIoFile, SVNRevision.UNDEFINED);
}
catch (SvnBindException e) {
myError = e;
}
}
@Nullable
private Node processInfo() {
Node result = null;
if (myError != null) {
if (!SvnUtil.isUnversionedOrNotFound(myError)) {
// error code does not indicate that myFile is unversioned or path is invalid => create result, but indicate error
result = new Node(myFile, getFakeUrl(), getFakeUrl(), myError);
}
}
else if (myInfo != null && myInfo.getRepositoryRootURL() != null && myInfo.getURL() != null) {
result = new Node(myFile, myInfo.getURL(), myInfo.getRepositoryRootURL());
}
return result;
}
// TODO: This should be updated when fully removing SVNKit object model from code
private SVNURL getFakeUrl() {
// do not have constants like SVNURL.EMPTY - use fake url - it should be never used in any real logic
try {
return SVNURL.fromFile(myIoFile);
}
catch (SVNException e) {
// should not occur
throw SvnUtil.createIllegalArgument(e);
}
}
}
}