Gradle, js, npm: resolve and warn about clashes in packages_imported

#KT-31697 Fixed
This commit is contained in:
Sergey Rostov
2019-05-31 12:47:50 +03:00
parent 46a1ec28bf
commit 85adee9804
3 changed files with 94 additions and 10 deletions
@@ -10,4 +10,7 @@ import java.io.File
/**
* Fake NodeJS module directory created from Gradle external module
*/
data class GradleNodeModule(val name: String, val version: String, val path: File)
data class GradleNodeModule(val name: String, val version: String, val path: File) {
val semver: SemVer
get() = SemVer.from(version)
}
@@ -0,0 +1,88 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.targets.js.yarn
import com.google.gson.Gson
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.targets.js.npm.GradleNodeModule
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProject
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProjectPackage
import org.jetbrains.kotlin.gradle.targets.js.npm.PackageJson
import java.io.File
class YarnImportedPackagesVersionResolver(
private val rootProject: Project,
private val npmProjects: MutableList<NpmProjectPackage>,
private val nodeJsWorldDir: File
) {
private val resolvedVersion = mutableMapOf<String, String>()
private val importedProjectWorkspaces = mutableListOf<String>()
private val externalModules = npmProjects.flatMapTo(mutableSetOf()) {
it.gradleDependencies.externalModules
}
fun resolveAndUpdatePackages(): MutableList<String> {
resolve()
updatePackages()
return importedProjectWorkspaces
}
private fun resolve() {
externalModules.groupBy { it.name }.forEach { (name, versions) ->
val selected: GradleNodeModule = if (versions.size > 1) {
val sorted = versions.sortedBy { it.semver }
rootProject.logger.warn(
"There are multiple versions of \"$name\" used in nodejs build: ${sorted.joinToString(", ") { it.version }}. " +
"Only latest version will be used."
)
val selected = sorted.last()
resolvedVersion[name] = selected.version
selected
} else versions.single()
importedProjectWorkspaces.add(selected.path.relativeTo(nodeJsWorldDir).path)
}
}
private fun updatePackages() {
if (resolvedVersion.isEmpty()) return
npmProjects.forEach {
updatePackageJson(it.packageJson, it.npmProject.packageJsonFile)
}
externalModules.forEach {
val packageJsonFile = it.path.resolve(NpmProject.PACKAGE_JSON)
val packageJson = packageJsonFile.reader().use {
Gson().fromJson<PackageJson>(it, PackageJson::class.java)
}
updatePackageJson(packageJson, packageJsonFile)
}
}
private fun updatePackageJson(
packageJson: PackageJson,
path: File
) {
val updates = listOf(packageJson.dependencies, packageJson.devDependencies).map { updateVersionsMap(it) }
if (updates.any { it }) {
packageJson.saveTo(path)
}
}
private fun updateVersionsMap(map: MutableMap<String, String>): Boolean {
var doneSomething = false
map.iterator().forEachRemaining {
val resolved = resolvedVersion[it.key]
if (resolved != null) {
it.setValue(resolved)
doneSomething = true
}
}
return doneSomething
}
}
@@ -7,10 +7,7 @@ package org.jetbrains.kotlin.gradle.targets.js.yarn
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.targets.js.nodejs.nodeJs
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmApi
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProject
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProjectPackage
import org.jetbrains.kotlin.gradle.targets.js.npm.PackageJson
import org.jetbrains.kotlin.gradle.targets.js.npm.*
import java.io.File
object YarnWorkspaces : YarnBasics() {
@@ -53,11 +50,7 @@ object YarnWorkspaces : YarnBasics() {
rootPackageJson.private = true
val npmProjectWorkspaces = npmProjects.map { it.npmProject.dir.relativeTo(nodeJsWorldDir).path }
val importedProjectWorkspaces = npmProjects.flatMapTo(mutableSetOf()) {
it.gradleDependencies.externalModules.map { importedProject ->
importedProject.path.relativeTo(nodeJsWorldDir).path
}
}
val importedProjectWorkspaces = YarnImportedPackagesVersionResolver(rootProject, npmProjects, nodeJsWorldDir).resolveAndUpdatePackages()
rootPackageJson.workspaces = npmProjectWorkspaces + importedProjectWorkspaces