Commit 0acab054 authored by Aleksey Pivovarov's avatar Aleksey Pivovarov
Browse files

vcs: compute and store roots for <Project> mapping

* Do not walk modules every time on `getMappingFor`.
* Ensure that all `getMappingFor` methods return same mappings.
* Remove duplicated methods from DefaultVcsRootPolicy.
parent 6f6d465a
Showing with 302 additions and 599 deletions
+302 -599
......@@ -9,8 +9,7 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.AbstractVcs;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
import com.intellij.openapi.vcs.VcsDirectoryMapping;
import com.intellij.openapi.vcs.impl.DefaultVcsRootPolicy;
import com.intellij.openapi.vcs.VcsRoot;
import com.intellij.openapi.vcs.impl.ProjectLevelVcsManagerImpl;
import com.intellij.openapi.vcs.impl.VcsInitObject;
import com.intellij.openapi.vfs.VirtualFile;
......@@ -236,15 +235,13 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr
@NotNull
private MultiMap<AbstractVcs, FilePath> getEverythingDirtyRoots() {
MultiMap<AbstractVcs, FilePath> dirtyRoots = MultiMap.createSet();
dirtyRoots.putAllValues(groupFilesByVcs(DefaultVcsRootPolicy.getInstance(myProject).getDirtyRoots()));
List<VcsDirectoryMapping> mappings = myVcsManager.getDirectoryMappings();
for (VcsDirectoryMapping mapping : mappings) {
if (!mapping.isDefaultMapping() && mapping.getVcs() != null) {
AbstractVcs vcs = myVcsManager.findVcsByName(mapping.getVcs());
if (vcs != null) {
dirtyRoots.putValue(vcs, VcsUtil.getFilePath(mapping.getDirectory(), true));
}
VcsRoot[] roots = myVcsManager.getAllVcsRoots();
for (VcsRoot root : roots) {
AbstractVcs vcs = root.getVcs();
VirtualFile path = root.getPath();
if (vcs != null && path != null) {
dirtyRoots.putValue(vcs, VcsUtil.getFilePath(path));
}
}
return dirtyRoots;
......
......@@ -2,61 +2,25 @@
package com.intellij.openapi.vcs.impl;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.impl.projectlevelman.NewMappings;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.platform.ProjectBaseDirectory;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* @author yole
*/
public class BasicDefaultVcsRootPolicy extends DefaultVcsRootPolicy {
private final VirtualFile myBaseDir;
public BasicDefaultVcsRootPolicy(@NotNull Project project) {
super(project);
myBaseDir = project.getBaseDir();
}
@Override
@NotNull
public Collection<VirtualFile> getDefaultVcsRoots(@NotNull NewMappings mappingList, @NotNull String vcsName) {
public Collection<VirtualFile> getDefaultVcsRoots() {
List<VirtualFile> result = ContainerUtil.newArrayList();
final VirtualFile baseDir = ProjectBaseDirectory.getInstance(myProject).getBaseDir(myBaseDir);
if (baseDir != null && vcsName.equals(mappingList.getVcsFor(baseDir))) {
result.add(baseDir);
}
final VirtualFile baseDir = ProjectBaseDirectory.getInstance(myProject).getBaseDir(myProject.getBaseDir());
if (baseDir != null) result.add(baseDir);
return result;
}
@Override
public boolean matchesDefaultMapping(@NotNull final VirtualFile file, final Object matchContext) {
return VfsUtil.isAncestor(ProjectBaseDirectory.getInstance(myProject).getBaseDir(myBaseDir), file, false);
}
@Override
@Nullable
public Object getMatchContext(final VirtualFile file) {
return null;
}
@Override
@Nullable
public VirtualFile getVcsRootFor(@NotNull final VirtualFile file) {
return ProjectBaseDirectory.getInstance(myProject).getBaseDir(myBaseDir);
}
@Override
@NotNull
public Collection<VirtualFile> getDirtyRoots() {
return Collections.singletonList(ProjectBaseDirectory.getInstance(myProject).getBaseDir(myBaseDir));
}
}
......@@ -17,18 +17,13 @@ package com.intellij.openapi.vcs.impl;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.impl.projectlevelman.NewMappings;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.project.ProjectKt;
import com.intellij.util.PathUtilRt;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
/**
* @author yole
*/
public abstract class DefaultVcsRootPolicy {
@NotNull protected final Project myProject;
......@@ -40,19 +35,12 @@ public abstract class DefaultVcsRootPolicy {
return ServiceManager.getService(project, DefaultVcsRootPolicy.class);
}
/**
* Return roots that belong to the project (ex: all content roots).
* If 'Project' mapping is configured, all vcs roots for these roots will be put to the mappings.
*/
@NotNull
public abstract Collection<VirtualFile> getDefaultVcsRoots(@NotNull NewMappings mappingList, @NotNull String vcsName);
public abstract boolean matchesDefaultMapping(@NotNull VirtualFile file, final Object matchContext);
@Nullable
public abstract Object getMatchContext(final VirtualFile file);
@Nullable
public abstract VirtualFile getVcsRootFor(@NotNull VirtualFile file);
@NotNull
public abstract Collection<VirtualFile> getDirtyRoots();
public abstract Collection<VirtualFile> getDefaultVcsRoots();
public String getProjectConfigurationMessage() {
boolean isDirectoryBased = ProjectKt.isDirectoryBased(myProject);
......
......@@ -17,159 +17,53 @@
package com.intellij.openapi.vcs.impl;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.FileIndexFacade;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.AbstractVcs;
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
import com.intellij.openapi.vcs.VcsDirectoryMapping;
import com.intellij.openapi.vcs.ex.ProjectLevelVcsManagerEx;
import com.intellij.openapi.vcs.impl.projectlevelman.NewMappings;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.project.ProjectKt;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.Collection;
import java.util.Set;
import java.util.stream.Collectors;
import static com.intellij.util.containers.ContainerUtil.newHashSet;
/**
* @author yole
*/
public class ModuleDefaultVcsRootPolicy extends DefaultVcsRootPolicy {
private static final Logger LOG = Logger.getInstance(ModuleDefaultVcsRootPolicy.class);
private final VirtualFile myBaseDir;
private final ModuleManager myModuleManager;
public ModuleDefaultVcsRootPolicy(@NotNull Project project) {
super(project);
myBaseDir = project.getBaseDir();
myModuleManager = ModuleManager.getInstance(myProject);
}
@Override
@NotNull
public Collection<VirtualFile> getDefaultVcsRoots(@NotNull NewMappings mappingList, @NotNull String vcsName) {
public Collection<VirtualFile> getDefaultVcsRoots() {
Set<VirtualFile> result = newHashSet();
final ProjectLevelVcsManager vcsManager = ProjectLevelVcsManager.getInstance(myProject);
if (myBaseDir != null && vcsName.equals(mappingList.getVcsFor(myBaseDir))) {
final AbstractVcs vcsFor = vcsManager.getVcsFor(myBaseDir);
if (vcsFor != null && vcsName.equals(vcsFor.getName())) {
result.add(myBaseDir);
}
VirtualFile baseDir = myProject.getBaseDir();
if (baseDir != null) {
result.add(baseDir);
}
if (ProjectKt.isDirectoryBased(myProject) && myBaseDir != null) {
if (ProjectKt.isDirectoryBased(myProject) && baseDir != null) {
final VirtualFile ideaDir = ProjectKt.getStateStore(myProject).getDirectoryStoreFile();
if (ideaDir != null) {
final AbstractVcs vcsFor = vcsManager.getVcsFor(ideaDir);
if (vcsFor != null && vcsName.equals(vcsFor.getName())) {
result.add(ideaDir);
}
result.add(ideaDir);
}
}
// assertion for read access inside
Module[] modules = ReadAction.compute(myModuleManager::getModules);
Module[] modules = ReadAction.compute(() -> ModuleManager.getInstance(myProject).getModules());
for (Module module : modules) {
final VirtualFile[] files = ModuleRootManager.getInstance(module).getContentRoots();
ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module);
final VirtualFile[] files = moduleRootManager.getContentRoots();
for (VirtualFile file : files) {
// if we're currently processing moduleAdded notification, getModuleForFile() will return null, so we pass the module
// explicitly (we know it anyway)
VcsDirectoryMapping mapping = mappingList.getMappingFor(file, module);
final String mappingVcs = mapping != null ? mapping.getVcs() : null;
if (vcsName.equals(mappingVcs) && file.isDirectory()) {
if (file.isDirectory()) {
result.add(file);
}
}
}
return result;
}
@Override
public boolean matchesDefaultMapping(@NotNull final VirtualFile file, final Object matchContext) {
if (matchContext != null) {
return true;
}
return myBaseDir != null && VfsUtilCore.isAncestor(myBaseDir, file, false);
}
@Override
@Nullable
public Object getMatchContext(final VirtualFile file) {
return ReadAction.compute(() -> myProject.isDisposed() ? null : ModuleUtilCore.findModuleForFile(file, myProject));
}
@Override
@Nullable
public VirtualFile getVcsRootFor(@NotNull VirtualFile file) {
if (myBaseDir != null && ReadAction.compute(() -> FileIndexFacade.getInstance(myProject).isValidAncestor(myBaseDir, file))) {
LOG.debug("File " + file + " is under project base dir " + myBaseDir);
return myBaseDir;
}
VirtualFile contentRoot = ProjectRootManager.getInstance(myProject).getFileIndex().getContentRootForFile(file, Registry.is("ide.hide.excluded.files"));
if (contentRoot != null) {
LOG.debug("Content root for file " + file + " is " + contentRoot);
if (contentRoot.isDirectory()) {
return contentRoot;
}
VirtualFile parent = contentRoot.getParent();
LOG.debug("Content root is not a directory, using its parent " + parent);
return parent;
}
if (ProjectKt.isDirectoryBased(myProject)) {
VirtualFile ideaDir = ProjectKt.getStateStore(myProject).getDirectoryStoreFile();
if (ideaDir != null && VfsUtilCore.isAncestor(ideaDir, file, false)) {
LOG.debug("File " + file + " is under .idea");
return ideaDir;
}
}
LOG.debug("Couldn't find proper root for " + file);
return null;
}
@NotNull
@Override
public Collection<VirtualFile> getDirtyRoots() {
Collection<VirtualFile> dirtyRoots = newHashSet();
if (ProjectKt.isDirectoryBased(myProject)) {
VirtualFile ideaDir = ProjectKt.getStateStore(myProject).getDirectoryStoreFile();
if (ideaDir != null) {
dirtyRoots.add(ideaDir);
}
else {
LOG.warn(".idea was not found for base dir [" + myBaseDir.getPath() + "]");
}
}
ContainerUtil.addAll(dirtyRoots, getContentRoots());
String defaultMapping = ((ProjectLevelVcsManagerEx)ProjectLevelVcsManager.getInstance(myProject)).haveDefaultMapping();
boolean haveDefaultMapping = !StringUtil.isEmpty(defaultMapping);
if (haveDefaultMapping && myBaseDir != null) {
dirtyRoots.add(myBaseDir);
}
return dirtyRoots;
}
@NotNull
private Collection<VirtualFile> getContentRoots() {
Module[] modules = ReadAction.compute(myModuleManager::getModules);
return Arrays.stream(modules)
.map(module -> ModuleRootManager.getInstance(module).getContentRoots())
.flatMap(Arrays::stream)
.collect(Collectors.toSet());
}
}
......@@ -36,14 +36,14 @@ class ModuleVcsDetector(private val myProject: Project,
}
private inner class MyModulesListener : ModuleRootListener, ModuleListener {
private val myMappingsForRemovedModules: MutableList<Pair<String, VcsDirectoryMapping>> = mutableListOf()
private val myMappingsForRemovedModules: MutableList<VcsDirectoryMapping> = mutableListOf()
override fun beforeRootsChange(event: ModuleRootEvent) {
myMappingsForRemovedModules.clear()
}
override fun rootsChanged(event: ModuleRootEvent) {
myMappingsForRemovedModules.forEach { (_, mapping) -> myVcsManager.removeDirectoryMapping(mapping) }
myMappingsForRemovedModules.forEach { mapping -> myVcsManager.removeDirectoryMapping(mapping) }
// the check calculates to true only before user has done any change to mappings, i.e. in case modules are detected/added automatically
// on start etc (look inside)
if (myVcsManager.needAutodetectMappings()) {
......@@ -90,7 +90,7 @@ class ModuleVcsDetector(private val myProject: Project,
var mappingsUpdated = false
for (file in module.rootManager.contentRoots) {
val vcs = myVcsManager.findVersioningVcs(file)
if (vcs != null && vcs !== myVcsManager.getVcsFor(file, module)) {
if (vcs != null && vcs !== myVcsManager.getVcsFor(file)) {
myVcsManager.setAutoDirectoryMapping(file.path, vcs.name)
mappingsUpdated = true
}
......@@ -100,10 +100,8 @@ class ModuleVcsDetector(private val myProject: Project,
}
}
private fun getMappings(module: Module): List<Pair<String, VcsDirectoryMapping>> {
val moduleName = module.name
private fun getMappings(module: Module): List<VcsDirectoryMapping> {
return module.rootManager.contentRoots
.mapNotNull { root -> myVcsManager.directoryMappings.firstOrNull { it.systemIndependentPath() == root.path } }
.map { moduleName to it }
}
}
......@@ -14,8 +14,6 @@ import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.components.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.util.BackgroundTaskUtil;
import com.intellij.openapi.project.Project;
......@@ -43,7 +41,6 @@ import com.intellij.openapi.vcs.update.ActionInfo;
import com.intellij.openapi.vcs.update.UpdateInfoTree;
import com.intellij.openapi.vcs.update.UpdatedFiles;
import com.intellij.openapi.vcs.update.UpdatedFilesListener;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.ToolWindow;
......@@ -67,8 +64,6 @@ import org.jetbrains.annotations.*;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import static com.intellij.openapi.util.text.StringUtil.nullize;
@State(name = "ProjectLevelVcsManager", storages = @Storage(StoragePathMacros.WORKSPACE_FILE))
public class ProjectLevelVcsManagerImpl extends ProjectLevelVcsManagerEx implements ProjectComponent, PersistentStateComponent<Element>, Disposable {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.impl.ProjectLevelVcsManagerImpl");
......@@ -94,7 +89,6 @@ public class ProjectLevelVcsManagerImpl extends ProjectLevelVcsManagerEx impleme
private boolean myMappingsLoaded;
private boolean myHaveLegacyVcsConfiguration;
private final DefaultVcsRootPolicy myDefaultVcsRootPolicy;
@NotNull private final AtomicInteger myBackgroundOperationCounter = new AtomicInteger();
......@@ -116,8 +110,6 @@ public class ProjectLevelVcsManagerImpl extends ProjectLevelVcsManagerEx impleme
mySerialization = new ProjectLevelVcsManagerSerialization();
myOptionsAndConfirmations = new OptionsAndConfirmations();
myDefaultVcsRootPolicy = defaultVcsRootPolicy;
if (!project.isDefault()) {
myInitialization = new VcsInitialization(myProject);
Disposer.register(project, myInitialization); // wait for the thread spawned in VcsInitialization to terminate
......@@ -132,7 +124,7 @@ public class ProjectLevelVcsManagerImpl extends ProjectLevelVcsManagerEx impleme
myInitialization = null;
}
myMappings = new NewMappings(myProject, this, manager);
myMappings = new NewMappings(myProject, this, manager, defaultVcsRootPolicy);
myMappingsToRoots = new MappingsToRoots(myMappings, myProject);
myVcsHistoryCache = new VcsHistoryCache();
......@@ -238,26 +230,8 @@ public class ProjectLevelVcsManagerImpl extends ProjectLevelVcsManagerEx impleme
public AbstractVcs getVcsFor(@NotNull VirtualFile file) {
if (myProject.isDisposed()) return null;
final String vcsName = myMappings.getVcsFor(file);
if (vcsName == null || vcsName.isEmpty()) {
return null;
}
return AllVcses.getInstance(myProject).getByName(vcsName);
}
/**
* Common {@link #getVcsFor(VirtualFile)} method uses {@link DefaultVcsRootPolicy#getMatchContext(VirtualFile)} if default mapping is
* present. Some implementations, like {@link ModuleDefaultVcsRootPolicy}, rely on indices state, which could be critical for some code
* flows. For instance, when processing {@link com.intellij.openapi.project.ModuleListener#moduleAdded(Project, Module)} events. In such
* cases, we could explicitly specify context (i.e. {@link Module}) to get correct result.
*/
AbstractVcs<?> getVcsFor(@NotNull VirtualFile file, @Nullable Object matchContext) {
if (myProject.isDisposed()) return null;
VcsDirectoryMapping mapping = myMappings.getMappingFor(file, matchContext);
String vcsName = mapping != null ? nullize(mapping.getVcs()) : null;
return vcsName != null ? AllVcses.getInstance(myProject).getByName(vcsName) : null;
NewMappings.MappedRoot root = myMappings.getMappedRootFor(file);
return root != null ? root.vcs : null;
}
@Override
......@@ -266,44 +240,25 @@ public class ProjectLevelVcsManagerImpl extends ProjectLevelVcsManagerEx impleme
if (myProject.isDisposed()) return null;
final VirtualFile vFile = ChangesUtil.findValidParentAccurately(file);
return ReadAction.compute(() -> {
if (!ApplicationManager.getApplication().isUnitTestMode() && !myProject.isInitialized()) return null;
if (myProject.isDisposed()) throw new ProcessCanceledException();
if (vFile != null) {
return getVcsFor(vFile);
}
return null;
});
return vFile != null ? getVcsFor(vFile) : null;
}
@Override
@Nullable
public VirtualFile getVcsRootFor(@Nullable VirtualFile file) {
if (file == null || myProject.isDisposed()) return null;
final VcsDirectoryMapping mapping = myMappings.getMappingFor(file);
if (mapping == null) {
return null;
}
final String directory = mapping.getDirectory();
if (directory.isEmpty()) {
return myDefaultVcsRootPolicy.getVcsRootFor(file);
}
return LocalFileSystem.getInstance().findFileByPath(directory);
NewMappings.MappedRoot root = myMappings.getMappedRootFor(file);
return root != null ? root.root : null;
}
@Override
@Nullable
public VcsRoot getVcsRootObjectFor(@Nullable VirtualFile file) {
if (file == null || myProject.isDisposed()) return null;
final VcsDirectoryMapping mapping = myMappings.getMappingFor(file);
if (mapping == null) return null;
final String directory = mapping.getDirectory();
final AbstractVcs vcs = findVcsByName(mapping.getVcs());
if (directory.isEmpty()) {
return new VcsRoot(vcs, myDefaultVcsRootPolicy.getVcsRootFor(file));
}
return new VcsRoot(vcs, LocalFileSystem.getInstance().findFileByPath(directory));
NewMappings.MappedRoot root = myMappings.getMappedRootFor(file);
return root != null ? new VcsRoot(root.vcs, root.root) : null;
}
@Override
......@@ -495,14 +450,19 @@ public class ProjectLevelVcsManagerImpl extends ProjectLevelVcsManagerEx impleme
@Override
@Nullable
public VcsDirectoryMapping getDirectoryMappingFor(@Nullable FilePath path) {
if (path == null || myProject.isDisposed()) return null;
public VcsDirectoryMapping getDirectoryMappingFor(@Nullable FilePath file) {
if (file == null || myProject.isDisposed()) return null;
VirtualFile vFile = ChangesUtil.findValidParentAccurately(path);
if (vFile != null) {
return myMappings.getMappingFor(vFile);
}
return null;
VirtualFile vFile = ChangesUtil.findValidParentAccurately(file);
return vFile != null ? getDirectoryMappingFor(vFile) : null;
}
@Nullable
private VcsDirectoryMapping getDirectoryMappingFor(@Nullable VirtualFile file) {
if (file == null || myProject.isDisposed()) return null;
NewMappings.MappedRoot root = myMappings.getMappedRootFor(file);
return root != null ? root.mapping : null;
}
@Override
......@@ -512,11 +472,8 @@ public class ProjectLevelVcsManagerImpl extends ProjectLevelVcsManagerEx impleme
myMappings.setMapping(FileUtil.toSystemIndependentName(path), activeVcsName);
}
public void setAutoDirectoryMapping(@NotNull String path, @NotNull String activeVcsName) {
final List<VirtualFile> defaultRoots = myMappings.getDefaultRoots();
if (defaultRoots.size() == 1 && StringUtil.isEmpty(myMappings.haveDefaultMapping())) {
myMappings.removeDirectoryMapping(new VcsDirectoryMapping("", ""));
}
public void setAutoDirectoryMapping(@NotNull String path, @Nullable String activeVcsName) {
myMappings.removeDirectoryMapping(new VcsDirectoryMapping("", ""));
myMappings.setMapping(path, activeVcsName);
}
......@@ -857,7 +814,7 @@ public class ProjectLevelVcsManagerImpl extends ProjectLevelVcsManagerEx impleme
}
private boolean hasExplicitMapping(@NotNull VirtualFile vFile) {
final VcsDirectoryMapping mapping = myMappings.getMappingFor(vFile);
final VcsDirectoryMapping mapping = getDirectoryMappingFor(vFile);
return mapping != null && !mapping.isDefaultMapping();
}
......
......@@ -23,15 +23,13 @@ import com.intellij.openapi.roots.FileIndexFacade;
import com.intellij.openapi.vcs.AbstractVcs;
import com.intellij.openapi.vcs.VcsDirectoryMapping;
import com.intellij.openapi.vcs.impl.DefaultVcsRootPolicy;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.*;
public class MappingsToRoots {
private final NewMappings myMappings;
......@@ -44,24 +42,18 @@ public class MappingsToRoots {
@NotNull
public VirtualFile[] getRootsUnderVcs(@NotNull AbstractVcs vcs) {
List<VirtualFile> result = myMappings.getMappingsAsFilesUnderVcs(vcs);
final AbstractVcs.RootsConvertor convertor = vcs.getCustomConvertor();
if (convertor != null) {
result = convertor.convertRoots(result);
}
final List<VirtualFile> result = new ArrayList<>(myMappings.getMappingsAsFilesUnderVcs(vcs));
Collections.sort(result, FilePathComparator.getInstance());
if (! vcs.allowsNestedRoots()) {
final FileIndexFacade facade = ServiceManager.getService(myProject, FileIndexFacade.class);
final List<VirtualFile> finalResult = result;
if (!vcs.allowsNestedRoots()) {
ApplicationManager.getApplication().runReadAction(() -> {
int i=1;
while(i < finalResult.size()) {
final VirtualFile previous = finalResult.get(i - 1);
final VirtualFile current = finalResult.get(i);
final FileIndexFacade facade = ServiceManager.getService(myProject, FileIndexFacade.class);
int i = 1;
while (i < result.size()) {
final VirtualFile previous = result.get(i - 1);
final VirtualFile current = result.get(i);
if (facade.isValidAncestor(previous, current)) {
finalResult.remove(i);
result.remove(i);
}
else {
i++;
......@@ -69,7 +61,6 @@ public class MappingsToRoots {
}
});
}
result.removeIf(file -> !file.isDirectory());
return VfsUtilCore.toVirtualFileArray(result);
}
......@@ -79,42 +70,44 @@ public class MappingsToRoots {
*/
@NotNull
public List<VirtualFile> getDetailedVcsMappings(@NotNull AbstractVcs vcs) {
// same as above, but no compression
final List<VirtualFile> result = myMappings.getMappingsAsFilesUnderVcs(vcs);
final List<VirtualFile> result = new ArrayList<>();
boolean haveDefaultMapping = vcs.getName().equals(myMappings.haveDefaultMapping());
boolean addInnerModules = true;
final String vcsName = vcs.getName();
final List<VcsDirectoryMapping> directoryMappings = myMappings.getDirectoryMappings(vcsName);
for (VcsDirectoryMapping directoryMapping : directoryMappings) {
if (directoryMapping.isDefaultMapping()) {
addInnerModules = false;
break;
List<VcsDirectoryMapping> directoryMappings = myMappings.getDirectoryMappings(vcs.getName());
for (VcsDirectoryMapping mapping : directoryMappings) {
if (!mapping.isDefaultMapping()) {
VirtualFile file = LocalFileSystem.getInstance().findFileByPath(mapping.getDirectory());
if (file != null) result.add(file);
}
}
Collection<VirtualFile> modules = DefaultVcsRootPolicy.getInstance(myProject).getDefaultVcsRoots();
Collection<VirtualFile> modulesUnderVcs = ContainerUtil.filter(modules, file -> {
if (!file.isDirectory()) return false;
if (haveDefaultMapping) return true;
NewMappings.MappedRoot root = myMappings.getMappedRootFor(file);
return root != null && vcs.equals(root.vcs);
});
Collections.sort(result, FilePathComparator.getInstance());
if (addInnerModules) {
ApplicationManager.getApplication().runReadAction(() -> {
final FileIndexFacade facade = ServiceManager.getService(myProject, FileIndexFacade.class);
final Collection<VirtualFile> modules = DefaultVcsRootPolicy.getInstance(myProject).getDefaultVcsRoots(myMappings, vcsName);
ApplicationManager.getApplication().runReadAction(() -> {
Iterator<VirtualFile> iterator = modules.iterator();
while (iterator.hasNext()) {
final VirtualFile module = iterator.next();
boolean included = false;
for (VirtualFile root : result) {
if (facade.isValidAncestor(root, module)) {
included = true;
break;
}
}
if (! included) {
iterator.remove();
Iterator<VirtualFile> iterator = modulesUnderVcs.iterator();
while (iterator.hasNext()) {
final VirtualFile module = iterator.next();
boolean included = false;
for (VirtualFile root : result) {
if (facade.isValidAncestor(root, module)) {
included = true;
break;
}
}
});
result.addAll(modules);
}
result.removeIf(file -> !file.isDirectory());
return result;
if (!included) {
iterator.remove();
}
}
});
return new ArrayList<>(ContainerUtil.union(result, modulesUnderVcs));
}
}
......@@ -7,6 +7,7 @@ import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vcs.actions.DescindingFilesFilter;
import com.intellij.openapi.vcs.changes.committed.MockAbstractVcs;
import com.intellij.openapi.vcs.impl.DefaultVcsRootPolicy;
import com.intellij.openapi.vcs.impl.ProjectLevelVcsManagerImpl;
import com.intellij.openapi.vcs.impl.projectlevelman.AllVcses;
import com.intellij.openapi.vcs.impl.projectlevelman.AllVcsesI;
......@@ -51,7 +52,7 @@ public class DirectoryMappingListTest extends PlatformTestCase {
vcses.registerManually(new MockAbstractVcs(myProject, "CVS"));
vcses.registerManually(new MockAbstractVcs(myProject, "mock2"));
myMappings = new NewMappings(myProject, (ProjectLevelVcsManagerImpl)ProjectLevelVcsManager.getInstance(myProject),
FileStatusManager.getInstance(myProject));
FileStatusManager.getInstance(myProject), DefaultVcsRootPolicy.getInstance(myProject));
startupManager.runPostStartupActivities();
}
......@@ -107,13 +108,13 @@ public class DirectoryMappingListTest extends PlatformTestCase {
assertEquals(2, myMappings.getDirectoryMappings().size());
myMappings.cleanupMappings();
assertEquals(2, myMappings.getDirectoryMappings().size());
assertEquals("mock2", myMappings.getVcsFor(myProjectRoot.findChild("a-b")));
assertEquals("CVS", myMappings.getVcsFor(myProjectRoot.findChild("a")));
assertEquals("mock2", getVcsFor(myProjectRoot.findChild("a-b")));
assertEquals("CVS", getVcsFor(myProjectRoot.findChild("a")));
}
public void testSamePrefixEmpty() {
myMappings.setMapping(myRootPath + "/a", "CVS");
assertNull(myMappings.getVcsFor(myProjectRoot.findChild("a-b")));
assertNull(getVcsFor(myProjectRoot.findChild("a-b")));
}
public void testSame() {
......@@ -156,18 +157,22 @@ public class DirectoryMappingListTest extends PlatformTestCase {
myMappings.setMapping(myRootPath + "/parent/child", "mock");
final String[] children = {
myRootPath + "/parent/child1", myRootPath + "\\parent\\middle\\child2", myRootPath + "/parent/middle/child3",
myRootPath + "/parent/child1",
myRootPath + "\\parent\\middle\\child2",
myRootPath + "/parent/middle/child3",
myRootPath + "/parent/child/inner"
};
createFiles(children);
myMappings.updateMappedRoots();
final String[] awaitedVcsNames = {"CVS","CVS","CVS","mock"};
final LocalFileSystem lfs = LocalFileSystem.getInstance();
for (int i = 0; i < children.length; i++) {
String child = children[i];
final VirtualFile vf = lfs.refreshAndFindFileByIoFile(new File(child));
assertNotNull(vf);
final VcsDirectoryMapping mapping = myMappings.getMappingFor(vf);
final VcsDirectoryMapping mapping = getMappingFor(vf);
assertNotNull(mapping);
assertEquals(awaitedVcsNames[i], mapping.getVcs());
}
......@@ -180,5 +185,17 @@ public class DirectoryMappingListTest extends PlatformTestCase {
assert created || file.isDirectory() : file;
myFilesToDelete.add(file);
}
LocalFileSystem.getInstance().refreshIoFiles(myFilesToDelete);
}
private String getVcsFor(VirtualFile file) {
NewMappings.MappedRoot root = myMappings.getMappedRootFor(file);
AbstractVcs vcs = root != null ? root.vcs : null;
return vcs != null ? vcs.getName() : null;
}
private VcsDirectoryMapping getMappingFor(VirtualFile file) {
NewMappings.MappedRoot root = myMappings.getMappedRootFor(file);
return root != null ? root.mapping : null;
}
}
......@@ -19,6 +19,7 @@ import com.intellij.mock.MockLocalFileSystem;
import com.intellij.openapi.vcs.FileStatusManager;
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
import com.intellij.openapi.vcs.VcsDirectoryMapping;
import com.intellij.openapi.vcs.impl.DefaultVcsRootPolicy;
import com.intellij.openapi.vcs.impl.ProjectLevelVcsManagerImpl;
import com.intellij.openapi.vcs.impl.projectlevelman.FileWatchRequestsManager;
import com.intellij.openapi.vcs.impl.projectlevelman.NewMappings;
......@@ -45,8 +46,8 @@ public class VcsFileWatchRequestManagementTest extends PlatformTestCase {
public void setUp() throws Exception {
super.setUp();
ProjectLevelVcsManagerImpl vcsManager = (ProjectLevelVcsManagerImpl)ProjectLevelVcsManager.getInstance(myProject);
myNewMappings = new NewMappings(myProject, vcsManager, FileStatusManager.getInstance(myProject));
myNewMappings = new NewMappings(myProject, (ProjectLevelVcsManagerImpl)ProjectLevelVcsManager.getInstance(myProject),
FileStatusManager.getInstance(myProject), DefaultVcsRootPolicy.getInstance(myProject));
myMockLocalFileSystem = new MyMockLocalFileSystem();
myNewMappings.setFileWatchRequestsManager(new FileWatchRequestsManager(myProject, myNewMappings, myMockLocalFileSystem));
myNewMappings.activateActiveVcses();
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment