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 * 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 npmProject: NpmProject,
val npmDependencies: Collection<NpmDependency>, val npmDependencies: Collection<NpmDependency>,
val gradleDependencies: NpmGradleDependencies, 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 byCompilation = mutableMapOf<KotlinJsCompilation, NpmProjectPackage>()
private val byNpmDependency = mutableMapOf<NpmDependency, NpmProjectPackage>() private val byNpmDependency = mutableMapOf<NpmDependency, NpmProjectPackage>()
private val taskRequirements = mutableMapOf<RequiresNpmDependencies, Collection<RequiredKotlinJsDependency>>() 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) { private fun addTaskRequirements(task: RequiresNpmDependencies) {
val requirements = task.requiredNpmDependencies.toList() val requirements = task.requiredNpmDependencies.toList()
taskRequirements[task] = requirements taskRequirements[task] = requirements
val requiredDependenciesList = requiredFromTasksByCompilation.getOrPut(task.compilation) { mutableListOf() } requiredFromTasksByCompilation
requirements.forEach { requiredDependency -> .getOrPut(task.compilation) { mutableListOf() }
requiredDependenciesList.add(requiredDependency.createDependency(project)) .add(task)
}
} }
private fun addNpmProject(resolved: NpmProjectPackage) { private fun addNpmProject(resolved: NpmProjectPackage) {
@@ -111,10 +110,14 @@ internal class NpmProjectVisitor(val resolver: NpmResolver, val project: Project
packageJson.main = npmProject.main packageJson.main = npmProject.main
val requiredByTasks = requiredFromTasksByCompilation[compilation] val requiredByTasks = requiredFromTasksByCompilation[compilation]
var nodeModulesRequired = false
if (requiredByTasks != null && requiredByTasks.isNotEmpty()) { if (requiredByTasks != null && requiredByTasks.isNotEmpty()) {
val configuration = project.configurations.create("$name-jsTools") val configuration = project.configurations.create("$name-jsTools")
requiredByTasks.forEach { requiredByTasks.forEach {
configuration.dependencies.add(it) if (it.nodeModulesRequired) nodeModulesRequired = true
it.requiredNpmDependencies.forEach { requirement ->
configuration.dependencies.add(requirement.createDependency(project))
}
} }
configuration.resolve() configuration.resolve()
visitConfiguration(configuration, npmDependencies, gradleDeps) visitConfiguration(configuration, npmDependencies, gradleDeps)
@@ -139,7 +142,7 @@ internal class NpmProjectVisitor(val resolver: NpmResolver, val project: Project
it(packageJson) it(packageJson)
} }
val npmPackage = NpmProjectPackage(project, npmProject, npmDependencies, gradleDeps, packageJson) val npmPackage = NpmProjectPackage(project, npmProject, npmDependencies, gradleDeps, packageJson, nodeModulesRequired)
npmPackage.packageJson.saveTo(npmProject.packageJsonFile) npmPackage.packageJson.saveTo(npmProject.packageJsonFile)
resolver.packageManager.resolveProject(npmPackage) 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.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsPlugin 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.NodeJsRootExtension
import org.jetbrains.kotlin.gradle.targets.js.nodejs.nodeJs
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmResolver.ResolutionCallResult.* 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 * 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() { fun resolve() {
resolve(rootProject) resolve(rootProject)
if (allNpmPackages.isNotEmpty()) { removeOutdatedPackages()
removeOutdatedPackages()
if (allNpmPackages.any { it.npmDependencies.isNotEmpty() }) {
packageManager.resolveRootProject(rootProject, allNpmPackages) packageManager.resolveRootProject(rootProject, allNpmPackages)
} else if (allNpmPackages.any { it.hasNodeModulesDependentTasks }) {
NpmSimpleLinker(rootProject).link(allNpmPackages)
} }
close() 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 { interface RequiresNpmDependencies {
val compilation: KotlinJsCompilation val compilation: KotlinJsCompilation
val nodeModulesRequired: Boolean
val requiredNpmDependencies: Collection<RequiredKotlinJsDependency> val requiredNpmDependencies: Collection<RequiredKotlinJsDependency>
} }
@@ -50,6 +50,9 @@ open class KotlinJsTest : KotlinTest(), RequiresNpmDependencies {
val nodeModulesToLoad: List<String> val nodeModulesToLoad: List<String>
@Internal get() = listOf("./" + compilation.npmProject.main) @Internal get() = listOf("./" + compilation.npmProject.main)
override val nodeModulesRequired: Boolean
@Internal get() = testFramework!!.nodeModulesRequired
override val requiredNpmDependencies: Collection<RequiredKotlinJsDependency> override val requiredNpmDependencies: Collection<RequiredKotlinJsDependency>
@Internal get() = testFramework!!.requiredNpmDependencies @Internal get() = testFramework!!.requiredNpmDependencies
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.gradle.targets.js.testing
import org.gradle.process.ProcessForkOptions import org.gradle.process.ProcessForkOptions
import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutionSpec import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutionSpec
import org.jetbrains.kotlin.gradle.plugin.HasKotlinDependencies
import org.jetbrains.kotlin.gradle.targets.js.npm.RequiresNpmDependencies import org.jetbrains.kotlin.gradle.targets.js.npm.RequiresNpmDependencies
interface KotlinJsTestFramework : RequiresNpmDependencies { interface KotlinJsTestFramework : RequiresNpmDependencies {
@@ -18,4 +17,7 @@ interface KotlinJsTestFramework : RequiresNpmDependencies {
forkOptions: ProcessForkOptions, forkOptions: ProcessForkOptions,
nodeJsArgs: MutableList<String> nodeJsArgs: MutableList<String>
): TCServiceMessagesTestExecutionSpec ): 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> override val requiredNpmDependencies: Collection<NpmPackageVersion>
@Internal get() = mutableListOf<NpmPackageVersion>().also { @Internal get() = mutableListOf<NpmPackageVersion>().also {
it.add(versions.webpack) it.add(versions.webpack)