IDEA-88958: Allow to mark directories as Excluded inside external libraries

This commit is contained in:
nik
2013-10-03 15:50:37 +04:00
parent 651dd75124
commit cef6103dc6
21 changed files with 544 additions and 164 deletions
@@ -151,7 +151,7 @@ public class CompileContextImpl extends UserDataHolderBase implements CompileCon
if (myGeneratedSources.contains(FileBasedIndex.getFileId(file))) {
return true;
}
if (isUnderRoots(myRootToModuleMap.keySet(), file)) {
if (VfsUtilCore.isUnder(file, myRootToModuleMap.keySet())) {
return true;
}
final Module module = getModuleByFile(file);
@@ -449,7 +449,7 @@ public class CompileContextImpl extends UserDataHolderBase implements CompileCon
if (myProjectFileIndex.isInTestSourceContent(fileOrDir)) {
return true;
}
if (isUnderRoots(myGeneratedTestRoots, fileOrDir)) {
if (VfsUtilCore.isUnder(fileOrDir, myGeneratedTestRoots)) {
return true;
}
return false;
@@ -459,25 +459,12 @@ public class CompileContextImpl extends UserDataHolderBase implements CompileCon
if (myProjectFileIndex.isInSourceContent(fileOrDir)) {
return true;
}
if (isUnderRoots(myRootToModuleMap.keySet(), fileOrDir)) {
if (VfsUtilCore.isUnder(fileOrDir, myRootToModuleMap.keySet())) {
return true;
}
return false;
}
public static boolean isUnderRoots(@NotNull Set<VirtualFile> roots, @NotNull VirtualFile file) {
VirtualFile parent = file;
while (true) {
if (parent == null) {
return false;
}
if (roots.contains(parent)) {
return true;
}
parent = parent.getParent();
}
}
public UUID getSessionId() {
return mySessionId;
}
@@ -0,0 +1,48 @@
/*
* Copyright 2000-2013 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.roots.ui.configuration.libraryEditor;
import com.intellij.icons.AllIcons;
import com.intellij.ide.util.treeView.NodeDescriptor;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFileManager;
import org.jetbrains.annotations.NotNull;
/**
* @author nik
*/
public class ExcludedRootElement extends LibraryTableTreeContentElement<ExcludedRootElement> {
@NotNull private final String myUrl;
public ExcludedRootElement(@NotNull NodeDescriptor parentDescriptor, String rootUrl, @NotNull String excludedUrl) {
super(parentDescriptor);
myUrl = excludedUrl;
if (excludedUrl.startsWith(rootUrl)) {
String relativePath = StringUtil.trimStart(excludedUrl.substring(rootUrl.length()), "/");
myName = relativePath.isEmpty() ? "<all>" : relativePath;
}
else {
myName = ItemElement.getPresentablePath(excludedUrl);
}
myColor = getForegroundColor(VirtualFileManager.getInstance().findFileByUrl(excludedUrl) != null);
setIcon(AllIcons.Modules.ExcludeRoot);
}
@NotNull
public String getUrl() {
return myUrl;
}
}
@@ -29,17 +29,17 @@ import java.util.Arrays;
import java.util.Collection;
public class ExistingLibraryEditor extends LibraryEditorBase implements Disposable {
private final Library myLibrary;
private final LibraryEx myLibrary;
private final LibraryEditorListener myListener;
private String myLibraryName = null;
private LibraryProperties myLibraryProperties;
private LibraryProperties myDetectedLibraryProperties;
private Library.ModifiableModel myModel = null;
private LibraryEx.ModifiableModelEx myModel = null;
private LibraryType<?> myDetectedType;
private boolean myDetectedTypeComputed;
public ExistingLibraryEditor(@NotNull Library library, @Nullable LibraryEditorListener listener) {
myLibrary = library;
myLibrary = (LibraryEx)library;
myListener = listener;
}
@@ -66,7 +66,7 @@ public class ExistingLibraryEditor extends LibraryEditorBase implements Disposab
@Override
public void setType(@NotNull LibraryType<?> type) {
((LibraryEx.ModifiableModelEx)getModel()).setKind(type.getKind());
getModel().setKind(type.getKind());
}
private LibraryType detectType() {
@@ -104,7 +104,7 @@ public class ExistingLibraryEditor extends LibraryEditorBase implements Disposab
}
private LibraryProperties getOriginalProperties() {
return ((LibraryEx)myLibrary).getProperties();
return myLibrary.getProperties();
}
@Override
@@ -131,6 +131,14 @@ public class ExistingLibraryEditor extends LibraryEditorBase implements Disposab
return myLibrary.getFiles(rootType);
}
@Override
public String[] getExcludedRootUrls() {
if (myModel != null) {
return myModel.getExcludedRootUrls();
}
return myLibrary.getExcludedRootUrls();
}
@Override
public void setName(String name) {
String oldName = getModel().getName();
@@ -151,6 +159,11 @@ public class ExistingLibraryEditor extends LibraryEditorBase implements Disposab
getModel().addRoot(url, rootType);
}
@Override
public void addExcludedRoot(@NotNull String url) {
getModel().addExcludedRoot(url);
}
@Override
public void addJarDirectory(VirtualFile file, boolean recursive, OrderRootType rootType) {
getModel().addJarDirectory(file, recursive, rootType);
@@ -163,13 +176,22 @@ public class ExistingLibraryEditor extends LibraryEditorBase implements Disposab
@Override
public void removeRoot(String url, OrderRootType rootType) {
while (getModel().removeRoot(url, rootType)) ;
boolean removed;
do {
removed = getModel().removeRoot(url, rootType);
}
while (removed);
}
@Override
public void removeExcludedRoot(@NotNull String url) {
getModel().removeExcludedRoot(url);
}
public void commit() {
if (myModel != null) {
if (myLibraryProperties != null) {
((LibraryEx.ModifiableModelEx)myModel).setProperties(myLibraryProperties);
myModel.setProperties(myLibraryProperties);
}
myModel.commit();
myModel = null;
@@ -178,7 +200,7 @@ public class ExistingLibraryEditor extends LibraryEditorBase implements Disposab
}
}
public Library.ModifiableModel getModel() {
public LibraryEx.ModifiableModelEx getModel() {
if (myModel == null) {
myModel = myLibrary.getModifiableModel();
}
@@ -23,69 +23,25 @@ import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.openapi.vfs.ex.http.HttpFileSystem;
import com.intellij.ui.JBColor;
import com.intellij.util.PlatformIcons;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.io.File;
class ItemElement extends LibraryTableTreeContentElement<ItemElement> {
private final String myUrl;
protected final String myUrl;
private final OrderRootType myRootType;
public ItemElement(OrderRootTypeElement parent, String url, OrderRootType rootType, final boolean isJarDirectory,
public ItemElement(@NotNull OrderRootTypeElement parent, @NotNull String url, @NotNull OrderRootType rootType, final boolean isJarDirectory,
boolean isValid) {
super(parent);
myUrl = url;
myRootType = rootType;
myName = getPresentablePath(url).replace('/', File.separatorChar);
myColor = isValid ? UIUtil.getListForeground() : JBColor.RED;
myColor = getForegroundColor(isValid);
setIcon(getIconForUrl(url, isValid, isJarDirectory));
}
public OrderRootTypeElement getParent() {
return (OrderRootTypeElement)getParentDescriptor();
}
@Override
public boolean update() {
return false;
}
@Override
public ItemElement getElement() {
return this;
}
public String getUrl() {
return myUrl;
}
public OrderRootType getRootType() {
return myRootType;
}
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ItemElement)) return false;
final ItemElement itemElement = (ItemElement)o;
if (!getParent().equals(itemElement.getParent())) return false;
if (!myRootType.equals(itemElement.myRootType)) return false;
if (!myUrl.equals(itemElement.myUrl)) return false;
return true;
}
public int hashCode() {
int result;
result = getParent().hashCode();
result = 29 * result + myUrl.hashCode();
result = 29 * result + myRootType.hashCode();
return result;
myRootType = rootType;
}
private static Icon getIconForUrl(final String url, final boolean isValid, final boolean isJarDirectory) {
@@ -126,7 +82,7 @@ class ItemElement extends LibraryTableTreeContentElement<ItemElement> {
return icon;
}
private static String getPresentablePath(final String url) {
public static String getPresentablePath(final String url) {
String presentablePath = VirtualFileManager.extractPath(url);
if (isJarFileRoot(url)) {
presentablePath = presentablePath.substring(0, presentablePath.length() - JarFileSystem.JAR_SEPARATOR.length());
@@ -137,4 +93,39 @@ class ItemElement extends LibraryTableTreeContentElement<ItemElement> {
private static boolean isJarFileRoot(final String url) {
return VirtualFileManager.extractPath(url).endsWith(JarFileSystem.JAR_SEPARATOR);
}
public OrderRootTypeElement getParent() {
return (OrderRootTypeElement)getParentDescriptor();
}
@NotNull
public OrderRootType getRootType() {
return myRootType;
}
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ItemElement)) return false;
final ItemElement itemElement = (ItemElement)o;
if (!getParent().equals(itemElement.getParent())) return false;
if (!myRootType.equals(itemElement.myRootType)) return false;
if (!myUrl.equals(itemElement.myUrl)) return false;
return true;
}
@NotNull
public String getUrl() {
return myUrl;
}
public int hashCode() {
int result;
result = getParent().hashCode();
result = 29 * result + myUrl.hashCode();
result = 29 * result + myRootType.hashCode();
return result;
}
}
@@ -15,6 +15,7 @@
*/
package com.intellij.openapi.roots.ui.configuration.libraryEditor;
import com.intellij.icons.AllIcons;
import com.intellij.ide.DataManager;
import com.intellij.ide.util.treeView.AbstractTreeStructure;
import com.intellij.ide.util.treeView.NodeDescriptor;
@@ -26,11 +27,13 @@ import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.fileChooser.FileChooser;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectBundle;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.PersistentOrderRootType;
import com.intellij.openapi.roots.libraries.LibraryKind;
import com.intellij.openapi.roots.libraries.LibraryProperties;
import com.intellij.openapi.roots.libraries.LibraryType;
@@ -42,14 +45,17 @@ import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vfs.JarFileSystem;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.ui.AnActionButton;
import com.intellij.ui.AnActionButtonRunnable;
import com.intellij.ui.AnActionButtonUpdater;
import com.intellij.ui.ToolbarDecorator;
import com.intellij.ui.treeStructure.Tree;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.PathUtil;
import com.intellij.util.containers.*;
import com.intellij.util.containers.HashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -75,6 +81,7 @@ public class LibraryRootsComponent implements Disposable, LibraryEditorComponent
private LibraryPropertiesEditor myPropertiesEditor;
private Tree myTree;
private LibraryTableTreeBuilder myTreeBuilder;
private VirtualFile myLastChosen;
private final Collection<Runnable> myListeners = ContainerUtil.createLockFreeCopyOnWriteList();
@Nullable private final Project myProject;
@@ -82,6 +89,7 @@ public class LibraryRootsComponent implements Disposable, LibraryEditorComponent
private final Computable<LibraryEditor> myLibraryEditorComputable;
private LibraryRootsComponentDescriptor myDescriptor;
private Module myContextModule;
private LibraryRootsComponent.AddExcludedRootActionButton myAddExcludedRootActionButton;
public LibraryRootsComponent(@Nullable Project project, @NotNull LibraryEditor libraryEditor) {
this(project, new Computable.PredefinedValueComputable<LibraryEditor>(libraryEditor));
@@ -105,6 +113,11 @@ public class LibraryRootsComponent implements Disposable, LibraryEditorComponent
}
init(new LibraryTreeStructure(this, myDescriptor));
updatePropertiesLabel();
onRootsChanged();
}
private void onRootsChanged() {
myAddExcludedRootActionButton.setEnabled(!getNotExcludedRoots().isEmpty());
}
@NotNull
@@ -166,10 +179,13 @@ public class LibraryRootsComponent implements Disposable, LibraryEditorComponent
getLibraryEditor().removeRoot(url, rootType);
}
}
else if (selectedElement instanceof ExcludedRootElement) {
getLibraryEditor().removeExcludedRoot(((ExcludedRootElement)selectedElement).getUrl());
}
}
}
});
librariesChanged(true);
libraryChanged(true);
}
});
@@ -187,6 +203,9 @@ public class LibraryRootsComponent implements Disposable, LibraryEditorComponent
popupItems.add(descriptor);
}
}
myAddExcludedRootActionButton = new AddExcludedRootActionButton();
toolbarDecorator.addExtraAction(myAddExcludedRootActionButton);
actionsOrder.add(myAddExcludedRootActionButton.getTemplatePresentation().getText());
actionsOrder.add("Remove");
toolbarDecorator.setAddAction(new AnActionButtonRunnable() {
@@ -212,22 +231,6 @@ public class LibraryRootsComponent implements Disposable, LibraryEditorComponent
toolbarDecorator.setButtonComparator(ArrayUtil.toStringArray(actionsOrder));
myTreePanel.add(toolbarDecorator.createPanel(), BorderLayout.CENTER);
ToolbarDecorator.findRemoveButton(myTreePanel).addCustomUpdater(new AnActionButtonUpdater() {
@Override
public boolean isEnabled(AnActionEvent e) {
final Object[] selectedElements = getSelectedElements();
for (Object element : selectedElements) {
if (element instanceof ItemElement) {
return true;
}
if (element instanceof OrderRootTypeElement && getLibraryEditor().getUrls(((OrderRootTypeElement)element).getOrderRootType()).length > 0) {
return true;
}
}
return false;
}
});
Disposer.register(this, myTreeBuilder);
}
@@ -330,7 +333,7 @@ public class LibraryRootsComponent implements Disposable, LibraryEditorComponent
public void renameLibrary(String newName) {
final LibraryEditor libraryEditor = getLibraryEditor();
libraryEditor.setName(newName);
librariesChanged(false);
libraryChanged(false);
}
@Override
@@ -360,6 +363,19 @@ public class LibraryRootsComponent implements Disposable, LibraryEditorComponent
}
}
@Nullable
private VirtualFile getFileToSelect() {
if (myLastChosen != null) {
return myLastChosen;
}
final VirtualFile directory = getExistingRootDirectory();
if (directory != null) {
return directory;
}
return getBaseDirectory();
}
private class AttachFilesAction extends AttachItemActionBase {
public AttachFilesAction(String title) {
super(title);
@@ -380,25 +396,10 @@ public class LibraryRootsComponent implements Disposable, LibraryEditorComponent
}
public abstract class AttachItemActionBase extends DumbAwareAction {
private VirtualFile myLastChosen = null;
protected AttachItemActionBase(String text) {
super(text);
}
@Nullable
protected VirtualFile getFileToSelect() {
if (myLastChosen != null) {
return myLastChosen;
}
final VirtualFile directory = getExistingRootDirectory();
if (directory != null) {
return directory;
}
return getBaseDirectory();
}
@Override
public void actionPerformed(@Nullable AnActionEvent e) {
VirtualFile toSelect = getFileToSelect();
@@ -410,7 +411,7 @@ public class LibraryRootsComponent implements Disposable, LibraryEditorComponent
if (first != null) {
myLastChosen = first.getFile();
}
fireLibrariesChanged();
fireLibraryChanged();
myTree.requestFocus();
}
@@ -449,6 +450,7 @@ public class LibraryRootsComponent implements Disposable, LibraryEditorComponent
}
});
updatePropertiesLabel();
onRootsChanged();
myTreeBuilder.queueUpdate();
}
return rootsToAttach;
@@ -465,16 +467,17 @@ public class LibraryRootsComponent implements Disposable, LibraryEditorComponent
return result;
}
private void librariesChanged(boolean putFocusIntoTree) {
private void libraryChanged(boolean putFocusIntoTree) {
onRootsChanged();
updatePropertiesLabel();
myTreeBuilder.queueUpdate();
if (putFocusIntoTree) {
myTree.requestFocus();
}
fireLibrariesChanged();
fireLibraryChanged();
}
private void fireLibrariesChanged() {
private void fireLibraryChanged() {
for (Runnable listener : myListeners) {
listener.run();
}
@@ -487,4 +490,61 @@ public class LibraryRootsComponent implements Disposable, LibraryEditorComponent
public void removeListener(Runnable listener) {
myListeners.remove(listener);
}
private Set<VirtualFile> getNotExcludedRoots() {
Set<VirtualFile> roots = new LinkedHashSet<VirtualFile>();
String[] excludedRootUrls = getLibraryEditor().getExcludedRootUrls();
Set<VirtualFile> excludedRoots = new HashSet<VirtualFile>();
for (String url : excludedRootUrls) {
ContainerUtil.addIfNotNull(excludedRoots, VirtualFileManager.getInstance().findFileByUrl(url));
}
for (PersistentOrderRootType type : OrderRootType.getAllPersistentTypes()) {
VirtualFile[] files = getLibraryEditor().getFiles(type);
for (VirtualFile file : files) {
if (!VfsUtilCore.isUnder(file, excludedRoots)) {
roots.add(PathUtil.getLocalFile(file));
}
}
}
return roots;
}
private class AddExcludedRootActionButton extends AnActionButton {
public AddExcludedRootActionButton() {
super("Add Excluded", null, AllIcons.Modules.ExcludeRoot);
}
@Override
public void actionPerformed(AnActionEvent e) {
FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createMultipleJavaPathDescriptor();
descriptor.setTitle("Add Excluded Roots");
descriptor.setDescription("Select directories which should be excluded from the library content. Content of excluded directories won't be processed by IDE.");
Set<VirtualFile> roots = getNotExcludedRoots();
descriptor.setRoots(roots.toArray(new VirtualFile[roots.size()]));
if (roots.size() < 2) {
descriptor.setIsTreeRootVisible(true);
}
VirtualFile toSelect = null;
for (Object o : getSelectedElements()) {
Object itemElement = o instanceof ExcludedRootElement ? ((ExcludedRootElement)o).getParentDescriptor() : o;
if (itemElement instanceof ItemElement) {
toSelect = VirtualFileManager.getInstance().findFileByUrl(((ItemElement)itemElement).getUrl());
break;
}
}
final VirtualFile[] files = FileChooser.chooseFiles(descriptor, myPanel, myProject, toSelect);
if (files.length > 0) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
for (VirtualFile file : files) {
getLibraryEditor().addExcludedRoot(file.getUrl());
}
}
});
myLastChosen = files[0];
libraryChanged(true);
}
}
}
}
@@ -41,7 +41,7 @@ class LibraryTableTreeBuilder extends AbstractTreeBuilder {
protected boolean isAutoExpandNode(NodeDescriptor nodeDescriptor) {
final Object element = nodeDescriptor.getElement();
final Object rootElement = getTreeStructure().getRootElement();
return rootElement.equals(element) || element instanceof OrderRootTypeElement;
return rootElement.equals(element) || element instanceof OrderRootTypeElement || element instanceof ItemElement;
}
@Override
@@ -16,10 +16,28 @@
package com.intellij.openapi.roots.ui.configuration.libraryEditor;
import com.intellij.ide.util.treeView.NodeDescriptor;
import com.intellij.ui.JBColor;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.Nullable;
import java.awt.*;
public abstract class LibraryTableTreeContentElement<E> extends NodeDescriptor<E> {
protected LibraryTableTreeContentElement(@Nullable NodeDescriptor parentDescriptor) {
super(null, parentDescriptor);
}
protected static Color getForegroundColor(boolean isValid) {
return isValid ? UIUtil.getListForeground() : JBColor.RED;
}
@Override
public boolean update() {
return false;
}
@Override
public E getElement() {
return (E)this;
}
}
@@ -21,11 +21,14 @@ import com.intellij.openapi.project.ProjectBundle;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.libraries.ui.LibraryRootsComponentDescriptor;
import com.intellij.openapi.roots.libraries.ui.OrderRootTypePresentation;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class LibraryTreeStructure extends AbstractTreeStructure {
private final NodeDescriptor myRootElementDescriptor;
@@ -55,11 +58,11 @@ public class LibraryTreeStructure extends AbstractTreeStructure {
@Override
public Object[] getChildElements(Object element) {
final LibraryEditor libraryEditor = myParentEditor.getLibraryEditor();
if (element == myRootElementDescriptor) {
ArrayList<LibraryTableTreeContentElement> elements = new ArrayList<LibraryTableTreeContentElement>(3);
final LibraryEditor parentEditor = myParentEditor.getLibraryEditor();
for (OrderRootType type : myComponentDescriptor.getRootTypes()) {
final String[] urls = parentEditor.getUrls(type);
final String[] urls = libraryEditor.getUrls(type);
if (urls.length > 0) {
OrderRootTypePresentation presentation = myComponentDescriptor.getRootTypePresentation(type);
if (presentation == null) {
@@ -75,7 +78,6 @@ public class LibraryTreeStructure extends AbstractTreeStructure {
OrderRootTypeElement rootTypeElement = (OrderRootTypeElement)element;
OrderRootType orderRootType = rootTypeElement.getOrderRootType();
ArrayList<ItemElement> items = new ArrayList<ItemElement>();
final LibraryEditor libraryEditor = myParentEditor.getLibraryEditor();
final String[] urls = libraryEditor.getUrls(orderRootType).clone();
Arrays.sort(urls, LibraryRootsComponent.ourUrlComparator);
for (String url : urls) {
@@ -83,6 +85,22 @@ public class LibraryTreeStructure extends AbstractTreeStructure {
}
return items.toArray();
}
if (element instanceof ItemElement) {
ItemElement itemElement = (ItemElement)element;
List<String> excludedUrls = new ArrayList<String>();
for (String excludedUrl : libraryEditor.getExcludedRootUrls()) {
if (VfsUtilCore.isEqualOrAncestor(itemElement.getUrl(), excludedUrl)) {
excludedUrls.add(excludedUrl);
}
}
ExcludedRootElement[] items = new ExcludedRootElement[excludedUrls.size()];
Collections.sort(excludedUrls, LibraryRootsComponent.ourUrlComparator);
for (int i = 0; i < excludedUrls.size(); i++) {
items[i] = new ExcludedRootElement(itemElement, itemElement.getUrl(), excludedUrls.get(i));
}
return items;
}
return ArrayUtil.EMPTY_OBJECT_ARRAY;
}
@@ -23,6 +23,7 @@ import com.intellij.openapi.roots.libraries.LibraryProperties;
import com.intellij.openapi.roots.libraries.LibraryType;
import com.intellij.openapi.roots.ui.LightFilePointer;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.MultiMap;
@@ -31,6 +32,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
/**
@@ -39,6 +41,7 @@ import java.util.List;
public class NewLibraryEditor extends LibraryEditorBase {
private String myLibraryName;
private final MultiMap<OrderRootType, LightFilePointer> myRoots;
private final List<LightFilePointer> myExcludedRoots;
private final JarDirectories myJarDirectories = new JarDirectories();
private LibraryType myType;
private LibraryProperties myProperties;
@@ -51,6 +54,7 @@ public class NewLibraryEditor extends LibraryEditorBase {
myType = type;
myProperties = properties;
myRoots = new MultiMap<OrderRootType, LightFilePointer>();
myExcludedRoots = new ArrayList<LightFilePointer>();
}
@Override
@@ -86,7 +90,10 @@ public class NewLibraryEditor extends LibraryEditorBase {
@Override
public String[] getUrls(OrderRootType rootType) {
final Collection<LightFilePointer> pointers = myRoots.get(rootType);
return pointersToUrls(myRoots.get(rootType));
}
private static String[] pointersToUrls(Collection<LightFilePointer> pointers) {
List<String> urls = new ArrayList<String>();
for (LightFilePointer pointer : pointers) {
urls.add(pointer.getUrl());
@@ -115,6 +122,11 @@ public class NewLibraryEditor extends LibraryEditorBase {
return VfsUtil.toVirtualFileArray(result);
}
@Override
public String[] getExcludedRootUrls() {
return pointersToUrls(myExcludedRoots);
}
@Override
public void setName(String name) {
myLibraryName = name;
@@ -135,6 +147,15 @@ public class NewLibraryEditor extends LibraryEditorBase {
addJarDirectory(file.getUrl(), recursive, rootType);
}
@Override
public void addExcludedRoot(@NotNull String url) {
myExcludedRoots.add(new LightFilePointer(url));
}
public void removeExcludedRoot(@NotNull String url) {
myExcludedRoots.remove(new LightFilePointer(url));
}
@Override
public void addJarDirectory(final String url, boolean recursive, OrderRootType rootType) {
addRoot(url, rootType);
@@ -144,9 +165,25 @@ public class NewLibraryEditor extends LibraryEditorBase {
@Override
public void removeRoot(String url, OrderRootType rootType) {
myRoots.remove(rootType, new LightFilePointer(url));
Iterator<LightFilePointer> iterator = myExcludedRoots.iterator();
while (iterator.hasNext()) {
LightFilePointer pointer = iterator.next();
if (!isUnderRoots(pointer.getUrl())) {
iterator.remove();
}
}
myJarDirectories.remove(rootType, url);
}
private boolean isUnderRoots(@NotNull String url) {
for (LightFilePointer pointer : myRoots.values()) {
if (VfsUtilCore.isEqualOrAncestor(pointer.getUrl(), url)) {
return true;
}
}
return false;
}
@Override
public boolean hasChanges() {
return true;
@@ -48,14 +48,4 @@ public class OrderRootTypeElement extends LibraryTableTreeContentElement<OrderRo
public boolean equals(Object obj) {
return obj instanceof OrderRootTypeElement && ((OrderRootTypeElement)obj).getOrderRootType().equals(myRootType);
}
@Override
public boolean update() {
return false;
}
@Override
public OrderRootTypeElement getElement() {
return this;
}
}
@@ -40,6 +40,7 @@ import org.jetbrains.jps.model.module.JpsModuleSourceRootType;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
@@ -74,6 +75,8 @@ public class DirectoryIndexTest extends IdeaTestCase {
private VirtualFile myModule1OutputDir;
private VirtualFile myResDir;
private VirtualFile myTestResDir;
private VirtualFile myExcludedLibSrcDir;
private VirtualFile myExcludedLibClsDir;
@Override
protected void setUp() throws Exception {
@@ -99,7 +102,9 @@ public class DirectoryIndexTest extends IdeaTestCase {
testRes
lib
src
exc
cls
exc
module2
src2
CVS
@@ -124,7 +129,9 @@ public class DirectoryIndexTest extends IdeaTestCase {
myLibDir = myModule1Dir.createChildDirectory(DirectoryIndexTest.this, "lib");
myLibSrcDir = myLibDir.createChildDirectory(DirectoryIndexTest.this, "src");
myExcludedLibSrcDir = myLibSrcDir.createChildDirectory(DirectoryIndexTest.this, "exc");
myLibClsDir = myLibDir.createChildDirectory(DirectoryIndexTest.this, "cls");
myExcludedLibClsDir = myLibClsDir.createChildDirectory(DirectoryIndexTest.this, "exc");
myModule2Dir = myModule1Dir.createChildDirectory(DirectoryIndexTest.this, "module2");
mySrcDir2 = myModule2Dir.createChildDirectory(DirectoryIndexTest.this, "src2");
myCvsDir = mySrcDir2.createChildDirectory(DirectoryIndexTest.this, "CVS");
@@ -149,6 +156,8 @@ public class DirectoryIndexTest extends IdeaTestCase {
ModuleRootModificationUtil.addModuleLibrary(myModule, "lib.js",
singletonList(myFileLibCls.getUrl()), singletonList(myFileLibSrc.getUrl()));
PsiTestUtil.addExcludedRoot(myModule, myExcludedLibClsDir);
PsiTestUtil.addExcludedRoot(myModule, myExcludedLibSrcDir);
}
// fill roots of module2
@@ -160,7 +169,8 @@ public class DirectoryIndexTest extends IdeaTestCase {
PsiTestUtil.addSourceRoot(myModule2, mySrcDir2);
PsiTestUtil.addExcludedRoot(myModule2, myExcludeDir);
ModuleRootModificationUtil.addModuleLibrary(myModule2, "lib",
singletonList(myLibClsDir.getUrl()), singletonList(myLibSrcDir.getUrl()));
singletonList(myLibClsDir.getUrl()), singletonList(myLibSrcDir.getUrl()),
Arrays.asList(myExcludedLibClsDir.getUrl(), myExcludedLibSrcDir.getUrl()), DependencyScope.COMPILE);
}
// fill roots of module3
@@ -212,6 +222,8 @@ public class DirectoryIndexTest extends IdeaTestCase {
checkInfo(mySrcDir2, myModule2, false, false, "", JavaSourceRootType.SOURCE, myModule2, myModule3);
checkInfoNull(myCvsDir);
checkInfoNull(myExcludeDir);
checkInfoNull(myExcludedLibClsDir);
checkInfoNull(myExcludedLibSrcDir);
checkInfo(myModule3Dir, myModule3, false, false, null, null);
}
@@ -339,6 +351,14 @@ public class DirectoryIndexTest extends IdeaTestCase {
myIndex.checkConsistency();
}
public void testExcludedDirsInLibraries() {
ProjectFileIndex index = ProjectRootManager.getInstance(myProject).getFileIndex();
assertFalse(index.isInLibraryClasses(myExcludedLibClsDir));
assertTrue(index.isIgnored(myExcludedLibClsDir));
assertFalse(index.isInLibrarySource(myExcludedLibSrcDir));
assertTrue(index.isIgnored(myExcludedLibSrcDir));
}
public void testExplicitExcludeOfInner() throws Exception {
PsiTestUtil.addExcludedRoot(myModule, myModule2Dir);
@@ -40,6 +40,7 @@ import java.net.URL;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import static com.intellij.openapi.vfs.VirtualFileVisitor.VisitorException;
@@ -69,6 +70,26 @@ public class VfsUtilCore {
}
}
/**
* @return {@code true} if {@code file} is located under one of {@code roots} or equal to one of them
*/
public static boolean isUnder(@NotNull VirtualFile file, @Nullable Set<VirtualFile> roots) {
if (roots == null || roots.isEmpty()) return false;
VirtualFile parent = file;
while (parent != null) {
if (roots.contains(parent)) {
return true;
}
parent = parent.getParent();
}
return false;
}
public static boolean isEqualOrAncestor(@NotNull String ancestorUrl, @NotNull String fileUrl) {
return ancestorUrl.equals(fileUrl) || StringUtil.startsWithConcatenation(fileUrl, ancestorUrl, "/");
}
public static boolean isAncestor(@NotNull File ancestor, @NotNull File file, boolean strict) {
File parent = strict ? file.getParentFile() : file;
while (parent != null) {
@@ -32,6 +32,8 @@ import com.intellij.openapi.progress.ProgressIndicatorProvider;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectBundle;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.roots.impl.libraries.LibraryEx;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.util.*;
import com.intellij.openapi.util.io.FileUtil;
@@ -245,12 +247,13 @@ public class DirectoryIndexImpl extends DirectoryIndex {
if (parentInfo.hasLibraryClassRoot()) {
String newDirPackageName = getPackageNameForSubdir(parentPackage, file.getName());
state.fillMapWithLibraryClasses(file, newDirPackageName, (NewVirtualFile)parentInfo.getLibraryClassRoot(), null, interned);
state.fillMapWithLibraryClasses(file, newDirPackageName, (NewVirtualFile)parentInfo.getLibraryClassRoot(), null, interned,
null);
}
if (parentInfo.isInLibrarySource()) {
String newDirPackageName = getPackageNameForSubdir(parentPackage, file.getName());
state.fillMapWithLibrarySources(file, newDirPackageName, (NewVirtualFile)parentInfo.getSourceRoot(), null, interned);
state.fillMapWithLibrarySources(file, newDirPackageName, (NewVirtualFile)parentInfo.getSourceRoot(), null, interned, null);
}
OrderEntry[] entries = parentInfo.getOrderEntries();
@@ -972,8 +975,10 @@ public class DirectoryIndexImpl extends DirectoryIndex {
return myDirToPackageName.get(id) == ArrayUtil.EMPTY_INT_ARRAY;
}
private void initLibrarySources(@NotNull Module module, @NotNull ProgressIndicator progress,
@Nullable TObjectIntHashMap<String> interned) {
private void initLibrarySources(@NotNull Module module,
@NotNull ProgressIndicator progress,
@Nullable TObjectIntHashMap<String> interned,
Map<Library, TIntHashSet> libraryExcludedRoots) {
assertWritable();
progress.checkCanceled();
progress.setText2(ProjectBundle.message("project.index.processing.library.sources.progress", module.getName()));
@@ -981,9 +986,10 @@ public class DirectoryIndexImpl extends DirectoryIndex {
for (OrderEntry orderEntry : getOrderEntries(module)) {
if (orderEntry instanceof LibraryOrSdkOrderEntry) {
VirtualFile[] sourceRoots = ((LibraryOrSdkOrderEntry)orderEntry).getRootFiles(OrderRootType.SOURCES);
TIntHashSet excludedRoots = getExcludedRootsOfLibrary((LibraryOrSdkOrderEntry)orderEntry, libraryExcludedRoots);
for (final VirtualFile sourceRoot : sourceRoots) {
if (sourceRoot instanceof NewVirtualFile) {
fillMapWithLibrarySources((NewVirtualFile)sourceRoot, "", (NewVirtualFile)sourceRoot, progress, interned);
fillMapWithLibrarySources((NewVirtualFile)sourceRoot, "", (NewVirtualFile)sourceRoot, progress, interned, excludedRoots);
}
}
}
@@ -994,7 +1000,8 @@ public class DirectoryIndexImpl extends DirectoryIndex {
@Nullable final String packageName,
@NotNull final NewVirtualFile sourceRoot,
@Nullable final ProgressIndicator progress,
@Nullable final TObjectIntHashMap<String> interned) {
@Nullable final TObjectIntHashMap<String> interned,
@Nullable final TIntHashSet excludedRoots) {
assertWritable();
if (!isValid(dir)) return;
VfsUtilCore.visitChildrenRecursively(dir, new VirtualFileVisitor<String>() {
@@ -1005,6 +1012,7 @@ public class DirectoryIndexImpl extends DirectoryIndex {
if (progress != null) progress.checkCanceled();
int dirId = ((NewVirtualFile)file).getId();
if (!file.isDirectory() && dirId != dir.getId() || isIgnored(file)) return false;
if (excludedRoots != null && excludedRoots.contains(dirId)) return false;
DirectoryInfo info = getOrCreateDirInfo(dirId);
if (info.isInLibrarySource()) { // library sources overlap
@@ -1024,8 +1032,10 @@ public class DirectoryIndexImpl extends DirectoryIndex {
});
}
private void initLibraryClasses(@NotNull Module module, @NotNull ProgressIndicator progress,
@Nullable TObjectIntHashMap<String> interned) {
private void initLibraryClasses(@NotNull Module module,
@NotNull ProgressIndicator progress,
@Nullable TObjectIntHashMap<String> interned,
@Nullable Map<Library, TIntHashSet> libraryExcludedRoots) {
assertWritable();
progress.checkCanceled();
progress.setText2(ProjectBundle.message("project.index.processing.library.classes.progress", module.getName()));
@@ -1033,9 +1043,10 @@ public class DirectoryIndexImpl extends DirectoryIndex {
for (OrderEntry orderEntry : getOrderEntries(module)) {
if (orderEntry instanceof LibraryOrSdkOrderEntry) {
VirtualFile[] classRoots = ((LibraryOrSdkOrderEntry)orderEntry).getRootFiles(OrderRootType.CLASSES);
TIntHashSet excludedRoots = getExcludedRootsOfLibrary((LibraryOrSdkOrderEntry)orderEntry, libraryExcludedRoots);
for (final VirtualFile classRoot : classRoots) {
if (classRoot instanceof NewVirtualFile) {
fillMapWithLibraryClasses((NewVirtualFile)classRoot, "", (NewVirtualFile)classRoot, progress, interned);
fillMapWithLibraryClasses((NewVirtualFile)classRoot, "", (NewVirtualFile)classRoot, progress, interned, excludedRoots);
}
}
}
@@ -1043,11 +1054,11 @@ public class DirectoryIndexImpl extends DirectoryIndex {
}
private void fillMapWithLibraryClasses(@NotNull final NewVirtualFile dir,
@NotNull final String packageName,
@NotNull final NewVirtualFile classRoot,
@Nullable final ProgressIndicator progress,
@Nullable final TObjectIntHashMap<String> interned
) {
@NotNull final String packageName,
@NotNull final NewVirtualFile classRoot,
@Nullable final ProgressIndicator progress,
@Nullable final TObjectIntHashMap<String> interned,
final TIntHashSet excludedRoots) {
assertWritable();
if (!isValid(dir)) return;
VfsUtilCore.visitChildrenRecursively(dir, new VirtualFileVisitor<String>() {
@@ -1059,6 +1070,7 @@ public class DirectoryIndexImpl extends DirectoryIndex {
if (!file.isDirectory() && !Comparing.equal(file, dir) || isIgnored(file)) return false;
int dirId = ((NewVirtualFile)file).getId();
if (excludedRoots != null && excludedRoots.contains(dirId)) return false;
DirectoryInfo info = getOrCreateDirInfo(dirId);
if (info.hasLibraryClassRoot()) { // library classes overlap
@@ -1079,6 +1091,30 @@ public class DirectoryIndexImpl extends DirectoryIndex {
});
}
@Nullable
private TIntHashSet getExcludedRootsOfLibrary(LibraryOrSdkOrderEntry orderEntry, Map<Library, TIntHashSet> libraryExcludedRoots) {
if (orderEntry instanceof LibraryOrderEntry) {
Library library = ((LibraryOrderEntry)orderEntry).getLibrary();
if (library != null) {
TIntHashSet cached = libraryExcludedRoots.get(library);
if (cached != null) return cached;
VirtualFile[] files = ((LibraryEx)library).getExcludedRoots();
if (files.length > 0) {
TIntHashSet set = new TIntHashSet();
for (VirtualFile file : files) {
if (file instanceof NewVirtualFile) {
set.add(((NewVirtualFile)file).getId());
}
}
libraryExcludedRoots.put(library, set);
return set;
}
}
}
return null;
}
private void initOrderEntries(@NotNull Module module,
@NotNull MultiMap<VirtualFile, OrderEntry> depEntries,
@NotNull MultiMap<VirtualFile, OrderEntry> libClassRootEntries,
@@ -1252,10 +1288,11 @@ public class DirectoryIndexImpl extends DirectoryIndex {
// Important! Because module's contents may overlap,
// first modules should be marked and only after that sources markup
// should be added. (src markup depends on module markup)
IdentityHashMap<Library, TIntHashSet> libraryExcludedRoots = new IdentityHashMap<Library, TIntHashSet>();
for (Module module : modules) {
initModuleSources(module, reverseAllSets, progress, interned);
initLibrarySources(module, progress, interned);
initLibraryClasses(module, progress , interned);
initLibrarySources(module, progress, interned, libraryExcludedRoots);
initLibraryClasses(module, progress , interned, libraryExcludedRoots);
}
progress.checkCanceled();
@@ -20,6 +20,7 @@ import com.intellij.openapi.roots.libraries.LibraryProperties;
import com.intellij.openapi.roots.libraries.LibraryType;
import com.intellij.openapi.roots.libraries.ui.OrderRoot;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
@@ -34,6 +35,8 @@ public interface LibraryEditor {
VirtualFile[] getFiles(OrderRootType rootType);
String[] getExcludedRootUrls();
void setName(String name);
void addRoot(VirtualFile file, OrderRootType rootType);
@@ -44,8 +47,12 @@ public interface LibraryEditor {
void addJarDirectory(String url, boolean recursive, OrderRootType rootType);
void addExcludedRoot(@NotNull String url);
void removeRoot(String url, OrderRootType rootType);
void removeExcludedRoot(@NotNull String url);
void removeAllRoots();
boolean hasChanges();
@@ -19,6 +19,7 @@ import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.impl.libraries.LibraryEx;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.util.Consumer;
import org.jetbrains.annotations.NotNull;
@@ -40,11 +41,19 @@ public class ModuleRootModificationUtil {
final List<String> classesRoots,
final List<String> sourceRoots,
final DependencyScope scope) {
addModuleLibrary(module, libName, classesRoots, sourceRoots, Collections.<String>emptyList(), scope);
}
public static void addModuleLibrary(final Module module, final String libName,
final List<String> classesRoots,
final List<String> sourceRoots,
final List<String> excludedRoots,
final DependencyScope scope) {
updateModel(module, new Consumer<ModifiableRootModel>() {
@Override
public void consume(final ModifiableRootModel model) {
final Library library = model.getModuleLibraryTable().createLibrary(libName);
final Library.ModifiableModel libraryModel = library.getModifiableModel();
final LibraryEx library = (LibraryEx)model.getModuleLibraryTable().createLibrary(libName);
final LibraryEx.ModifiableModelEx libraryModel = library.getModifiableModel();
for (String root : classesRoots) {
libraryModel.addRoot(root, OrderRootType.CLASSES);
@@ -52,6 +61,9 @@ public class ModuleRootModificationUtil {
for (String root : sourceRoots) {
libraryModel.addRoot(root, OrderRootType.SOURCES);
}
for (String excluded : excludedRoots) {
libraryModel.addExcludedRoot(excluded);
}
LibraryOrderEntry entry = model.findLibraryOrderEntry(library);
assert entry != null : library;
@@ -24,6 +24,7 @@ import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.roots.impl.libraries.LibraryEx;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.libraries.LibraryTable;
import com.intellij.openapi.util.Comparing;
@@ -592,6 +593,14 @@ public class RootModelImpl extends RootModelBase implements ModifiableRootModel
boolean equal = Comparing.equal(libraryOrderEntry1.getLibraryName(), libraryOrderEntry2.getLibraryName())
&& Comparing.equal(libraryOrderEntry1.getLibraryLevel(), libraryOrderEntry2.getLibraryLevel());
if (!equal) return false;
Library library1 = libraryOrderEntry1.getLibrary();
Library library2 = libraryOrderEntry2.getLibrary();
if (library1 != null && library2 != null) {
if (!Arrays.equals(((LibraryEx)library1).getExcludedRootUrls(), ((LibraryEx)library2).getExcludedRootUrls())) {
return false;
}
}
}
final OrderRootType[] allTypes = OrderRootType.getAllTypes();
@@ -21,6 +21,8 @@ import com.intellij.openapi.roots.impl.RootModelImpl;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.libraries.LibraryProperties;
import com.intellij.openapi.roots.libraries.PersistentLibraryKind;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
@@ -35,11 +37,21 @@ public interface LibraryEx extends Library {
boolean isDisposed();
@NotNull
@Override
ModifiableModelEx getModifiableModel();
@Nullable
PersistentLibraryKind<?> getKind();
LibraryProperties getProperties();
@NotNull
String[] getExcludedRootUrls();
@NotNull
VirtualFile[] getExcludedRoots();
interface ModifiableModelEx extends ModifiableModel {
void setProperties(LibraryProperties properties);
@@ -48,5 +60,12 @@ public interface LibraryEx extends Library {
void setKind(PersistentLibraryKind<?> type);
PersistentLibraryKind<?> getKind();
void addExcludedRoot(@NotNull String url);
boolean removeExcludedRoot(@NotNull String url);
@NotNull
String[] getExcludedRootUrls();
}
}
@@ -62,9 +62,11 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi
@NonNls public static final String ELEMENT = "library";
@NonNls public static final String PROPERTIES_ELEMENT = "properties";
private static final SkipDefaultValuesSerializationFilters SERIALIZATION_FILTERS = new SkipDefaultValuesSerializationFilters();
private static final String EXCLUDED_ROOTS_TAG = "excluded";
private String myName;
private final LibraryTable myLibraryTable;
private final Map<OrderRootType, VirtualFilePointerContainer> myRoots;
private VirtualFilePointerContainer myExcludedRoots;
private final JarDirectories myJarDirectories = new JarDirectories();
private final LibraryImpl mySource;
private PersistentLibraryKind<?> myKind;
@@ -105,6 +107,9 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi
final VirtualFilePointerContainer thatContainer = from.myRoots.get(rootType);
thisContainer.addAll(thatContainer);
}
if (from.myExcludedRoots != null) {
myExcludedRoots = from.myExcludedRoots.clone(myPointersDisposable);
}
myJarDirectories.copyFrom(from.myJarDirectories);
}
@@ -197,7 +202,7 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi
/* you have to commit modifiable model or dispose it by yourself! */
@Override
@NotNull
public ModifiableModel getModifiableModel() {
public ModifiableModelEx getModifiableModel() {
assert !isDisposed();
return new LibraryImpl(this, this, myRootModel);
}
@@ -287,6 +292,17 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi
VirtualFilePointerContainer roots = myRoots.get(rootType);
roots.readExternal(rootChild, ROOT_PATH_ELEMENT);
}
Element excludedRoot = element.getChild(EXCLUDED_ROOTS_TAG);
if (excludedRoot != null) {
getOrCreateExcludedRoots().readExternal(excludedRoot, ROOT_PATH_ELEMENT);
}
}
private VirtualFilePointerContainer getOrCreateExcludedRoots() {
if (myExcludedRoots == null) {
myExcludedRoots = VirtualFilePointerManager.getInstance().createContainer(myPointersDisposable);
}
return myExcludedRoots;
}
//TODO<rv> Remove the next two methods as a temporary solution. Sort in OrderRootType.
@@ -342,6 +358,11 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi
roots.writeExternal(rootTypeElement, ROOT_PATH_ELEMENT);
element.addContent(rootTypeElement);
}
if (myExcludedRoots != null && myExcludedRoots.size() > 0) {
Element excluded = new Element(EXCLUDED_ROOTS_TAG);
myExcludedRoots.writeExternal(excluded, ROOT_PATH_ELEMENT);
element.addContent(excluded);
}
myJarDirectories.writeExternal(element);
rootElement.addContent(element);
}
@@ -356,6 +377,35 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi
return myKind;
}
@Override
public void addExcludedRoot(@NotNull String url) {
getOrCreateExcludedRoots().add(url);
}
@Override
public boolean removeExcludedRoot(@NotNull String url) {
if (myExcludedRoots != null) {
VirtualFilePointer pointer = myExcludedRoots.findByUrl(url);
if (pointer != null) {
myExcludedRoots.remove(pointer);
return true;
}
}
return false;
}
@NotNull
@Override
public String[] getExcludedRootUrls() {
return myExcludedRoots != null ? myExcludedRoots.getUrls() : ArrayUtil.EMPTY_STRING_ARRAY;
}
@NotNull
@Override
public VirtualFile[] getExcludedRoots() {
return myExcludedRoots != null ? myExcludedRoots.getFiles() : VirtualFile.EMPTY_ARRAY;
}
@Override
public LibraryProperties getProperties() {
return myProperties;
@@ -439,12 +489,31 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi
final VirtualFilePointer byUrl = container.findByUrl(url);
if (byUrl != null) {
container.remove(byUrl);
for (String excludedRoot : myExcludedRoots.getUrls()) {
if (!isUnderRoots(excludedRoot)) {
VirtualFilePointer pointer = myExcludedRoots.findByUrl(url);
if (pointer != null) {
myExcludedRoots.remove(pointer);
}
}
}
myJarDirectories.remove(rootType, url);
return true;
}
return false;
}
private boolean isUnderRoots(@NotNull String url) {
for (VirtualFilePointerContainer container : myRoots.values()) {
for (String rootUrl : container.getUrls()) {
if (VfsUtilCore.isEqualOrAncestor(rootUrl, url)) {
return true;
}
}
}
return false;
}
@Override
public void moveRootUp(@NotNull String url, @NotNull OrderRootType rootType) {
assert !isDisposed();
@@ -531,12 +600,17 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi
VirtualFilePointerContainer clone = container.clone(myPointersDisposable);
myRoots.put(rootType, clone);
}
VirtualFilePointerContainer excludedRoots = fromModel.myExcludedRoots;
myExcludedRoots = excludedRoots != null ? excludedRoots.clone(myPointersDisposable) : null;
}
private void disposeMyPointers() {
for (VirtualFilePointerContainer container : new THashSet<VirtualFilePointerContainer>(myRoots.values())) {
container.killAll();
}
if (myExcludedRoots != null) {
myExcludedRoots.killAll();
}
Disposer.dispose(myPointersDisposable);
Disposer.register(this, myPointersDisposable);
}
@@ -575,6 +649,7 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi
if (myRoots != null ? !myRoots.equals(library.myRoots) : library.myRoots != null) return false;
if (myKind != null ? !myKind.equals(library.myKind) : library.myKind != null) return false;
if (myProperties != null ? !myProperties.equals(library.myProperties) : library.myProperties != null) return false;
if (!Comparing.equal(myExcludedRoots, library.myExcludedRoots)) return false;
return true;
}
@@ -582,7 +657,7 @@ public class LibraryImpl extends TraceableDisposable implements LibraryEx.Modifi
public int hashCode() {
int result = myName != null ? myName.hashCode() : 0;
result = 31 * result + (myRoots != null ? myRoots.hashCode() : 0);
result = 31 * result + (myJarDirectories != null ? myJarDirectories.hashCode() : 0);
result = 31 * result + myJarDirectories.hashCode();
return result;
}
@@ -145,10 +145,22 @@ public class JpsLibraryDelegate implements LibraryEx {
@NotNull
@Override
public ModifiableModel getModifiableModel() {
public ModifiableModelEx getModifiableModel() {
throw new UnsupportedOperationException("'getModifiableModel' not implemented in " + getClass().getName());
}
@NotNull
@Override
public String[] getExcludedRootUrls() {
return ArrayUtil.EMPTY_STRING_ARRAY;
}
@NotNull
@Override
public VirtualFile[] getExcludedRoots() {
return VirtualFile.EMPTY_ARRAY;
}
@Override
public void readExternal(Element element) throws InvalidDataException {
throw new UnsupportedOperationException();
@@ -25,6 +25,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModifiableRootModel;
import com.intellij.openapi.roots.impl.ModifiableModelCommitter;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.util.ArrayUtil;
import com.intellij.util.PairConsumer;
import com.intellij.util.containers.LinkedMultiMap;
@@ -153,8 +154,8 @@ public class MavenFoldersImporter {
private void addSourceFolderIfNotOverlap(String path, JpsModuleSourceRootType<?> type, List<String> addedPaths) {
String canonicalPath = myModel.toPath(path).getPath();
for (String existing : addedPaths) {
if (MavenRootModelAdapter.isEqualOrAncestor(existing, canonicalPath)
|| MavenRootModelAdapter.isEqualOrAncestor(canonicalPath, existing)) {
if (VfsUtilCore.isEqualOrAncestor(existing, canonicalPath)
|| VfsUtilCore.isEqualOrAncestor(canonicalPath, existing)) {
return;
}
}
@@ -25,8 +25,8 @@ import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.JarFileSystem;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.util.Processor;
@@ -81,7 +81,7 @@ public class MavenRootModelAdapter {
private ContentEntry getContentRootFor(Url url) {
for (ContentEntry e : myRootModel.getContentEntries()) {
if (isEqualOrAncestor(e.getUrl(), url.getUrl())) return e;
if (VfsUtilCore.isEqualOrAncestor(e.getUrl(), url.getUrl())) return e;
}
return null;
}
@@ -155,7 +155,7 @@ public class MavenRootModelAdapter {
String url = toUrl(f.getPath()).getUrl();
for (ContentEntry eachEntry : myRootModel.getContentEntries()) {
for (SourceFolder eachFolder : eachEntry.getSourceFolders()) {
if (isEqualOrAncestor(url, eachFolder.getUrl())) return true;
if (VfsUtilCore.isEqualOrAncestor(url, eachFolder.getUrl())) return true;
}
}
return false;
@@ -165,16 +165,12 @@ public class MavenRootModelAdapter {
String url = toUrl(f.getPath()).getUrl();
for (ContentEntry eachEntry : myRootModel.getContentEntries()) {
for (ExcludeFolder eachFolder : eachEntry.getExcludeFolders()) {
if (isEqualOrAncestor(eachFolder.getUrl(), url)) return true;
if (VfsUtilCore.isEqualOrAncestor(eachFolder.getUrl(), url)) return true;
}
}
return false;
}
public static boolean isEqualOrAncestor(String ancestor, String child) {
return ancestor.equals(child) || StringUtil.startsWithConcatenation(child, ancestor, "/");
}
private boolean exists(String path) {
return new File(toPath(path).getPath()).exists();
}
@@ -196,7 +192,7 @@ public class MavenRootModelAdapter {
for (SourceFolder eachFolder : eachEntry.getSourceFolders()) {
String ancestor = under ? url.getUrl() : eachFolder.getUrl();
String child = under ? eachFolder.getUrl() : url.getUrl();
if (isEqualOrAncestor(ancestor, child)) {
if (VfsUtilCore.isEqualOrAncestor(ancestor, child)) {
eachEntry.removeSourceFolder(eachFolder);
}
}
@@ -206,7 +202,7 @@ public class MavenRootModelAdapter {
String ancestor = under ? url.getUrl() : eachFolder.getUrl();
String child = under ? eachFolder.getUrl() : url.getUrl();
if (isEqualOrAncestor(ancestor, child)) {
if (VfsUtilCore.isEqualOrAncestor(ancestor, child)) {
if (eachFolder.isSynthetic()) {
getCompilerExtension().setExcludeOutput(false);
}
@@ -225,7 +221,7 @@ public class MavenRootModelAdapter {
for (SourceFolder eachFolder : eachEntry.getSourceFolders()) {
String ancestor = url.getUrl();
String child = eachFolder.getUrl();
if (isEqualOrAncestor(ancestor, child) || isEqualOrAncestor(child, ancestor)) {
if (VfsUtilCore.isEqualOrAncestor(ancestor, child) || VfsUtilCore.isEqualOrAncestor(child, ancestor)) {
return true;
}
}
@@ -234,7 +230,7 @@ public class MavenRootModelAdapter {
String ancestor = url.getUrl();
String child = eachFolder.getUrl();
if (isEqualOrAncestor(ancestor, child) || isEqualOrAncestor(child, ancestor)) {
if (VfsUtilCore.isEqualOrAncestor(ancestor, child) || VfsUtilCore.isEqualOrAncestor(child, ancestor)) {
return true;
}
}