From 13f75062c4e88ad8ca646587f81a31bf04c0b62c Mon Sep 17 00:00:00 2001 From: nik Date: Wed, 3 Aug 2011 11:40:04 +0400 Subject: [PATCH] new framework detection: show only valid detected framework in the dialog, tests added --- .../impl/DetectedFrameworksData.java | 4 +- ...acetBasedDetectedFrameworkDescription.java | 12 +- .../impl/FrameworkDetectionManager.java | 147 +++++++++++++----- .../impl/FrameworkDetectorRegistry.java | 2 +- .../impl/FrameworkDetectorRegistryImpl.java | 9 +- .../intellij/testFramework/PsiTestUtil.java | 25 +++ .../intellij/testFramework/VfsTestUtil.java | 93 +++++++++++ 7 files changed, 243 insertions(+), 49 deletions(-) create mode 100644 platform/testFramework/src/com/intellij/testFramework/VfsTestUtil.java diff --git a/platform/lang-impl/src/com/intellij/framework/detection/impl/DetectedFrameworksData.java b/platform/lang-impl/src/com/intellij/framework/detection/impl/DetectedFrameworksData.java index 4c948af42dbb..8b30d085f14b 100644 --- a/platform/lang-impl/src/com/intellij/framework/detection/impl/DetectedFrameworksData.java +++ b/platform/lang-impl/src/com/intellij/framework/detection/impl/DetectedFrameworksData.java @@ -109,8 +109,8 @@ public class DetectedFrameworksData { return myDetectedFrameworks; } - public List updateFrameworksList(Integer detectorId, - List frameworks) { + public Collection updateFrameworksList(Integer detectorId, + Collection frameworks) { final Collection oldFrameworks = myDetectedFrameworks.remove(detectorId); myDetectedFrameworks.putValues(detectorId, frameworks); if (oldFrameworks != null) { diff --git a/platform/lang-impl/src/com/intellij/framework/detection/impl/FacetBasedDetectedFrameworkDescription.java b/platform/lang-impl/src/com/intellij/framework/detection/impl/FacetBasedDetectedFrameworkDescription.java index 24b6967dffe6..0032b5432456 100644 --- a/platform/lang-impl/src/com/intellij/framework/detection/impl/FacetBasedDetectedFrameworkDescription.java +++ b/platform/lang-impl/src/com/intellij/framework/detection/impl/FacetBasedDetectedFrameworkDescription.java @@ -24,7 +24,6 @@ import com.intellij.openapi.roots.ModifiableModelsProvider; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; -import javax.swing.*; import java.util.Collection; import java.util.Set; @@ -45,8 +44,11 @@ public abstract class FacetBasedDetectedFrameworkDescription facetType) { + return new FrameworkType(facetType.getStringId(), facetType.getPresentableName(), facetType.getIcon()); } @NotNull @@ -61,6 +63,10 @@ public abstract class FacetBasedDetectedFrameworkDescription myDetectorsToProcess = new HashSet(); @@ -81,6 +84,10 @@ public class FrameworkDetectionManager extends AbstractProjectComponent implemen public void initComponent() { if (myProject.isDefault()) return; myDetectionQueue = new MergingUpdateQueue("FrameworkDetectionQueue", 500, true, null, myProject); + if (ApplicationManager.getApplication().isUnitTestMode()) { + myDetectionQueue.setPassThrough(false); + myDetectionQueue.hideNotify(); + } myDetectedFrameworksData = new DetectedFrameworksData(myProject); FrameworkDetectionIndex.getInstance().addListener(this, myProject); myProject.getMessageBus().connect().subscribe(DumbService.DUMB_MODE, new DumbService.DumbModeListener() { @@ -98,12 +105,10 @@ public class FrameworkDetectionManager extends AbstractProjectComponent implemen @Override public void projectOpened() { - final int[] ids = FrameworkDetectorRegistry.getInstance().getAllDetectorIds(); + final Collection ids = FrameworkDetectorRegistry.getInstance().getAllDetectorIds(); synchronized (myLock) { myDetectorsToProcess.clear(); - for (int id : ids) { - myDetectorsToProcess.add(id); - } + myDetectorsToProcess.addAll(ids); } queueDetection(); } @@ -136,7 +141,7 @@ public class FrameworkDetectionManager extends AbstractProjectComponent implemen return null; } - private void runDetection() { + private void doRunDetection() { Set detectorsToProcess; synchronized (myLock) { detectorsToProcess = new HashSet(myDetectorsToProcess); @@ -149,34 +154,16 @@ public class FrameworkDetectionManager extends AbstractProjectComponent implemen LOG.debug("Starting framework detectors: " + detectorsToProcess); } final FileBasedIndex index = FileBasedIndex.getInstance(); - Map> newDescriptions = new HashMap>(); + Map> newDescriptions = new HashMap>(); final DetectionExcludesConfiguration excludesConfiguration = DetectionExcludesConfiguration.getInstance(myProject); for (Integer id : detectorsToProcess) { - Collection files = index.getContainingFiles(FrameworkDetectionIndex.NAME, id, GlobalSearchScope.projectScope(myProject)); - final Collection newFiles = myDetectedFrameworksData.retainNewFiles(id, files); - FrameworkDetector detector = FrameworkDetectorRegistry.getInstance().getDetectorById(id); - if (detector != null) { - excludesConfiguration.removeExcluded(newFiles, detector); - if (LOG.isDebugEnabled()) { - LOG.debug("Detector '" + detector.getDetectorId() + "': " + files.size() + " accepted files, " + newFiles.size() + " files to process"); - } - final List frameworks; - if (!newFiles.isEmpty()) { - frameworks = detector.detect(newFiles, new FrameworkDetectionContextImpl(myProject)); - } - else { - frameworks = Collections.emptyList(); - } - final List updated = myDetectedFrameworksData.updateFrameworksList(id, frameworks); - if (LOG.isDebugEnabled()) { - LOG.debug(frameworks.size() + " frameworks detected, " + updated.size() + " changed"); - } - if (!updated.isEmpty()) { - newDescriptions.put(id, updated); - } + final List frameworks = runDetector(id, index, excludesConfiguration, true); + final Collection updated = myDetectedFrameworksData.updateFrameworksList(id, frameworks); + if (LOG.isDebugEnabled()) { + LOG.debug(frameworks.size() + " frameworks detected, " + updated.size() + " changed"); } - else { - LOG.info("Framework detector not found by id " + id); + if (!updated.isEmpty()) { + newDescriptions.put(id, updated); } } @@ -201,15 +188,44 @@ public class FrameworkDetectionManager extends AbstractProjectComponent implemen } } + private List runDetector(Integer detectorId, + FileBasedIndex index, + DetectionExcludesConfiguration excludesConfiguration, + final boolean processNewFilesOnly) { + Collection acceptedFiles = index.getContainingFiles(FrameworkDetectionIndex.NAME, detectorId, GlobalSearchScope.projectScope(myProject)); + final Collection filesToProcess; + if (processNewFilesOnly) { + filesToProcess = myDetectedFrameworksData.retainNewFiles(detectorId, acceptedFiles); + } + else { + filesToProcess = new ArrayList(acceptedFiles); + } + FrameworkDetector detector = FrameworkDetectorRegistry.getInstance().getDetectorById(detectorId); + if (detector == null) { + LOG.info("Framework detector not found by id " + detectorId); + return Collections.emptyList(); + } + + excludesConfiguration.removeExcluded(filesToProcess, detector); + if (LOG.isDebugEnabled()) { + LOG.debug("Detector '" + detector.getDetectorId() + "': " + acceptedFiles.size() + " accepted files, " + filesToProcess.size() + " files to process"); + } + final List frameworks; + if (!filesToProcess.isEmpty()) { + frameworks = detector.detect(filesToProcess, new FrameworkDetectionContextImpl(myProject)); + } + else { + frameworks = Collections.emptyList(); + } + return frameworks; + } + private void showSetupFrameworksDialog(Notification notification) { - final MultiMap frameworks = myDetectedFrameworksData.getDetectedFrameworks(); IdentityHashMap frameworksToId = new IdentityHashMap(); - List descriptions = new ArrayList(); - for (Integer id : frameworks.keySet()) { - for (DetectedFrameworkDescription description : frameworks.get(id)) { - descriptions.add(description); - frameworksToId.put(description, id); - } + List descriptions = getValidDetectedFrameworks(frameworksToId); + if (descriptions.isEmpty()) { + Messages.showInfoMessage(myProject, "No frameworks are detected", "Framework Detection"); + return; } final ConfigureDetectedFrameworksDialog dialog = new ConfigureDetectedFrameworksDialog(myProject, descriptions); dialog.show(); @@ -230,6 +246,57 @@ public class FrameworkDetectionManager extends AbstractProjectComponent implemen } } + private List getValidDetectedFrameworks(IdentityHashMap frameworksToId) { + final MultiMap frameworksMap = myDetectedFrameworksData.getDetectedFrameworks(); + List descriptions = new ArrayList(); + final FileBasedIndex index = FileBasedIndex.getInstance(); + final DetectionExcludesConfiguration excludesConfiguration = DetectionExcludesConfiguration.getInstance(myProject); + for (Integer id : frameworksMap.keySet()) { + final Collection acceptedFiles = index.getContainingFiles(FrameworkDetectionIndex.NAME, id, + GlobalSearchScope.projectScope(myProject)); + boolean obsolete = false; + for (DetectedFrameworkDescription description : frameworksMap.get(id)) { + if (!acceptedFiles.containsAll(description.getRelatedFiles())) { + if (LOG.isDebugEnabled()) { + LOG.debug("Some files from " + description.getRelatedFiles() + " aren't accepted by detector any more (accepted = " + acceptedFiles + ")"); + } + obsolete = true; + break; + } + } + final Collection frameworks; + if (obsolete) { + frameworks = runDetector(id, index, excludesConfiguration, false); + } + else { + frameworks = frameworksMap.get(id); + } + + for (DetectedFrameworkDescription framework : frameworks) { + descriptions.add(framework); + frameworksToId.put(framework, id); + } + } + return descriptions; + } + + @TestOnly + public void runDetection() { + ensureIndexIsUpToDate(FrameworkDetectorRegistry.getInstance().getAllDetectorIds()); + doRunDetection(); + } + + @TestOnly + public List getDetectedFrameworks() { + return getValidDetectedFrameworks(new IdentityHashMap()); + } + + private void ensureIndexIsUpToDate(final Collection detectors) { + for (Integer detectorId : detectors) { + FileBasedIndex.getInstance().getValues(FrameworkDetectionIndex.NAME, detectorId, GlobalSearchScope.projectScope(myProject)); + } + } + private class FrameworkDetectionHighlightingPass extends TextEditorHighlightingPass { private final Collection myDetectors; @@ -240,9 +307,7 @@ public class FrameworkDetectionManager extends AbstractProjectComponent implemen @Override public void doCollectInformation(ProgressIndicator progress) { - for (Integer detectorId : myDetectors) { - FileBasedIndex.getInstance().getValues(FrameworkDetectionIndex.NAME, detectorId, GlobalSearchScope.projectScope(myProject)); - } + ensureIndexIsUpToDate(myDetectors); } @Override diff --git a/platform/lang-impl/src/com/intellij/framework/detection/impl/FrameworkDetectorRegistry.java b/platform/lang-impl/src/com/intellij/framework/detection/impl/FrameworkDetectorRegistry.java index 7e0235a7480d..88b668505476 100644 --- a/platform/lang-impl/src/com/intellij/framework/detection/impl/FrameworkDetectorRegistry.java +++ b/platform/lang-impl/src/com/intellij/framework/detection/impl/FrameworkDetectorRegistry.java @@ -50,5 +50,5 @@ public abstract class FrameworkDetectorRegistry { @NotNull public abstract Collection getDetectorIds(@NotNull FileType fileType); - public abstract int[] getAllDetectorIds(); + public abstract Collection getAllDetectorIds(); } diff --git a/platform/lang-impl/src/com/intellij/framework/detection/impl/FrameworkDetectorRegistryImpl.java b/platform/lang-impl/src/com/intellij/framework/detection/impl/FrameworkDetectorRegistryImpl.java index f7567374f1b5..fc3f9227985a 100644 --- a/platform/lang-impl/src/com/intellij/framework/detection/impl/FrameworkDetectorRegistryImpl.java +++ b/platform/lang-impl/src/com/intellij/framework/detection/impl/FrameworkDetectorRegistryImpl.java @@ -189,7 +189,12 @@ public class FrameworkDetectorRegistryImpl extends FrameworkDetectorRegistry { } @Override - public int[] getAllDetectorIds() { - return myDetectorIds.getValues(); + public Collection getAllDetectorIds() { + final int[] ids = myDetectorIds.getValues(); + final List result = new ArrayList(); + for (int id : ids) { + result.add(id); + } + return result; } } diff --git a/platform/testFramework/src/com/intellij/testFramework/PsiTestUtil.java b/platform/testFramework/src/com/intellij/testFramework/PsiTestUtil.java index 0e30eea44b64..f0d432a9c577 100644 --- a/platform/testFramework/src/com/intellij/testFramework/PsiTestUtil.java +++ b/platform/testFramework/src/com/intellij/testFramework/PsiTestUtil.java @@ -15,8 +15,10 @@ */ package com.intellij.testFramework; +import com.intellij.openapi.application.AccessToken; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.Result; +import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; @@ -43,6 +45,7 @@ import org.jetbrains.annotations.NonNls; import java.io.File; import java.io.IOException; +import java.util.Arrays; import java.util.Collection; @NonNls public class PsiTestUtil { @@ -187,6 +190,28 @@ import java.util.Collection; return null; } + public static void addExcludedRoot(Module module, VirtualFile dir) { + AccessToken token = WriteAction.start(); + try { + final ModifiableRootModel model = ModuleRootManager.getInstance(module).getModifiableModel(); + boolean added = false; + for (ContentEntry entry : model.getContentEntries()) { + if (VfsUtil.isAncestor(entry.getFile(), dir, false)) { + entry.addExcludeFolder(dir); + added = true; + break; + } + } + if (!added) { + throw new RuntimeException(dir + " is not under content roots: " + Arrays.toString(model.getContentRoots())); + } + model.commit(); + } + finally { + token.finish(); + } + } + public static void removeContentEntry(final Module module, final ContentEntry e) { new WriteCommandAction.Simple(module.getProject()) { @Override diff --git a/platform/testFramework/src/com/intellij/testFramework/VfsTestUtil.java b/platform/testFramework/src/com/intellij/testFramework/VfsTestUtil.java new file mode 100644 index 000000000000..6dcffbd70251 --- /dev/null +++ b/platform/testFramework/src/com/intellij/testFramework/VfsTestUtil.java @@ -0,0 +1,93 @@ +/* + * Copyright 2000-2011 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.testFramework; + +import com.intellij.openapi.application.AccessToken; +import com.intellij.openapi.application.WriteAction; +import com.intellij.openapi.vfs.VfsUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.PathUtil; +import com.intellij.util.text.StringTokenizer; +import junit.framework.Assert; + +import java.io.IOException; + +/** + * @author nik + */ +public class VfsTestUtil { + private VfsTestUtil() { + } + + public static VirtualFile createFile(final VirtualFile root, final String relativePath) { + return createFile(root, relativePath, ""); + } + + public static VirtualFile createFile(final VirtualFile root, final String relativePath, final String text) { + return createFileOrDir(root, relativePath, text, false); + } + + public static VirtualFile createDir(final VirtualFile root, final String relativePath) { + return createFileOrDir(root, relativePath, "", true); + } + + private static VirtualFile createFileOrDir(final VirtualFile root, + final String relativePath, + final String text, + final boolean dir) { + try { + AccessToken token = WriteAction.start(); + try { + VirtualFile parent = root; + Assert.assertNotNull(parent); + StringTokenizer parents = new StringTokenizer(PathUtil.getParentPath(relativePath), "/"); + while (parents.hasMoreTokens()) { + final String name = parents.nextToken(); + VirtualFile child = parent.findChild(name); + if (child == null || !child.isValid()) { + child = parent.createChildDirectory(VfsTestUtil.class, name); + } + parent = child; + } + final VirtualFile file; + if (dir) { + file = parent.createChildDirectory(VfsTestUtil.class, PathUtil.getFileName(relativePath)); + } + else { + file = parent.createChildData(VfsTestUtil.class, PathUtil.getFileName(relativePath)); + VfsUtil.saveText(file, text); + } + return file; + } + finally { + token.finish(); + } + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static void clearContent(VirtualFile file) { + Assert.assertNotNull(file); + try { + VfsUtil.saveText(file, ""); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } +}