Gradle, js: implement NpmSimpleLinker for cases when there are no npm dependencies

This commit is contained in:
Sergey Rostov
2019-05-19 11:58:56 +03:00
parent 75708dad87
commit 52f01ef43f
9 changed files with 77 additions and 12 deletions
@@ -10,4 +10,4 @@ import java.io.File
/**
* Fake NodeJS module directory created from Gradle external module
*/
class GradleNodeModule(val name: String, val version: String, val path: File)
data class GradleNodeModule(val name: String, val version: String, val path: File)
@@ -15,5 +15,6 @@ class NpmProjectPackage(
val npmProject: NpmProject,
val npmDependencies: Collection<NpmDependency>,
val gradleDependencies: NpmGradleDependencies,
val packageJson: PackageJson
val packageJson: PackageJson,
val hasNodeModulesDependentTasks: Boolean
)
@@ -28,17 +28,16 @@ internal class NpmProjectVisitor(val resolver: NpmResolver, val project: Project
private val byCompilation = mutableMapOf<KotlinJsCompilation, NpmProjectPackage>()
private val byNpmDependency = mutableMapOf<NpmDependency, NpmProjectPackage>()
private val taskRequirements = mutableMapOf<RequiresNpmDependencies, Collection<RequiredKotlinJsDependency>>()
private val requiredFromTasksByCompilation = mutableMapOf<KotlinJsCompilation, MutableList<Dependency>>()
private val requiredFromTasksByCompilation = mutableMapOf<KotlinJsCompilation, MutableList<RequiresNpmDependencies>>()
private fun addTaskRequirements(task: RequiresNpmDependencies) {
val requirements = task.requiredNpmDependencies.toList()
taskRequirements[task] = requirements
val requiredDependenciesList = requiredFromTasksByCompilation.getOrPut(task.compilation) { mutableListOf() }
requirements.forEach { requiredDependency ->
requiredDependenciesList.add(requiredDependency.createDependency(project))
}
requiredFromTasksByCompilation
.getOrPut(task.compilation) { mutableListOf() }
.add(task)
}
private fun addNpmProject(resolved: NpmProjectPackage) {
@@ -111,10 +110,14 @@ internal class NpmProjectVisitor(val resolver: NpmResolver, val project: Project
packageJson.main = npmProject.main
val requiredByTasks = requiredFromTasksByCompilation[compilation]
var nodeModulesRequired = false
if (requiredByTasks != null && requiredByTasks.isNotEmpty()) {
val configuration = project.configurations.create("$name-jsTools")
requiredByTasks.forEach {
configuration.dependencies.add(it)
if (it.nodeModulesRequired) nodeModulesRequired = true
it.requiredNpmDependencies.forEach { requirement ->
configuration.dependencies.add(requirement.createDependency(project))
}
}
configuration.resolve()
visitConfiguration(configuration, npmDependencies, gradleDeps)
@@ -139,7 +142,7 @@ internal class NpmProjectVisitor(val resolver: NpmResolver, val project: Project
it(packageJson)
}
val npmPackage = NpmProjectPackage(project, npmProject, npmDependencies, gradleDeps, packageJson)
val npmPackage = NpmProjectPackage(project, npmProject, npmDependencies, gradleDeps, packageJson, nodeModulesRequired)
npmPackage.packageJson.saveTo(npmProject.packageJsonFile)
resolver.packageManager.resolveProject(npmPackage)
@@ -9,7 +9,9 @@ import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsPlugin
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension
import org.jetbrains.kotlin.gradle.targets.js.nodejs.nodeJs
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmResolver.ResolutionCallResult.*
import java.nio.file.Files
/**
* Generates `package.json` file for [NpmProject] with npm or js dependencies and
@@ -92,9 +94,12 @@ internal class NpmResolver private constructor(val rootProject: Project) : AutoC
fun resolve() {
resolve(rootProject)
if (allNpmPackages.isNotEmpty()) {
removeOutdatedPackages()
removeOutdatedPackages()
if (allNpmPackages.any { it.npmDependencies.isNotEmpty() }) {
packageManager.resolveRootProject(rootProject, allNpmPackages)
} else if (allNpmPackages.any { it.hasNodeModulesDependentTasks }) {
NpmSimpleLinker(rootProject).link(allNpmPackages)
}
close()
@@ -0,0 +1,47 @@
/*
* 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.npm
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.targets.js.nodejs.nodeJs
import java.nio.file.Files
/**
* Handles simple case, when there are no npm depenencies required, but some tasks steel needs
* node_modules with symlinked packages and packages_imported
*/
class NpmSimpleLinker(rootProject: Project) {
private val rootProjectNodeModules = rootProject.nodeJs.root.rootPackageDir.resolve(NpmProject.NODE_MODULES)
fun link(projects: Collection<NpmProjectPackage>) {
rootProjectNodeModules.listFiles()?.forEach {
val path = it.toPath()
when {
Files.isSymbolicLink(path) ->
Files.delete(path)
else -> it.deleteRecursively()
}
}
rootProjectNodeModules.mkdirs()
// packages
projects.forEach {
Files.createSymbolicLink(getNodeModulePath(it.npmProject.name), it.npmProject.dir.canonicalFile.toPath())
}
// packages_imported
projects.flatMapTo(mutableSetOf()) {
it.gradleDependencies.externalModules.map { gradleNodeModule -> gradleNodeModule }
}.forEach {
Files.createSymbolicLink(getNodeModulePath(it.name), it.path.canonicalFile.toPath())
}
}
private fun getNodeModulePath(name: String) =
rootProjectNodeModules.resolve(name).canonicalFile.toPath()
}
@@ -10,5 +10,6 @@ import org.jetbrains.kotlin.gradle.targets.js.RequiredKotlinJsDependency
interface RequiresNpmDependencies {
val compilation: KotlinJsCompilation
val nodeModulesRequired: Boolean
val requiredNpmDependencies: Collection<RequiredKotlinJsDependency>
}
@@ -50,6 +50,9 @@ open class KotlinJsTest : KotlinTest(), RequiresNpmDependencies {
val nodeModulesToLoad: List<String>
@Internal get() = listOf("./" + compilation.npmProject.main)
override val nodeModulesRequired: Boolean
@Internal get() = testFramework!!.nodeModulesRequired
override val requiredNpmDependencies: Collection<RequiredKotlinJsDependency>
@Internal get() = testFramework!!.requiredNpmDependencies
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.gradle.targets.js.testing
import org.gradle.process.ProcessForkOptions
import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutionSpec
import org.jetbrains.kotlin.gradle.plugin.HasKotlinDependencies
import org.jetbrains.kotlin.gradle.targets.js.npm.RequiresNpmDependencies
interface KotlinJsTestFramework : RequiresNpmDependencies {
@@ -18,4 +17,7 @@ interface KotlinJsTestFramework : RequiresNpmDependencies {
forkOptions: ProcessForkOptions,
nodeJsArgs: MutableList<String>
): TCServiceMessagesTestExecutionSpec
override val nodeModulesRequired: Boolean
get() = true
}
@@ -95,6 +95,9 @@ open class KotlinWebpack : DefaultTask(), RequiresNpmDependencies {
)
)
override val nodeModulesRequired: Boolean
@Internal get() = true
override val requiredNpmDependencies: Collection<NpmPackageVersion>
@Internal get() = mutableListOf<NpmPackageVersion>().also {
it.add(versions.webpack)