Reformat and cleanup idea-maven_main module

This commit is contained in:
Nikolay Krasko
2018-01-17 18:39:29 +03:00
parent 7f1cc81d39
commit 4a2440ea0f
23 changed files with 2059 additions and 1788 deletions
+1
View File
@@ -2,6 +2,7 @@
<dictionary name="Nikolay.Krasko"> <dictionary name="Nikolay.Krasko">
<words> <words>
<w>accessors</w> <w>accessors</w>
<w>coroutines</w>
<w>crossinline</w> <w>crossinline</w>
<w>fqname</w> <w>fqname</w>
<w>goto</w> <w>goto</w>
@@ -29,10 +29,36 @@ import java.net.HttpURLConnection
import java.net.URLEncoder import java.net.URLEncoder
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
class KotlinMavenArchetypesProvider(val kotlinPluginVersion: String, val predefinedInternalMode: Boolean?) : MavenArchetypesProvider { class KotlinMavenArchetypesProvider(private val kotlinPluginVersion: String, private val predefinedInternalMode: Boolean?) :
MavenArchetypesProvider {
@Suppress("unused")
constructor() : this(KotlinPluginUtil.getPluginVersion(), null) constructor() : this(KotlinPluginUtil.getPluginVersion(), null)
val VERSIONS_LIST_URL = mavenSearchUrl("org.jetbrains.kotlin", packaging = "maven-archetype", rowsLimit = 1000) companion object {
private val VERSIONS_LIST_URL = mavenSearchUrl("org.jetbrains.kotlin", packaging = "maven-archetype", rowsLimit = 1000)
private fun mavenSearchUrl(
group: String,
artifactId: String? = null,
version: String? = null,
packaging: String? = null,
rowsLimit: Int = 20
): String {
val q = listOf(
"g" to group,
"a" to artifactId,
"v" to version,
"p" to packaging
)
.filter { it.second != null }.joinToString(separator = " AND ") { "${it.first}:\"${it.second}\"" }
return "http://search.maven.org/solrsearch/select?q=${q.encodeURL()}&core=gav&rows=$rowsLimit&wt=json"
}
private fun String.encodeURL() = URLEncoder.encode(this, "UTF-8")
}
private val versionPrefix by lazy { versionPrefix(kotlinPluginVersion) } private val versionPrefix by lazy { versionPrefix(kotlinPluginVersion) }
private val fallbackVersion = "1.0.3" private val fallbackVersion = "1.0.3"
private val internalMode: Boolean private val internalMode: Boolean
@@ -41,8 +67,7 @@ class KotlinMavenArchetypesProvider(val kotlinPluginVersion: String, val predefi
private val archetypesBlocking by lazy { private val archetypesBlocking by lazy {
try { try {
loadVersions().ifEmpty { fallbackArchetypes() } loadVersions().ifEmpty { fallbackArchetypes() }
} } catch (t: Throwable) {
catch (t: Throwable) {
fallbackArchetypes() fallbackArchetypes()
} }
} }
@@ -50,8 +75,8 @@ class KotlinMavenArchetypesProvider(val kotlinPluginVersion: String, val predefi
override fun getArchetypes() = archetypesBlocking.toMutableList() override fun getArchetypes() = archetypesBlocking.toMutableList()
private fun fallbackArchetypes() = private fun fallbackArchetypes() =
listOf("kotlin-archetype-jvm", "kotlin-archetype-js") listOf("kotlin-archetype-jvm", "kotlin-archetype-js")
.map { MavenArchetype("org.jetbrains.kotlin", it, fallbackVersion, null, null) } .map { MavenArchetype("org.jetbrains.kotlin", it, fallbackVersion, null, null) }
private fun loadVersions(): List<MavenArchetype> { private fun loadVersions(): List<MavenArchetype> {
return connectAndApply(VERSIONS_LIST_URL) { urlConnection -> return connectAndApply(VERSIONS_LIST_URL) { urlConnection ->
@@ -62,39 +87,27 @@ class KotlinMavenArchetypesProvider(val kotlinPluginVersion: String, val predefi
} }
internal fun extractVersions(root: JsonElement) = internal fun extractVersions(root: JsonElement) =
root.asJsonObject.get("response") root.asJsonObject.get("response")
.asJsonObject.get("docs") .asJsonObject.get("docs")
.asJsonArray .asJsonArray
.map { it.asJsonObject } .map { it.asJsonObject }
.map { MavenArchetype(it.get("g").asString, it.get("a").asString, it.get("v").asString, null, null) } .map { MavenArchetype(it.get("g").asString, it.get("a").asString, it.get("v").asString, null, null) }
.let { versions -> .let { versions ->
val prefix = versionPrefix val prefix = versionPrefix
when { when {
internalMode || prefix == null -> versions internalMode || prefix == null -> versions
else -> versions.filter { it.version?.startsWith(prefix) ?: false }.ifEmpty { versions } else -> versions.filter { it.version?.startsWith(prefix) ?: false }.ifEmpty { versions }
} }
.groupBy { it.groupId + ":" + it.artifactId + ":" + versionPrefix(it.version) } .groupBy { it.groupId + ":" + it.artifactId + ":" + versionPrefix(it.version) }
.mapValues { chooseVersion(it.value) } .mapValues { chooseVersion(it.value) }
.mapNotNull { it.value } .mapNotNull { it.value }
} }
private fun chooseVersion(versions: List<MavenArchetype>): MavenArchetype? { private fun chooseVersion(versions: List<MavenArchetype>): MavenArchetype? {
return versions.maxBy { MavenVersionComparable(it.version) } return versions.maxBy { MavenVersionComparable(it.version) }
} }
private fun mavenSearchUrl(group: String, artifactId: String? = null, version: String? = null, packaging: String? = null, rowsLimit: Int = 20): String {
val q = listOf(
"g" to group,
"a" to artifactId,
"v" to version,
"p" to packaging
)
.filter { it.second != null }.joinToString(separator = " AND ") { "${it.first}:\"${it.second}\"" }
return "http://search.maven.org/solrsearch/select?q=${q.encodeURL()}&core=gav&rows=$rowsLimit&wt=json"
}
private fun <R> connectAndApply(url: String, timeoutSeconds: Int = 15, block: (HttpURLConnection) -> R): R { private fun <R> connectAndApply(url: String, timeoutSeconds: Int = 15, block: (HttpURLConnection) -> R): R {
return HttpConfigurable.getInstance().openHttpConnection(url).use { urlConnection -> return HttpConfigurable.getInstance().openHttpConnection(url).use { urlConnection ->
val timeout = TimeUnit.SECONDS.toMillis(timeoutSeconds.toLong()).toInt() val timeout = TimeUnit.SECONDS.toMillis(timeoutSeconds.toLong()).toInt()
@@ -107,14 +120,11 @@ class KotlinMavenArchetypesProvider(val kotlinPluginVersion: String, val predefi
} }
private fun <R> HttpURLConnection.use(block: (HttpURLConnection) -> R): R = private fun <R> HttpURLConnection.use(block: (HttpURLConnection) -> R): R =
try { try {
block(this) block(this)
} } finally {
finally { disconnect()
disconnect() }
}
private fun String.encodeURL() = URLEncoder.encode(this, "UTF-8")
private fun versionPrefix(version: String) = """^\d+\.\d+\.""".toRegex().find(version)?.value private fun versionPrefix(version: String) = """^\d+\.\d+\.""".toRegex().find(version)?.value
} }
@@ -53,8 +53,8 @@ import java.util.*
interface MavenProjectImportHandler { interface MavenProjectImportHandler {
companion object : ProjectExtensionDescriptor<MavenProjectImportHandler>( companion object : ProjectExtensionDescriptor<MavenProjectImportHandler>(
"org.jetbrains.kotlin.mavenProjectImportHandler", "org.jetbrains.kotlin.mavenProjectImportHandler",
MavenProjectImportHandler::class.java MavenProjectImportHandler::class.java
) )
operator fun invoke(facet: KotlinFacet, mavenProject: MavenProject) operator fun invoke(facet: KotlinFacet, mavenProject: MavenProject)
@@ -62,30 +62,42 @@ interface MavenProjectImportHandler {
class KotlinMavenImporter : MavenImporter(KOTLIN_PLUGIN_GROUP_ID, KOTLIN_PLUGIN_ARTIFACT_ID) { class KotlinMavenImporter : MavenImporter(KOTLIN_PLUGIN_GROUP_ID, KOTLIN_PLUGIN_ARTIFACT_ID) {
companion object { companion object {
val KOTLIN_PLUGIN_GROUP_ID = "org.jetbrains.kotlin" const val KOTLIN_PLUGIN_GROUP_ID = "org.jetbrains.kotlin"
val KOTLIN_PLUGIN_ARTIFACT_ID = "kotlin-maven-plugin" const val KOTLIN_PLUGIN_ARTIFACT_ID = "kotlin-maven-plugin"
val KOTLIN_PLUGIN_SOURCE_DIRS_CONFIG = "sourceDirs" const val KOTLIN_PLUGIN_SOURCE_DIRS_CONFIG = "sourceDirs"
} }
override fun preProcess(module: Module, mavenProject: MavenProject, changes: MavenProjectChanges, modifiableModelsProvider: IdeModifiableModelsProvider) { override fun preProcess(
module: Module,
mavenProject: MavenProject,
changes: MavenProjectChanges,
modifiableModelsProvider: IdeModifiableModelsProvider
) {
} }
override fun process(modifiableModelsProvider: IdeModifiableModelsProvider, override fun process(
module: Module, modifiableModelsProvider: IdeModifiableModelsProvider,
rootModel: MavenRootModelAdapter, module: Module,
mavenModel: MavenProjectsTree, rootModel: MavenRootModelAdapter,
mavenProject: MavenProject, mavenModel: MavenProjectsTree,
changes: MavenProjectChanges, mavenProject: MavenProject,
mavenProjectToModuleName: MutableMap<MavenProject, String>, changes: MavenProjectChanges,
postTasks: MutableList<MavenProjectsProcessorTask>) { mavenProjectToModuleName: MutableMap<MavenProject, String>,
postTasks: MutableList<MavenProjectsProcessorTask>
) {
if (changes.plugins) { if (changes.plugins) {
contributeSourceDirectories(mavenProject, module, rootModel) contributeSourceDirectories(mavenProject, module, rootModel)
} }
} }
override fun postProcess(module: Module, mavenProject: MavenProject, changes: MavenProjectChanges, modifiableModelsProvider: IdeModifiableModelsProvider) { override fun postProcess(
module: Module,
mavenProject: MavenProject,
changes: MavenProjectChanges,
modifiableModelsProvider: IdeModifiableModelsProvider
) {
super.postProcess(module, mavenProject, changes, modifiableModelsProvider) super.postProcess(module, mavenProject, changes, modifiableModelsProvider)
if (changes.dependencies) { if (changes.dependencies) {
@@ -108,7 +120,8 @@ class KotlinMavenImporter : MavenImporter(KOTLIN_PLUGIN_GROUP_ID, KOTLIN_PLUGIN_
private fun scheduleDownloadStdlibSources(mavenProject: MavenProject, module: Module) { private fun scheduleDownloadStdlibSources(mavenProject: MavenProject, module: Module) {
// TODO: here we have to process all kotlin libraries but for now we only handle standard libraries // TODO: here we have to process all kotlin libraries but for now we only handle standard libraries
val artifacts = mavenProject.dependencyArtifactIndex.data[KOTLIN_PLUGIN_GROUP_ID]?.values?.flatMap { it.filter { it.isResolved } } ?: emptyList() val artifacts = mavenProject.dependencyArtifactIndex.data[KOTLIN_PLUGIN_GROUP_ID]?.values?.flatMap { it.filter { it.isResolved } }
?: emptyList()
val librariesWithNoSources = ArrayList<Library>() val librariesWithNoSources = ArrayList<Library>()
OrderEnumerator.orderEntries(module).forEachLibrary { library -> OrderEnumerator.orderEntries(module).forEachLibrary { library ->
@@ -121,21 +134,26 @@ class KotlinMavenImporter : MavenImporter(KOTLIN_PLUGIN_GROUP_ID, KOTLIN_PLUGIN_
val toBeDownloaded = artifacts.filter { it.libraryName in libraryNames } val toBeDownloaded = artifacts.filter { it.libraryName in libraryNames }
if (toBeDownloaded.isNotEmpty()) { if (toBeDownloaded.isNotEmpty()) {
MavenProjectsManager.getInstance(module.project).scheduleArtifactsDownloading(listOf(mavenProject), toBeDownloaded, true, false, AsyncResult()) MavenProjectsManager.getInstance(module.project)
.scheduleArtifactsDownloading(listOf(mavenProject), toBeDownloaded, true, false, AsyncResult())
} }
} }
private fun getCompilerArgumentsByConfigurationElement(mavenProject: MavenProject, private fun getCompilerArgumentsByConfigurationElement(
configuration: Element?, mavenProject: MavenProject,
platform: TargetPlatformKind<*>): List<String> { configuration: Element?,
platform: TargetPlatformKind<*>
): List<String> {
val arguments = when (platform) { val arguments = when (platform) {
is TargetPlatformKind.Jvm -> K2JVMCompilerArguments() is TargetPlatformKind.Jvm -> K2JVMCompilerArguments()
is TargetPlatformKind.JavaScript -> K2JSCompilerArguments() TargetPlatformKind.JavaScript -> K2JSCompilerArguments()
is TargetPlatformKind.Common -> K2MetadataCompilerArguments() TargetPlatformKind.Common -> K2MetadataCompilerArguments()
} }
arguments.apiVersion = configuration?.getChild("apiVersion")?.text ?: mavenProject.properties["kotlin.compiler.apiVersion"]?.toString() arguments.apiVersion = configuration?.getChild("apiVersion")?.text ?:
arguments.languageVersion = configuration?.getChild("languageVersion")?.text ?: mavenProject.properties["kotlin.compiler.languageVersion"]?.toString() mavenProject.properties["kotlin.compiler.apiVersion"]?.toString()
arguments.languageVersion = configuration?.getChild("languageVersion")?.text ?:
mavenProject.properties["kotlin.compiler.languageVersion"]?.toString()
arguments.multiPlatform = configuration?.getChild("multiPlatform")?.text?.trim()?.toBoolean() ?: false arguments.multiPlatform = configuration?.getChild("multiPlatform")?.text?.trim()?.toBoolean() ?: false
arguments.suppressWarnings = configuration?.getChild("nowarn")?.text?.trim()?.toBoolean() ?: false arguments.suppressWarnings = configuration?.getChild("nowarn")?.text?.trim()?.toBoolean() ?: false
@@ -147,7 +165,8 @@ class KotlinMavenImporter : MavenImporter(KOTLIN_PLUGIN_GROUP_ID, KOTLIN_PLUGIN_
is K2JVMCompilerArguments -> { is K2JVMCompilerArguments -> {
arguments.classpath = configuration?.getChild("classpath")?.text arguments.classpath = configuration?.getChild("classpath")?.text
arguments.jdkHome = configuration?.getChild("jdkHome")?.text arguments.jdkHome = configuration?.getChild("jdkHome")?.text
arguments.jvmTarget = configuration?.getChild("jvmTarget")?.text ?: mavenProject.properties["kotlin.compiler.jvmTarget"]?.toString() arguments.jvmTarget = configuration?.getChild("jvmTarget")?.text ?:
mavenProject.properties["kotlin.compiler.jvmTarget"]?.toString()
} }
is K2JSCompilerArguments -> { is K2JSCompilerArguments -> {
arguments.sourceMap = configuration?.getChild("sourceMap")?.text?.trim()?.toBoolean() ?: false arguments.sourceMap = configuration?.getChild("sourceMap")?.text?.trim()?.toBoolean() ?: false
@@ -181,11 +200,13 @@ class KotlinMavenImporter : MavenImporter(KOTLIN_PLUGIN_GROUP_ID, KOTLIN_PLUGIN_
return ArgumentUtils.convertArgumentsToStringList(arguments) return ArgumentUtils.convertArgumentsToStringList(arguments)
} }
private val compilationGoals = listOf(PomFile.KotlinGoals.Compile, private val compilationGoals = listOf(
PomFile.KotlinGoals.TestCompile, PomFile.KotlinGoals.Compile,
PomFile.KotlinGoals.Js, PomFile.KotlinGoals.TestCompile,
PomFile.KotlinGoals.TestJs, PomFile.KotlinGoals.Js,
PomFile.KotlinGoals.MetaData) PomFile.KotlinGoals.TestJs,
PomFile.KotlinGoals.MetaData
)
private fun configureFacet(mavenProject: MavenProject, modifiableModelsProvider: IdeModifiableModelsProvider, module: Module) { private fun configureFacet(mavenProject: MavenProject, modifiableModelsProvider: IdeModifiableModelsProvider, module: Module) {
val mavenPlugin = mavenProject.findPlugin(KotlinMavenConfigurator.GROUP_ID, KotlinMavenConfigurator.MAVEN_PLUGIN_ID) ?: return val mavenPlugin = mavenProject.findPlugin(KotlinMavenConfigurator.GROUP_ID, KotlinMavenConfigurator.MAVEN_PLUGIN_ID) ?: return
@@ -197,9 +218,9 @@ class KotlinMavenImporter : MavenImporter(KOTLIN_PLUGIN_GROUP_ID, KOTLIN_PLUGIN_
val configuredPlatform = kotlinFacet.configuration.settings.targetPlatformKind!! val configuredPlatform = kotlinFacet.configuration.settings.targetPlatformKind!!
val configuration = mavenPlugin.configurationElement val configuration = mavenPlugin.configurationElement
val sharedArguments = getCompilerArgumentsByConfigurationElement(mavenProject, configuration, configuredPlatform) val sharedArguments = getCompilerArgumentsByConfigurationElement(mavenProject, configuration, configuredPlatform)
val executionArguments = mavenPlugin.executions?.filter { it.goals.any { it in compilationGoals } } val executionArguments = mavenPlugin.executions
?.firstOrNull() ?.firstOrNull { it.goals.any { it in compilationGoals } }
?.configurationElement?.let { getCompilerArgumentsByConfigurationElement(mavenProject, it, configuredPlatform) } ?.configurationElement?.let { getCompilerArgumentsByConfigurationElement(mavenProject, it, configuredPlatform) }
parseCompilerArgumentsToFacet(sharedArguments, emptyList(), kotlinFacet, modifiableModelsProvider) parseCompilerArgumentsToFacet(sharedArguments, emptyList(), kotlinFacet, modifiableModelsProvider)
if (executionArguments != null) { if (executionArguments != null) {
parseCompilerArgumentsToFacet(executionArguments, emptyList(), kotlinFacet, modifiableModelsProvider) parseCompilerArgumentsToFacet(executionArguments, emptyList(), kotlinFacet, modifiableModelsProvider)
@@ -209,18 +230,19 @@ class KotlinMavenImporter : MavenImporter(KOTLIN_PLUGIN_GROUP_ID, KOTLIN_PLUGIN_
kotlinFacet.noVersionAutoAdvance() kotlinFacet.noVersionAutoAdvance()
} }
private fun detectPlatform(mavenProject: MavenProject) = detectPlatformByExecutions(mavenProject) ?: private fun detectPlatform(mavenProject: MavenProject) =
detectPlatformByLibraries(mavenProject) detectPlatformByExecutions(mavenProject) ?: detectPlatformByLibraries(mavenProject)
private fun detectPlatformByExecutions(mavenProject: MavenProject): TargetPlatformKind<*>? { private fun detectPlatformByExecutions(mavenProject: MavenProject): TargetPlatformKind<*>? {
return mavenProject.findPlugin(KOTLIN_PLUGIN_GROUP_ID, KOTLIN_PLUGIN_ARTIFACT_ID)?.executions?.flatMap { it.goals }?.mapNotNull { goal -> return mavenProject.findPlugin(KOTLIN_PLUGIN_GROUP_ID, KOTLIN_PLUGIN_ARTIFACT_ID)?.executions?.flatMap { it.goals }
when (goal) { ?.mapNotNull { goal ->
PomFile.KotlinGoals.Compile, PomFile.KotlinGoals.TestCompile -> TargetPlatformKind.Jvm[JvmTarget.JVM_1_6] when (goal) {
PomFile.KotlinGoals.Js, PomFile.KotlinGoals.TestJs -> TargetPlatformKind.JavaScript PomFile.KotlinGoals.Compile, PomFile.KotlinGoals.TestCompile -> TargetPlatformKind.Jvm[JvmTarget.JVM_1_6]
PomFile.KotlinGoals.MetaData -> TargetPlatformKind.Common PomFile.KotlinGoals.Js, PomFile.KotlinGoals.TestJs -> TargetPlatformKind.JavaScript
else -> null PomFile.KotlinGoals.MetaData -> TargetPlatformKind.Common
} else -> null
}?.distinct()?.singleOrNull() }
}?.distinct()?.singleOrNull()
} }
private fun detectPlatformByLibraries(mavenProject: MavenProject): TargetPlatformKind<*>? { private fun detectPlatformByLibraries(mavenProject: MavenProject): TargetPlatformKind<*>? {
@@ -270,10 +292,12 @@ class KotlinMavenImporter : MavenImporter(KOTLIN_PLUGIN_GROUP_ID, KOTLIN_PLUGIN_
} }
private fun collectSourceDirectories(mavenProject: MavenProject): List<Pair<SourceType, String>> = private fun collectSourceDirectories(mavenProject: MavenProject): List<Pair<SourceType, String>> =
mavenProject.plugins.filter { it.isKotlinPlugin() }.flatMap { plugin -> mavenProject.plugins.filter { it.isKotlinPlugin() }.flatMap { plugin ->
plugin.configurationElement.sourceDirectories().map { SourceType.PROD to it } + plugin.configurationElement.sourceDirectories().map { SourceType.PROD to it } +
plugin.executions.flatMap { execution -> execution.configurationElement.sourceDirectories().map { execution.sourceType() to it } } plugin.executions.flatMap { execution ->
}.distinct() execution.configurationElement.sourceDirectories().map { execution.sourceType() to it }
}
}.distinct()
private fun setImplementedModuleName(kotlinFacet: KotlinFacet, mavenProject: MavenProject, module: Module) { private fun setImplementedModuleName(kotlinFacet: KotlinFacet, mavenProject: MavenProject, module: Module) {
if (kotlinFacet.configuration.settings.targetPlatformKind == TargetPlatformKind.Common) { if (kotlinFacet.configuration.settings.targetPlatformKind == TargetPlatformKind.Common) {
@@ -288,12 +312,17 @@ class KotlinMavenImporter : MavenImporter(KOTLIN_PLUGIN_GROUP_ID, KOTLIN_PLUGIN_
} }
} }
private fun MavenPlugin.isKotlinPlugin() = groupId == KotlinMavenImporter.KOTLIN_PLUGIN_GROUP_ID && artifactId == KotlinMavenImporter.KOTLIN_PLUGIN_ARTIFACT_ID private fun MavenPlugin.isKotlinPlugin() =
private fun Element?.sourceDirectories(): List<String> = this?.getChildren(KotlinMavenImporter.KOTLIN_PLUGIN_SOURCE_DIRS_CONFIG)?.flatMap { it.children ?: emptyList() }?.map { it.textTrim } ?: emptyList() groupId == KotlinMavenImporter.KOTLIN_PLUGIN_GROUP_ID && artifactId == KotlinMavenImporter.KOTLIN_PLUGIN_ARTIFACT_ID
private fun Element?.sourceDirectories(): List<String> =
this?.getChildren(KotlinMavenImporter.KOTLIN_PLUGIN_SOURCE_DIRS_CONFIG)?.flatMap { it.children ?: emptyList() }?.map { it.textTrim }
?: emptyList()
private fun MavenPlugin.Execution.sourceType() = private fun MavenPlugin.Execution.sourceType() =
goals.map { if (isTestGoalName(it)) SourceType.TEST else SourceType.PROD } goals.map { if (isTestGoalName(it)) SourceType.TEST else SourceType.PROD }
.distinct() .distinct()
.singleOrNull() ?: SourceType.PROD .singleOrNull() ?: SourceType.PROD
private fun isTestGoalName(goalName: String) = goalName.startsWith("test-") private fun isTestGoalName(goalName: String) = goalName.startsWith("test-")
@@ -301,14 +330,14 @@ private enum class SourceType {
PROD, TEST PROD, TEST
} }
@State(name = "AutoImportedSourceRoots", @State(
storages = arrayOf( name = "AutoImportedSourceRoots",
Storage(id = "other", file = StoragePathMacros.MODULE_FILE) storages = [(Storage(id = "other", file = StoragePathMacros.MODULE_FILE))]
)) )
class KotlinImporterComponent : PersistentStateComponent<KotlinImporterComponent.State> { class KotlinImporterComponent : PersistentStateComponent<KotlinImporterComponent.State> {
class State(var directories: List<String> = ArrayList()) class State(var directories: List<String> = ArrayList())
val addedSources = Collections.synchronizedSet(HashSet<String>()) val addedSources: MutableSet<String> = Collections.synchronizedSet(HashSet<String>())
override fun loadState(state: State?) { override fun loadState(state: State?) {
addedSources.clear() addedSources.clear()
@@ -24,21 +24,21 @@ import org.jetbrains.kotlin.config.LanguageVersion
import org.jetbrains.kotlin.idea.actions.internal.KotlinInternalMode import org.jetbrains.kotlin.idea.actions.internal.KotlinInternalMode
class MavenLanguageVersionsCompletionProvider : MavenFixedValueReferenceProvider( class MavenLanguageVersionsCompletionProvider : MavenFixedValueReferenceProvider(
LanguageVersion.values().filter { it.isStable || KotlinInternalMode.enabled }.map { it.versionString }.toTypedArray() LanguageVersion.values().filter { it.isStable || KotlinInternalMode.enabled }.map { it.versionString }.toTypedArray()
) )
class MavenApiVersionsCompletionProvider : MavenFixedValueReferenceProvider( class MavenApiVersionsCompletionProvider : MavenFixedValueReferenceProvider(
LanguageVersion.values().filter { it.isStable || KotlinInternalMode.enabled }.map { it.versionString }.toTypedArray() LanguageVersion.values().filter { it.isStable || KotlinInternalMode.enabled }.map { it.versionString }.toTypedArray()
) )
class MavenJvmTargetsCompletionProvider : MavenFixedValueReferenceProvider( class MavenJvmTargetsCompletionProvider : MavenFixedValueReferenceProvider(
JvmTarget.values().map(JvmTarget::description).toTypedArray() JvmTarget.values().map(JvmTarget::description).toTypedArray()
) )
class MavenJsModuleKindsCompletionProvider : MavenFixedValueReferenceProvider( class MavenJsModuleKindsCompletionProvider : MavenFixedValueReferenceProvider(
DefaultValues.JsModuleKinds.possibleValues!!.map(StringUtil::unquoteString).toTypedArray() DefaultValues.JsModuleKinds.possibleValues!!.map(StringUtil::unquoteString).toTypedArray()
) )
class MavenJsMainCallCompletionProvider : MavenFixedValueReferenceProvider( class MavenJsMainCallCompletionProvider : MavenFixedValueReferenceProvider(
DefaultValues.JsMain.possibleValues!!.map(StringUtil::unquoteString).toTypedArray() DefaultValues.JsMain.possibleValues!!.map(StringUtil::unquoteString).toTypedArray()
) )
@@ -47,8 +47,12 @@ import java.util.*
fun kotlinPluginId(version: String?) = MavenId(KotlinMavenConfigurator.GROUP_ID, KotlinMavenConfigurator.MAVEN_PLUGIN_ID, version) fun kotlinPluginId(version: String?) = MavenId(KotlinMavenConfigurator.GROUP_ID, KotlinMavenConfigurator.MAVEN_PLUGIN_ID, version)
class PomFile private constructor(val xmlFile: XmlFile, val domModel: MavenDomProjectModel) { class PomFile private constructor(private val xmlFile: XmlFile, val domModel: MavenDomProjectModel) {
constructor(xmlFile: XmlFile) : this(xmlFile, MavenDomUtil.getMavenDomProjectModel(xmlFile.project, xmlFile.virtualFile) ?: throw IllegalStateException("No DOM model found for pom ${xmlFile.name}")) constructor(xmlFile: XmlFile) : this(
xmlFile,
MavenDomUtil.getMavenDomProjectModel(xmlFile.project, xmlFile.virtualFile)
?: throw IllegalStateException("No DOM model found for pom ${xmlFile.name}")
)
private val nodesByName = HashMap<String, XmlTag>() private val nodesByName = HashMap<String, XmlTag>()
private val projectElement: XmlTag private val projectElement: XmlTag
@@ -62,12 +66,10 @@ class PomFile private constructor(val xmlFile: XmlFile, val domModel: MavenDomPr
if (element is XmlTag && element.localName in recommendedElementsOrder && element.parent === projectElement) { if (element is XmlTag && element.localName in recommendedElementsOrder && element.parent === projectElement) {
nodesByName[element.localName] = element nodesByName[element.localName] = element
} } else if (element is XmlTag && element.localName == "project") {
else if (element is XmlTag && element.localName == "project") {
projectElement = element projectElement = element
element.acceptChildren(this) element.acceptChildren(this)
} } else {
else {
element.acceptChildren(this) element.acceptChildren(this)
} }
} }
@@ -86,13 +88,11 @@ class PomFile private constructor(val xmlFile: XmlFile, val domModel: MavenDomPr
val textNode = tag.children.filterIsInstance<XmlText>().firstOrNull() val textNode = tag.children.filterIsInstance<XmlText>().firstOrNull()
if (textNode != null) { if (textNode != null) {
textNode.value = value textNode.value = value
} } else {
else {
tag.replace(projectElement.createChildTag(name, value)) tag.replace(projectElement.createChildTag(name, value))
} }
} }
} } else {
else {
properties.add(projectElement.createChildTag(name, value)) properties.add(projectElement.createChildTag(name, value))
} }
} }
@@ -102,7 +102,13 @@ class PomFile private constructor(val xmlFile: XmlFile, val domModel: MavenDomPr
return propertiesNode.findFirstSubTag(name) return propertiesNode.findFirstSubTag(name)
} }
fun addDependency(artifact: MavenId, scope: MavenArtifactScope? = null, classifier: String? = null, optional: Boolean = false, systemPath: String? = null): MavenDomDependency { fun addDependency(
artifact: MavenId,
scope: MavenArtifactScope? = null,
classifier: String? = null,
optional: Boolean = false,
systemPath: String? = null
): MavenDomDependency {
require(systemPath == null || scope == MavenArtifactScope.SYSTEM) { "systemPath is only applicable for system scope dependency" } require(systemPath == null || scope == MavenArtifactScope.SYSTEM) { "systemPath is only applicable for system scope dependency" }
require(artifact.groupId != null) { "groupId shouldn't be null" } require(artifact.groupId != null) { "groupId shouldn't be null" }
require(artifact.artifactId != null) { "artifactId shouldn't be null" } require(artifact.artifactId != null) { "artifactId shouldn't be null" }
@@ -163,7 +169,7 @@ class PomFile private constructor(val xmlFile: XmlFile, val domModel: MavenDomPr
return true return true
} }
fun ensurePluginAfter(plugin: MavenDomPlugin, referencePlugin: MavenDomPlugin): MavenDomPlugin { private fun ensurePluginAfter(plugin: MavenDomPlugin, referencePlugin: MavenDomPlugin): MavenDomPlugin {
if (!isPluginAfter(plugin, referencePlugin)) { if (!isPluginAfter(plugin, referencePlugin)) {
// rearrange // rearrange
val referenceElement = referencePlugin.xmlElement!! val referenceElement = referencePlugin.xmlElement!!
@@ -180,8 +186,9 @@ class PomFile private constructor(val xmlFile: XmlFile, val domModel: MavenDomPr
fun findKotlinExecutions(vararg goals: String) = findKotlinExecutions().filter { it.goals.goals.any { it.rawText in goals } } fun findKotlinExecutions(vararg goals: String) = findKotlinExecutions().filter { it.goals.goals.any { it.rawText in goals } }
fun findKotlinExecutions() = findKotlinPlugins().flatMap { it.executions.executions } fun findKotlinExecutions() = findKotlinPlugins().flatMap { it.executions.executions }
fun findExecutions(plugin: MavenDomPlugin) = plugin.executions.executions private fun findExecutions(plugin: MavenDomPlugin) = plugin.executions.executions
fun findExecutions(plugin: MavenDomPlugin, vararg goals: String) = findExecutions(plugin).filter { it.goals.goals.any { it.rawText in goals } } fun findExecutions(plugin: MavenDomPlugin, vararg goals: String) =
findExecutions(plugin).filter { it.goals.goals.any { it.rawText in goals } }
fun addExecution(plugin: MavenDomPlugin, executionId: String, phase: String, goals: List<String>): MavenDomPluginExecution { fun addExecution(plugin: MavenDomPlugin, executionId: String, phase: String, goals: List<String>): MavenDomPluginExecution {
require(executionId.isNotEmpty()) { "executionId shouldn't be empty" } require(executionId.isNotEmpty()) { "executionId shouldn't be empty" }
@@ -200,32 +207,39 @@ class PomFile private constructor(val xmlFile: XmlFile, val domModel: MavenDomPr
return execution return execution
} }
fun addKotlinExecution(module: Module, plugin: MavenDomPlugin, executionId: String, phase: String, isTest: Boolean, goals: List<String>) { fun addKotlinExecution(
module: Module,
plugin: MavenDomPlugin,
executionId: String,
phase: String,
isTest: Boolean,
goals: List<String>
) {
val execution = addExecution(plugin, executionId, phase, goals) val execution = addExecution(plugin, executionId, phase, goals)
val sourceDirs = ModuleRootManager.getInstance(module) val sourceDirs = ModuleRootManager.getInstance(module)
.contentEntries .contentEntries
.flatMap { it.sourceFolders.filter { it.isRelatedSourceRoot(isTest) } } .flatMap { it.sourceFolders.filter { it.isRelatedSourceRoot(isTest) } }
.mapNotNull { it.file } .mapNotNull { it.file }
.mapNotNull { VfsUtilCore.getRelativePath(it, xmlFile.virtualFile.parent, '/') } .mapNotNull { VfsUtilCore.getRelativePath(it, xmlFile.virtualFile.parent, '/') }
executionSourceDirs(execution, sourceDirs) executionSourceDirs(execution, sourceDirs)
} }
fun isPluginExecutionMissing(plugin: MavenPlugin?, excludedExecutionId: String, goal: String) = plugin == null || plugin.executions.none { it.executionId != excludedExecutionId && goal in it.goals } fun isPluginExecutionMissing(plugin: MavenPlugin?, excludedExecutionId: String, goal: String) =
plugin == null || plugin.executions.none { it.executionId != excludedExecutionId && goal in it.goals }
fun addJavacExecutions(module: Module, kotlinPlugin: MavenDomPlugin) { fun addJavacExecutions(module: Module, kotlinPlugin: MavenDomPlugin) {
val javacPlugin = ensurePluginAfter(addPlugin(MavenId("org.apache.maven.plugins", "maven-compiler-plugin", null)), kotlinPlugin) val javacPlugin = ensurePluginAfter(addPlugin(MavenId("org.apache.maven.plugins", "maven-compiler-plugin", null)), kotlinPlugin)
val project: MavenProject = val project: MavenProject =
MavenProjectsManager.getInstance(module.project).findProject(module) ?: MavenProjectsManager.getInstance(module.project).findProject(module) ?: run {
run { if (ApplicationManager.getApplication().isUnitTestMode) {
if (ApplicationManager.getApplication().isUnitTestMode) { LOG.warn("WARNING: Bad project configuration in tests. Javac execution configuration was skipped.")
LOG.warn("WARNING: Bad project configuration in tests. Javac execution configuration was skipped.") return
return
}
error("Can't find maven project for $module")
} }
error("Can't find maven project for $module")
}
val plugin = project.findPlugin("org.apache.maven.plugins", "maven-compiler-plugin") val plugin = project.findPlugin("org.apache.maven.plugins", "maven-compiler-plugin")
@@ -252,16 +266,17 @@ class PomFile private constructor(val xmlFile: XmlFile, val domModel: MavenDomPr
} }
if (domModel.build.plugins.plugins.any { if (domModel.build.plugins.plugins.any {
it.groupId.stringValue == "org.apache.maven.plugins" it.groupId.stringValue == "org.apache.maven.plugins"
&& it.artifactId.stringValue == "maven-compiler-plugin" && it.artifactId.stringValue == "maven-compiler-plugin"
&& it.executions.executions.any { it.id.stringValue == executionId && it.phase.stringValue == DefaultPhases.None } && it.executions.executions.any { it.id.stringValue == executionId && it.phase.stringValue == DefaultPhases.None }
}) { }) {
return false return false
} }
// TODO: getPhase has been added as per https://youtrack.jetbrains.com/issue/IDEA-153582 and available only in latest IDEAs // TODO: getPhase has been added as per https://youtrack.jetbrains.com/issue/IDEA-153582 and available only in latest IDEAs
return plugin.executions.filter { it.executionId == executionId }.all { execution -> return plugin.executions.filter { it.executionId == executionId }.all { execution ->
execution::class.java.methods.filter { it.name == "getPhase" && it.parameterTypes.isEmpty() }.all { it.invoke(execution) == DefaultPhases.None } execution::class.java.methods.filter { it.name == "getPhase" && it.parameterTypes.isEmpty() }
.all { it.invoke(execution) == DefaultPhases.None }
} }
} }
@@ -272,20 +287,17 @@ class PomFile private constructor(val xmlFile: XmlFile, val domModel: MavenDomPr
val defaultDir = if (isTest) "test" else "main" val defaultDir = if (isTest) "test" else "main"
val singleDirectoryElement = if (isTest) { val singleDirectoryElement = if (isTest) {
domModel.build.testSourceDirectory domModel.build.testSourceDirectory
} } else {
else {
domModel.build.sourceDirectory domModel.build.sourceDirectory
} }
if (sourceDirs.isEmpty() || sourceDirs.singleOrNull() == "src/$defaultDir/java") { if (sourceDirs.isEmpty() || sourceDirs.singleOrNull() == "src/$defaultDir/java") {
execution.configuration.xmlTag?.findSubTags("sourceDirs")?.forEach { it.deleteCascade() } execution.configuration.xmlTag?.findSubTags("sourceDirs")?.forEach { it.deleteCascade() }
singleDirectoryElement.undefine() singleDirectoryElement.undefine()
} } else if (sourceDirs.size == 1 && !forceSingleSource) {
else if (sourceDirs.size == 1 && !forceSingleSource) {
singleDirectoryElement.stringValue = sourceDirs.single() singleDirectoryElement.stringValue = sourceDirs.single()
execution.configuration.xmlTag?.findSubTags("sourceDirs")?.forEach { it.deleteCascade() } execution.configuration.xmlTag?.findSubTags("sourceDirs")?.forEach { it.deleteCascade() }
} } else {
else {
val sourceDirsTag = executionConfiguration(execution, "sourceDirs") val sourceDirsTag = executionConfiguration(execution, "sourceDirs")
val newSourceDirsTag = execution.configuration.createChildTag("sourceDirs") val newSourceDirsTag = execution.configuration.createChildTag("sourceDirs")
for (dir in sourceDirs) { for (dir in sourceDirs) {
@@ -297,13 +309,13 @@ class PomFile private constructor(val xmlFile: XmlFile, val domModel: MavenDomPr
fun executionSourceDirs(execution: MavenDomPluginExecution): List<String> { fun executionSourceDirs(execution: MavenDomPluginExecution): List<String> {
return execution.configuration.xmlTag return execution.configuration.xmlTag
.getChildrenOfType<XmlTag>().firstOrNull { it.localName == "sourceDirs" } .getChildrenOfType<XmlTag>().firstOrNull { it.localName == "sourceDirs" }
?.getChildrenOfType<XmlTag>() ?.getChildrenOfType<XmlTag>()
?.map { it.getChildrenOfType<XmlText>().joinToString("") { it.text } } ?.map { it.getChildrenOfType<XmlText>().joinToString("") { it.text } }
?: emptyList() ?: emptyList()
} }
fun executionConfiguration(execution: MavenDomPluginExecution, name: String): XmlTag { private fun executionConfiguration(execution: MavenDomPluginExecution, name: String): XmlTag {
val configurationTag = execution.configuration.ensureTagExists()!! val configurationTag = execution.configuration.ensureTagExists()!!
val existingTag = configurationTag.findSubTags(name).firstOrNull() val existingTag = configurationTag.findSubTags(name).firstOrNull()
@@ -320,39 +332,70 @@ class PomFile private constructor(val xmlFile: XmlFile, val domModel: MavenDomPr
val existingTag = configurationTag.findFirstSubTag(optionName) val existingTag = configurationTag.findFirstSubTag(optionName)
if (existingTag != null) { if (existingTag != null) {
existingTag.value.text = optionValue existingTag.value.text = optionValue
} } else {
else {
configurationTag.add(configurationTag.createChildTag(optionName, optionValue)) configurationTag.add(configurationTag.createChildTag(optionName, optionValue))
} }
return configurationTag return configurationTag
} }
fun addPluginRepository(id: String, name: String, url: String, snapshots: Boolean = false, releases: Boolean = true): MavenDomRepository { private fun addPluginRepository(
id: String,
name: String,
url: String,
snapshots: Boolean = false,
releases: Boolean = true
): MavenDomRepository {
ensurePluginRepositories() ensurePluginRepositories()
return addRepository(id, name, url, snapshots, releases, { domModel.pluginRepositories.pluginRepositories }, { domModel.pluginRepositories.addPluginRepository() }) return addRepository(
id,
name,
url,
snapshots,
releases,
{ domModel.pluginRepositories.pluginRepositories },
{ domModel.pluginRepositories.addPluginRepository() })
} }
fun addPluginRepository(description: RepositoryDescription) { fun addPluginRepository(description: RepositoryDescription) {
addPluginRepository(description.id, description.name, description.url, description.isSnapshot, true) addPluginRepository(description.id, description.name, description.url, description.isSnapshot, true)
} }
fun addLibraryRepository(id: String, name: String, url: String, snapshots: Boolean = false, releases: Boolean = true): MavenDomRepository { private fun addLibraryRepository(
id: String,
name: String,
url: String,
snapshots: Boolean = false,
releases: Boolean = true
): MavenDomRepository {
ensureRepositories() ensureRepositories()
return addRepository(id, name, url, snapshots, releases, { domModel.repositories.repositories }, { domModel.repositories.addRepository() }) return addRepository(
id,
name,
url,
snapshots,
releases,
{ domModel.repositories.repositories },
{ domModel.repositories.addRepository() })
} }
fun addLibraryRepository(description: RepositoryDescription) { fun addLibraryRepository(description: RepositoryDescription) {
addLibraryRepository(description.id, description.name, description.url, description.isSnapshot, true) addLibraryRepository(description.id, description.name, description.url, description.isSnapshot, true)
} }
private fun addRepository(id: String, name: String, url: String, snapshots: Boolean, releases: Boolean, existing: () -> List<MavenDomRepository>, create: () -> MavenDomRepository): MavenDomRepository { private fun addRepository(
id: String,
name: String,
url: String,
snapshots: Boolean,
releases: Boolean,
existing: () -> List<MavenDomRepository>,
create: () -> MavenDomRepository
): MavenDomRepository {
val repository = val repository =
existing().firstOrNull { it.id.stringValue == id } ?: existing().firstOrNull { it.id.stringValue == id } ?: existing().firstOrNull { it.url.stringValue == url } ?: create()
existing().firstOrNull { it.url.stringValue == url } ?:
create()
if (repository.id.isEmpty()) { if (repository.id.isEmpty()) {
repository.id.stringValue = id repository.id.stringValue = id
@@ -371,42 +414,37 @@ class PomFile private constructor(val xmlFile: XmlFile, val domModel: MavenDomPr
return repository return repository
} }
fun hasPlugin(artifact: MavenId) = domModel.build.plugins.plugins.any { it.matches(artifact) }
fun hasDependency(artifact: MavenId, scope: MavenArtifactScope? = null) =
domModel.dependencies.dependencies.any { it.matches(artifact, scope) }
fun findDependencies(artifact: MavenId, scope: MavenArtifactScope? = null) = fun findDependencies(artifact: MavenId, scope: MavenArtifactScope? = null) =
domModel.dependencies.dependencies.filter { it.matches(artifact, scope) } domModel.dependencies.dependencies.filter { it.matches(artifact, scope) }
fun ensureBuild(): XmlTag = ensureElement(projectElement, "build") private fun ensureBuild(): XmlTag = ensureElement(projectElement, "build")
fun ensureDependencies(): XmlTag = ensureElement(projectElement, "dependencies") private fun ensureDependencies(): XmlTag = ensureElement(projectElement, "dependencies")
fun ensurePluginRepositories(): XmlTag = ensureElement(projectElement, "pluginRepositories") private fun ensurePluginRepositories(): XmlTag = ensureElement(projectElement, "pluginRepositories")
fun ensureRepositories(): XmlTag = ensureElement(projectElement, "repositories") private fun ensureRepositories(): XmlTag = ensureElement(projectElement, "repositories")
private fun MavenDomPlugin.isKotlinMavenPlugin() = groupId.stringValue == KotlinMavenConfigurator.GROUP_ID private fun MavenDomPlugin.isKotlinMavenPlugin() = groupId.stringValue == KotlinMavenConfigurator.GROUP_ID
&& artifactId.stringValue == KotlinMavenConfigurator.MAVEN_PLUGIN_ID && artifactId.stringValue == KotlinMavenConfigurator.MAVEN_PLUGIN_ID
private fun MavenDomDependency.matches(artifact: MavenId, scope: MavenArtifactScope?) = private fun MavenDomDependency.matches(artifact: MavenId, scope: MavenArtifactScope?) =
this.matches(artifact) && (this.scope.stringValue == scope?.name?.toLowerCase() || scope == null && this.scope.stringValue == "compile") this.matches(artifact) && (this.scope.stringValue == scope?.name?.toLowerCase() || scope == null && this.scope.stringValue == "compile")
private fun MavenDomArtifactCoordinates.matches(artifact: MavenId) = private fun MavenDomArtifactCoordinates.matches(artifact: MavenId) =
(artifact.groupId == null || groupId.stringValue == artifact.groupId) (artifact.groupId == null || groupId.stringValue == artifact.groupId)
&& (artifact.artifactId == null || artifactId.stringValue == artifact.artifactId) && (artifact.artifactId == null || artifactId.stringValue == artifact.artifactId)
&& (artifact.version == null || version.stringValue == artifact.version) && (artifact.version == null || version.stringValue == artifact.version)
private fun MavenId.withNoVersion() = MavenId(groupId, artifactId, null) private fun MavenId.withNoVersion() = MavenId(groupId, artifactId, null)
private fun MavenId.withoutJDKSpecificSuffix() = MavenId( private fun MavenId.withoutJDKSpecificSuffix() = MavenId(
groupId, groupId,
artifactId?.substringBeforeLast("-jre")?.substringBeforeLast("-jdk"), artifactId?.substringBeforeLast("-jre")?.substringBeforeLast("-jdk"),
null) null
)
private fun MavenDomElement.createChildTag(name: String, value: String? = null) = xmlTag.createChildTag(name, value) private fun MavenDomElement.createChildTag(name: String, value: String? = null) = xmlTag.createChildTag(name, value)
private fun XmlTag.createChildTag(name: String, value: String? = null) = createChildTag(name, namespace, value, false)!! private fun XmlTag.createChildTag(name: String, value: String? = null) = createChildTag(name, namespace, value, false)!!
tailrec private tailrec fun XmlTag.deleteCascade() {
private fun XmlTag.deleteCascade() {
val oldParent = this.parentTag val oldParent = this.parentTag
delete() delete()
@@ -451,12 +489,12 @@ class PomFile private constructor(val xmlFile: XmlFile, val domModel: MavenDomPr
private fun insertEmptyLines(node: XmlTag) { private fun insertEmptyLines(node: XmlTag) {
node.prevSibling?.let { before -> node.prevSibling?.let { before ->
if (!(before.hasEmptyLine() || before.lastChild?.hasEmptyLine() ?: false)) { if (!(before.hasEmptyLine() || before.lastChild?.hasEmptyLine() == true)) {
node.parent.addBefore(createEmptyLine(), node) node.parent.addBefore(createEmptyLine(), node)
} }
} }
node.nextSibling?.let { after -> node.nextSibling?.let { after ->
if (!(after.hasEmptyLine() || after.firstChild?.hasEmptyLine() ?: false)) { if (!(after.hasEmptyLine() || after.firstChild?.hasEmptyLine() == true)) {
node.parent.addAfter(createEmptyLine(), node) node.parent.addAfter(createEmptyLine(), node)
} }
} }
@@ -481,45 +519,47 @@ class PomFile private constructor(val xmlFile: XmlFile, val domModel: MavenDomPr
@Suppress("Unused") @Suppress("Unused")
object DefaultPhases { object DefaultPhases {
val None = "none" const val None = "none"
val Validate = "validate" const val Validate = "validate"
val Initialize = "initialize" const val Initialize = "initialize"
val GenerateSources = "generate-sources" const val GenerateSources = "generate-sources"
val ProcessSources = "process-sources" const val ProcessSources = "process-sources"
val GenerateResources = "generate-resources" const val GenerateResources = "generate-resources"
val ProcessResources = "process-resources" const val ProcessResources = "process-resources"
val Compile = "compile" const val Compile = "compile"
val ProcessClasses = "process-classes" const val ProcessClasses = "process-classes"
val GenerateTestSources = "generate-test-sources" const val GenerateTestSources = "generate-test-sources"
val ProcessTestSources = "process-test-sources" const val ProcessTestSources = "process-test-sources"
val GenerateTestResources = "generate-test-resources" const val GenerateTestResources = "generate-test-resources"
val ProcessTestResources = "process-test-resources" const val ProcessTestResources = "process-test-resources"
val TestCompile = "test-compile" const val TestCompile = "test-compile"
val ProcessTestClasses = "process-test-classes" const val ProcessTestClasses = "process-test-classes"
val Test = "test" const val Test = "test"
val PreparePackage = "prepare-package" const val PreparePackage = "prepare-package"
val Package = "package" const val Package = "package"
val PreIntegrationTest = "pre-integration-test" const val PreIntegrationTest = "pre-integration-test"
val IntegrationTest = "integration-test" const val IntegrationTest = "integration-test"
val PostIntegrationTest = "post-integration-test" const val PostIntegrationTest = "post-integration-test"
val Verify = "verify" const val Verify = "verify"
val Install = "install" const val Install = "install"
val Deploy = "deploy" const val Deploy = "deploy"
} }
object KotlinGoals { object KotlinGoals {
val Compile = "compile" const val Compile = "compile"
val TestCompile = "test-compile" const val TestCompile = "test-compile"
val Js = "js" const val Js = "js"
val TestJs = "test-js" const val TestJs = "test-js"
val MetaData = "metadata" const val MetaData = "metadata"
} }
companion object { companion object {
private val LOG = Logger.getInstance(PomFile::class.java) private val LOG = Logger.getInstance(PomFile::class.java)
fun forFileOrNull(xmlFile: XmlFile): PomFile? = MavenDomUtil.getMavenDomProjectModel(xmlFile.project, xmlFile.virtualFile)?.let { PomFile(xmlFile, it) } fun forFileOrNull(xmlFile: XmlFile): PomFile? =
MavenDomUtil.getMavenDomProjectModel(xmlFile.project, xmlFile.virtualFile)?.let { PomFile(xmlFile, it) }
@Suppress("DeprecatedCallableAddReplaceWith")
@Deprecated("We shouldn't use phase but additional compiler configuration in most cases") @Deprecated("We shouldn't use phase but additional compiler configuration in most cases")
fun getPhase(hasJavaFiles: Boolean, isTest: Boolean) = when { fun getPhase(hasJavaFiles: Boolean, isTest: Boolean) = when {
hasJavaFiles -> when { hasJavaFiles -> when {
@@ -577,18 +617,22 @@ class PomFile private constructor(val xmlFile: XmlFile, val domModel: MavenDomPr
<profiles/> <profiles/>
""".lines() """.lines()
.map { it.trim().removePrefix("<").removeSuffix("/>").trim() } .map { it.trim().removePrefix("<").removeSuffix("/>").trim() }
.filter(String::isNotEmpty) .filter(String::isNotEmpty)
.toCollection(LinkedHashSet()) .toCollection(LinkedHashSet())
val recommendedOrderAsList = recommendedElementsOrder.toList() val recommendedOrderAsList = recommendedElementsOrder.toList()
} }
} }
fun PomFile.changeLanguageVersion(languageVersion: String?, apiVersion: String?): PsiElement? { fun PomFile.changeLanguageVersion(languageVersion: String?, apiVersion: String?): PsiElement? {
val kotlinPlugin = findPlugin(MavenId(KotlinMavenConfigurator.GROUP_ID, val kotlinPlugin = findPlugin(
KotlinMavenConfigurator.MAVEN_PLUGIN_ID, MavenId(
null)) ?: return null KotlinMavenConfigurator.GROUP_ID,
KotlinMavenConfigurator.MAVEN_PLUGIN_ID,
null
)
) ?: return null
val languageElement = languageVersion?.let { val languageElement = languageVersion?.let {
changeConfigurationOrProperty(kotlinPlugin, "languageVersion", "kotlin.compiler.languageVersion", it) changeConfigurationOrProperty(kotlinPlugin, "languageVersion", "kotlin.compiler.languageVersion", it)
} }
@@ -598,9 +642,11 @@ fun PomFile.changeLanguageVersion(languageVersion: String?, apiVersion: String?)
return languageElement ?: apiElement return languageElement ?: apiElement
} }
private fun PomFile.changeConfigurationOrProperty(kotlinPlugin: MavenDomPlugin, private fun PomFile.changeConfigurationOrProperty(
configurationTagName: String, kotlinPlugin: MavenDomPlugin,
propertyName: String, value: String): XmlTag? { configurationTagName: String,
propertyName: String, value: String
): XmlTag? {
val configuration = kotlinPlugin.configuration val configuration = kotlinPlugin.configuration
if (configuration.exists()) { if (configuration.exists()) {
val subTag = configuration.xmlTag.findFirstSubTag(configurationTagName) val subTag = configuration.xmlTag.findFirstSubTag(configurationTagName)
@@ -623,8 +669,12 @@ private fun PomFile.changeConfigurationOrProperty(kotlinPlugin: MavenDomPlugin,
} }
fun PomFile.changeCoroutineConfiguration(value: String): PsiElement? { fun PomFile.changeCoroutineConfiguration(value: String): PsiElement? {
val kotlinPlugin = findPlugin(MavenId(KotlinMavenConfigurator.GROUP_ID, val kotlinPlugin = findPlugin(
KotlinMavenConfigurator.MAVEN_PLUGIN_ID, MavenId(
null)) ?: return null KotlinMavenConfigurator.GROUP_ID,
KotlinMavenConfigurator.MAVEN_PLUGIN_ID,
null
)
) ?: return null
return changeConfigurationOrProperty(kotlinPlugin, "experimentalCoroutines", "kotlin.compiler.experimental.coroutines", value) return changeConfigurationOrProperty(kotlinPlugin, "experimentalCoroutines", "kotlin.compiler.experimental.coroutines", value)
} }
@@ -110,7 +110,11 @@ class MavenPluginSourcesMoveToBuild : PsiElementBaseIntentionAction() {
} }
} }
private fun tryInvoke(project: Project, element: PsiElement, block: (pom: PomFile, dir: String, execution: MavenDomPluginExecution, build: MavenDomBuild) -> Unit = { _, _, _, _ -> }): Boolean { private fun tryInvoke(
project: Project,
element: PsiElement,
block: (pom: PomFile, dir: String, execution: MavenDomPluginExecution, build: MavenDomBuild) -> Unit = { _, _, _, _ -> }
): Boolean {
val file = element.containingFile val file = element.containingFile
if (file == null || !MavenDomUtil.isMavenFile(file) || (element !is XmlElement && element.parent !is XmlElement)) { if (file == null || !MavenDomUtil.isMavenFile(file) || (element !is XmlElement && element.parent !is XmlElement)) {
@@ -122,9 +126,9 @@ class MavenPluginSourcesMoveToBuild : PsiElementBaseIntentionAction() {
val execution = domElement.getParentOfType(MavenDomPluginExecution::class.java, false) ?: return false val execution = domElement.getParentOfType(MavenDomPluginExecution::class.java, false) ?: return false
tag.parentsWithSelf tag.parentsWithSelf
.takeWhile { it != execution.xmlElement } .takeWhile { it != execution.xmlElement }
.filterIsInstance<XmlTag>() .filterIsInstance<XmlTag>()
.firstOrNull { it.localName == "sourceDirs" } ?: return false .firstOrNull { it.localName == "sourceDirs" } ?: return false
val pom = PomFile.forFileOrNull(element.containingFile as XmlFile) ?: return false val pom = PomFile.forFileOrNull(element.containingFile as XmlFile) ?: return false
val sourceDirsToMove = pom.executionSourceDirs(execution) val sourceDirsToMove = pom.executionSourceDirs(execution)
@@ -137,12 +141,12 @@ class MavenPluginSourcesMoveToBuild : PsiElementBaseIntentionAction() {
var couldMove = 0 var couldMove = 0
if (shouldMoveCompileSourceRoot(execution)) { if (shouldMoveCompileSourceRoot(execution)) {
if (!build.sourceDirectory.exists() || build.sourceDirectory.stringValue == sourceDirsToMove.single()) { if (!build.sourceDirectory.exists() || build.sourceDirectory.stringValue == sourceDirsToMove.single()) {
couldMove ++ couldMove++
} }
} }
if (shouldMoveTestSourceRoot(execution)) { if (shouldMoveTestSourceRoot(execution)) {
if (!build.testSourceDirectory.exists() || build.testSourceDirectory.stringValue == sourceDirsToMove.single()) { if (!build.testSourceDirectory.exists() || build.testSourceDirectory.stringValue == sourceDirsToMove.single()) {
couldMove ++ couldMove++
} }
} }
@@ -158,5 +162,5 @@ class MavenPluginSourcesMoveToBuild : PsiElementBaseIntentionAction() {
execution.goals.goals.any { it.stringValue == PomFile.KotlinGoals.Compile || it.stringValue == PomFile.KotlinGoals.Js } execution.goals.goals.any { it.stringValue == PomFile.KotlinGoals.Compile || it.stringValue == PomFile.KotlinGoals.Js }
private fun shouldMoveTestSourceRoot(execution: MavenDomPluginExecution) = private fun shouldMoveTestSourceRoot(execution: MavenDomPluginExecution) =
execution.goals.goals.any { it.stringValue == PomFile.KotlinGoals.TestCompile || it.stringValue == PomFile.KotlinGoals.TestJs } execution.goals.goals.any { it.stringValue == PomFile.KotlinGoals.TestCompile || it.stringValue == PomFile.KotlinGoals.TestJs }
} }
@@ -33,11 +33,15 @@ import org.jetbrains.kotlin.idea.maven.configuration.KotlinMavenConfigurator
import org.jetbrains.kotlin.idea.versions.MAVEN_STDLIB_ID import org.jetbrains.kotlin.idea.versions.MAVEN_STDLIB_ID
import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.endOffset
class GenerateMavenCompileExecutionAction : PomFileActionBase(KotlinMavenExecutionProvider(PomFile.KotlinGoals.Compile, PomFile.DefaultPhases.Compile)) class GenerateMavenCompileExecutionAction :
class GenerateMavenTestCompileExecutionAction : PomFileActionBase(KotlinMavenExecutionProvider(PomFile.KotlinGoals.TestCompile, PomFile.DefaultPhases.TestCompile)) PomFileActionBase(KotlinMavenExecutionProvider(PomFile.KotlinGoals.Compile, PomFile.DefaultPhases.Compile))
class GenerateMavenTestCompileExecutionAction :
PomFileActionBase(KotlinMavenExecutionProvider(PomFile.KotlinGoals.TestCompile, PomFile.DefaultPhases.TestCompile))
class GenerateMavenPluginAction : PomFileActionBase(KotlinMavenPluginProvider()) class GenerateMavenPluginAction : PomFileActionBase(KotlinMavenPluginProvider())
private val DefaultKotlinVersion = "\${kotlin.version}" private const val DefaultKotlinVersion = "\${kotlin.version}"
open class PomFileActionBase(generateProvider: AbstractDomGenerateProvider<*>) : GenerateDomElementAction(generateProvider) { open class PomFileActionBase(generateProvider: AbstractDomGenerateProvider<*>) : GenerateDomElementAction(generateProvider) {
override fun isValidForFile(project: Project, editor: Editor, file: PsiFile): Boolean { override fun isValidForFile(project: Project, editor: Editor, file: PsiFile): Boolean {
@@ -47,7 +51,8 @@ open class PomFileActionBase(generateProvider: AbstractDomGenerateProvider<*>) :
override fun startInWriteAction() = true override fun startInWriteAction() = true
} }
private class KotlinMavenPluginProvider : AbstractDomGenerateProvider<MavenDomPlugin>("kotlin-maven-plugin-provider", MavenDomPlugin::class.java) { private class KotlinMavenPluginProvider :
AbstractDomGenerateProvider<MavenDomPlugin>("kotlin-maven-plugin-provider", MavenDomPlugin::class.java) {
override fun generate(parent: DomElement?, editor: Editor?): MavenDomPlugin? { override fun generate(parent: DomElement?, editor: Editor?): MavenDomPlugin? {
if (parent !is MavenDomProjectModel) { if (parent !is MavenDomProjectModel) {
@@ -82,7 +87,8 @@ private class KotlinMavenPluginProvider : AbstractDomGenerateProvider<MavenDomPl
} }
} }
private class KotlinMavenExecutionProvider(val goal: String, val phase: String) : AbstractDomGenerateProvider<MavenDomPlugin>("kotlin-maven-execution-provider", MavenDomPlugin::class.java) { private class KotlinMavenExecutionProvider(val goal: String, val phase: String) :
AbstractDomGenerateProvider<MavenDomPlugin>("kotlin-maven-execution-provider", MavenDomPlugin::class.java) {
override fun generate(parent: DomElement?, editor: Editor?): MavenDomPlugin? { override fun generate(parent: DomElement?, editor: Editor?): MavenDomPlugin? {
if (parent !is MavenDomPlugin) { if (parent !is MavenDomPlugin) {
@@ -99,7 +105,7 @@ private class KotlinMavenExecutionProvider(val goal: String, val phase: String)
return parent return parent
} }
override fun getElementToNavigate(t: MavenDomPlugin?) = null override fun getElementToNavigate(t: MavenDomPlugin?): DomElement? = null
override fun getParentDomElement(project: Project?, editor: Editor?, file: PsiFile?): DomElement? { override fun getParentDomElement(project: Project?, editor: Editor?, file: PsiFile?): DomElement? {
if (project == null || editor == null || file == null) { if (project == null || editor == null || file == null) {
@@ -112,8 +118,8 @@ private class KotlinMavenExecutionProvider(val goal: String, val phase: String)
override fun isAvailableForElement(contextElement: DomElement): Boolean { override fun isAvailableForElement(contextElement: DomElement): Boolean {
val plugin = contextElement.findPlugin() val plugin = contextElement.findPlugin()
return plugin != null return plugin != null
&& plugin.isKotlinMavenPlugin() && plugin.isKotlinMavenPlugin()
&& plugin.executions.executions.none { it.goals.goals.any { it.value == goal } } && plugin.executions.executions.none { it.goals.goals.any { it.value == goal } }
} }
} }
@@ -129,11 +135,14 @@ private fun Char.isRangeEnd() = this == ']' || this == ')'
private fun String.isRangeVersion() = length > 2 && this[0].isRangeStart() && last().isRangeEnd() private fun String.isRangeVersion() = length > 2 && this[0].isRangeStart() && last().isRangeEnd()
private fun DomElement.findProject(): MavenDomProjectModel? = this as? MavenDomProjectModel ?: DomUtil.getParentOfType(this, MavenDomProjectModel::class.java, true) private fun DomElement.findProject(): MavenDomProjectModel? =
private fun DomElement.findPlugin(): MavenDomPlugin? = this as? MavenDomPlugin ?: DomUtil.getParentOfType(this, MavenDomPlugin::class.java, true) this as? MavenDomProjectModel ?: DomUtil.getParentOfType(this, MavenDomProjectModel::class.java, true)
private fun DomElement.findPlugin(): MavenDomPlugin? =
this as? MavenDomPlugin ?: DomUtil.getParentOfType(this, MavenDomPlugin::class.java, true)
private fun MavenDomPlugin.isKotlinMavenPlugin() = groupId.stringValue == KotlinMavenConfigurator.GROUP_ID private fun MavenDomPlugin.isKotlinMavenPlugin() = groupId.stringValue == KotlinMavenConfigurator.GROUP_ID
&& artifactId.stringValue == KotlinMavenConfigurator.MAVEN_PLUGIN_ID && artifactId.stringValue == KotlinMavenConfigurator.MAVEN_PLUGIN_ID
private fun MavenDomDependency.isKotlinStdlib() = groupId.stringValue == KotlinMavenConfigurator.GROUP_ID private fun MavenDomDependency.isKotlinStdlib() = groupId.stringValue == KotlinMavenConfigurator.GROUP_ID
&& artifactId.stringValue == MAVEN_STDLIB_ID && artifactId.stringValue == MAVEN_STDLIB_ID
@@ -29,16 +29,21 @@ import org.jetbrains.kotlin.idea.versions.getStdlibArtifactId
import org.jetbrains.kotlin.resolve.TargetPlatform import org.jetbrains.kotlin.resolve.TargetPlatform
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
class KotlinJavaMavenConfigurator : KotlinMavenConfigurator(KotlinJavaMavenConfigurator.TEST_LIB_ID, false, KotlinJavaMavenConfigurator.NAME, KotlinJavaMavenConfigurator.PRESENTABLE_TEXT) { class KotlinJavaMavenConfigurator : KotlinMavenConfigurator(
KotlinJavaMavenConfigurator.TEST_LIB_ID,
false,
KotlinJavaMavenConfigurator.NAME,
KotlinJavaMavenConfigurator.PRESENTABLE_TEXT
) {
override fun isKotlinModule(module: Module) = override fun isKotlinModule(module: Module) =
hasKotlinJvmRuntimeInScope(module) hasKotlinJvmRuntimeInScope(module)
override fun isRelevantGoal(goalName: String) = override fun isRelevantGoal(goalName: String) =
goalName == PomFile.KotlinGoals.Compile goalName == PomFile.KotlinGoals.Compile
override fun getStdlibArtifactId(module: Module, version: String): String = override fun getStdlibArtifactId(module: Module, version: String): String =
getStdlibArtifactId(ModuleRootManager.getInstance(module).sdk, version) getStdlibArtifactId(ModuleRootManager.getInstance(module).sdk, version)
override fun createExecutions(pomFile: PomFile, kotlinPlugin: MavenDomPlugin, module: Module) { override fun createExecutions(pomFile: PomFile, kotlinPlugin: MavenDomPlugin, module: Module) {
createExecution(pomFile, kotlinPlugin, PomFile.DefaultPhases.Compile, PomFile.KotlinGoals.Compile, module, false) createExecution(pomFile, kotlinPlugin, PomFile.DefaultPhases.Compile, PomFile.KotlinGoals.Compile, module, false)
@@ -66,8 +71,8 @@ class KotlinJavaMavenConfigurator : KotlinMavenConfigurator(KotlinJavaMavenConfi
get() = JvmPlatform get() = JvmPlatform
companion object { companion object {
private val NAME = "maven" private const val NAME = "maven"
val TEST_LIB_ID = "kotlin-test" const val TEST_LIB_ID = "kotlin-test"
private val PRESENTABLE_TEXT = "Maven" private const val PRESENTABLE_TEXT = "Maven"
} }
} }
@@ -24,7 +24,8 @@ import org.jetbrains.kotlin.idea.versions.MAVEN_JS_STDLIB_ID
import org.jetbrains.kotlin.js.resolve.JsPlatform import org.jetbrains.kotlin.js.resolve.JsPlatform
import org.jetbrains.kotlin.resolve.TargetPlatform import org.jetbrains.kotlin.resolve.TargetPlatform
class KotlinJavascriptMavenConfigurator : KotlinMavenConfigurator(null, false, KotlinJavascriptMavenConfigurator.NAME, KotlinJavascriptMavenConfigurator.PRESENTABLE_TEXT) { class KotlinJavascriptMavenConfigurator :
KotlinMavenConfigurator(null, false, KotlinJavascriptMavenConfigurator.NAME, KotlinJavascriptMavenConfigurator.PRESENTABLE_TEXT) {
override fun getStdlibArtifactId(module: Module, version: String) = MAVEN_JS_STDLIB_ID override fun getStdlibArtifactId(module: Module, version: String) = MAVEN_JS_STDLIB_ID
@@ -47,7 +48,7 @@ class KotlinJavascriptMavenConfigurator : KotlinMavenConfigurator(null, false, K
override fun getMinimumSupportedVersion() = "1.1.0" override fun getMinimumSupportedVersion() = "1.1.0"
companion object { companion object {
private val NAME = "js maven" private const val NAME = "js maven"
private val PRESENTABLE_TEXT = "Maven (JavaScript)" private const val PRESENTABLE_TEXT = "Maven (JavaScript)"
} }
} }
@@ -41,10 +41,12 @@ import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.idea.versions.LibraryJarDescriptor import org.jetbrains.kotlin.idea.versions.LibraryJarDescriptor
abstract class KotlinMavenConfigurator abstract class KotlinMavenConfigurator
protected constructor(private val testArtifactId: String?, protected constructor(
private val addJunit: Boolean, private val testArtifactId: String?,
override val name: String, private val addJunit: Boolean,
override val presentableText: String) : KotlinProjectConfigurator { override val name: String,
override val presentableText: String
) : KotlinProjectConfigurator {
override fun getStatus(moduleSourceRootGroup: ModuleSourceRootGroup): ConfigureKotlinStatus { override fun getStatus(moduleSourceRootGroup: ModuleSourceRootGroup): ConfigureKotlinStatus {
val module = moduleSourceRootGroup.baseModule val module = moduleSourceRootGroup.baseModule
@@ -77,8 +79,8 @@ abstract class KotlinMavenConfigurator
val mavenProject = mavenProjectsManager.findProject(module) ?: return ConfigureKotlinStatus.BROKEN val mavenProject = mavenProjectsManager.findProject(module) ?: return ConfigureKotlinStatus.BROKEN
val kotlinPluginId = kotlinPluginId(null) val kotlinPluginId = kotlinPluginId(null)
val kotlinPlugin = mavenProject.plugins.find { it.mavenId.equals(kotlinPluginId.groupId, kotlinPluginId.artifactId)} val kotlinPlugin = mavenProject.plugins.find { it.mavenId.equals(kotlinPluginId.groupId, kotlinPluginId.artifactId) }
?: return ConfigureKotlinStatus.CAN_BE_CONFIGURED ?: return ConfigureKotlinStatus.CAN_BE_CONFIGURED
if (kotlinPlugin.executions.any { it.goals.any(this::isRelevantGoal) }) { if (kotlinPlugin.executions.any { it.goals.any(this::isRelevantGoal) }) {
return ConfigureKotlinStatus.CONFIGURED return ConfigureKotlinStatus.CONFIGURED
@@ -108,8 +110,7 @@ abstract class KotlinMavenConfigurator
if (file != null && canConfigureFile(file)) { if (file != null && canConfigureFile(file)) {
configureModule(module, file, dialog.kotlinVersion, collector) configureModule(module, file, dialog.kotlinVersion, collector)
OpenFileAction.openFile(file.virtualFile, project) OpenFileAction.openFile(file.virtualFile, project)
} } else {
else {
showErrorMessage(project, "Cannot find pom.xml for module " + module.name) showErrorMessage(project, "Cannot find pom.xml for module " + module.name)
} }
} }
@@ -126,13 +127,13 @@ abstract class KotlinMavenConfigurator
protected abstract fun getStdlibArtifactId(module: Module, version: String): String protected abstract fun getStdlibArtifactId(module: Module, version: String): String
open fun configureModule(module: Module, file: PsiFile, version: String, collector: NotificationMessageCollector): Boolean = open fun configureModule(module: Module, file: PsiFile, version: String, collector: NotificationMessageCollector): Boolean =
changePomFile(module, file, version, collector) changePomFile(module, file, version, collector)
private fun changePomFile( private fun changePomFile(
module: Module, module: Module,
file: PsiFile, file: PsiFile,
version: String, version: String,
collector: NotificationMessageCollector collector: NotificationMessageCollector
): Boolean { ): Boolean {
val virtualFile = file.virtualFile ?: error("Virtual file should exists for psi file " + file.name) val virtualFile = file.virtualFile ?: error("Virtual file should exists for psi file " + file.name)
val domModel = MavenDomUtil.getMavenDomProjectModel(module.project, virtualFile) val domModel = MavenDomUtil.getMavenDomProjectModel(module.project, virtualFile)
@@ -144,7 +145,13 @@ abstract class KotlinMavenConfigurator
val pom = PomFile.forFileOrNull(file as XmlFile) ?: return false val pom = PomFile.forFileOrNull(file as XmlFile) ?: return false
pom.addProperty(KOTLIN_VERSION_PROPERTY, version) pom.addProperty(KOTLIN_VERSION_PROPERTY, version)
pom.addDependency(MavenId(GROUP_ID, getStdlibArtifactId(module, version), "\${$KOTLIN_VERSION_PROPERTY}"), MavenArtifactScope.COMPILE, null, false, null) pom.addDependency(
MavenId(GROUP_ID, getStdlibArtifactId(module, version), "\${$KOTLIN_VERSION_PROPERTY}"),
MavenArtifactScope.COMPILE,
null,
false,
null
)
if (testArtifactId != null) { if (testArtifactId != null) {
pom.addDependency(MavenId(GROUP_ID, testArtifactId, "\${$KOTLIN_VERSION_PROPERTY}"), MavenArtifactScope.TEST, null, false, null) pom.addDependency(MavenId(GROUP_ID, testArtifactId, "\${$KOTLIN_VERSION_PROPERTY}"), MavenArtifactScope.TEST, null, false, null)
} }
@@ -174,13 +181,13 @@ abstract class KotlinMavenConfigurator
} }
protected fun createExecution( protected fun createExecution(
pomFile: PomFile, pomFile: PomFile,
kotlinPlugin: MavenDomPlugin, kotlinPlugin: MavenDomPlugin,
executionId: String, executionId: String,
goalName: String, goalName: String,
module: Module, module: Module,
isTest: Boolean) { isTest: Boolean
) {
pomFile.addKotlinExecution(module, kotlinPlugin, executionId, PomFile.getPhase(false, isTest), isTest, listOf(goalName)) pomFile.addKotlinExecution(module, kotlinPlugin, executionId, PomFile.getPhase(false, isTest), isTest, listOf(goalName))
if (hasJavaFiles(module)) { if (hasJavaFiles(module)) {
@@ -189,18 +196,19 @@ abstract class KotlinMavenConfigurator
} }
override fun updateLanguageVersion( override fun updateLanguageVersion(
module: Module, module: Module,
languageVersion: String?, languageVersion: String?,
apiVersion: String?, apiVersion: String?,
requiredStdlibVersion: ApiVersion, requiredStdlibVersion: ApiVersion,
forTests: Boolean forTests: Boolean
) { ) {
fun doUpdateMavenLanguageVersion(): PsiElement? { fun doUpdateMavenLanguageVersion(): PsiElement? {
val psi = KotlinMavenConfigurator.findModulePomFile(module) as? XmlFile ?: return null val psi = KotlinMavenConfigurator.findModulePomFile(module) as? XmlFile ?: return null
val pom = PomFile.forFileOrNull(psi) ?: return null val pom = PomFile.forFileOrNull(psi) ?: return null
return pom.changeLanguageVersion( return pom.changeLanguageVersion(
languageVersion, languageVersion,
apiVersion) apiVersion
)
} }
val runtimeUpdateRequired = getRuntimeLibraryVersion(module)?.let { ApiVersion.parse(it) }?.let { runtimeVersion -> val runtimeUpdateRequired = getRuntimeLibraryVersion(module)?.let { ApiVersion.parse(it) }?.let { runtimeVersion ->
@@ -208,39 +216,49 @@ abstract class KotlinMavenConfigurator
} ?: false } ?: false
if (runtimeUpdateRequired) { if (runtimeUpdateRequired) {
Messages.showErrorDialog(module.project, Messages.showErrorDialog(
"This language feature requires version $requiredStdlibVersion or later of the Kotlin runtime library. " + module.project,
"Please update the version in your build script.", "This language feature requires version $requiredStdlibVersion or later of the Kotlin runtime library. " +
"Update Language Version") "Please update the version in your build script.",
"Update Language Version"
)
return return
} }
val element = doUpdateMavenLanguageVersion() val element = doUpdateMavenLanguageVersion()
if (element == null) { if (element == null) {
Messages.showErrorDialog(module.project, Messages.showErrorDialog(
"Failed to update.pom.xml. Please update the file manually.", module.project,
"Update Language Version") "Failed to update.pom.xml. Please update the file manually.",
} "Update Language Version"
else { )
} else {
OpenFileDescriptor(module.project, element.containingFile.virtualFile, element.textRange.startOffset).navigate(true) OpenFileDescriptor(module.project, element.containingFile.virtualFile, element.textRange.startOffset).navigate(true)
} }
} }
override fun addLibraryDependency(module: Module, element: PsiElement, library: ExternalLibraryDescriptor, libraryJarDescriptors: List<LibraryJarDescriptor>) { override fun addLibraryDependency(
module: Module,
element: PsiElement,
library: ExternalLibraryDescriptor,
libraryJarDescriptors: List<LibraryJarDescriptor>
) {
val scope = OrderEntryFix.suggestScopeByLocation(module, element) val scope = OrderEntryFix.suggestScopeByLocation(module, element)
JavaProjectModelModificationService.getInstance(module.project).addDependency(module, library, scope) JavaProjectModelModificationService.getInstance(module.project).addDependency(module, library, scope)
} }
override fun changeCoroutineConfiguration(module: Module, state: LanguageFeature.State) { override fun changeCoroutineConfiguration(module: Module, state: LanguageFeature.State) {
val runtimeUpdateRequired = state != LanguageFeature.State.DISABLED && val runtimeUpdateRequired = state != LanguageFeature.State.DISABLED &&
(getRuntimeLibraryVersion(module)?.startsWith("1.0") ?: false) (getRuntimeLibraryVersion(module)?.startsWith("1.0") ?: false)
val messageTitle = ChangeCoroutineSupportFix.getFixText(state) val messageTitle = ChangeCoroutineSupportFix.getFixText(state)
if (runtimeUpdateRequired) { if (runtimeUpdateRequired) {
Messages.showErrorDialog(module.project, Messages.showErrorDialog(
"Coroutines support requires version 1.1 or later of the Kotlin runtime library. " + module.project,
"Please update the version in your build script.", "Coroutines support requires version 1.1 or later of the Kotlin runtime library. " +
messageTitle) "Please update the version in your build script.",
messageTitle
)
return return
} }
@@ -261,19 +279,19 @@ abstract class KotlinMavenConfigurator
val element = doChangeMavenCoroutineConfiguration() val element = doChangeMavenCoroutineConfiguration()
if (element == null) { if (element == null) {
Messages.showErrorDialog(module.project, Messages.showErrorDialog(
"Failed to update.pom.xml. Please update the file manually.", module.project,
messageTitle) "Failed to update.pom.xml. Please update the file manually.",
messageTitle
)
} }
return element return element
} }
companion object { companion object {
val NAME = "maven" const val GROUP_ID = "org.jetbrains.kotlin"
const val MAVEN_PLUGIN_ID = "kotlin-maven-plugin"
val GROUP_ID = "org.jetbrains.kotlin" private const val KOTLIN_VERSION_PROPERTY = "kotlin.version"
val MAVEN_PLUGIN_ID = "kotlin-maven-plugin"
private val KOTLIN_VERSION_PROPERTY = "kotlin.version"
private fun hasJavaFiles(module: Module): Boolean { private fun hasJavaFiles(module: Module): Boolean {
return !FileTypeIndex.getFiles(JavaFileType.INSTANCE, GlobalSearchScope.moduleScope(module)).isEmpty() return !FileTypeIndex.getFiles(JavaFileType.INSTANCE, GlobalSearchScope.moduleScope(module)).isEmpty()
@@ -296,11 +314,13 @@ abstract class KotlinMavenConfigurator
} }
private fun showErrorMessage(project: Project, message: String?) { private fun showErrorMessage(project: Project, message: String?) {
Messages.showErrorDialog(project, Messages.showErrorDialog(
"<html>Couldn't configure kotlin-maven plugin automatically.<br/>" + project,
(if (message != null) "$message</br>" else "") + "<html>Couldn't configure kotlin-maven plugin automatically.<br/>" +
"See manual installation instructions <a href=\"http://confluence.jetbrains.com/display/Kotlin/Kotlin+Build+Tools#KotlinBuildTools-Maven\">here</a>.</html>", (if (message != null) "$message</br>" else "") +
"Configure Kotlin-Maven Plugin") "See manual installation instructions <a href=\"http://confluence.jetbrains.com/display/Kotlin/Kotlin+Build+Tools#KotlinBuildTools-Maven\">here</a>.</html>",
"Configure Kotlin-Maven Plugin"
)
} }
} }
} }
@@ -41,23 +41,26 @@ class DeprecatedMavenDependencyInspection : DomElementsInspection<MavenDomProjec
for (libInfo in DEPRECATED_LIBRARIES_INFORMATION) { for (libInfo in DEPRECATED_LIBRARIES_INFORMATION) {
pomFile.findDependencies(MavenId(libInfo.old.groupId, libInfo.old.name, null)) pomFile.findDependencies(MavenId(libInfo.old.groupId, libInfo.old.name, null))
.filter { it.version?.stringValue != null } .filter { it.version?.stringValue != null }
.filter { .filter {
val libVersion = project.findDependencies(libInfo.old.groupId, libInfo.old.name).map { it.version }.distinct().singleOrNull() val libVersion =
libVersion != null && VersionComparatorUtil.COMPARATOR.compare(libVersion, libInfo.outdatedAfterVersion) >= 0 project.findDependencies(libInfo.old.groupId, libInfo.old.name).map { it.version }.distinct().singleOrNull()
} libVersion != null && VersionComparatorUtil.COMPARATOR.compare(libVersion, libInfo.outdatedAfterVersion) >= 0
.forEach { dependency -> }
val xmlElement = dependency.artifactId.xmlElement .forEach { dependency ->
if (xmlElement != null) { val xmlElement = dependency.artifactId.xmlElement
val fix = ReplaceStringInDocumentFix(xmlElement, libInfo.old.name, libInfo.new.name) if (xmlElement != null) {
val fix = ReplaceStringInDocumentFix(xmlElement, libInfo.old.name, libInfo.new.name)
holder.createProblem(dependency.artifactId, holder.createProblem(
ProblemHighlightType.LIKE_DEPRECATED, dependency.artifactId,
libInfo.message, ProblemHighlightType.LIKE_DEPRECATED,
null, libInfo.message,
fix) null,
} fix
)
} }
}
} }
} }
} }
@@ -28,7 +28,8 @@ import org.jetbrains.kotlin.idea.inspections.PluginVersionDependentInspection
import org.jetbrains.kotlin.idea.maven.PomFile import org.jetbrains.kotlin.idea.maven.PomFile
import org.jetbrains.kotlin.idea.versions.bundledRuntimeVersion import org.jetbrains.kotlin.idea.versions.bundledRuntimeVersion
class DifferentKotlinMavenVersionInspection : DomElementsInspection<MavenDomProjectModel>(MavenDomProjectModel::class.java), PluginVersionDependentInspection { class DifferentKotlinMavenVersionInspection : DomElementsInspection<MavenDomProjectModel>(MavenDomProjectModel::class.java),
PluginVersionDependentInspection {
private val idePluginVersion by lazy { bundledRuntimeVersion() } private val idePluginVersion by lazy { bundledRuntimeVersion() }
override var testVersionMessage: String? = null override var testVersionMessage: String? = null
@@ -53,8 +54,11 @@ class DifferentKotlinMavenVersionInspection : DomElementsInspection<MavenDomProj
} }
private fun createProblem(holder: DomElementAnnotationHolder, plugin: MavenDomPlugin) { private fun createProblem(holder: DomElementAnnotationHolder, plugin: MavenDomPlugin) {
holder.createProblem(plugin.version, holder.createProblem(
HighlightSeverity.WARNING, plugin.version,
"Kotlin version that is used for building with Maven (${plugin.version.stringValue}) differs from the one bundled into the IDE plugin (${testVersionMessage ?: idePluginVersion})") HighlightSeverity.WARNING,
"Kotlin version that is used for building with Maven (${plugin.version.stringValue}) differs from the one bundled into the IDE plugin (${testVersionMessage
?: idePluginVersion})"
)
} }
} }
@@ -57,11 +57,12 @@ class DifferentMavenStdlibVersionInspection : DomElementsInspection<MavenDomProj
createFixes(project, plugin.version, stdlibVersion + version) createFixes(project, plugin.version, stdlibVersion + version)
} ?: emptyList() } ?: emptyList()
holder.createProblem(plugin.version, holder.createProblem(
HighlightSeverity.WARNING, plugin.version,
"Plugin version (${plugin.version}) is not the same as library version (${stdlibVersion.joinToString(",", "", "")})", HighlightSeverity.WARNING,
*fixes.toTypedArray() "Plugin version (${plugin.version}) is not the same as library version (${stdlibVersion.joinToString(",", "", "")})",
) *fixes.toTypedArray()
)
} }
pomFile.findDependencies(MavenId(KotlinMavenConfigurator.GROUP_ID, MAVEN_STDLIB_ID, null)) pomFile.findDependencies(MavenId(KotlinMavenConfigurator.GROUP_ID, MAVEN_STDLIB_ID, null))
@@ -71,10 +72,12 @@ class DifferentMavenStdlibVersionInspection : DomElementsInspection<MavenDomProj
createFixes(project, dependency.version, listOf(version, pluginVersion)) createFixes(project, dependency.version, listOf(version, pluginVersion))
} ?: emptyList() } ?: emptyList()
holder.createProblem(dependency.version, holder.createProblem(
HighlightSeverity.WARNING, dependency.version,
"Plugin version ($pluginVersion) is not the same as library version (${dependency.version})", HighlightSeverity.WARNING,
*fixes.toTypedArray()) "Plugin version ($pluginVersion) is not the same as library version (${dependency.version})",
*fixes.toTypedArray()
)
} }
} }
@@ -87,11 +90,14 @@ class DifferentMavenStdlibVersionInspection : DomElementsInspection<MavenDomProj
val properties = project.properties.entries.filter { it.value == bestVersion }.map { "\${${it.key}}" } val properties = project.properties.entries.filter { it.value == bestVersion }.map { "\${${it.key}}" }
return properties.map { SetVersionQuickFix(versionElement, it, bestVersion) } + return properties.map { SetVersionQuickFix(versionElement, it, bestVersion) } +
SetVersionQuickFix(versionElement, bestVersion, null) SetVersionQuickFix(versionElement, bestVersion, null)
} }
private class SetVersionQuickFix(val versionElement: GenericDomValue<*>, val newVersion: String, val versionResolved: String?) : LocalQuickFix { private class SetVersionQuickFix(val versionElement: GenericDomValue<*>, val newVersion: String, val versionResolved: String?) :
override fun getName() = if (versionResolved == null) "Change version to $newVersion" else "Change version to $newVersion ($versionResolved)" LocalQuickFix {
override fun getName() =
if (versionResolved == null) "Change version to $newVersion" else "Change version to $newVersion ($versionResolved)"
override fun getFamilyName() = "Change version" override fun getFamilyName() = "Change version"
override fun applyFix(project: Project, descriptor: ProblemDescriptor) { override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
@@ -59,8 +59,8 @@ class KotlinMavenPluginPhaseInspection : DomElementsInspection<MavenDomProjectMo
// all executions including inherited // all executions including inherited
val executions = mavenProject.plugins val executions = mavenProject.plugins
.filter { it.isKotlinMavenPlugin() } .filter { it.isKotlinMavenPlugin() }
.flatMap { it.executions } .flatMap { it.executions }
val allGoalsSet: Set<String> = executions.flatMapTo(HashSet()) { it.goals } val allGoalsSet: Set<String> = executions.flatMapTo(HashSet()) { it.goals }
val hasJvmExecution = PomFile.KotlinGoals.Compile in allGoalsSet || PomFile.KotlinGoals.TestCompile in allGoalsSet val hasJvmExecution = PomFile.KotlinGoals.Compile in allGoalsSet || PomFile.KotlinGoals.TestCompile in allGoalsSet
val hasJsExecution = PomFile.KotlinGoals.Js in allGoalsSet || PomFile.KotlinGoals.TestJs in allGoalsSet val hasJsExecution = PomFile.KotlinGoals.Js in allGoalsSet || PomFile.KotlinGoals.TestJs in allGoalsSet
@@ -71,45 +71,52 @@ class KotlinMavenPluginPhaseInspection : DomElementsInspection<MavenDomProjectMo
if (PomFile.KotlinGoals.Compile !in allGoalsSet && PomFile.KotlinGoals.Js !in allGoalsSet) { if (PomFile.KotlinGoals.Compile !in allGoalsSet && PomFile.KotlinGoals.Js !in allGoalsSet) {
val fixes = if (hasJavaFiles) { val fixes = if (hasJavaFiles) {
arrayOf(AddExecutionLocalFix(domFileElement.file, module, kotlinPlugin, PomFile.KotlinGoals.Compile)) arrayOf(AddExecutionLocalFix(domFileElement.file, module, kotlinPlugin, PomFile.KotlinGoals.Compile))
} } else {
else { arrayOf(
arrayOf(AddExecutionLocalFix(domFileElement.file, module, kotlinPlugin, PomFile.KotlinGoals.Compile), AddExecutionLocalFix(domFileElement.file, module, kotlinPlugin, PomFile.KotlinGoals.Compile),
AddExecutionLocalFix(domFileElement.file, module, kotlinPlugin, PomFile.KotlinGoals.Js)) AddExecutionLocalFix(domFileElement.file, module, kotlinPlugin, PomFile.KotlinGoals.Js)
)
} }
holder.createProblem(kotlinPlugin.artifactId.createStableCopy(), holder.createProblem(
HighlightSeverity.WARNING, kotlinPlugin.artifactId.createStableCopy(),
"Kotlin plugin has no compile executions", HighlightSeverity.WARNING,
*fixes) "Kotlin plugin has no compile executions",
} *fixes
else { )
} else {
if (hasJavaFiles) { if (hasJavaFiles) {
pom.findExecutions(kotlinPlugin, PomFile.KotlinGoals.Compile).notAtPhase(PomFile.DefaultPhases.ProcessSources).forEach { badExecution -> pom.findExecutions(kotlinPlugin, PomFile.KotlinGoals.Compile).notAtPhase(PomFile.DefaultPhases.ProcessSources)
val javacPlugin = mavenProject.findPlugin("org.apache.maven.plugins", "maven-compiler-plugin") .forEach { badExecution ->
val existingJavac = pom.domModel.build.plugins.plugins.firstOrNull { val javacPlugin = mavenProject.findPlugin("org.apache.maven.plugins", "maven-compiler-plugin")
it.groupId.stringValue == "org.apache.maven.plugins" && val existingJavac = pom.domModel.build.plugins.plugins.firstOrNull {
it.artifactId.stringValue == "maven-compiler-plugin" it.groupId.stringValue == "org.apache.maven.plugins" &&
} it.artifactId.stringValue == "maven-compiler-plugin"
}
if (existingJavac == null if (existingJavac == null
|| !pom.isPluginAfter(existingJavac, kotlinPlugin) || !pom.isPluginAfter(existingJavac, kotlinPlugin)
|| pom.isExecutionEnabled(javacPlugin, "default-compile") || pom.isExecutionEnabled(javacPlugin, "default-compile")
|| pom.isExecutionEnabled(javacPlugin, "default-testCompile") || pom.isExecutionEnabled(javacPlugin, "default-testCompile")
|| pom.isPluginExecutionMissing(javacPlugin, "default-compile", "compile") || pom.isPluginExecutionMissing(javacPlugin, "default-compile", "compile")
|| pom.isPluginExecutionMissing(javacPlugin, "default-testCompile", "testCompile")) { || pom.isPluginExecutionMissing(javacPlugin, "default-testCompile", "testCompile")) {
holder.createProblem(badExecution.phase.createStableCopy(), holder.createProblem(
HighlightSeverity.WARNING, badExecution.phase.createStableCopy(),
"Kotlin plugin should run before javac so kotlin classes could be visible from Java", HighlightSeverity.WARNING,
FixExecutionPhaseLocalFix(badExecution, PomFile.DefaultPhases.ProcessSources), "Kotlin plugin should run before javac so kotlin classes could be visible from Java",
AddJavaExecutionsLocalFix(module, domFileElement.file, kotlinPlugin)) FixExecutionPhaseLocalFix(badExecution, PomFile.DefaultPhases.ProcessSources),
AddJavaExecutionsLocalFix(module, domFileElement.file, kotlinPlugin)
)
}
} }
}
pom.findExecutions(kotlinPlugin, PomFile.KotlinGoals.Js, PomFile.KotlinGoals.TestJs).forEach { badExecution -> pom.findExecutions(kotlinPlugin, PomFile.KotlinGoals.Js, PomFile.KotlinGoals.TestJs).forEach { badExecution ->
holder.createProblem(badExecution.goals.goals.first { it.isJsGoal() }.createStableCopy(), holder.createProblem(
HighlightSeverity.WARNING, badExecution.goals.goals.first { it.isJsGoal() }.createStableCopy(),
"JavaScript goal configured for module with Java files") HighlightSeverity.WARNING,
"JavaScript goal configured for module with Java files"
)
} }
} }
@@ -117,16 +124,20 @@ class KotlinMavenPluginPhaseInspection : DomElementsInspection<MavenDomProjectMo
val jsDependencies = mavenProject.findDependencies(KotlinMavenConfigurator.GROUP_ID, MAVEN_JS_STDLIB_ID) val jsDependencies = mavenProject.findDependencies(KotlinMavenConfigurator.GROUP_ID, MAVEN_JS_STDLIB_ID)
if (hasJvmExecution && stdlibDependencies.isEmpty()) { if (hasJvmExecution && stdlibDependencies.isEmpty()) {
holder.createProblem(kotlinPlugin.artifactId.createStableCopy(), holder.createProblem(
HighlightSeverity.WARNING, kotlinPlugin.artifactId.createStableCopy(),
"Kotlin JVM compiler configured but no $MAVEN_STDLIB_ID dependency", HighlightSeverity.WARNING,
FixAddStdlibLocalFix(domFileElement.file, MAVEN_STDLIB_ID, kotlinPlugin.version.rawText)) "Kotlin JVM compiler configured but no $MAVEN_STDLIB_ID dependency",
FixAddStdlibLocalFix(domFileElement.file, MAVEN_STDLIB_ID, kotlinPlugin.version.rawText)
)
} }
if (hasJsExecution && jsDependencies.isEmpty()) { if (hasJsExecution && jsDependencies.isEmpty()) {
holder.createProblem(kotlinPlugin.artifactId.createStableCopy(), holder.createProblem(
HighlightSeverity.WARNING, kotlinPlugin.artifactId.createStableCopy(),
"Kotlin JavaScript compiler configured but no $MAVEN_JS_STDLIB_ID dependency", HighlightSeverity.WARNING,
FixAddStdlibLocalFix(domFileElement.file, MAVEN_JS_STDLIB_ID, kotlinPlugin.version.rawText)) "Kotlin JavaScript compiler configured but no $MAVEN_JS_STDLIB_ID dependency",
FixAddStdlibLocalFix(domFileElement.file, MAVEN_JS_STDLIB_ID, kotlinPlugin.version.rawText)
)
} }
} }
} }
@@ -134,40 +145,48 @@ class KotlinMavenPluginPhaseInspection : DomElementsInspection<MavenDomProjectMo
val stdlibDependencies = pom.findDependencies(MavenId(KotlinMavenConfigurator.GROUP_ID, MAVEN_STDLIB_ID, null)) val stdlibDependencies = pom.findDependencies(MavenId(KotlinMavenConfigurator.GROUP_ID, MAVEN_STDLIB_ID, null))
if (!hasJvmExecution && stdlibDependencies.isNotEmpty()) { if (!hasJvmExecution && stdlibDependencies.isNotEmpty()) {
stdlibDependencies.forEach { dep -> stdlibDependencies.forEach { dep ->
holder.createProblem(dep.artifactId.createStableCopy(), holder.createProblem(
HighlightSeverity.WARNING, dep.artifactId.createStableCopy(),
"You have ${dep.artifactId} configured but no corresponding plugin execution", HighlightSeverity.WARNING,
ConfigurePluginExecutionLocalFix(module, domFileElement.file, PomFile.KotlinGoals.Compile, dep.version.rawText)) "You have ${dep.artifactId} configured but no corresponding plugin execution",
ConfigurePluginExecutionLocalFix(module, domFileElement.file, PomFile.KotlinGoals.Compile, dep.version.rawText)
)
} }
} }
val stdlibJsDependencies = pom.findDependencies(MavenId(KotlinMavenConfigurator.GROUP_ID, MAVEN_JS_STDLIB_ID, null)) val stdlibJsDependencies = pom.findDependencies(MavenId(KotlinMavenConfigurator.GROUP_ID, MAVEN_JS_STDLIB_ID, null))
if (!hasJsExecution && stdlibJsDependencies.isNotEmpty()) { if (!hasJsExecution && stdlibJsDependencies.isNotEmpty()) {
stdlibJsDependencies.forEach { dep -> stdlibJsDependencies.forEach { dep ->
holder.createProblem(dep.artifactId.createStableCopy(), holder.createProblem(
HighlightSeverity.WARNING, dep.artifactId.createStableCopy(),
"You have ${dep.artifactId} configured but no corresponding plugin execution", HighlightSeverity.WARNING,
ConfigurePluginExecutionLocalFix(module, domFileElement.file, PomFile.KotlinGoals.Js, dep.version.rawText)) "You have ${dep.artifactId} configured but no corresponding plugin execution",
ConfigurePluginExecutionLocalFix(module, domFileElement.file, PomFile.KotlinGoals.Js, dep.version.rawText)
)
} }
} }
pom.findKotlinExecutions().filter { pom.findKotlinExecutions().filter {
it.goals.goals.any { it.rawText == PomFile.KotlinGoals.Compile || it.rawText == PomFile.KotlinGoals.Js } it.goals.goals.any { it.rawText == PomFile.KotlinGoals.Compile || it.rawText == PomFile.KotlinGoals.Js }
&& it.goals.goals.any { it.rawText == PomFile.KotlinGoals.TestCompile || it.rawText == PomFile.KotlinGoals.TestJs } && it.goals.goals.any { it.rawText == PomFile.KotlinGoals.TestCompile || it.rawText == PomFile.KotlinGoals.TestJs }
}.forEach { badExecution -> }.forEach { badExecution ->
holder.createProblem(badExecution.goals.createStableCopy(), holder.createProblem(
HighlightSeverity.WEAK_WARNING, badExecution.goals.createStableCopy(),
"It is not recommended to have both test and compile goals in the same execution") HighlightSeverity.WEAK_WARNING,
} "It is not recommended to have both test and compile goals in the same execution"
)
}
} }
private class AddExecutionLocalFix(val file: XmlFile, val module: Module, val kotlinPlugin: MavenDomPlugin, val goal: String) : LocalQuickFix { private class AddExecutionLocalFix(val file: XmlFile, val module: Module, val kotlinPlugin: MavenDomPlugin, val goal: String) :
LocalQuickFix {
override fun getName() = "Create $goal execution" override fun getName() = "Create $goal execution"
override fun getFamilyName() = "Create kotlin execution" override fun getFamilyName() = "Create kotlin execution"
override fun applyFix(project: Project, descriptor: ProblemDescriptor) { override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
PomFile.forFileOrNull(file)?.addKotlinExecution(module, kotlinPlugin, goal, PomFile.getPhase(module.hasJavaFiles(), false), false, listOf(goal)) PomFile.forFileOrNull(file)
?.addKotlinExecution(module, kotlinPlugin, goal, PomFile.getPhase(module.hasJavaFiles(), false), false, listOf(goal))
} }
} }
@@ -195,11 +214,13 @@ class KotlinMavenPluginPhaseInspection : DomElementsInspection<MavenDomProjectMo
override fun getFamilyName() = "Add dependency" override fun getFamilyName() = "Add dependency"
override fun applyFix(project: Project, descriptor: ProblemDescriptor) { override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
PomFile.forFileOrNull(pomFile)?.addDependency(MavenId(KotlinMavenConfigurator.GROUP_ID, id, version), MavenArtifactScope.COMPILE) PomFile.forFileOrNull(pomFile)
?.addDependency(MavenId(KotlinMavenConfigurator.GROUP_ID, id, version), MavenArtifactScope.COMPILE)
} }
} }
private class ConfigurePluginExecutionLocalFix(val module: Module, val xmlFile: XmlFile, val goal: String, val version: String?) : LocalQuickFix { private class ConfigurePluginExecutionLocalFix(val module: Module, val xmlFile: XmlFile, val goal: String, val version: String?) :
LocalQuickFix {
override fun getName() = "Create $goal execution of kotlin-maven-compiler" override fun getName() = "Create $goal execution of kotlin-maven-compiler"
override fun getFamilyName() = "Create kotlin execution" override fun getFamilyName() = "Create kotlin execution"
@@ -217,7 +238,7 @@ fun Module.hasJavaFiles(): Boolean {
} }
private fun MavenPlugin.isKotlinMavenPlugin() = groupId == KotlinMavenConfigurator.GROUP_ID private fun MavenPlugin.isKotlinMavenPlugin() = groupId == KotlinMavenConfigurator.GROUP_ID
&& artifactId == KotlinMavenConfigurator.MAVEN_PLUGIN_ID && artifactId == KotlinMavenConfigurator.MAVEN_PLUGIN_ID
private fun MavenDomGoal.isJsGoal() = rawText == PomFile.KotlinGoals.Js || rawText == PomFile.KotlinGoals.TestJs private fun MavenDomGoal.isJsGoal() = rawText == PomFile.KotlinGoals.Js || rawText == PomFile.KotlinGoals.TestJs
@@ -42,7 +42,7 @@ import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
class KotlinMavenUnresolvedReferenceQuickFixProvider : UnresolvedReferenceQuickFixProvider<KtSimpleNameReference>() { class KotlinMavenUnresolvedReferenceQuickFixProvider : UnresolvedReferenceQuickFixProvider<KtSimpleNameReference>() {
override fun getReferenceClass(): Class<KtSimpleNameReference> = KtSimpleNameReference::class.java override fun getReferenceClass(): Class<KtSimpleNameReference> = KtSimpleNameReference::class.java
override fun registerFixes(ref: KtSimpleNameReference, registrar: QuickFixActionRegistrar) { override fun registerFixes(ref: KtSimpleNameReference, registrar: QuickFixActionRegistrar) {
val module = ModuleUtilCore.findModuleForPsiElement(ref.expression) ?: return val module = ModuleUtilCore.findModuleForPsiElement(ref.expression) ?: return
@@ -59,15 +59,14 @@ class KotlinMavenUnresolvedReferenceQuickFixProvider : UnresolvedReferenceQuickF
} else { } else {
importDirective.importedFqName?.asString() importDirective.importedFqName?.asString()
} }
} } else {
else {
val typeReference = expression.getParentOfType<KtTypeReference>(true) val typeReference = expression.getParentOfType<KtTypeReference>(true)
val referenced = typeReference?.text ?: expression.getReferencedName() val referenced = typeReference?.text ?: expression.getReferencedName()
expression.containingKtFile expression.containingKtFile
.importDirectives .importDirectives
.firstOrNull { !it.isAllUnder && it.aliasName == referenced || it.importedFqName?.shortName()?.asString() == referenced } .firstOrNull { !it.isAllUnder && it.aliasName == referenced || it.importedFqName?.shortName()?.asString() == referenced }
?.let { it.importedFqName?.asString() } ?.let { it.importedFqName?.asString() }
?: referenced ?: referenced
} }
@@ -77,12 +76,16 @@ class KotlinMavenUnresolvedReferenceQuickFixProvider : UnresolvedReferenceQuickF
} }
} }
class AddMavenDependencyQuickFix(val className: String, val smartPsiElementPointer: SmartPsiElementPointer<KtSimpleNameExpression>) : IntentionAction, LowPriorityAction { class AddMavenDependencyQuickFix(
val className: String,
private val smartPsiElementPointer: SmartPsiElementPointer<KtSimpleNameExpression>
) :
IntentionAction, LowPriorityAction {
override fun getText() = "Add Maven dependency..." override fun getText() = "Add Maven dependency..."
override fun getFamilyName() = text override fun getFamilyName() = text
override fun startInWriteAction() = false override fun startInWriteAction() = false
override fun isAvailable(project: Project, editor: Editor?, file: PsiFile?) = override fun isAvailable(project: Project, editor: Editor?, file: PsiFile?) =
smartPsiElementPointer.element.let { it != null && it.isValid } && file != null && MavenDomUtil.findContainingProject(file) != null smartPsiElementPointer.element.let { it != null && it.isValid } && file != null && MavenDomUtil.findContainingProject(file) != null
override fun invoke(project: Project, editor: Editor?, file: PsiFile?) { override fun invoke(project: Project, editor: Editor?, file: PsiFile?) {
if (editor == null || file == null) { if (editor == null || file == null) {
@@ -45,14 +45,15 @@ class KotlinTestJUnitInspection : DomElementsInspection<MavenDomProjectModel>(Ma
} }
val kotlinTestDependencies = domFileElement.rootElement.dependencies val kotlinTestDependencies = domFileElement.rootElement.dependencies
.dependencies.filter { it.groupId.rawText == KotlinMavenConfigurator.GROUP_ID && it.artifactId.rawText == KotlinJavaMavenConfigurator.TEST_LIB_ID } .dependencies.filter { it.groupId.rawText == KotlinMavenConfigurator.GROUP_ID && it.artifactId.rawText == KotlinJavaMavenConfigurator.TEST_LIB_ID }
kotlinTestDependencies.forEach { kotlinTestDependencies.forEach {
holder.createProblem(it.artifactId, holder.createProblem(
HighlightSeverity.WEAK_WARNING, it.artifactId,
"kotlin-test-junit is better with junit", HighlightSeverity.WEAK_WARNING,
ReplaceToKotlinTest(it) "kotlin-test-junit is better with junit",
) ReplaceToKotlinTest(it)
)
} }
} }
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.idea.maven
import com.intellij.codeInspection.CommonProblemDescriptor import com.intellij.codeInspection.CommonProblemDescriptor
import com.intellij.codeInspection.ProblemDescriptorBase import com.intellij.codeInspection.ProblemDescriptorBase
import com.intellij.codeInspection.QuickFix import com.intellij.codeInspection.QuickFix
import com.intellij.codeInspection.reference.RefEntity
import com.intellij.ide.highlighter.JavaFileType import com.intellij.ide.highlighter.JavaFileType
import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.Result import com.intellij.openapi.application.Result
@@ -60,29 +59,32 @@ abstract class AbstractKotlinMavenInspectionTest : MavenImportingTestCase() {
mkJavaFile() mkJavaFile()
} }
val inspectionClassName = "<!--\\s*inspection:\\s*([\\S]+)\\s-->".toRegex().find(pomText)?.groups?.get(1)?.value ?: KotlinMavenPluginPhaseInspection::class.qualifiedName !! val inspectionClassName = "<!--\\s*inspection:\\s*([\\S]+)\\s-->".toRegex().find(pomText)?.groups?.get(1)?.value
?: KotlinMavenPluginPhaseInspection::class.qualifiedName!!
val inspectionClass = Class.forName(inspectionClassName) val inspectionClass = Class.forName(inspectionClassName)
val matcher = "<!--\\s*problem:\\s*on\\s*([^,]+),\\s*title\\s*(.+)\\s*-->".toRegex() val matcher = "<!--\\s*problem:\\s*on\\s*([^,]+),\\s*title\\s*(.+)\\s*-->".toRegex()
val expected = pomText.lines().mapNotNull { matcher.find(it) }.map { SimplifiedProblemDescription(it.groups[2]!!.value.trim(), it.groups[1]!!.value.trim()) } val expected = pomText.lines().mapNotNull { matcher.find(it) }
.map { SimplifiedProblemDescription(it.groups[2]!!.value.trim(), it.groups[1]!!.value.trim()) }
val problemElements = runInspection(inspectionClass, myProject).problemElements val problemElements = runInspection(inspectionClass, myProject).problemElements
val actualProblems = problemElements val actualProblems = problemElements
.keys() .keys()
.filter { it.name == "pom.xml" } .filter { it.name == "pom.xml" }
.map { problemElements.get(it) } .map { problemElements.get(it) }
.flatMap { it.toList() } .flatMap { it.toList() }
.mapNotNull { it as? ProblemDescriptorBase } .mapNotNull { it as? ProblemDescriptorBase }
val actual = actualProblems val actual = actualProblems
.map { SimplifiedProblemDescription(it.descriptionTemplate, it.psiElement.text.replace("\\s+".toRegex(), "")) to it } .map { SimplifiedProblemDescription(it.descriptionTemplate, it.psiElement.text.replace("\\s+".toRegex(), "")) to it }
.sortedBy { it.first.text } .sortedBy { it.first.text }
assertEquals(expected.sortedBy { it.text }, actual.map { it.first }) assertEquals(expected.sortedBy { it.text }, actual.map { it.first })
val suggestedFixes = actual.flatMap { p -> p.second.fixes?.sortedBy { it.familyName }?.map { p.second to it } ?: emptyList() } val suggestedFixes = actual.flatMap { p -> p.second.fixes?.sortedBy { it.familyName }?.map { p.second to it } ?: emptyList() }
val filenamePrefix = pomFile.nameWithoutExtension + ".fixed." val filenamePrefix = pomFile.nameWithoutExtension + ".fixed."
val fixFiles = pomFile.parentFile.listFiles { _, name -> name.startsWith(filenamePrefix) && name.endsWith(".xml") }.sortedBy { it.name } val fixFiles =
pomFile.parentFile.listFiles { _, name -> name.startsWith(filenamePrefix) && name.endsWith(".xml") }.sortedBy { it.name }
if (fixFiles.size > suggestedFixes.size) { if (fixFiles.size > suggestedFixes.size) {
fail("Not all fixes were suggested by the inspection: expected count: ${fixFiles.size}, actual fixes count: ${suggestedFixes.size}") fail("Not all fixes were suggested by the inspection: expected count: ${fixFiles.size}, actual fixes count: ${suggestedFixes.size}")
@@ -144,7 +146,8 @@ abstract class AbstractKotlinMavenInspectionTest : MavenImportingTestCase() {
} }
private fun mkJavaFile() { private fun mkJavaFile() {
val sourceFolder = getContentRoots(myProject.allModules().single().name).single().getSourceFolders(JavaSourceRootType.SOURCE).single() val sourceFolder =
getContentRoots(myProject.allModules().single().name).single().getSourceFolders(JavaSourceRootType.SOURCE).single()
ApplicationManager.getApplication().runWriteAction { ApplicationManager.getApplication().runWriteAction {
val javaFile = sourceFolder.file?.toPsiDirectory(myProject)?.createFile("Test.java") ?: throw IllegalStateException() val javaFile = sourceFolder.file?.toPsiDirectory(myProject)?.createFile("Test.java") ?: throw IllegalStateException()
javaFile.viewProvider.document!!.setText("class Test {}\n") javaFile.viewProvider.document!!.setText("class Test {}\n")
@@ -24,7 +24,9 @@ import org.junit.Test
import java.io.File import java.io.File
class KotlinMavenArchetypesProviderTest { class KotlinMavenArchetypesProviderTest {
private val BASE_PATH = "idea/testData/configuration/" companion object {
private const val BASE_PATH = "idea/testData/configuration/"
}
@Test @Test
fun extractVersions() { fun extractVersions() {
@@ -38,11 +40,11 @@ class KotlinMavenArchetypesProviderTest {
val versions = KotlinMavenArchetypesProvider("1.0.0-Release-Something-1886", false).extractVersions(json) val versions = KotlinMavenArchetypesProvider("1.0.0-Release-Something-1886", false).extractVersions(json)
assertEquals( assertEquals(
listOf( listOf(
MavenArchetype("org.jetbrains.kotlin", "kotlin-archetype-jvm", "1.0.1-2", null, null), MavenArchetype("org.jetbrains.kotlin", "kotlin-archetype-jvm", "1.0.1-2", null, null),
MavenArchetype("org.jetbrains.kotlin", "kotlin-archetype-js", "1.0.0", null, null) MavenArchetype("org.jetbrains.kotlin", "kotlin-archetype-js", "1.0.0", null, null)
).sortedBy { it.artifactId + "." + it.version }, ).sortedBy { it.artifactId + "." + it.version },
versions.sortedBy { it.artifactId + "." + it.version } versions.sortedBy { it.artifactId + "." + it.version }
) )
} }
@@ -58,10 +60,10 @@ class KotlinMavenArchetypesProviderTest {
val versions = KotlinMavenArchetypesProvider("1.1.0-Next-Release-Something-9999", false).extractVersions(json) val versions = KotlinMavenArchetypesProvider("1.1.0-Next-Release-Something-9999", false).extractVersions(json)
assertEquals( assertEquals(
listOf( listOf(
MavenArchetype("org.jetbrains.kotlin", "kotlin-archetype-jvm", "1.1.2", null, null) MavenArchetype("org.jetbrains.kotlin", "kotlin-archetype-jvm", "1.1.2", null, null)
).sortedBy { it.artifactId + "." + it.version }, ).sortedBy { it.artifactId + "." + it.version },
versions.sortedBy { it.artifactId + "." + it.version } versions.sortedBy { it.artifactId + "." + it.version }
) )
} }
@@ -77,12 +79,12 @@ class KotlinMavenArchetypesProviderTest {
val versions = KotlinMavenArchetypesProvider("1.0.0-Release-Something-1886", true).extractVersions(json) val versions = KotlinMavenArchetypesProvider("1.0.0-Release-Something-1886", true).extractVersions(json)
assertEquals( assertEquals(
listOf( listOf(
MavenArchetype("org.jetbrains.kotlin", "kotlin-archetype-jvm", "1.0.1-2", null, null), MavenArchetype("org.jetbrains.kotlin", "kotlin-archetype-jvm", "1.0.1-2", null, null),
MavenArchetype("org.jetbrains.kotlin", "kotlin-archetype-jvm", "1.1.2", null, null), MavenArchetype("org.jetbrains.kotlin", "kotlin-archetype-jvm", "1.1.2", null, null),
MavenArchetype("org.jetbrains.kotlin", "kotlin-archetype-js", "1.0.0", null, null) MavenArchetype("org.jetbrains.kotlin", "kotlin-archetype-js", "1.0.0", null, null)
).sortedBy { it.artifactId + "." + it.version }, ).sortedBy { it.artifactId + "." + it.version },
versions.sortedBy { it.artifactId + "." + it.version } versions.sortedBy { it.artifactId + "." + it.version }
) )
} }
@@ -98,12 +100,12 @@ class KotlinMavenArchetypesProviderTest {
val versions = KotlinMavenArchetypesProvider("1.9.0-Missing-Release-Something-1886", false).extractVersions(json) val versions = KotlinMavenArchetypesProvider("1.9.0-Missing-Release-Something-1886", false).extractVersions(json)
assertEquals( assertEquals(
listOf( listOf(
MavenArchetype("org.jetbrains.kotlin", "kotlin-archetype-jvm", "1.0.1-2", null, null), MavenArchetype("org.jetbrains.kotlin", "kotlin-archetype-jvm", "1.0.1-2", null, null),
MavenArchetype("org.jetbrains.kotlin", "kotlin-archetype-jvm", "1.1.2", null, null), MavenArchetype("org.jetbrains.kotlin", "kotlin-archetype-jvm", "1.1.2", null, null),
MavenArchetype("org.jetbrains.kotlin", "kotlin-archetype-js", "1.0.0", null, null) MavenArchetype("org.jetbrains.kotlin", "kotlin-archetype-js", "1.0.0", null, null)
).sortedBy { it.artifactId + "." + it.version }, ).sortedBy { it.artifactId + "." + it.version },
versions.sortedBy { it.artifactId + "." + it.version } versions.sortedBy { it.artifactId + "." + it.version }
) )
} }
@@ -119,12 +121,12 @@ class KotlinMavenArchetypesProviderTest {
val versions = KotlinMavenArchetypesProvider("@snapshot@", false).extractVersions(json) val versions = KotlinMavenArchetypesProvider("@snapshot@", false).extractVersions(json)
assertEquals( assertEquals(
listOf( listOf(
MavenArchetype("org.jetbrains.kotlin", "kotlin-archetype-jvm", "1.0.1-2", null, null), MavenArchetype("org.jetbrains.kotlin", "kotlin-archetype-jvm", "1.0.1-2", null, null),
MavenArchetype("org.jetbrains.kotlin", "kotlin-archetype-jvm", "1.1.2", null, null), MavenArchetype("org.jetbrains.kotlin", "kotlin-archetype-jvm", "1.1.2", null, null),
MavenArchetype("org.jetbrains.kotlin", "kotlin-archetype-js", "1.0.0", null, null) MavenArchetype("org.jetbrains.kotlin", "kotlin-archetype-js", "1.0.0", null, null)
).sortedBy { it.artifactId + "." + it.version }, ).sortedBy { it.artifactId + "." + it.version },
versions.sortedBy { it.artifactId + "." + it.version } versions.sortedBy { it.artifactId + "." + it.version }
) )
} }
} }
File diff suppressed because it is too large Load Diff
@@ -217,14 +217,17 @@ public abstract class MavenImportingTestCase extends MavenTestCase {
assertModuleLibDepPath(lib, OrderRootType.CLASSES, classesPath == null ? null : Collections.singletonList(classesPath)); assertModuleLibDepPath(lib, OrderRootType.CLASSES, classesPath == null ? null : Collections.singletonList(classesPath));
assertModuleLibDepPath(lib, OrderRootType.SOURCES, sourcePath == null ? null : Collections.singletonList(sourcePath)); assertModuleLibDepPath(lib, OrderRootType.SOURCES, sourcePath == null ? null : Collections.singletonList(sourcePath));
assertModuleLibDepPath(lib, JavadocOrderRootType.getInstance(), javadocPath == null ? null : Collections.singletonList(javadocPath)); assertModuleLibDepPath(lib, JavadocOrderRootType.getInstance(),
javadocPath == null ? null : Collections.singletonList(javadocPath));
} }
protected void assertModuleLibDep(String moduleName, protected void assertModuleLibDep(
String moduleName,
String depName, String depName,
List<String> classesPaths, List<String> classesPaths,
List<String> sourcePaths, List<String> sourcePaths,
List<String> javadocPaths) { List<String> javadocPaths
) {
LibraryOrderEntry lib = getModuleLibDep(moduleName, depName); LibraryOrderEntry lib = getModuleLibDep(moduleName, depName);
assertModuleLibDepPath(lib, OrderRootType.CLASSES, classesPaths); assertModuleLibDepPath(lib, OrderRootType.CLASSES, classesPaths);
@@ -255,19 +258,20 @@ public abstract class MavenImportingTestCase extends MavenTestCase {
protected void assertExportedDeps(String moduleName, String... expectedDeps) { protected void assertExportedDeps(String moduleName, String... expectedDeps) {
final List<String> actual = new ArrayList<String>(); final List<String> actual = new ArrayList<String>();
getRootManager(moduleName).orderEntries().withoutSdk().withoutModuleSourceEntries().exportedOnly().process(new RootPolicy<Object>() { getRootManager(moduleName).orderEntries().withoutSdk().withoutModuleSourceEntries().exportedOnly()
@Override .process(new RootPolicy<Object>() {
public Object visitModuleOrderEntry(ModuleOrderEntry e, Object value) { @Override
actual.add(e.getModuleName()); public Object visitModuleOrderEntry(ModuleOrderEntry e, Object value) {
return null; actual.add(e.getModuleName());
} return null;
}
@Override @Override
public Object visitLibraryOrderEntry(LibraryOrderEntry e, Object value) { public Object visitLibraryOrderEntry(LibraryOrderEntry e, Object value) {
actual.add(e.getLibraryName()); actual.add(e.getLibraryName());
return null; return null;
} }
}, null); }, null);
assertOrderedElementsAreEqual(actual, expectedDeps); assertOrderedElementsAreEqual(actual, expectedDeps);
} }
@@ -305,7 +309,7 @@ public abstract class MavenImportingTestCase extends MavenTestCase {
for (OrderEntry e : getRootManager(moduleName).getOrderEntries()) { for (OrderEntry e : getRootManager(moduleName).getOrderEntries()) {
if (clazz.isInstance(e) && e.getPresentableName().equals(depName)) { if (clazz.isInstance(e) && e.getPresentableName().equals(depName)) {
dep = (T)e; dep = (T) e;
} }
} }
assertNotNull("Dependency not found: " + depName assertNotNull("Dependency not found: " + depName
@@ -507,8 +511,10 @@ public abstract class MavenImportingTestCase extends MavenTestCase {
downloadArtifacts(myProjectsManager.getProjects(), null); downloadArtifacts(myProjectsManager.getProjects(), null);
} }
protected MavenArtifactDownloader.DownloadResult downloadArtifacts(Collection<MavenProject> projects, protected MavenArtifactDownloader.DownloadResult downloadArtifacts(
List<MavenArtifact> artifacts) { Collection<MavenProject> projects,
List<MavenArtifact> artifacts
) {
final MavenArtifactDownloader.DownloadResult[] unresolved = new MavenArtifactDownloader.DownloadResult[1]; final MavenArtifactDownloader.DownloadResult[] unresolved = new MavenArtifactDownloader.DownloadResult[1];
AsyncResult<MavenArtifactDownloader.DownloadResult> result = new AsyncResult<MavenArtifactDownloader.DownloadResult>(); AsyncResult<MavenArtifactDownloader.DownloadResult> result = new AsyncResult<MavenArtifactDownloader.DownloadResult>();
@@ -67,7 +67,7 @@ public abstract class MavenTestCase extends UsefulTestCase {
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setConnectTimeout(1000); urlConnection.setConnectTimeout(1000);
int responseCode = urlConnection.getResponseCode(); int responseCode = urlConnection.getResponseCode();
if(responseCode < 400) { if (responseCode < 400) {
mirrorDiscoverable = true; mirrorDiscoverable = true;
} }
} }
@@ -137,7 +137,6 @@ public abstract class MavenTestCase extends UsefulTestCase {
}); });
} }
}); });
} }
private void ensureTempDirCreated() throws IOException { private void ensureTempDirCreated() throws IOException {
@@ -277,7 +276,9 @@ public abstract class MavenTestCase extends UsefulTestCase {
} }
protected static String getEnvVar() { protected static String getEnvVar() {
if (SystemInfo.isWindows) return "TEMP"; if (SystemInfo.isWindows) {
return "TEMP";
}
else if (SystemInfo.isLinux) return "HOME"; else if (SystemInfo.isLinux) return "HOME";
return "TMPDIR"; return "TMPDIR";
} }
@@ -409,8 +410,9 @@ public abstract class MavenTestCase extends UsefulTestCase {
return f; return f;
} }
@NonNls @Language(value="XML") @NonNls
public static String createPomXml(@NonNls @Language(value="XML", prefix="<xml>", suffix="</xml>") String xml) { @Language(value = "XML")
public static String createPomXml(@NonNls @Language(value = "XML", prefix = "<xml>", suffix = "</xml>") String xml) {
return "<?xml version=\"1.0\"?>" + return "<?xml version=\"1.0\"?>" +
"<project xmlns=\"http://maven.apache.org/POM/4.0.0\"" + "<project xmlns=\"http://maven.apache.org/POM/4.0.0\"" +
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" +
@@ -542,6 +544,7 @@ public abstract class MavenTestCase extends UsefulTestCase {
protected static <T> void assertUnorderedElementsAreEqual(Collection<T> actual, Collection<T> expected) { protected static <T> void assertUnorderedElementsAreEqual(Collection<T> actual, Collection<T> expected) {
assertEquals(new HashSet<T>(expected), new HashSet<T>(actual)); assertEquals(new HashSet<T>(expected), new HashSet<T>(actual));
} }
protected static void assertUnorderedPathsAreEqual(Collection<String> actual, Collection<String> expected) { protected static void assertUnorderedPathsAreEqual(Collection<String> actual, Collection<String> expected) {
assertEquals(new SetWithToString<String>(new THashSet<String>(expected, FileUtil.PATH_HASHING_STRATEGY)), assertEquals(new SetWithToString<String>(new THashSet<String>(expected, FileUtil.PATH_HASHING_STRATEGY)),
new SetWithToString<String>(new THashSet<String>(actual, FileUtil.PATH_HASHING_STRATEGY))); new SetWithToString<String>(new THashSet<String>(actual, FileUtil.PATH_HASHING_STRATEGY)));
@@ -641,5 +644,4 @@ public abstract class MavenTestCase extends UsefulTestCase {
return myDelegate.hashCode(); return myDelegate.hashCode();
} }
} }
} }
@@ -33,7 +33,8 @@ import kotlin.reflect.KMutableProperty0
class MavenUpdateConfigurationQuickFixTest : MavenImportingTestCase() { class MavenUpdateConfigurationQuickFixTest : MavenImportingTestCase() {
private lateinit var codeInsightTestFixture: CodeInsightTestFixture private lateinit var codeInsightTestFixture: CodeInsightTestFixture
fun getTestDataPath() = KotlinTestUtils.getHomeDirectory() + "/idea/idea-maven/testData/languageFeature/" + getTestName(true).substringBefore('_') private fun getTestDataPath() =
KotlinTestUtils.getHomeDirectory() + "/idea/idea-maven/testData/languageFeature/" + getTestName(true).substringBefore('_')
override fun setUpFixtures() { override fun setUpFixtures() {
myTestFixture = IdeaTestFixtureFactory.getFixtureFactory().createFixtureBuilder(getName()).fixture myTestFixture = IdeaTestFixtureFactory.getFixtureFactory().createFixtureBuilder(getName()).fixture
@@ -43,31 +44,38 @@ class MavenUpdateConfigurationQuickFixTest : MavenImportingTestCase() {
override fun tearDownFixtures() { override fun tearDownFixtures() {
codeInsightTestFixture.tearDown() codeInsightTestFixture.tearDown()
@Suppress("UNCHECKED_CAST")
(this::codeInsightTestFixture as KMutableProperty0<CodeInsightTestFixture?>).set(null) (this::codeInsightTestFixture as KMutableProperty0<CodeInsightTestFixture?>).set(null)
myTestFixture = null myTestFixture = null
} }
@Test fun testUpdateLanguageVersion() { @Test
fun testUpdateLanguageVersion() {
doTest("Set module language version to 1.1") doTest("Set module language version to 1.1")
} }
@Test fun testUpdateLanguageVersionProperty() { @Test
fun testUpdateLanguageVersionProperty() {
doTest("Set module language version to 1.1") doTest("Set module language version to 1.1")
} }
@Test fun testUpdateApiVersion() { @Test
fun testUpdateApiVersion() {
doTest("Set module API version to 1.1") doTest("Set module API version to 1.1")
} }
@Test fun testUpdateLanguageAndApiVersion() { @Test
fun testUpdateLanguageAndApiVersion() {
doTest("Set module language version to 1.1") doTest("Set module language version to 1.1")
} }
@Test fun testEnableCoroutines() { @Test
fun testEnableCoroutines() {
doTest("Enable coroutine support in the current module") doTest("Enable coroutine support in the current module")
} }
@Test fun testAddKotlinReflect() { @Test
fun testAddKotlinReflect() {
doTest("Add kotlin-reflect.jar to the classpath") doTest("Add kotlin-reflect.jar to the classpath")
} }
@@ -39,7 +39,13 @@ abstract class AbstractMavenConfigureProjectByChangingFileTest : AbstractConfigu
doTest(pathWithFile, pathWithFile.replace("pom", "pom_after"), KotlinJavascriptMavenConfigurator()) doTest(pathWithFile, pathWithFile.replace("pom", "pom_after"), KotlinJavascriptMavenConfigurator())
} }
override fun runConfigurator(module: Module, file: PsiFile, configurator: KotlinMavenConfigurator, version: String, collector: NotificationMessageCollector) { override fun runConfigurator(
module: Module,
file: PsiFile,
configurator: KotlinMavenConfigurator,
version: String,
collector: NotificationMessageCollector
) {
WriteCommandAction.runWriteCommandAction(module.project) { WriteCommandAction.runWriteCommandAction(module.project) {
configurator.configureModule(module, file, version, collector) configurator.configureModule(module, file, version, collector)
} }