/* * Copyright 2000-2016 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 com.intellij.openapi.vcs.impl; import com.intellij.lifecycle.PeriodicalTasksCloser; import com.intellij.openapi.application.ApplicationManager; 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.Computable; 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.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.List; /** * @author yole */ public class ModuleDefaultVcsRootPolicy extends DefaultVcsRootPolicy { private static final Logger LOG = Logger.getInstance(ModuleDefaultVcsRootPolicy.class); private final Project myProject; private final VirtualFile myBaseDir; private final ModuleManager myModuleManager; public ModuleDefaultVcsRootPolicy(final Project project) { myProject = project; myBaseDir = project.getBaseDir(); myModuleManager = ModuleManager.getInstance(myProject); } @Override public void addDefaultVcsRoots(final NewMappings mappingList, @NotNull final String vcsName, final List<VirtualFile> result) { 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); } } if (myBaseDir != null) { final VirtualFile ideaDir = myBaseDir.findChild(Project.DIRECTORY_STORE_FOLDER); if (ideaDir != null && ideaDir.isValid() && ideaDir.isDirectory()) { final AbstractVcs vcsFor = vcsManager.getVcsFor(ideaDir); if (vcsFor != null && vcsName.equals(vcsFor.getName())) { result.add(ideaDir); } } } // assertion for read access inside final Module[] modules = ApplicationManager.getApplication().runReadAction(new Computable<Module[]>() { @Override public Module[] compute() { return myModuleManager.getModules(); } }); for (Module module : modules) { final VirtualFile[] files = ModuleRootManager.getInstance(module).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) && !result.contains(file)) { result.add(file); } } } } @Override public boolean matchesDefaultMapping(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 ModuleUtilCore.findModuleForFile(file, myProject); } @Override @Nullable public VirtualFile getVcsRootFor(final VirtualFile file) { if (myBaseDir != null && PeriodicalTasksCloser.getInstance().safeGetService(myProject, FileIndexFacade.class).isValidAncestor(myBaseDir, file)) { return myBaseDir; } final VirtualFile contentRoot = ProjectRootManager.getInstance(myProject).getFileIndex().getContentRootForFile(file, Registry.is("ide.hide.excluded.files")); if (contentRoot != null) { return contentRoot; } if (myBaseDir != null) { final VirtualFile ideaDir = myBaseDir.findChild(Project.DIRECTORY_STORE_FOLDER); if (ideaDir != null && ideaDir.isValid() && ideaDir.isDirectory()) { if (VfsUtilCore.isAncestor(ideaDir, file, false)) { return ideaDir; } } } return null; } @NotNull @Override public Collection<VirtualFile> getDirtyRoots() { Collection<VirtualFile> dirtyRoots = ContainerUtil.newHashSet(); if (myBaseDir != null) { final VirtualFile ideaDir = myBaseDir.findChild(Project.DIRECTORY_STORE_FOLDER); if (ideaDir != null && ideaDir.isValid() && ideaDir.isDirectory()) { dirtyRoots.add(ideaDir); } } 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() { return ApplicationManager.getApplication().runReadAction(new Computable<List<VirtualFile>>() { @Override public List<VirtualFile> compute() { List<VirtualFile> contentRoots = ContainerUtil.newArrayList(); for (Module module : myModuleManager.getModules()) { ContainerUtil.addAll(contentRoots, ModuleRootManager.getInstance(module).getContentRoots()); } return contentRoots; } }); } }