cleanup project roots

This commit is contained in:
Alexey Kudravtsev
2017-04-26 13:38:44 +03:00
parent d2a4dca0f0
commit 551d75ef9c
6 changed files with 87 additions and 126 deletions
@@ -403,10 +403,10 @@ public class JavaSdkImpl extends JavaSdk {
}
};
rootContainer.startChange();
addClasses(jdkHomeFile, sdkModificator, isJre);
addSources(jdkHomeFile, sdkModificator);
rootContainer.finishChange();
rootContainer.changeRoots(() -> {
addClasses(jdkHomeFile, sdkModificator, isJre);
addSources(jdkHomeFile, sdkModificator);
});
ProjectJdkImpl jdk = new ProjectJdkImpl(jdkName, this, homePath, jdkName) {
@Override
@@ -503,7 +503,7 @@ public class JavaSdkImpl extends JavaSdk {
}
};
ProjectJdkImpl.copyRoots(rootContainer, jdk);
jdk.copyRootsFrom(rootContainer);
return jdk;
}
@@ -326,7 +326,8 @@ public class VirtualFilePointerManagerImpl extends VirtualFilePointerManager imp
try {
for (VirtualFilePointerImpl pointer : pointers) {
if (!myStoredPointers.contains(pointer)) {
pointer.throwDisposalError("Virtual pointer hasn't been disposed: "+pointer);
pointer.throwDisposalError("Virtual pointer '" + pointer +
"' hasn't been disposed: "+pointer.getStackTrace());
}
}
}
@@ -33,8 +33,8 @@ public interface ProjectRootContainer {
VirtualFile[] getRootFiles(@NotNull OrderRootType type);
@NotNull ProjectRoot[] getRoots(@NotNull OrderRootType type);
void startChange();
void finishChange();
// must execute modifications inside this method only
void changeRoots(@NotNull Runnable change);
@NotNull
ProjectRoot addRoot(@NotNull VirtualFile virtualFile, @NotNull OrderRootType type);
@@ -24,11 +24,11 @@ import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.RootProvider;
import com.intellij.openapi.roots.impl.RootProviderBaseImpl;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.UserDataHolderBase;
import com.intellij.openapi.vfs.StandardFileSystems;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jdom.Element;
@@ -55,10 +55,6 @@ public class ProjectJdkImpl extends UserDataHolderBase implements Sdk, SdkModifi
@NonNls public static final String ELEMENT_TYPE = "type";
@NonNls private static final String ELEMENT_VERSION = "version";
@NonNls private static final String ELEMENT_ROOTS = "roots";
@NonNls private static final String ELEMENT_ROOT = "root";
@NonNls private static final String ELEMENT_PROPERTY = "property";
@NonNls private static final String VALUE_JDKHOME = "jdkHome";
@NonNls private static final String ATTRIBUTE_FILE = "file";
@NonNls private static final String ELEMENT_HOMEPATH = "homePath";
@NonNls private static final String ELEMENT_ADDITIONAL = "additional";
@@ -134,7 +130,7 @@ public class ProjectJdkImpl extends UserDataHolderBase implements Sdk, SdkModifi
readExternal(element, null);
}
public void readExternal(@NotNull Element element, @Nullable ProjectJdkTable projectJdkTable) {
public void readExternal(@NotNull Element element, @Nullable ProjectJdkTable projectJdkTable) throws InvalidDataException {
myName = element.getChild(ELEMENT_NAME).getAttributeValue(ATTRIBUTE_VALUE);
final Element typeChild = element.getChild(ELEMENT_TYPE);
final String sdkTypeName = typeChild != null ? typeChild.getAttributeValue(ATTRIBUTE_VALUE) : null;
@@ -155,25 +151,14 @@ public class ProjectJdkImpl extends UserDataHolderBase implements Sdk, SdkModifi
myVersionDefined = false;
}
if (element.getAttribute(ELEMENT_VERSION) == null || !"2".equals(element.getAttributeValue(ELEMENT_VERSION))) {
myRootContainer.startChange();
myRootContainer.readOldVersion(element.getChild(ELEMENT_ROOTS));
final List children = element.getChild(ELEMENT_ROOTS).getChildren(ELEMENT_ROOT);
for (final Object aChildren : children) {
Element root = (Element)aChildren;
for (final Object o : root.getChildren(ELEMENT_PROPERTY)) {
Element prop = (Element)o;
if (ELEMENT_TYPE.equals(prop.getAttributeValue(ELEMENT_NAME)) && VALUE_JDKHOME.equals(prop.getAttributeValue(ATTRIBUTE_VALUE))) {
myHomePath = VirtualFileManager.extractPath(root.getAttributeValue(ATTRIBUTE_FILE));
}
}
myRootContainer.changeRoots(() -> {
String versionValue = element.getAttributeValue(ELEMENT_VERSION, "");
if (versionValue.isEmpty() || !"2".equals(versionValue)) {
throw new InvalidDataException("Too old version is not supported: " + versionValue);
}
myRootContainer.finishChange();
}
else {
myHomePath = element.getChild(ELEMENT_HOMEPATH).getAttributeValue(ATTRIBUTE_VALUE);
myRootContainer.readExternal(element.getChild(ELEMENT_ROOTS));
}
});
final Element additional = element.getChild(ELEMENT_ADDITIONAL);
if (additional != null) {
@@ -244,26 +229,18 @@ public class ProjectJdkImpl extends UserDataHolderBase implements Sdk, SdkModifi
return myRootProvider;
}
void copyTo(ProjectJdkImpl dest) {
void copyTo(@NotNull ProjectJdkImpl dest) {
final String name = getName();
dest.setName(name);
dest.setHomePath(getHomePath());
dest.myVersionDefined = myVersionDefined;
dest.myVersionString = myVersionString;
dest.setSdkAdditionalData(getSdkAdditionalData());
copyRoots(myRootContainer, dest);
dest.copyRootsFrom(myRootContainer);
}
static void copyRoots(@NotNull ProjectRootContainerImpl rootContainer, @NotNull ProjectJdkImpl dest) {
dest.myRootContainer.startChange();
dest.myRootContainer.removeAllRoots();
for (OrderRootType rootType : OrderRootType.getAllTypes()) {
final ProjectRoot[] newRoots = rootContainer.getRoots(rootType);
for (ProjectRoot newRoot : newRoots) {
dest.myRootContainer.addRoot(newRoot, rootType);
}
}
dest.myRootContainer.finishChange();
void copyRootsFrom(@NotNull ProjectRootContainerImpl rootContainer) {
myRootContainer.copyRootsFrom(rootContainer);
}
private class MyRootProvider extends RootProviderBaseImpl implements ProjectRootListener {
@@ -329,7 +306,7 @@ public class ProjectJdkImpl extends UserDataHolderBase implements Sdk, SdkModifi
@Override
public void commitChanges() {
LOG.assertTrue(isWritable());
myRootContainer.finishChange();
copyTo(myOrigin);
myOrigin = null;
}
@@ -28,7 +28,7 @@ import com.intellij.openapi.util.JDOMExternalizable;
import com.intellij.openapi.vfs.*;
import com.intellij.util.ObjectUtils;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashMap;
import gnu.trove.THashMap;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
@@ -40,9 +40,8 @@ import java.util.Map;
*/
public class ProjectRootContainerImpl implements JDOMExternalizable, ProjectRootContainer {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.projectRoots.impl.ProjectRootContainerImpl");
private final Map<OrderRootType, CompositeProjectRoot> myRoots = new HashMap<>();
private Map<OrderRootType, VirtualFile[]> myFiles = new HashMap<>();
private final Map<OrderRootType, CompositeProjectRoot> myRoots = new THashMap<>();
private final Map<OrderRootType, VirtualFile[]> myCachedFiles = new THashMap<>();
private boolean myInsideChange;
private final List<ProjectRootListener> myListeners = ContainerUtil.createLockFreeCopyOnWriteList();
@@ -54,14 +53,14 @@ public class ProjectRootContainerImpl implements JDOMExternalizable, ProjectRoot
for (OrderRootType rootType : OrderRootType.getAllTypes()) {
myRoots.put(rootType, new CompositeProjectRoot());
myFiles.put(rootType, VirtualFile.EMPTY_ARRAY);
myCachedFiles.put(rootType, VirtualFile.EMPTY_ARRAY);
}
}
@Override
@NotNull
public VirtualFile[] getRootFiles(@NotNull OrderRootType type) {
return ObjectUtils.chooseNotNull(myFiles.get(type), VirtualFile.EMPTY_ARRAY);
return ObjectUtils.chooseNotNull(myCachedFiles.get(type), VirtualFile.EMPTY_ARRAY);
}
@Override
@@ -70,29 +69,46 @@ public class ProjectRootContainerImpl implements JDOMExternalizable, ProjectRoot
return myRoots.get(type).getProjectRoots();
}
@Override
public void startChange() {
LOG.assertTrue(!myInsideChange);
void startChange() {
myInsideChange = true; // argh!! has to have this abomination just because of horrible Sdk.getSdkModificator()/commitChanges() are separated
}
myInsideChange = true;
private void assertNotInsideChange() {
if (myInsideChange) throw new IllegalStateException();
}
private void assertInsideChange() {
if (!myInsideChange) throw new IllegalStateException();
}
@Override
public void finishChange() {
LOG.assertTrue(myInsideChange);
Map<OrderRootType, VirtualFile[]> oldRoots = new HashMap<>(myFiles);
public void changeRoots(@NotNull Runnable change) {
assertNotInsideChange();
myInsideChange = true;
Map<OrderRootType, VirtualFile[]> oldRoots = new THashMap<>(myCachedFiles);
boolean changes = false;
try {
change.run();
}
finally {
myInsideChange = false;
if (cacheFiles(oldRoots)) {
fireRootsChanged();
}
}
}
private boolean cacheFiles(@NotNull Map<OrderRootType, VirtualFile[]> oldRoots) {
myCachedFiles.clear();
boolean changed = false;
for (OrderRootType orderRootType : OrderRootType.getAllTypes()) {
final VirtualFile[] roots = myRoots.get(orderRootType).getVirtualFiles();
changes = changes || !Comparing.equal(roots, oldRoots.get(orderRootType));
myFiles.put(orderRootType, roots);
changed |= !Comparing.equal(roots, oldRoots.get(orderRootType));
myCachedFiles.put(orderRootType, roots);
}
if (changes) {
fireRootsChanged();
}
myInsideChange = false;
return changed;
}
void addProjectRootContainerListener(@NotNull ProjectRootListener listener) {
@@ -109,41 +125,40 @@ public class ProjectRootContainerImpl implements JDOMExternalizable, ProjectRoot
}
}
@Override
public void removeRoot(@NotNull ProjectRoot root, @NotNull OrderRootType type) {
LOG.assertTrue(myInsideChange);
assertInsideChange();
myRoots.get(type).remove(root);
}
@Override
@NotNull
public ProjectRoot addRoot(@NotNull VirtualFile virtualFile, @NotNull OrderRootType type) {
LOG.assertTrue(myInsideChange);
assertInsideChange();
return myRoots.get(type).add(virtualFile);
}
@Override
public void addRoot(@NotNull ProjectRoot root, @NotNull OrderRootType type) {
LOG.assertTrue(myInsideChange);
assertInsideChange();
myRoots.get(type).add(root);
}
@Override
public void removeAllRoots(@NotNull OrderRootType type) {
LOG.assertTrue(myInsideChange);
assertInsideChange();
myRoots.get(type).clear();
}
@Override
public void removeRoot(@NotNull VirtualFile root, @NotNull OrderRootType type) {
LOG.assertTrue(myInsideChange);
assertInsideChange();
myRoots.get(type).remove(root);
}
@Override
public void removeAllRoots() {
LOG.assertTrue(myInsideChange);
assertInsideChange();
for (CompositeProjectRoot myRoot : myRoots.values()) {
myRoot.clear();
}
@@ -151,7 +166,7 @@ public class ProjectRootContainerImpl implements JDOMExternalizable, ProjectRoot
@Override
public void update() {
LOG.assertTrue(myInsideChange);
assertInsideChange();
for (CompositeProjectRoot myRoot : myRoots.values()) {
myRoot.update();
}
@@ -159,19 +174,18 @@ public class ProjectRootContainerImpl implements JDOMExternalizable, ProjectRoot
@Override
public void readExternal(Element element) {
assertInsideChange();
for (PersistentOrderRootType type : OrderRootType.getAllPersistentTypes()) {
read(element, type);
}
ApplicationManager.getApplication().runReadAction(() -> {
myFiles = new HashMap<>();
for (Map.Entry<OrderRootType, CompositeProjectRoot> entry : myRoots.entrySet()) {
CompositeProjectRoot root = entry.getValue();
myRoots.values().forEach(root -> {
if (myNoCopyJars) {
setNoCopyJars(root);
}
myFiles.put(entry.getKey(), root.getVirtualFiles());
}
});
cacheFiles(new THashMap<>(myCachedFiles));
});
for (OrderRootType type : OrderRootType.getAllTypes()) {
@@ -192,6 +206,18 @@ public class ProjectRootContainerImpl implements JDOMExternalizable, ProjectRoot
}
}
void copyRootsFrom(@NotNull ProjectRootContainerImpl rootContainer) {
changeRoots(() -> {
removeAllRoots();
for (OrderRootType rootType : OrderRootType.getAllTypes()) {
final ProjectRoot[] newRoots = rootContainer.getRoots(rootType);
for (ProjectRoot newRoot : newRoots) {
addRoot(newRoot, rootType);
}
}
});
}
private static void setNoCopyJars(ProjectRoot root) {
if (root instanceof SimpleProjectRoot) {
String url = ((SimpleProjectRoot)root).getUrl();
@@ -220,7 +246,9 @@ public class ProjectRootContainerImpl implements JDOMExternalizable, ProjectRoot
}
List<Element> children = child.getChildren();
LOG.assertTrue(children.size() == 1);
if (children.size() != 1) {
LOG.error(children);
}
CompositeProjectRoot root = (CompositeProjectRoot)ProjectRootUtil.read(children.get(0));
myRoots.put(type, root);
}
@@ -234,33 +262,4 @@ public class ProjectRootContainerImpl implements JDOMExternalizable, ProjectRoot
e.addContent(root);
}
}
@SuppressWarnings("HardCodedStringLiteral")
void readOldVersion(Element child) {
for (Element root : child.getChildren("root")) {
String url = root.getAttributeValue("file");
SimpleProjectRoot projectRoot = new SimpleProjectRoot(url);
String type = root.getChild("property").getAttributeValue("value");
for (PersistentOrderRootType rootType : OrderRootType.getAllPersistentTypes()) {
if (type.equals(rootType.getOldSdkRootName())) {
addRoot(projectRoot, rootType);
break;
}
}
}
myFiles = new HashMap<>();
for (Map.Entry<OrderRootType, CompositeProjectRoot> entry : myRoots.entrySet()) {
myFiles.put(entry.getKey(), entry.getValue().getVirtualFiles());
}
for (OrderRootType type : OrderRootType.getAllTypes()) {
final VirtualFile[] oldRoots = VirtualFile.EMPTY_ARRAY;
final VirtualFile[] newRoots = getRootFiles(type);
if (!Comparing.equal(oldRoots, newRoots)) {
fireRootsChanged();
break;
}
}
}
}
@@ -18,10 +18,8 @@ package com.intellij.openapi.projectRoots.impl;
import com.intellij.openapi.projectRoots.ex.ProjectRoot;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.util.PathUtil;
import com.intellij.util.io.URLUtil;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
@@ -81,7 +79,7 @@ public class SimpleProjectRoot implements ProjectRoot {
@Override
@NotNull
public String[] getUrls() {
return new String[]{myUrl};
return new String[]{getUrl()};
}
@Override
@@ -120,21 +118,7 @@ public class SimpleProjectRoot implements ProjectRoot {
@NotNull
private static String readUrl(Element element) {
String url = element.getAttributeValue(ATTRIBUTE_URL);
return migrateJdkAnnotationsToCommunityForDevIdea(url);
}
// hack to migrate internal IDEA jdk annos dir from IDEA_PROJECT_HOME/jdkAnnotations to IDEA_PROJECT_HOME/community/java/jdkAnnotations
@NotNull
private static String migrateJdkAnnotationsToCommunityForDevIdea(@NotNull String url) {
File root = new File(VfsUtilCore.urlToPath(url) + "/..");
boolean isOldJdkAnnotations = new File(root, "community/java/jdkAnnotations").exists()
&& new File(root, "idea.iml").exists()
&& new File(root, "testData").exists();
if (isOldJdkAnnotations) {
return VfsUtilCore.pathToUrl(PathUtil.getCanonicalPath(VfsUtilCore.urlToPath(url + "/../community/java/jdkAnnotations")));
}
return url;
return element.getAttributeValue(ATTRIBUTE_URL);
}
public void writeExternal(Element element) {
@@ -142,6 +126,6 @@ public class SimpleProjectRoot implements ProjectRoot {
initialize();
}
element.setAttribute(ATTRIBUTE_URL, myUrl);
element.setAttribute(ATTRIBUTE_URL, getUrl());
}
}