blob: 9ab84c95849e3d58b566a660838581a6578ca510 [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.util.Getter;
import com.intellij.openapi.vcs.impl.VcsRootIterator;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.Nullable;
import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil;
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
import org.tmatesoft.svn.core.wc.SVNInfo;
import java.util.*;
public class ForNestedRootChecker {
static class DirInfo {
private final VirtualFile myFile;
private final String myUrl;
DirInfo(final VirtualFile file, final String url) {
myFile = file;
myUrl = url;
}
public VirtualFile getFile() {
return myFile;
}
public String getUrl() {
return myUrl;
}
}
private static class UrlConstructor {
final SvnVcs myVcs;
private UrlConstructor(final SvnVcs vcs) {
myVcs = vcs;
}
@Nullable
public Real createReal(final VirtualFile file, final VirtualFile vcsRoot) {
final SVNInfo info = myVcs.getInfo(file);
if (info == null || info.getRepositoryRootURL() == null || info.getURL() == null) {
return null;
}
return new Real(file, info, vcsRoot);
}
public Node createReplaceable(final VirtualFile file) {
return new Node(file, null);
}
public Node createSupposed(final Real parent, final VirtualFile child) {
return new Node(child, getForChild(parent.getUrl(), child.getName()));
}
public boolean replaceWithReal(final Real real, final Node supposed) {
return supposed.getUrl() == null || ((supposed.getUrl() != null) && (! supposed.getUrl().equals(real.getUrl())));
}
@Nullable
private String getSupposedUrl(final String parentUrl, final List<String> subpath) {
if (parentUrl == null) return null;
final StringBuilder sb = new StringBuilder();
for (String s : subpath) {
sb.append(s).append('/');
}
if (sb.length() > 0) {
sb.deleteCharAt(sb.length() - 1);
}
return SVNPathUtil.append(parentUrl, sb.toString());
}
public String getForChild(final String parentUrl, final String childName) {
return parentUrl == null ? null : SVNPathUtil.append(parentUrl, SVNEncodingUtil.uriEncode(childName));
}
}
public static<T extends RootUrlPair> void filterOutSuperfluousChildren(final SvnVcs vcs, final List<T> list,
final List<T> result) {
final UrlConstructor constructor = new UrlConstructor(vcs);
Collections.sort(list, new Comparator<RootUrlPair>() {
public int compare(final RootUrlPair o1, final RootUrlPair o2) {
return o1.getVirtualFile().getPath().compareTo(o2.getVirtualFile().getPath());
}
});
for (int i = 0; i < list.size(); i++) {
final T child = list.get(i);
boolean add = true;
for (T parent : result) {
if (parent.getVirtualFile().getPath().equals(child.getVirtualFile().getPath())) {
add = false;
break;
}
final List<String> subpath = subpathIfAncestor(parent.getVirtualFile(), child.getVirtualFile());
if (subpath != null) {
// get child's supposed and real urls
final String supposed = constructor.getSupposedUrl(parent.getUrl(), subpath);
if (supposed.equals(child.getUrl())) {
add = false;
break;
}
}
}
if (add) {
result.add(child);
}
}
}
@Nullable
private static List<String> subpathIfAncestor(final VirtualFile parent, final VirtualFile child) {
if (! VfsUtil.isAncestor(parent, child, true)) return null;
final List<String> result = new ArrayList<String>();
VirtualFile tmp = child;
final String parentPath = parent.getPath();
while ((tmp != null) && (! tmp.getPath().equals(parentPath))) {
result.add(tmp.getName());
tmp = tmp.getParent();
}
Collections.reverse(result);
return result;
}
/*public static List<Real> getAllNestedWorkingCopies(final VirtualFile[] roots, final SvnVcs vcs, final boolean goIntoNested) {
if (goIntoNested) {
FilterDescendantVirtualFiles.filter(Arrays.asList(roots));
}
final VcsRootIterator rootIterator = new VcsRootIterator(vcs.getProject(), vcs);
final List<Real> result = new ArrayList<Real>();
for (VirtualFile root : roots) {
result.addAll(getForOne(root, vcs, goIntoNested, rootIterator));
}
if (! goIntoNested) {
final List<Real> filtered = new ArrayList<Real>(result.size());
filterOutSuperfluousChildren(vcs, result, filtered);
return filtered;
}
return result;
}*/
public static List<Real> getAllNestedWorkingCopies(final VirtualFile root, final SvnVcs vcs, final boolean goIntoNested, final Getter<Boolean> cancelledGetter) {
final VcsRootIterator rootIterator = new VcsRootIterator(vcs.getProject(), vcs);
return getForOne(root, vcs, goIntoNested, rootIterator, cancelledGetter);
}
private static List<Real> getForOne(final VirtualFile root, final SvnVcs vcs, final boolean goIntoNested,
final VcsRootIterator rootIterator, final Getter<Boolean> cancelledGetter) {
final UrlConstructor constructor = new UrlConstructor(vcs);
final LinkedList<Node> queue = new LinkedList<Node>();
final LinkedList<Real> result = new LinkedList<Real>();
queue.add(constructor.createReplaceable(root));
while (! queue.isEmpty()) {
final Node node = queue.removeFirst();
if (Boolean.TRUE.equals(cancelledGetter.get())) throw new ProcessCanceledException();
// check self
final Real real = constructor.createReal(node.getFile(), root);
if (real != null) {
if (constructor.replaceWithReal(real, node)) {
result.add(real);
if (! goIntoNested) continue;
}
}
// for next step
final VirtualFile file = node.getFile();
if (file.isDirectory() && (! SvnUtil.isAdminDirectory(file))) {
for (VirtualFile child : file.getChildren()) {
if (Boolean.TRUE.equals(cancelledGetter.get())) throw new ProcessCanceledException();
if (rootIterator.acceptFolderUnderVcs(root, child)) {
if (real == null) {
queue.add(constructor.createReplaceable(child));
} else {
queue.add(constructor.createSupposed(real, child));
}
}
}
}
}
return result;
}
}