IDEA-64312 Maven: frequent .iml changes after exclude/source folder updates

This commit is contained in:
Vladislav.Soroka
2014-05-12 17:02:55 +04:00
parent c5c647100f
commit e85f16db86
6 changed files with 225 additions and 108 deletions
@@ -350,6 +350,12 @@ public class RootModelImpl extends RootModelBase implements ModifiableRootModel
getSourceModel().setOrderEntriesFrom(this);
}
for (ModuleExtension extension : myExtensions) {
if (extension.isChanged()) {
extension.commit();
}
}
if (areContentEntriesChanged()) {
getSourceModel().removeAllContentEntries();
for (ContentEntry contentEntry : myContent) {
@@ -357,12 +363,6 @@ public class RootModelImpl extends RootModelBase implements ModifiableRootModel
getSourceModel().myContent.add(cloned);
}
}
for (ModuleExtension extension : myExtensions) {
if (extension.isChanged()) {
extension.commit();
}
}
}
@Override
@@ -107,7 +107,6 @@ public class MavenFoldersImporter {
configOutputFolders();
}
configGeneratedAndExcludedFolders();
myModel.sortSourceFolders();
}
private void configSourceFolders() {
@@ -25,7 +25,6 @@ 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;
@@ -41,15 +40,12 @@ import org.jetbrains.idea.maven.project.MavenProjectsManager;
import org.jetbrains.idea.maven.utils.Path;
import org.jetbrains.idea.maven.utils.Url;
import org.jetbrains.jps.model.JpsElement;
import org.jetbrains.jps.model.java.JavaSourceRootProperties;
import org.jetbrains.jps.model.java.JavaSourceRootType;
import org.jetbrains.jps.model.java.JpsJavaExtensionService;
import org.jetbrains.jps.model.module.JpsModuleSourceRootType;
import java.io.File;
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
public class MavenRootModelAdapter {
@@ -57,12 +53,17 @@ public class MavenRootModelAdapter {
private final ModifiableModuleModel myModuleModel;
private final ModifiableRootModel myRootModel;
private final MavenSourceFoldersModuleExtension myRootModelModuleExtension;
private final Set<String> myOrderEntriesBeforeJdk = new THashSet<String>();
public MavenRootModelAdapter(@NotNull MavenProject p, @NotNull Module module, final MavenModifiableModelsProvider rootModelsProvider) {
myMavenProject = p;
myModuleModel = rootModelsProvider.getModuleModel();
myRootModel = rootModelsProvider.getRootModel(module);
myRootModelModuleExtension = myRootModel.getModuleExtension(MavenSourceFoldersModuleExtension.class);
myRootModelModuleExtension.init(module, myRootModel);
}
public void init(boolean isNewlyCreatedModule) {
@@ -132,9 +133,7 @@ public class MavenRootModelAdapter {
}
public void clearSourceFolders() {
for (ContentEntry each : myRootModel.getContentEntries()) {
each.clearSourceFolders();
}
myRootModelModuleExtension.clearSourceFolders();
}
public <P extends JpsElement> void addSourceFolder(String path, final JpsModuleSourceRootType<P> rootType) {
@@ -156,34 +155,18 @@ public class MavenRootModelAdapter {
}
Url url = toUrl(path);
ContentEntry e = getContentRootFor(url);
if (e == null) return;
unregisterAll(path, true, true);
unregisterAll(path, false, true);
e.addSourceFolder(url.getUrl(), rootType, properties);
myRootModelModuleExtension.addSourceFolder(url, rootType, properties);
}
public boolean hasRegisteredSourceSubfolder(File f) {
public boolean hasRegisteredSourceSubfolder(@NotNull File f) {
String url = toUrl(f.getPath()).getUrl();
for (ContentEntry eachEntry : myRootModel.getContentEntries()) {
for (SourceFolder eachFolder : eachEntry.getSourceFolders()) {
if (VfsUtilCore.isEqualOrAncestor(url, eachFolder.getUrl())) return true;
}
}
return false;
return myRootModelModuleExtension.hasRegisteredSourceSubfolder(url);
}
@Nullable
public SourceFolder getSourceFolder(File folder) {
String url = toUrl(folder.getPath()).getUrl();
for (ContentEntry entry : myRootModel.getContentEntries()) {
for (SourceFolder sourceFolder : entry.getSourceFolders()) {
if (sourceFolder.getUrl().equals(url)) {
return sourceFolder;
}
}
}
return null;
return myRootModelModuleExtension.getSourceFolder(url);
}
public boolean isAlreadyExcluded(File f) {
@@ -212,13 +195,7 @@ public class MavenRootModelAdapter {
for (ContentEntry eachEntry : myRootModel.getContentEntries()) {
if (unregisterSources) {
for (SourceFolder eachFolder : eachEntry.getSourceFolders()) {
String ancestor = under ? url.getUrl() : eachFolder.getUrl();
String child = under ? eachFolder.getUrl() : url.getUrl();
if (VfsUtilCore.isEqualOrAncestor(ancestor, child)) {
eachEntry.removeSourceFolder(eachFolder);
}
}
myRootModelModuleExtension.unregisterAll(url, under);
}
for (String excludedUrl : eachEntry.getExcludeFolderUrls()) {
@@ -505,68 +482,4 @@ public class MavenRootModelAdapter {
//bad value was stored
}
}
public void sortSourceFolders() {
for (ContentEntry eachEntry : myRootModel.getContentEntries()) {
final Set<SourceFolderData> sourceFolders = new TreeSet<SourceFolderData>(SourceFolderDataComparator.INSTANCE);
for (SourceFolder eachFolder : eachEntry.getSourceFolders()) {
final JpsElement properties = eachFolder.getJpsElement().getProperties();
//noinspection unchecked
JpsModuleSourceRootType<JpsElement> sourceRootType = (JpsModuleSourceRootType<JpsElement>)eachFolder.getRootType();
if (properties instanceof JavaSourceRootProperties) {
sourceFolders.add(
new SourceFolderData<JpsElement>(eachFolder.getUrl(), sourceRootType, ((JavaSourceRootProperties)properties).createCopy())
);
}
else {
sourceFolders.add(new SourceFolderData<JpsElement>(eachFolder.getUrl(), sourceRootType, null));
}
eachEntry.removeSourceFolder(eachFolder);
}
for (SourceFolderData data : sourceFolders) {
if (data.getProperties() == null) {
eachEntry.addSourceFolder(data.getUrl(), data.getType());
}
else {
eachEntry.addSourceFolder(data.getUrl(), data.getType(), data.getProperties());
}
}
}
}
private static final class SourceFolderData<P extends JpsElement> {
@NotNull private final String url;
@NotNull private final JpsModuleSourceRootType<P> type;
@Nullable private final P properties;
private SourceFolderData(@NotNull String url, @NotNull JpsModuleSourceRootType<P> type, @Nullable P properties) {
this.url = url;
this.type = type;
this.properties = properties;
}
@NotNull
public String getUrl() {
return url;
}
@NotNull
public JpsModuleSourceRootType<P> getType() {
return type;
}
@Nullable
public P getProperties() {
return properties;
}
}
private static final class SourceFolderDataComparator implements Comparator<SourceFolderData> {
public static final SourceFolderDataComparator INSTANCE = new SourceFolderDataComparator();
@Override
public int compare(@NotNull SourceFolderData o1, @NotNull SourceFolderData o2) {
return StringUtil.naturalCompare(o1.getUrl(), o2.getUrl());
}
}
}
@@ -0,0 +1,206 @@
/*
* Copyright 2000-2014 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 org.jetbrains.idea.maven.importing;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.project.model.impl.module.JpsRootModel;
import com.intellij.project.model.impl.module.content.JpsContentEntry;
import com.intellij.project.model.impl.module.content.JpsSourceFolder;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.maven.utils.Url;
import org.jetbrains.jps.model.JpsElement;
import org.jetbrains.jps.model.JpsElementFactory;
import org.jetbrains.jps.model.ex.JpsElementBase;
import org.jetbrains.jps.model.java.JpsJavaModuleType;
import org.jetbrains.jps.model.module.JpsModule;
import org.jetbrains.jps.model.module.JpsModuleSourceRoot;
import org.jetbrains.jps.model.module.JpsModuleSourceRootType;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
/**
* @author Vladislav.Soroka
* @since 4/30/2014
*/
public class MavenSourceFoldersModuleExtension extends ModuleExtension<MavenSourceFoldersModuleExtension> {
private ModifiableRootModel myRootModel;
private JpsModule myDummyJpsModule;
private JpsRootModel myDummyJpsRootModel;
private final Set<JpsSourceFolder> myJpsSourceFolders = new TreeSet<JpsSourceFolder>(ContentFolderComparator.INSTANCE);
private boolean isJpsSourceFoldersChanged;
public void init(@NotNull Module module, @NotNull ModifiableRootModel modifiableRootModel) {
myRootModel = modifiableRootModel;
myDummyJpsModule = JpsElementFactory.getInstance()
.createModule(module.getName(), JpsJavaModuleType.INSTANCE, JpsElementFactory.getInstance().createDummyElement());
myDummyJpsRootModel = new JpsRootModel(module, myDummyJpsModule);
myJpsSourceFolders.clear();
for (ContentEntry eachEntry : modifiableRootModel.getContentEntries()) {
for (SourceFolder eachFolder : eachEntry.getSourceFolders()) {
//noinspection unchecked
final JpsModuleSourceRoot jpsModuleSourceRoot =
JpsElementFactory.getInstance().createModuleSourceRoot(
eachFolder.getUrl(),
(JpsModuleSourceRootType<JpsElement>)eachFolder.getRootType(),
eachFolder.getJpsElement().getProperties().getBulkModificationSupport().createCopy());
final JpsContentEntry dummyJpsContentEntry = new JpsContentEntry(myDummyJpsModule, myDummyJpsRootModel, eachFolder.getUrl());
myJpsSourceFolders.add(new JpsSourceFolder(jpsModuleSourceRoot, dummyJpsContentEntry));
}
}
}
@Override
public ModuleExtension getModifiableModel(boolean writable) {
return new MavenSourceFoldersModuleExtension();
}
@Override
public void commit() {
if (!isJpsSourceFoldersChanged) return;
for (ContentEntry eachEntry : myRootModel.getContentEntries()) {
for (SourceFolder eachFolder : eachEntry.getSourceFolders()) {
boolean found = false;
for (JpsSourceFolder jpsSourceFolder : myJpsSourceFolders) {
if (StringUtil.equals(jpsSourceFolder.getUrl(), eachFolder.getUrl())
&& eachFolder.getRootType().equals(jpsSourceFolder.getRootType())) {
found = true;
eachFolder.setPackagePrefix(jpsSourceFolder.getPackagePrefix());
myJpsSourceFolders.remove(jpsSourceFolder);
break;
}
}
if (!found) {
eachEntry.removeSourceFolder(eachFolder);
}
}
}
for (JpsSourceFolder jpsSourceFolder : myJpsSourceFolders) {
Url url = new Url(jpsSourceFolder.getUrl());
ContentEntry e = getContentRootFor(url);
if (e == null) continue;
//noinspection unchecked
JpsModuleSourceRootType<JpsElement> sourceRootType = (JpsModuleSourceRootType<JpsElement>)jpsSourceFolder.getRootType();
final JpsElementBase properties = (JpsElementBase)jpsSourceFolder.getSourceRoot().getProperties();
//noinspection unchecked
properties.setParent(null);
e.addSourceFolder(url.getUrl(), sourceRootType, properties);
}
isJpsSourceFoldersChanged = false;
}
@Override
public boolean isChanged() {
return isJpsSourceFoldersChanged;
}
@Override
public void dispose() {
myJpsSourceFolders.clear();
}
@Override
public void readExternal(Element element) throws InvalidDataException {
}
@Override
public void writeExternal(Element element) throws WriteExternalException {
}
public void clearSourceFolders() {
myJpsSourceFolders.clear();
isJpsSourceFoldersChanged = true;
}
public <P extends JpsElement> void addSourceFolder(final @NotNull Url url,
final @NotNull JpsModuleSourceRootType<P> rootType,
final @NotNull P properties) {
for (Iterator<JpsSourceFolder> iterator = myJpsSourceFolders.iterator(); iterator.hasNext(); ) {
SourceFolder eachFolder = iterator.next();
if (VfsUtilCore.isEqualOrAncestor(url.getUrl(), eachFolder.getUrl()) ||
VfsUtilCore.isEqualOrAncestor(eachFolder.getUrl(), url.getUrl())) {
iterator.remove();
}
}
final JpsModuleSourceRoot jpsModuleSourceRoot =
JpsElementFactory.getInstance().createModuleSourceRoot(url.getUrl(), rootType, properties);
final JpsContentEntry dummyJpsContentEntry = new JpsContentEntry(myDummyJpsModule, myDummyJpsRootModel, url.getUrl());
myJpsSourceFolders.add(new JpsSourceFolder(jpsModuleSourceRoot, dummyJpsContentEntry));
isJpsSourceFoldersChanged = true;
}
public boolean hasRegisteredSourceSubfolder(@NotNull String url) {
for (JpsSourceFolder eachFolder : myJpsSourceFolders) {
if (VfsUtilCore.isEqualOrAncestor(url, eachFolder.getUrl())) return true;
}
return false;
}
@Nullable
public SourceFolder getSourceFolder(@NotNull String url) {
for (JpsSourceFolder eachFolder : myJpsSourceFolders) {
if (eachFolder.getUrl().equals(url)) return eachFolder;
}
return null;
}
@Nullable
private ContentEntry getContentRootFor(@NotNull Url url) {
for (ContentEntry e : myRootModel.getContentEntries()) {
if (VfsUtilCore.isEqualOrAncestor(e.getUrl(), url.getUrl())) return e;
}
return null;
}
public void unregisterAll(@NotNull Url url, boolean under) {
for (Iterator<JpsSourceFolder> iterator = myJpsSourceFolders.iterator(); iterator.hasNext(); ) {
JpsSourceFolder eachFolder = iterator.next();
String ancestor = under ? url.getUrl() : eachFolder.getUrl();
String child = under ? eachFolder.getUrl() : url.getUrl();
if (VfsUtilCore.isEqualOrAncestor(ancestor, child)) {
iterator.remove();
}
}
}
private static final class ContentFolderComparator implements Comparator<ContentFolder> {
public static final ContentFolderComparator INSTANCE = new ContentFolderComparator();
@Override
public int compare(@NotNull ContentFolder o1, @NotNull ContentFolder o2) {
return StringUtil.naturalCompare(o1.getUrl(), o2.getUrl());
}
}
}
@@ -39,6 +39,7 @@
<projectImportBuilder implementation="org.jetbrains.idea.maven.wizards.MavenProjectBuilder"/>
<moduleBuilder builderClass="org.jetbrains.idea.maven.wizards.MavenModuleBuilder"/>
<frameworkSupport implementation="org.jetbrains.idea.maven.wizards.MavenFrameworkSupportProvider"/>
<moduleExtension implementation="org.jetbrains.idea.maven.importing.MavenSourceFoldersModuleExtension"/>
<applicationService serviceImplementation="org.jetbrains.idea.maven.server.MavenServerManager"/>
<applicationService serviceImplementation="org.jetbrains.idea.maven.indices.MavenIndicesManager"/>
@@ -16,7 +16,6 @@
package org.jetbrains.idea.maven.importing;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.idea.maven.MavenCustomRepositoryHelper;
import org.jetbrains.idea.maven.MavenImportingTestCase;
@@ -173,8 +172,7 @@ public class FoldersImportingTest extends MavenImportingTestCase {
" <sourceDirectory>src1</sourceDirectory>" +
"</build>");
assertSources("project", "src1", "src2");
assertSources("project", "src2", "src1");
}
public void testCustomSourceFolders() throws Exception {