From 67cf17d913547d7dfb6f39d4b36cd7629286cee6 Mon Sep 17 00:00:00 2001 From: "Vladislav.Soroka" Date: Mon, 28 Apr 2014 17:25:46 +0400 Subject: [PATCH] Maven: stable order of source folders IDEA-64312 Maven: frequent .iml changes after exclude/source folder updates --- .../maven/importing/MavenFoldersImporter.java | 1 + .../importing/MavenRootModelAdapter.java | 68 ++++++++++++++ .../idea/maven/MavenImportingTestCase.java | 2 +- .../maven/importing/FoldersImportingTest.java | 88 ++++++++++++++++--- .../maven/importing/GroovyImporterTest.java | 40 ++++----- 5 files changed, 168 insertions(+), 31 deletions(-) diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenFoldersImporter.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenFoldersImporter.java index 1b40dfadccee..f3ad1ff78c29 100755 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenFoldersImporter.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenFoldersImporter.java @@ -107,6 +107,7 @@ public class MavenFoldersImporter { configOutputFolders(); } configGeneratedAndExcludedFolders(); + myModel.sortSourceFolders(); } private void configSourceFolders() { diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenRootModelAdapter.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenRootModelAdapter.java index 8f1af42006b4..63ebdd3fa56a 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenRootModelAdapter.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenRootModelAdapter.java @@ -25,6 +25,7 @@ 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; @@ -40,12 +41,15 @@ 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 { @@ -501,4 +505,68 @@ public class MavenRootModelAdapter { //bad value was stored } } + + public void sortSourceFolders() { + for (ContentEntry eachEntry : myRootModel.getContentEntries()) { + final Set sourceFolders = new TreeSet(SourceFolderDataComparator.INSTANCE); + for (SourceFolder eachFolder : eachEntry.getSourceFolders()) { + final JpsElement properties = eachFolder.getJpsElement().getProperties(); + //noinspection unchecked + JpsModuleSourceRootType sourceRootType = (JpsModuleSourceRootType)eachFolder.getRootType(); + if (properties instanceof JavaSourceRootProperties) { + sourceFolders.add( + new SourceFolderData(eachFolder.getUrl(), sourceRootType, ((JavaSourceRootProperties)properties).createCopy()) + ); + } + else { + sourceFolders.add(new SourceFolderData(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

{ + @NotNull private final String url; + @NotNull private final JpsModuleSourceRootType

type; + @Nullable private final P properties; + + private SourceFolderData(@NotNull String url, @NotNull JpsModuleSourceRootType

type, @Nullable P properties) { + this.url = url; + this.type = type; + this.properties = properties; + } + + @NotNull + public String getUrl() { + return url; + } + + @NotNull + public JpsModuleSourceRootType

getType() { + return type; + } + + @Nullable + public P getProperties() { + return properties; + } + } + + private static final class SourceFolderDataComparator implements Comparator { + public static final SourceFolderDataComparator INSTANCE = new SourceFolderDataComparator(); + + @Override + public int compare(@NotNull SourceFolderData o1, @NotNull SourceFolderData o2) { + return StringUtil.naturalCompare(o1.getUrl(), o2.getUrl()); + } + } } diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/MavenImportingTestCase.java b/plugins/maven/src/test/java/org/jetbrains/idea/maven/MavenImportingTestCase.java index 9de33c5a3536..0a6bd7660046 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/MavenImportingTestCase.java +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/MavenImportingTestCase.java @@ -179,7 +179,7 @@ public abstract class MavenImportingTestCase extends MavenTestCase { actual.add(folderUrl); } - assertUnorderedPathsAreEqual(actual, Arrays.asList(expected)); + assertOrderedElementsAreEqual(actual, Arrays.asList(expected)); } protected void assertModuleOutput(String moduleName, String output, String testOutput) { diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/importing/FoldersImportingTest.java b/plugins/maven/src/test/java/org/jetbrains/idea/maven/importing/FoldersImportingTest.java index 28b6dfdbd835..254bff02c202 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/importing/FoldersImportingTest.java +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/importing/FoldersImportingTest.java @@ -321,7 +321,7 @@ public class FoldersImportingTest extends MavenImportingTestCase { resolveFoldersAndImport(); assertModules("project"); - assertSources("project", "src/main/java", "extraResources"); + assertSources("project", "extraResources", "src/main/java"); assertResources("project", "src/main/resources"); } @@ -361,7 +361,7 @@ public class FoldersImportingTest extends MavenImportingTestCase { resolveFoldersAndImport(); assertModules("project"); - assertTestSources("project", "src/test/java", "extraTestResources"); + assertTestSources("project", "extraTestResources", "src/test/java"); assertTestResources("project", "src/test/resources"); } @@ -399,7 +399,7 @@ public class FoldersImportingTest extends MavenImportingTestCase { resolveFoldersAndImport(); assertModules("project"); - assertSources("project", "src/main/java", "relativePath"); + assertSources("project", "relativePath", "src/main/java"); assertResources("project", "src/main/resources"); } @@ -500,7 +500,7 @@ public class FoldersImportingTest extends MavenImportingTestCase { assertModules("project", "m1", "m2"); resolveFoldersAndImport(); - assertSources("m1", "src/main/java", "src/foo"); + assertSources("m1", "src/foo", "src/main/java"); assertResources("m1", "src/main/resources"); } @@ -814,8 +814,8 @@ public class FoldersImportingTest extends MavenImportingTestCase { assertModules("project"); assertExcludes("project", - "targetCustom", "outputCustom", + "targetCustom", "testCustom"); assertModuleOutput("project", getProjectPath() + "/outputCustom", @@ -902,7 +902,7 @@ public class FoldersImportingTest extends MavenImportingTestCase { "project" + "1"); - assertExcludes("project", "target/foo", "target/bar"); + assertExcludes("project", "target/bar", "target/foo"); assertSources("project", "src/main/java", @@ -996,6 +996,74 @@ public class FoldersImportingTest extends MavenImportingTestCase { assertExcludes("project", "target/foo"); } + public void testSourceFoldersOrder() throws Exception { + createStdProjectFolders(); + + final VirtualFile target = createProjectSubDir("target"); + createProjectSubDirsWithFile("anno", + "target/generated-sources/foo", + "target/generated-sources/annotations", + "target/generated-sources/test-annotations", + "target/generated-test-sources/foo"); + + createProjectSubDir("test-anno"); + + importProject("test" + + "project" + + "1" + + + "" + + " " + + " " + + " org.apache.maven.plugins" + + " maven-compiler-plugin" + + " 2.3.2" + + " " + + " ${basedir}/anno" + + " ${basedir}/test-anno" + + " " + + " " + + " " + + ""); + + final Runnable testAssertions = new Runnable() { + @Override + public void run() { + assertSources("project", + "anno", + "src/main/java", + "target/generated-sources/annotations", + "target/generated-sources/foo", + "target/generated-sources/test-annotations"); + + assertResources("project", "src/main/resources"); + assertTestSources("project", + "src/test/java", + "target/generated-test-sources/foo"); + assertTestResources("project", "src/test/resources"); + } + }; + + testAssertions.run(); + + ApplicationManager.getApplication().runWriteAction(new Runnable() { + public void run() { + try { + target.delete(this); + } + catch (IOException e) { + fail("Unable to delete the file: " + e.getMessage()); + } + } + }); + + testAssertions.run(); + importProject(); + testAssertions.run(); + resolveFoldersAndImport(); + testAssertions.run(); + } + public void testUnexcludeNewSources() throws Exception { createProjectSubDirs("target/foo"); createProjectSubDirs("target/src"); @@ -1060,8 +1128,8 @@ public class FoldersImportingTest extends MavenImportingTestCase { assertSources("project", "src/main/java", - "target/generated-sources/foo", - "target/generated-sources/annotations"); + "target/generated-sources/annotations", + "target/generated-sources/foo"); assertResources("project", "src/main/resources"); assertTestSources("project", @@ -1100,10 +1168,10 @@ public class FoldersImportingTest extends MavenImportingTestCase { ""); assertSources("project", - "src/main/java", "anno", - "target/generated-sources/foo", + "src/main/java", "target/generated-sources/annotations", + "target/generated-sources/foo", "target/generated-sources/test-annotations"); assertResources("project", "src/main/resources"); diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/importing/GroovyImporterTest.java b/plugins/maven/src/test/java/org/jetbrains/idea/maven/importing/GroovyImporterTest.java index 0ba45198208a..b91b7f66f3e1 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/importing/GroovyImporterTest.java +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/importing/GroovyImporterTest.java @@ -92,12 +92,12 @@ public class GroovyImporterTest extends MavenImportingTestCase { assertModules("project"); assertSources("project", - "src/main/java", - "src/main/groovy"); + "src/main/groovy", + "src/main/java"); assertResources("project", "src/main/resources"); assertTestSources("project", - "src/test/java", - "src/test/groovy"); + "src/test/groovy", + "src/test/java"); assertTestResources("project", "src/test/resources"); } @@ -122,12 +122,12 @@ public class GroovyImporterTest extends MavenImportingTestCase { assertModules("project"); assertSources("project", - "src/main/java", - "src/main/groovy"); + "src/main/groovy", + "src/main/java"); assertResources("project", "src/main/resources"); assertTestSources("project", - "src/test/java", - "src/test/groovy"); + "src/test/groovy", + "src/test/java"); assertTestResources("project", "src/test/resources"); } @@ -185,12 +185,12 @@ public class GroovyImporterTest extends MavenImportingTestCase { assertModules("project"); assertSources("project", - "src/main/java", - "src/main/groovy"); + "src/main/groovy", + "src/main/java"); assertResources("project", "src/main/resources"); assertTestSources("project", - "src/test/java", - "src/test/groovy"); + "src/test/groovy", + "src/test/java"); assertTestResources("project", "src/test/resources"); } @@ -253,14 +253,14 @@ public class GroovyImporterTest extends MavenImportingTestCase { assertModules("project"); assertSources("project", - "src/main/java", "src/foo1", - "src/foo2"); + "src/foo2", + "src/main/java"); assertResources("project", "src/main/resources"); assertTestSources("project", - "src/test/java", "src/test-foo1", - "src/test-foo2"); + "src/test-foo2", + "src/test/java"); assertTestResources("project", "src/test/resources"); } @@ -406,8 +406,8 @@ public class GroovyImporterTest extends MavenImportingTestCase { assertTestResources("project", "src/test/resources"); assertExcludes("project", - "target/generated-sources/foo", - "target/generated-sources/bar"); + "target/generated-sources/bar", + "target/generated-sources/foo"); } public void testDoNotAddCustomGroovySpecificGeneratedSourcesByRelativePath() throws Exception { @@ -455,8 +455,8 @@ public class GroovyImporterTest extends MavenImportingTestCase { assertTestSources("project"); assertExcludes("project", - "target/generated-sources/foo", - "target/generated-sources/bar"); + "target/generated-sources/bar", + "target/generated-sources/foo"); } public void testUpdatingGroovySpecificGeneratedSourcesOnFoldersUpdate() throws Exception {