From 072ec2645203b5fac6189ae8978c90be50fd026a Mon Sep 17 00:00:00 2001 From: Sergey Mashkov Date: Mon, 4 Apr 2016 15:27:57 +0300 Subject: [PATCH] Maven: convert to Kotlin --- .../KotlinJavaMavenConfigurator.java | 64 ----- .../KotlinJavaMavenConfigurator.kt | 55 ++++ .../KotlinJavascriptMavenConfigurator.java | 71 ----- .../KotlinJavascriptMavenConfigurator.kt | 61 ++++ .../KotlinMavenConfigurator.java | 261 ------------------ .../configuration/KotlinMavenConfigurator.kt | 217 +++++++++++++++ .../KotlinMavenPluginPhaseInspection.kt | 11 +- .../inspections/SameVersionInspection.kt | 2 +- 8 files changed, 339 insertions(+), 403 deletions(-) delete mode 100644 idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/configuration/KotlinJavaMavenConfigurator.java create mode 100644 idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/configuration/KotlinJavaMavenConfigurator.kt delete mode 100644 idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/configuration/KotlinJavascriptMavenConfigurator.java create mode 100644 idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/configuration/KotlinJavascriptMavenConfigurator.kt delete mode 100644 idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/configuration/KotlinMavenConfigurator.java create mode 100644 idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/configuration/KotlinMavenConfigurator.kt diff --git a/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/configuration/KotlinJavaMavenConfigurator.java b/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/configuration/KotlinJavaMavenConfigurator.java deleted file mode 100644 index c81dc847187..00000000000 --- a/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/configuration/KotlinJavaMavenConfigurator.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2010-2016 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.kotlin.idea.maven.configuration; - -import com.intellij.openapi.module.Module; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.idea.maven.dom.model.MavenDomPlugin; -import org.jetbrains.kotlin.idea.configuration.ConfigureKotlinInProjectUtilsKt; -import org.jetbrains.kotlin.idea.maven.PomFile; -import org.jetbrains.kotlin.resolve.TargetPlatform; -import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform; - -public class KotlinJavaMavenConfigurator extends KotlinMavenConfigurator { - private static final String NAME = "maven"; - public static final String STD_LIB_ID = "kotlin-stdlib"; - public static final String TEST_LIB_ID = "kotlin-test"; - private static final String PRESENTABLE_TEXT = "Maven"; - - public KotlinJavaMavenConfigurator() { - super(STD_LIB_ID, TEST_LIB_ID, false, NAME, PRESENTABLE_TEXT); - } - - @Override - protected boolean isKotlinModule(@NotNull Module module) { - return ConfigureKotlinInProjectUtilsKt.hasKotlinJvmRuntimeInScope(module); - } - - @Override - protected boolean isRelevantGoal(@NotNull String goalName) { - return goalName.equals(PomFile.KotlinGoals.INSTANCE.getCompile()); - } - - @Override - protected void createExecutions(@NotNull PomFile pomFile, @NotNull MavenDomPlugin kotlinPlugin, @NotNull Module module) { - createExecution(pomFile, kotlinPlugin, module, false); - createExecution(pomFile, kotlinPlugin, module, true); - } - - @NotNull - @Override - protected String getGoal(boolean isTest) { - return isTest ? PomFile.KotlinGoals.INSTANCE.getTestCompile() : PomFile.KotlinGoals.INSTANCE.getCompile(); - } - - @NotNull - @Override - public TargetPlatform getTargetPlatform() { - return JvmPlatform.INSTANCE; - } -} diff --git a/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/configuration/KotlinJavaMavenConfigurator.kt b/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/configuration/KotlinJavaMavenConfigurator.kt new file mode 100644 index 00000000000..cb255728240 --- /dev/null +++ b/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/configuration/KotlinJavaMavenConfigurator.kt @@ -0,0 +1,55 @@ +/* + * Copyright 2010-2016 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.kotlin.idea.maven.configuration + +import com.intellij.openapi.module.Module +import org.jetbrains.idea.maven.dom.model.MavenDomPlugin +import org.jetbrains.kotlin.idea.configuration.* +import org.jetbrains.kotlin.idea.maven.PomFile +import org.jetbrains.kotlin.resolve.TargetPlatform +import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform + +class KotlinJavaMavenConfigurator : KotlinMavenConfigurator(KotlinJavaMavenConfigurator.STD_LIB_ID, KotlinJavaMavenConfigurator.TEST_LIB_ID, false, KotlinJavaMavenConfigurator.NAME, KotlinJavaMavenConfigurator.PRESENTABLE_TEXT) { + + override fun isKotlinModule(module: Module): Boolean { + return hasKotlinRuntimeInScope(module) + } + + override fun isRelevantGoal(goalName: String): Boolean { + return goalName == PomFile.KotlinGoals.Compile + } + + override fun createExecutions(pomFile: PomFile, kotlinPlugin: MavenDomPlugin, module: Module) { + createExecution(pomFile, kotlinPlugin, module, false) + createExecution(pomFile, kotlinPlugin, module, true) + } + + override fun getGoal(isTest: Boolean): String { + return if (isTest) PomFile.KotlinGoals.TestCompile else PomFile.KotlinGoals.Compile + } + + override fun getTargetPlatform(): TargetPlatform { + return JvmPlatform + } + + companion object { + private val NAME = "maven" + val STD_LIB_ID = "kotlin-stdlib" + val TEST_LIB_ID = "kotlin-test" + private val PRESENTABLE_TEXT = "Maven" + } +} diff --git a/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/configuration/KotlinJavascriptMavenConfigurator.java b/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/configuration/KotlinJavascriptMavenConfigurator.java deleted file mode 100644 index 153c5f4e3d0..00000000000 --- a/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/configuration/KotlinJavascriptMavenConfigurator.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2010-2016 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.kotlin.idea.maven.configuration; - -import com.intellij.openapi.module.Module; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.idea.maven.dom.model.MavenDomPlugin; -import org.jetbrains.kotlin.idea.maven.PomFile; -import org.jetbrains.kotlin.js.resolve.JsPlatform; -import org.jetbrains.kotlin.resolve.TargetPlatform; - -public class KotlinJavascriptMavenConfigurator extends KotlinMavenConfigurator { - private static final String NAME = "js maven"; - public static final String STD_LIB_ID = "kotlin-js-library"; - private static final String JS_GOAL = "js"; - private static final String JS_TEST_GOAL = "test-js"; - private static final String JS_EXECUTION_ID = "js"; - private static final String PRESENTABLE_TEXT = "JavaScript Maven - experimental"; - - public KotlinJavascriptMavenConfigurator() { - super(STD_LIB_ID, null, false, NAME, PRESENTABLE_TEXT); - } - - @Override - protected boolean isKotlinModule(@NotNull Module module) { - return ConfigureKotlinInProjectUtilsKt.hasKotlinJsRuntimeInScope(module); - } - - @Override - protected boolean isRelevantGoal(@NotNull String goalName) { - return goalName.equals(PomFile.KotlinGoals.INSTANCE.getJs()); - } - - @Override - protected void createExecutions(@NotNull PomFile pomFile, @NotNull MavenDomPlugin kotlinPlugin, @NotNull Module module) { - createExecution(pomFile, kotlinPlugin, module, false); - createExecution(pomFile, kotlinPlugin, module, true); - } - - @NotNull - @Override - protected String getExecutionId(boolean isTest) { - return JS_EXECUTION_ID + (isTest ? "-test" : ""); - } - - @NotNull - @Override - protected String getGoal(boolean isTest) { - return isTest ? JS_TEST_GOAL : JS_GOAL; - } - - @NotNull - @Override - public TargetPlatform getTargetPlatform() { - return JsPlatform.INSTANCE; - } -} diff --git a/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/configuration/KotlinJavascriptMavenConfigurator.kt b/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/configuration/KotlinJavascriptMavenConfigurator.kt new file mode 100644 index 00000000000..462fe097f66 --- /dev/null +++ b/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/configuration/KotlinJavascriptMavenConfigurator.kt @@ -0,0 +1,61 @@ +/* + * Copyright 2010-2016 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.kotlin.idea.maven.configuration + +import com.intellij.openapi.module.Module +import org.jetbrains.idea.maven.dom.model.MavenDomPlugin +import org.jetbrains.kotlin.idea.maven.PomFile +import org.jetbrains.kotlin.idea.project.ProjectStructureUtil +import org.jetbrains.kotlin.js.resolve.JsPlatform +import org.jetbrains.kotlin.resolve.TargetPlatform + +class KotlinJavascriptMavenConfigurator : KotlinMavenConfigurator(KotlinJavascriptMavenConfigurator.STD_LIB_ID, null, false, KotlinJavascriptMavenConfigurator.NAME, KotlinJavascriptMavenConfigurator.PRESENTABLE_TEXT) { + + override fun isKotlinModule(module: Module): Boolean { + return ProjectStructureUtil.isJsKotlinModule(module) + } + + override fun isRelevantGoal(goalName: String): Boolean { + return goalName == PomFile.KotlinGoals.Js + } + + override fun createExecutions(pomFile: PomFile, kotlinPlugin: MavenDomPlugin, module: Module) { + createExecution(pomFile, kotlinPlugin, module, false) + createExecution(pomFile, kotlinPlugin, module, true) + } + + override fun getExecutionId(isTest: Boolean): String { + return JS_EXECUTION_ID + if (isTest) "-test" else "" + } + + override fun getGoal(isTest: Boolean): String { + return if (isTest) JS_TEST_GOAL else JS_GOAL + } + + override fun getTargetPlatform(): TargetPlatform { + return JsPlatform + } + + companion object { + private val NAME = "js maven" + val STD_LIB_ID = "kotlin-js-library" + private val JS_GOAL = "js" + private val JS_TEST_GOAL = "test-js" + private val JS_EXECUTION_ID = "js" + private val PRESENTABLE_TEXT = "JavaScript Maven - experimental" + } +} diff --git a/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/configuration/KotlinMavenConfigurator.java b/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/configuration/KotlinMavenConfigurator.java deleted file mode 100644 index 7b50858b88d..00000000000 --- a/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/configuration/KotlinMavenConfigurator.java +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Copyright 2010-2016 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.kotlin.idea.maven.configuration; - -import com.intellij.codeInsight.CodeInsightUtilCore; -import com.intellij.ide.actions.OpenFileAction; -import com.intellij.ide.highlighter.JavaFileType; -import com.intellij.openapi.application.Result; -import com.intellij.openapi.command.WriteCommandAction; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleUtilCore; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.Messages; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.WritingAccessProvider; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiManager; -import com.intellij.psi.search.FileTypeIndex; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.xml.XmlFile; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.idea.maven.dom.MavenDomUtil; -import org.jetbrains.idea.maven.dom.model.MavenDomPlugin; -import org.jetbrains.idea.maven.dom.model.MavenDomProjectModel; -import org.jetbrains.idea.maven.model.MavenId; -import org.jetbrains.idea.maven.model.MavenPlugin; -import org.jetbrains.idea.maven.project.MavenProject; -import org.jetbrains.idea.maven.project.MavenProjectsManager; -import org.jetbrains.idea.maven.utils.MavenArtifactScope; -import org.jetbrains.kotlin.idea.KotlinPluginUtil; -import org.jetbrains.kotlin.idea.configuration.*; -import org.jetbrains.kotlin.idea.framework.ui.ConfigureDialogWithModulesAndVersion; -import org.jetbrains.kotlin.idea.maven.MavenModulesRelationshipKt; -import org.jetbrains.kotlin.idea.maven.PomFile; - -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -public abstract class KotlinMavenConfigurator implements KotlinProjectConfigurator { - public static final String NAME = "maven"; - - public static final String GROUP_ID = "org.jetbrains.kotlin"; - public static final String MAVEN_PLUGIN_ID = "kotlin-maven-plugin"; - private static final String KOTLIN_VERSION_PROPERTY = "kotlin.version"; - - private static final String TEST_COMPILE_EXECUTION_ID = "test-compile"; - private static final String COMPILE_EXECUTION_ID = "compile"; - - private final String stdlibArtifactId; - private final String testArtifactId; - private final boolean addJunit; - private final String name; - private final String presentableText; - - protected KotlinMavenConfigurator(@NotNull String stdlibArtifactId, @Nullable String testArtifactId, boolean addJunit, @NotNull String name, @NotNull String presentableText) { - this.stdlibArtifactId = stdlibArtifactId; - this.testArtifactId = testArtifactId; - this.addJunit = addJunit; - this.name = name; - this.presentableText = presentableText; - } - - @Override - public boolean isApplicable(@NotNull Module module) { - return KotlinPluginUtil.isMavenModule(module); - } - - @NotNull - @Override - public String getPresentableText() { - return presentableText; - } - - @NotNull - @Override - public String getName() { - return name; - } - - @Override - public boolean isConfigured(@NotNull Module module) { - if (!isKotlinModule(module)) { - return false; - } - - PsiFile psi = findModulePomFile(module); - if (psi == null - || !psi.isValid() - || !(psi instanceof XmlFile) - || psi.getVirtualFile() == null - || MavenDomUtil.getMavenDomProjectModel(module.getProject(), psi.getVirtualFile()) == null) { - return false; - } - - MavenProject mavenProject = MavenProjectsManager.getInstance(module.getProject()).findProject(module); - if (mavenProject == null) { - return false; - } - - MavenPlugin plugin = mavenProject.findPlugin(GROUP_ID, MAVEN_PLUGIN_ID); - if (plugin == null) { - return false; - } - - if (plugin.getExecutions() != null) { - for (MavenPlugin.Execution execution : plugin.getExecutions()) { - if (execution.getGoals() != null) { - for (String goal : execution.getGoals()) { - if (goal != null && isRelevantGoal(goal)) { - return true; - } - } - } - } - } - - return false; - } - - @Override - public void configure(@NotNull Project project, Collection excludeModules) { - ConfigureDialogWithModulesAndVersion dialog = - new ConfigureDialogWithModulesAndVersion(project, this, excludeModules); - - dialog.show(); - if (!dialog.isOK()) return; - - NotificationMessageCollector collector = NotificationMessageCollectorKt.createConfigureKotlinNotificationCollector(project); - for (Module module : MavenModulesRelationshipKt.excludeMavenChildrenModules(project, dialog.getModulesToConfigure())) { - PsiFile file = findModulePomFile(module); - if (file != null && canConfigureFile(file)) { - changePomFile(module, file, dialog.getKotlinVersion(), collector); - OpenFileAction.openFile(file.getVirtualFile(), project); - } - else { - showErrorMessage(project, "Cannot find pom.xml for module " + module.getName()); - } - } - collector.showNotification(); - } - - protected abstract boolean isKotlinModule(@NotNull Module module); - protected abstract boolean isRelevantGoal(@NotNull String goalName); - - protected abstract void createExecutions(@NotNull PomFile pomFile, @NotNull MavenDomPlugin kotlinPlugin, @NotNull Module module); - - @NotNull - protected abstract String getGoal(boolean isTest); - - @NotNull - protected String getExecutionId(boolean isTest) { - return isTest ? TEST_COMPILE_EXECUTION_ID : COMPILE_EXECUTION_ID; - } - - protected void changePomFile( - @NotNull final Module module, - final @NotNull PsiFile file, - @NotNull final String version, - @NotNull NotificationMessageCollector collector - ) { - VirtualFile virtualFile = file.getVirtualFile(); - assert virtualFile != null : "Virtual file should exists for psi file " + file.getName(); - MavenDomProjectModel domModel = MavenDomUtil.getMavenDomProjectModel(module.getProject(), virtualFile); - if (domModel == null) { - showErrorMessage(module.getProject(), null); - return; - } - - new WriteCommandAction(file.getProject()) { - @Override - protected void run(@NotNull Result result) { - PomFile pom = new PomFile((XmlFile) file); - pom.addProperty(KOTLIN_VERSION_PROPERTY, version); - - pom.addDependency(new MavenId(GROUP_ID, stdlibArtifactId, "${" + KOTLIN_VERSION_PROPERTY + "}"), MavenArtifactScope.COMPILE, null, false, null); - if (testArtifactId != null) { - pom.addDependency(new MavenId(GROUP_ID, testArtifactId, "${" + KOTLIN_VERSION_PROPERTY + "}"), MavenArtifactScope.TEST, null, false, null); - } - if (addJunit) { - pom.addDependency(new MavenId("junit", "junit", "4.12"), MavenArtifactScope.TEST, null, false, null); - } - - if (isSnapshot(version)) { - pom.addLibraryRepository(ConfigureKotlinInProjectUtilsKt.SNAPSHOT_REPOSITORY, true, false); - pom.addPluginRepository(ConfigureKotlinInProjectUtilsKt.SNAPSHOT_REPOSITORY, true, false); - } - if (ConfigureKotlinInProjectUtilsKt.isEap(version)) { - pom.addLibraryRepository(ConfigureKotlinInProjectUtilsKt.EAP_REPOSITORY, true, false); - pom.addPluginRepository(ConfigureKotlinInProjectUtilsKt.EAP_REPOSITORY, true, false); - } - - MavenDomPlugin plugin = pom.addPlugin(new MavenId(GROUP_ID, MAVEN_PLUGIN_ID, "${" + KOTLIN_VERSION_PROPERTY + "}")); - createExecutions(pom, plugin, module); - - CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(file); - } - }.execute(); - - collector.addMessage(virtualFile.getPath() + " was modified"); - } - - protected void createExecution( - @NotNull PomFile pomFile, - @NotNull MavenDomPlugin kotlinPlugin, - @NotNull Module module, - boolean isTest - ) { - pomFile.addKotlinExecution(module, kotlinPlugin, getExecutionId(isTest), PomFile.Companion.getPhase(hasJavaFiles(module), isTest), isTest, - Collections.singletonList(getGoal(isTest))); - } - - private static boolean hasJavaFiles(@NotNull Module module) { - return !FileTypeIndex.getFiles(JavaFileType.INSTANCE, GlobalSearchScope.moduleScope(module)).isEmpty(); - } - - @Nullable - private static PsiFile findModulePomFile(@NotNull Module module) { - List files = MavenProjectsManager.getInstance(module.getProject()).getProjectsFiles(); - for (VirtualFile file : files) { - Module fileModule = ModuleUtilCore.findModuleForFile(file, module.getProject()); - if (!module.equals(fileModule)) continue; - PsiFile psiFile = PsiManager.getInstance(module.getProject()).findFile(file); - if (psiFile == null) continue; - if (!MavenDomUtil.isProjectFile(psiFile)) continue; - return psiFile; - } - return null; - } - - private static boolean isSnapshot(@NotNull String version) { - return version.contains("SNAPSHOT"); - } - - private static boolean canConfigureFile(@NotNull PsiFile file) { - return WritingAccessProvider.isPotentiallyWritable(file.getVirtualFile(), null); - } - - private static void showErrorMessage(@NotNull Project project, @Nullable String message) { - Messages.showErrorDialog(project, - "Couldn't configure kotlin-maven plugin automatically.
" + - (message != null ? message : "") + - "See manual installation instructions here", - "Configure Kotlin-Maven Plugin"); - } -} diff --git a/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/configuration/KotlinMavenConfigurator.kt b/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/configuration/KotlinMavenConfigurator.kt new file mode 100644 index 00000000000..baded41847f --- /dev/null +++ b/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/configuration/KotlinMavenConfigurator.kt @@ -0,0 +1,217 @@ +/* + * Copyright 2010-2016 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.kotlin.idea.maven.configuration + +import com.intellij.codeInsight.CodeInsightUtilCore +import com.intellij.ide.actions.OpenFileAction +import com.intellij.ide.highlighter.JavaFileType +import com.intellij.openapi.command.WriteCommandAction +import com.intellij.openapi.module.Module +import com.intellij.openapi.module.ModuleUtilCore +import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.Messages +import com.intellij.openapi.vfs.WritingAccessProvider +import com.intellij.psi.PsiFile +import com.intellij.psi.PsiManager +import com.intellij.psi.search.FileTypeIndex +import com.intellij.psi.search.GlobalSearchScope +import com.intellij.psi.xml.XmlFile +import org.jetbrains.idea.maven.dom.MavenDomUtil +import org.jetbrains.idea.maven.dom.model.MavenDomPlugin +import org.jetbrains.idea.maven.model.MavenId +import org.jetbrains.idea.maven.project.MavenProjectsManager +import org.jetbrains.idea.maven.utils.MavenArtifactScope +import org.jetbrains.kotlin.idea.KotlinPluginUtil +import org.jetbrains.kotlin.idea.configuration.KotlinProjectConfigurator +import org.jetbrains.kotlin.idea.configuration.NotificationMessageCollector +import org.jetbrains.kotlin.idea.configuration.createConfigureKotlinNotificationCollector +import org.jetbrains.kotlin.idea.framework.ui.ConfigureDialogWithModulesAndVersion +import org.jetbrains.kotlin.idea.maven.PomFile +import org.jetbrains.kotlin.idea.maven.excludeMavenChildrenModules + +abstract class KotlinMavenConfigurator protected constructor(private val stdlibArtifactId: String, private val testArtifactId: String?, private val addJunit: Boolean, private val name: String, private val presentableText: String) : KotlinProjectConfigurator { + + override fun isApplicable(module: Module): Boolean { + return KotlinPluginUtil.isMavenModule(module) + } + + override fun getPresentableText(): String { + return presentableText + } + + override fun getName(): String { + return name + } + + override fun isConfigured(module: Module): Boolean { + if (!isKotlinModule(module)) { + return false + } + + val psi = findModulePomFile(module) + if (psi == null + || !psi.isValid + || psi !is XmlFile + || psi.virtualFile == null + || MavenDomUtil.getMavenDomProjectModel(module.project, psi.virtualFile) == null) { + return false + } + + val mavenProject = MavenProjectsManager.getInstance(module.project).findProject(module) ?: return false + + val plugin = mavenProject.findPlugin(GROUP_ID, MAVEN_PLUGIN_ID) ?: return false + + if (plugin.executions != null) { + for (execution in plugin.executions) { + if (execution.goals != null) { + for (goal in execution.goals) { + if (goal != null && isRelevantGoal(goal)) { + return true + } + } + } + } + } + + return false + } + + override fun configure(project: Project, excludeModules: Collection) { + val dialog = ConfigureDialogWithModulesAndVersion(project, this, excludeModules) + + dialog.show() + if (!dialog.isOK) return + + val collector = createConfigureKotlinNotificationCollector(project) + for (module in excludeMavenChildrenModules(project, dialog.modulesToConfigure)) { + val file = findModulePomFile(module) + if (file != null && canConfigureFile(file)) { + changePomFile(module, file, dialog.kotlinVersion, collector) + OpenFileAction.openFile(file.virtualFile, project) + } + else { + showErrorMessage(project, "Cannot find pom.xml for module " + module.name) + } + } + collector.showNotification() + } + + protected abstract fun isKotlinModule(module: Module): Boolean + protected abstract fun isRelevantGoal(goalName: String): Boolean + + protected abstract fun createExecutions(pomFile: PomFile, kotlinPlugin: MavenDomPlugin, module: Module) + + protected abstract fun getGoal(isTest: Boolean): String + + protected open fun getExecutionId(isTest: Boolean): String { + return if (isTest) TEST_COMPILE_EXECUTION_ID else COMPILE_EXECUTION_ID + } + + fun changePomFile( + module: Module, + file: PsiFile, + version: String, + collector: NotificationMessageCollector) { + + val virtualFile = file.virtualFile ?: error("Virtual file should exists for psi file " + file.name) + val domModel = MavenDomUtil.getMavenDomProjectModel(module.project, virtualFile) + if (domModel == null) { + showErrorMessage(module.project, null) + return + } + + WriteCommandAction.runWriteCommandAction(module.project) { + val pom = PomFile(file as XmlFile) + pom.addProperty(KOTLIN_VERSION_PROPERTY, version) + + pom.addDependency(MavenId(GROUP_ID, stdlibArtifactId, "\${$KOTLIN_VERSION_PROPERTY}"), MavenArtifactScope.COMPILE, null, false, null) + if (testArtifactId != null) { + pom.addDependency(MavenId(GROUP_ID, testArtifactId, "\${$KOTLIN_VERSION_PROPERTY}"), MavenArtifactScope.TEST, null, false, null) + } + if (addJunit) { + pom.addDependency(MavenId("junit", "junit", "4.12"), MavenArtifactScope.TEST, null, false, null) + } + + if (isSnapshot(version)) { + pom.addLibraryRepository(SNAPSHOT_REPOSITORY_ID, SONATYPE_OSS_REPOSITORY_NAME, SONATYPE_OSS_REPOSITORY_URL, true, false) + pom.addPluginRepository(SNAPSHOT_REPOSITORY_ID, SONATYPE_OSS_REPOSITORY_NAME, SONATYPE_OSS_REPOSITORY_URL, true, false) + } + + val plugin = pom.addPlugin(MavenId(GROUP_ID, MAVEN_PLUGIN_ID, "\${$KOTLIN_VERSION_PROPERTY}")) + createExecutions(pom, plugin, module) + + CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(file) + } + + collector.addMessage(virtualFile.path + " was modified") + } + + protected fun createExecution( + pomFile: PomFile, + kotlinPlugin: MavenDomPlugin, + module: Module, + isTest: Boolean) { + pomFile.addKotlinExecution(module, kotlinPlugin, getExecutionId(isTest), PomFile.getPhase(hasJavaFiles(module), isTest), isTest, + listOf(getGoal(isTest))) + } + + companion object { + val NAME = "maven" + + val GROUP_ID = "org.jetbrains.kotlin" + val MAVEN_PLUGIN_ID = "kotlin-maven-plugin" + private val KOTLIN_VERSION_PROPERTY = "kotlin.version" + private val SNAPSHOT_REPOSITORY_ID = "sonatype.oss.snapshots" + private val SONATYPE_OSS_REPOSITORY_NAME = "Sonatype OSS Snapshot Repository" + private val SONATYPE_OSS_REPOSITORY_URL = "http://oss.sonatype.org/content/repositories/snapshots" + + private val TEST_COMPILE_EXECUTION_ID = "test-compile" + private val COMPILE_EXECUTION_ID = "compile" + + private fun hasJavaFiles(module: Module): Boolean { + return !FileTypeIndex.getFiles(JavaFileType.INSTANCE, GlobalSearchScope.moduleScope(module)).isEmpty() + } + + private fun findModulePomFile(module: Module): PsiFile? { + val files = MavenProjectsManager.getInstance(module.project).projectsFiles + for (file in files) { + val fileModule = ModuleUtilCore.findModuleForFile(file, module.project) + if (module != fileModule) continue + val psiFile = PsiManager.getInstance(module.project).findFile(file) ?: continue + if (!MavenDomUtil.isProjectFile(psiFile)) continue + return psiFile + } + return null + } + + private fun isSnapshot(version: String): Boolean { + return version.contains("SNAPSHOT") + } + + private fun canConfigureFile(file: PsiFile): Boolean { + return WritingAccessProvider.isPotentiallyWritable(file.virtualFile, null) + } + + private fun showErrorMessage(project: Project, message: String?) { + Messages.showErrorDialog(project, + "Couldn't configure kotlin-maven plugin automatically.
" + + (message ?: "") + + "See manual installation instructions here", + "Configure Kotlin-Maven Plugin") + } + } +} diff --git a/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/inspections/KotlinMavenPluginPhaseInspection.kt b/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/inspections/KotlinMavenPluginPhaseInspection.kt index 2940ff5c7ab..ee7d2af3934 100644 --- a/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/inspections/KotlinMavenPluginPhaseInspection.kt +++ b/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/inspections/KotlinMavenPluginPhaseInspection.kt @@ -36,7 +36,6 @@ import org.jetbrains.idea.maven.model.MavenId import org.jetbrains.idea.maven.model.MavenPlugin import org.jetbrains.idea.maven.project.MavenProjectsManager import org.jetbrains.idea.maven.utils.MavenArtifactScope -import org.jetbrains.kotlin.idea.KotlinFileType import org.jetbrains.kotlin.idea.maven.PomFile import org.jetbrains.kotlin.idea.maven.configuration.KotlinJavaMavenConfigurator import org.jetbrains.kotlin.idea.maven.configuration.KotlinJavascriptMavenConfigurator @@ -99,8 +98,8 @@ class KotlinMavenPluginPhaseInspection : DomElementsInspection holder.createProblem(dep.artifactId.createStableCopy(), @@ -127,7 +126,7 @@ class KotlinMavenPluginPhaseInspection : DomElementsInspection holder.createProblem(dep.artifactId.createStableCopy(), @@ -175,7 +174,7 @@ class KotlinMavenPluginPhaseInspection : DomElementsInspection(MavenD "Plugin version (${plugin.version}) is not the same as library version (${stdlibVersion.joinToString(",", "", "")})") } - pomFile.findDependencies(MavenId(KotlinJavaMavenConfigurator.GROUP_ID, KotlinJavaMavenConfigurator.STD_LIB_ID, null)) + pomFile.findDependencies(MavenId(KotlinMavenConfigurator.GROUP_ID, KotlinJavaMavenConfigurator.STD_LIB_ID, null)) .filter { it.version.stringValue != pluginVersion } .forEach { dependency -> holder.createProblem(dependency.version, HighlightSeverity.WARNING, "Plugin version ($pluginVersion) is not the same as library version (${dependency.version})")