Gradle, js: create npm packages per compilation
#KT-30530
This commit is contained in:
+9
-5
@@ -3,13 +3,16 @@
|
|||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
* 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
|
package org.jetbrains.kotlin.gradle.targets.js
|
||||||
|
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.gradle.api.artifacts.Dependency
|
import org.gradle.api.artifacts.Dependency
|
||||||
import org.gradle.api.artifacts.ExternalModuleDependency
|
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmDependency
|
||||||
|
|
||||||
class NpmPackages {
|
/**
|
||||||
|
* Package versions used by tasks
|
||||||
|
*/
|
||||||
|
class NpmVersions {
|
||||||
val webpack = NpmPackageVersion("webpack", "4.29.6")
|
val webpack = NpmPackageVersion("webpack", "4.29.6")
|
||||||
val webpackCli = NpmPackageVersion("webpack-cli", "3.3.0")
|
val webpackCli = NpmPackageVersion("webpack-cli", "3.3.0")
|
||||||
val webpackBundleAnalyzer = NpmPackageVersion("webpack-bundle-analyzer", "3.3.2")
|
val webpackBundleAnalyzer = NpmPackageVersion("webpack-bundle-analyzer", "3.3.2")
|
||||||
@@ -47,10 +50,11 @@ interface RequiredKotlinJsDependency {
|
|||||||
}
|
}
|
||||||
|
|
||||||
data class NpmPackageVersion(val name: String, var version: String) : RequiredKotlinJsDependency {
|
data class NpmPackageVersion(val name: String, var version: String) : RequiredKotlinJsDependency {
|
||||||
override fun createDependency(project: Project) = NpmDependency(project, null, name, version)
|
override fun createDependency(project: Project): Dependency =
|
||||||
|
NpmDependency(project, null, name, version)
|
||||||
}
|
}
|
||||||
|
|
||||||
data class KotlinGradleNpmPackage(val simpleModuleName: String): RequiredKotlinJsDependency {
|
data class KotlinGradleNpmPackage(val simpleModuleName: String) : RequiredKotlinJsDependency {
|
||||||
override fun createDependency(project: Project): Dependency =
|
override fun createDependency(project: Project): Dependency =
|
||||||
project.dependencies.create("org.jetbrains.kotlin:kotlin-$simpleModuleName")
|
project.dependencies.create("org.jetbrains.kotlin:kotlin-$simpleModuleName")
|
||||||
}
|
}
|
||||||
+2
-2
@@ -6,7 +6,7 @@
|
|||||||
package org.jetbrains.kotlin.gradle.targets.js.nodejs
|
package org.jetbrains.kotlin.gradle.targets.js.nodejs
|
||||||
|
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmPackages
|
import org.jetbrains.kotlin.gradle.targets.js.NpmVersions
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.npm.PackageJson
|
import org.jetbrains.kotlin.gradle.targets.js.npm.PackageJson
|
||||||
|
|
||||||
open class NodeJsExtension(val project: Project) {
|
open class NodeJsExtension(val project: Project) {
|
||||||
@@ -15,7 +15,7 @@ open class NodeJsExtension(val project: Project) {
|
|||||||
|
|
||||||
internal val packageJsonHandlers = mutableListOf<PackageJson.() -> Unit>()
|
internal val packageJsonHandlers = mutableListOf<PackageJson.() -> Unit>()
|
||||||
|
|
||||||
val versions = NpmPackages()
|
val versions = NpmVersions()
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
fun packageJson(handler: PackageJson.() -> Unit) {
|
fun packageJson(handler: PackageJson.() -> Unit) {
|
||||||
|
|||||||
+4
-15
@@ -6,7 +6,6 @@ import org.gradle.api.plugins.BasePlugin
|
|||||||
import org.gradle.api.tasks.Delete
|
import org.gradle.api.tasks.Delete
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension.Companion.NODE_JS
|
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension.Companion.NODE_JS
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmResolveTask
|
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmResolveTask
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject
|
|
||||||
|
|
||||||
open class NodeJsPlugin : Plugin<Project> {
|
open class NodeJsPlugin : Plugin<Project> {
|
||||||
override fun apply(project: Project): Unit = project.run {
|
override fun apply(project: Project): Unit = project.run {
|
||||||
@@ -33,25 +32,15 @@ open class NodeJsPlugin : Plugin<Project> {
|
|||||||
|
|
||||||
private fun setupCleanNodeModulesTask(project: Project) {
|
private fun setupCleanNodeModulesTask(project: Project) {
|
||||||
project.tasks.create("cleanNodeModules", Delete::class.java) {
|
project.tasks.create("cleanNodeModules", Delete::class.java) {
|
||||||
it.description = "Deletes node_modules and package.json file"
|
it.description = "Deletes nodeJs projects created during build"
|
||||||
it.group = BasePlugin.BUILD_GROUP
|
it.group = BasePlugin.BUILD_GROUP
|
||||||
|
it.delete.add(project.nodeJs.root.rootPackageDir)
|
||||||
it.doLast {
|
|
||||||
project.nodeJs.root.packageManager.cleanProject(project)
|
|
||||||
}
|
|
||||||
|
|
||||||
project.tasks.maybeCreate(BasePlugin.CLEAN_TASK_NAME).dependsOn(it)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
project.tasks.create("cleanGradleNodeModules", Delete::class.java) {
|
project.tasks.create("cleanGradleNodeModules", Delete::class.java) {
|
||||||
it.description = "Deletes node_modules_gradle"
|
it.description = "Deletes node modules imported from gradle external modules"
|
||||||
it.group = BasePlugin.BUILD_GROUP
|
it.group = BasePlugin.BUILD_GROUP
|
||||||
|
it.delete.add(project.nodeJs.root.nodeModulesGradleCacheDir)
|
||||||
it.doLast {
|
|
||||||
project.npmProject.gradleNodeModulesDir.deleteRecursively()
|
|
||||||
}
|
|
||||||
|
|
||||||
project.tasks.maybeCreate(BasePlugin.CLEAN_TASK_NAME).dependsOn(it)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+9
-4
@@ -2,12 +2,9 @@ package org.jetbrains.kotlin.gradle.targets.js.nodejs
|
|||||||
|
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.jetbrains.kotlin.gradle.logging.kotlinInfo
|
import org.jetbrains.kotlin.gradle.logging.kotlinInfo
|
||||||
import org.jetbrains.kotlin.gradle.plugin.TaskHolder
|
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProjectLayout
|
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmApi
|
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmApi
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmResolveTask
|
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmResolveTask
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.yarn.Yarn
|
import org.jetbrains.kotlin.gradle.targets.js.yarn.Yarn
|
||||||
import org.jetbrains.kotlin.gradle.tasks.locateOrRegisterTask
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
open class NodeJsRootExtension(project: Project) : NodeJsExtension(project) {
|
open class NodeJsRootExtension(project: Project) : NodeJsExtension(project) {
|
||||||
@@ -23,7 +20,6 @@ open class NodeJsRootExtension(project: Project) : NodeJsExtension(project) {
|
|||||||
|
|
||||||
var nodeCommand = "node"
|
var nodeCommand = "node"
|
||||||
|
|
||||||
var layout: NpmProjectLayout = NpmProjectLayout.ROOT_PROJECT_BUILD_DIR
|
|
||||||
var packageManager: NpmApi = Yarn
|
var packageManager: NpmApi = Yarn
|
||||||
|
|
||||||
val nodeJsSetupTask: NodeJsSetupTask
|
val nodeJsSetupTask: NodeJsSetupTask
|
||||||
@@ -32,6 +28,15 @@ open class NodeJsRootExtension(project: Project) : NodeJsExtension(project) {
|
|||||||
val npmResolveTask: NpmResolveTask
|
val npmResolveTask: NpmResolveTask
|
||||||
get() = project.tasks.getByName(NpmResolveTask.NAME) as NpmResolveTask
|
get() = project.tasks.getByName(NpmResolveTask.NAME) as NpmResolveTask
|
||||||
|
|
||||||
|
val nodeModulesGradleCacheDir: File
|
||||||
|
get() = project.buildDir.resolve("node_modules_gradle")
|
||||||
|
|
||||||
|
val rootPackageDir: File
|
||||||
|
get() = project.buildDir.resolve("js")
|
||||||
|
|
||||||
|
val projectPackagesDir: File
|
||||||
|
get() = rootPackageDir.resolve("packages")
|
||||||
|
|
||||||
internal val environment: NodeJsEnv
|
internal val environment: NodeJsEnv
|
||||||
get() {
|
get() {
|
||||||
val platform = NodeJsPlatform.name
|
val platform = NodeJsPlatform.name
|
||||||
|
|||||||
+3
@@ -7,4 +7,7 @@ package org.jetbrains.kotlin.gradle.targets.js.npm
|
|||||||
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fake NodeJS module directory created from Gradle external module
|
||||||
|
*/
|
||||||
class GradleNodeModule(val name: String, val path: File)
|
class GradleNodeModule(val name: String, val path: File)
|
||||||
+3
@@ -12,6 +12,9 @@ import org.gradle.api.artifacts.ResolvedArtifact
|
|||||||
import org.gradle.api.artifacts.ResolvedDependency
|
import org.gradle.api.artifacts.ResolvedDependency
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates fake NodeJS module directory from given gradle [dependency].
|
||||||
|
*/
|
||||||
internal class GradleNodeModuleBuilder(
|
internal class GradleNodeModuleBuilder(
|
||||||
val project: Project,
|
val project: Project,
|
||||||
val dependency: ResolvedDependency,
|
val dependency: ResolvedDependency,
|
||||||
|
|||||||
+5
-1
@@ -11,13 +11,17 @@ import org.gradle.api.artifacts.ResolvedArtifact
|
|||||||
import org.gradle.api.artifacts.ResolvedDependency
|
import org.gradle.api.artifacts.ResolvedDependency
|
||||||
import org.gradle.api.artifacts.component.ProjectComponentIdentifier
|
import org.gradle.api.artifacts.component.ProjectComponentIdentifier
|
||||||
import org.jetbrains.kotlin.gradle.internal.ProcessedFilesCache
|
import org.jetbrains.kotlin.gradle.internal.ProcessedFilesCache
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.js.nodejs.nodeJs
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache for storing already created [GradleNodeModule]s
|
||||||
|
*/
|
||||||
internal class GradleNodeModulesCache(val project: Project) : AutoCloseable {
|
internal class GradleNodeModulesCache(val project: Project) : AutoCloseable {
|
||||||
companion object {
|
companion object {
|
||||||
const val STATE_FILE_NAME = ".visited"
|
const val STATE_FILE_NAME = ".visited"
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val dir = project.buildDir.resolve("node_modules_gradle")
|
internal val dir = project.nodeJs.root.nodeModulesGradleCacheDir
|
||||||
private val cache = ProcessedFilesCache(project, dir, STATE_FILE_NAME, "5")
|
private val cache = ProcessedFilesCache(project, dir, STATE_FILE_NAME, "5")
|
||||||
private val visited = mutableSetOf<ResolvedDependency>()
|
private val visited = mutableSetOf<ResolvedDependency>()
|
||||||
|
|
||||||
|
|||||||
+5
-22
@@ -7,36 +7,19 @@ package org.jetbrains.kotlin.gradle.targets.js.npm
|
|||||||
|
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NodeJS package manager API
|
||||||
|
*/
|
||||||
interface NpmApi {
|
interface NpmApi {
|
||||||
fun setup(project: Project)
|
fun setup(project: Project)
|
||||||
|
|
||||||
@Suppress("EXPOSED_PARAMETER_TYPE")
|
fun resolveProject(resolvedNpmProject: NpmProjectPackage)
|
||||||
fun resolveProject(npmPackage: NpmResolver.NpmPackage)
|
|
||||||
|
|
||||||
@Suppress("EXPOSED_PARAMETER_TYPE")
|
|
||||||
fun resolveRootProject(
|
fun resolveRootProject(
|
||||||
rootProject: Project,
|
rootProject: Project,
|
||||||
subprojects: MutableList<NpmResolver.NpmPackage>
|
subProjects: MutableList<NpmProjectPackage>
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
|
||||||
* Change contents of root's project `package.json`.
|
|
||||||
* @return true if `package.json` is required even it is empty
|
|
||||||
*/
|
|
||||||
@Suppress("EXPOSED_PARAMETER_TYPE")
|
|
||||||
fun hookRootPackage(
|
|
||||||
rootProject: Project,
|
|
||||||
rootPackageJson: PackageJson,
|
|
||||||
allWorkspaces: Collection<NpmResolver.NpmPackage>
|
|
||||||
): Boolean = false
|
|
||||||
|
|
||||||
fun cleanProject(project: Project) {
|
|
||||||
val npmProject = project.npmProject
|
|
||||||
|
|
||||||
npmProject.nodeModulesDir.deleteRecursively()
|
|
||||||
npmProject.packageJsonFile.delete()
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun resolveOperationDescription(packageManagerTitle: String): String =
|
fun resolveOperationDescription(packageManagerTitle: String): String =
|
||||||
"Resolving NPM dependencies using $packageManagerTitle"
|
"Resolving NPM dependencies using $packageManagerTitle"
|
||||||
|
|||||||
+35
-29
@@ -28,12 +28,14 @@ data class NpmDependency(
|
|||||||
SelfResolvingDependencyInternal,
|
SelfResolvingDependencyInternal,
|
||||||
ResolvableDependency,
|
ResolvableDependency,
|
||||||
FileCollectionDependency {
|
FileCollectionDependency {
|
||||||
|
|
||||||
override fun getGroup(): String? = org
|
override fun getGroup(): String? = org
|
||||||
|
|
||||||
internal val dependencies = mutableSetOf<NpmDependency>()
|
internal val dependencies = mutableSetOf<NpmDependency>()
|
||||||
|
|
||||||
override fun resolve(): MutableSet<File> {
|
override fun resolve(transitive: Boolean): MutableSet<File> {
|
||||||
resolveProject() ?: return mutableSetOf()
|
val npmPackage = resolveProject() ?: return mutableSetOf()
|
||||||
|
val npmProject = npmPackage.npmProject
|
||||||
|
|
||||||
val all = mutableSetOf<File>()
|
val all = mutableSetOf<File>()
|
||||||
val visited = mutableSetOf<NpmDependency>()
|
val visited = mutableSetOf<NpmDependency>()
|
||||||
@@ -41,9 +43,16 @@ data class NpmDependency(
|
|||||||
fun visit(item: NpmDependency) {
|
fun visit(item: NpmDependency) {
|
||||||
if (item in visited) return
|
if (item in visited) return
|
||||||
visited.add(item)
|
visited.add(item)
|
||||||
item.project.npmProject.resolve(item.key)?.let {
|
|
||||||
|
npmProject.resolve(item.key)?.let {
|
||||||
all.add(it)
|
all.add(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (transitive) {
|
||||||
|
item.dependencies.forEach {
|
||||||
|
visit(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
visit(this)
|
visit(this)
|
||||||
@@ -51,45 +60,42 @@ data class NpmDependency(
|
|||||||
return all
|
return all
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun resolveProject(): NpmResolver.ResolvedProject? {
|
override fun resolve(): MutableSet<File> {
|
||||||
|
val npmPackage = resolveProject() ?: return mutableSetOf()
|
||||||
|
return mutableSetOf(npmPackage.npmProject.resolve(key)!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun resolve(context: DependencyResolveContext) {
|
||||||
|
val npmPackage = resolveProject()
|
||||||
|
if (npmPackage != null) {
|
||||||
|
npmPackage.project.files(npmPackage.npmProject.resolve(key))
|
||||||
|
dependencies.forEach {
|
||||||
|
context.add(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun resolveProject(): NpmProjectPackage? {
|
||||||
val result =
|
val result =
|
||||||
if (isInIdeaSync) NpmResolver.resolve(project)
|
if (isInIdeaSync) NpmResolver.resolveIfNeeded(project)
|
||||||
else NpmResolver.getAlreadyResolvedOrNull(project)
|
else NpmResolver.getAlreadyResolvedOrNull(project)
|
||||||
|
|
||||||
return when (result) {
|
return when (result) {
|
||||||
null -> null
|
null -> null
|
||||||
is AlreadyInProgress -> null
|
is AlreadyInProgress -> null
|
||||||
is AlreadyResolved -> {
|
is AlreadyResolved -> findIn(result.resolution) ?: error("Project hierarchy is already resolved in NPM without $this")
|
||||||
check(this in result.resolution.npmPackage!!.npmDependencies) {
|
is ResolvedNow -> findIn(result.resolution) ?: error("Cannot find $this after NPM project resolve")
|
||||||
"Project hierarchy is already resolved in NPM without $this"
|
|
||||||
}
|
|
||||||
|
|
||||||
result.resolution
|
|
||||||
}
|
|
||||||
is ResolvedNow -> {
|
|
||||||
check(this in result.resolution.npmPackage!!.npmDependencies) {
|
|
||||||
"$this was not visited during resolution"
|
|
||||||
}
|
|
||||||
|
|
||||||
result.resolution
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun findIn(npmProjects: NpmProjects) =
|
||||||
|
npmProjects.npmProjectsByNpmDependency[this]
|
||||||
|
|
||||||
val key: String = if (org == null) name else "@$org/$name"
|
val key: String = if (org == null) name else "@$org/$name"
|
||||||
|
|
||||||
override fun toString() = "$key: $version"
|
override fun toString() = "$key: $version"
|
||||||
|
|
||||||
override fun resolve(context: DependencyResolveContext) {
|
override fun getFiles(): FileCollection = project.files(resolve(true))
|
||||||
resolve()
|
|
||||||
dependencies.forEach {
|
|
||||||
context.add(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun resolve(transitive: Boolean): MutableSet<File> = resolve()
|
|
||||||
|
|
||||||
override fun getFiles(): FileCollection = project.files(resolve())
|
|
||||||
|
|
||||||
override fun getName() = name
|
override fun getName() = name
|
||||||
|
|
||||||
|
|||||||
+58
-34
@@ -7,41 +7,52 @@ package org.jetbrains.kotlin.gradle.targets.js.npm
|
|||||||
|
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.gradle.process.ExecSpec
|
import org.gradle.process.ExecSpec
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsPlugin
|
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.nodeJs
|
import org.jetbrains.kotlin.gradle.targets.js.nodejs.nodeJs
|
||||||
import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
open class NpmProject(
|
val KotlinJsCompilation.npmProject: NpmProject
|
||||||
val project: Project,
|
get() = NpmProject(this)
|
||||||
val nodeWorkDir: File,
|
|
||||||
val searchInParents: Boolean
|
/**
|
||||||
) {
|
* Basic info for [NpmProject] created from [compilation].
|
||||||
|
* This class contains only basic info.
|
||||||
|
*
|
||||||
|
* More info can be obtained from [NpmProjectPackage], which is available after project resolution (after [NpmResolveTask] execution).
|
||||||
|
*/
|
||||||
|
open class NpmProject(val compilation: KotlinJsCompilation) {
|
||||||
|
val name: String
|
||||||
|
get() = buildNpmProjectName()
|
||||||
|
|
||||||
|
val dir: File
|
||||||
|
get() = project.nodeJs.root.projectPackagesDir.resolve(name)
|
||||||
|
|
||||||
|
val target: KotlinTarget
|
||||||
|
get() = compilation.target
|
||||||
|
|
||||||
|
val project: Project
|
||||||
|
get() = target.project
|
||||||
|
|
||||||
val nodeModulesDir
|
val nodeModulesDir
|
||||||
get() = nodeWorkDir.resolve(NODE_MODULES)
|
get() = dir.resolve(NODE_MODULES)
|
||||||
|
|
||||||
val packageJsonFile: File
|
val packageJsonFile: File
|
||||||
get() = nodeWorkDir.resolve(PACKAGE_JSON)
|
get() = dir.resolve(PACKAGE_JSON)
|
||||||
|
|
||||||
open val compileOutputCopyDest: File?
|
val main: String
|
||||||
get() = nodeModulesDir
|
get() = "kotlin/$name.js"
|
||||||
|
|
||||||
private val modules = object : NpmProjectModules(nodeWorkDir, nodeModulesDir) {
|
private val modules = object : NpmProjectModules(dir, nodeModulesDir) {
|
||||||
override val parent get() = if (searchInParents) parentModules else null
|
override val parent get() = rootNodeModules
|
||||||
}
|
}
|
||||||
|
|
||||||
private val parentModules: NpmProjectModules?
|
private val rootNodeModules: NpmProjectModules?
|
||||||
get() = project.parent?.npmProject?.modules
|
get() = NpmProjectModules(project.nodeJs.root.rootPackageDir)
|
||||||
|
|
||||||
val gradleNodeModulesDir: File
|
|
||||||
get() = project.rootProject.npmProject.nodeModulesDir
|
|
||||||
|
|
||||||
open fun compileOutput(compilationTask: Kotlin2JsCompile): File {
|
|
||||||
return compileOutputCopyDest?.resolve(compilationTask.outputFile.name) ?: compilationTask.outputFile
|
|
||||||
}
|
|
||||||
|
|
||||||
fun useTool(exec: ExecSpec, tool: String, vararg args: String) {
|
fun useTool(exec: ExecSpec, tool: String, vararg args: String) {
|
||||||
exec.workingDir = nodeWorkDir
|
exec.workingDir = dir
|
||||||
exec.executable = project.nodeJs.root.environment.nodeExecutable
|
exec.executable = project.nodeJs.root.environment.nodeExecutable
|
||||||
exec.args = listOf(require(tool)) + args
|
exec.args = listOf(require(tool)) + args
|
||||||
}
|
}
|
||||||
@@ -60,19 +71,32 @@ open class NpmProject(
|
|||||||
*/
|
*/
|
||||||
internal fun resolve(name: String): File? = modules.resolve(name)
|
internal fun resolve(name: String): File? = modules.resolve(name)
|
||||||
|
|
||||||
override fun toString() = "NpmProject($nodeWorkDir)"
|
private fun buildNpmProjectName(): String {
|
||||||
|
val project = target.project
|
||||||
|
val name = StringBuilder()
|
||||||
|
|
||||||
|
name.append(project.rootProject.name)
|
||||||
|
|
||||||
|
if (project != project.rootProject) {
|
||||||
|
name.append("-")
|
||||||
|
name.append(project.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target.name.isNotEmpty() && target.name.toLowerCase() != "js") {
|
||||||
|
name.append("-").append(target.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (compilation.name != KotlinCompilation.MAIN_COMPILATION_NAME) {
|
||||||
|
name.append("-").append(compilation.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return name.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString() = "NpmProject($name)"
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val PACKAGE_JSON = "package.json"
|
const val PACKAGE_JSON = "package.json"
|
||||||
const val NODE_MODULES = "node_modules"
|
const val NODE_MODULES = "node_modules"
|
||||||
|
|
||||||
operator fun get(project: Project): NpmProject {
|
|
||||||
val nodeJsRootExtension = NodeJsPlugin.apply(project)
|
|
||||||
|
|
||||||
return nodeJsRootExtension.root.layout.newNpmProject(project)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val Project.npmProject
|
|
||||||
get() = NpmProject[this]
|
|
||||||
+3
@@ -7,6 +7,9 @@ package org.jetbrains.kotlin.gradle.targets.js.npm
|
|||||||
|
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gradle dependencies for [NpmProject].
|
||||||
|
*/
|
||||||
class NpmProjectGradleDeps {
|
class NpmProjectGradleDeps {
|
||||||
val internalModules = mutableSetOf<Project>()
|
val internalModules = mutableSetOf<Project>()
|
||||||
val externalModules = mutableSetOf<GradleNodeModule>()
|
val externalModules = mutableSetOf<GradleNodeModule>()
|
||||||
|
|||||||
-47
@@ -1,47 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2019 JetBrains s.r.o. 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.plugin.mpp.KotlinJsCompilation
|
|
||||||
import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
enum class NpmProjectLayout {
|
|
||||||
PROJECT_DIR {
|
|
||||||
override val allowYarnWorkspaces: Boolean
|
|
||||||
get() = true
|
|
||||||
|
|
||||||
override fun newNpmProject(project: Project) =
|
|
||||||
NpmProject(project, project.projectDir, searchInParents = true)
|
|
||||||
},
|
|
||||||
ROOT_PROJECT_BUILD_DIR {
|
|
||||||
override val allowYarnWorkspaces: Boolean
|
|
||||||
get() = true
|
|
||||||
|
|
||||||
override fun newNpmProject(project: Project): NpmProject {
|
|
||||||
val nodeJsWorldDir = project.rootProject.buildDir.resolve("nodejs-project")
|
|
||||||
|
|
||||||
val workDir =
|
|
||||||
if (project == project.rootProject) nodeJsWorldDir
|
|
||||||
else {
|
|
||||||
val projectPackage = project.path.removePrefix(":").replace(":", File.separator)
|
|
||||||
nodeJsWorldDir.resolve("packages").resolve(projectPackage)
|
|
||||||
}
|
|
||||||
|
|
||||||
return NpmProject(project, workDir, searchInParents = true)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
BUILD_DIR {
|
|
||||||
override fun newNpmProject(project: Project) =
|
|
||||||
NpmProject(project, project.buildDir, searchInParents = false)
|
|
||||||
};
|
|
||||||
|
|
||||||
open val allowYarnWorkspaces: Boolean
|
|
||||||
get() = false
|
|
||||||
|
|
||||||
abstract fun newNpmProject(project: Project): NpmProject
|
|
||||||
}
|
|
||||||
+4
-1
@@ -11,9 +11,12 @@ import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProject.Companion.NODE_MODU
|
|||||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProject.Companion.PACKAGE_JSON
|
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProject.Companion.PACKAGE_JSON
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search modules in node_modules according to https://nodejs.org/api/modules.html.
|
||||||
|
*/
|
||||||
internal open class NpmProjectModules(
|
internal open class NpmProjectModules(
|
||||||
val dir: File,
|
val dir: File,
|
||||||
val nodeModulesDir: File = dir.resolve(NODE_MODULES)
|
private val nodeModulesDir: File = dir.resolve(NODE_MODULES)
|
||||||
) {
|
) {
|
||||||
/**
|
/**
|
||||||
* Require [request] nodejs module and return canonical path to it's main js file.
|
* Require [request] nodejs module and return canonical path to it's main js file.
|
||||||
|
|||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [NpmProject] full package info
|
||||||
|
*/
|
||||||
|
class NpmProjectPackage(
|
||||||
|
val project: Project,
|
||||||
|
val npmProject: NpmProject,
|
||||||
|
val npmDependencies: Collection<NpmDependency>,
|
||||||
|
val packageJson: PackageJson
|
||||||
|
)
|
||||||
+164
@@ -0,0 +1,164 @@
|
|||||||
|
/*
|
||||||
|
* 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.gradle.api.artifacts.Configuration
|
||||||
|
import org.gradle.api.artifacts.Dependency
|
||||||
|
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
||||||
|
import org.jetbrains.kotlin.gradle.dsl.KotlinSingleTargetExtension
|
||||||
|
import org.jetbrains.kotlin.gradle.dsl.kotlinExtensionOrNull
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.js.RequiredKotlinJsDependency
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.js.nodejs.nodeJs
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits given gradle [project] for all of its [NpmProject],
|
||||||
|
* creates `package.json` for them ([NpmProjectPackage]) and runs
|
||||||
|
* selected [NodeJsRootExtension.packageManager] to download and install all of it's dependencies.
|
||||||
|
*/
|
||||||
|
internal class NpmProjectVisitor(val resolver: NpmResolver, val project: Project) {
|
||||||
|
private val npmProjects = mutableListOf<NpmProjectPackage>()
|
||||||
|
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 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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addNpmProject(resolved: NpmProjectPackage) {
|
||||||
|
val compilation = resolved.npmProject.compilation
|
||||||
|
byCompilation[compilation] = resolved
|
||||||
|
resolved.npmDependencies.forEach {
|
||||||
|
byNpmDependency[it] = resolved
|
||||||
|
}
|
||||||
|
npmProjects.add(resolved)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun visitProject(): NpmProjects {
|
||||||
|
visitTasksRequiredDependencies()
|
||||||
|
|
||||||
|
val kotlin = project.kotlinExtensionOrNull
|
||||||
|
|
||||||
|
if (kotlin != null) {
|
||||||
|
when (kotlin) {
|
||||||
|
is KotlinSingleTargetExtension -> visitTarget(kotlin.target)
|
||||||
|
is KotlinMultiplatformExtension -> kotlin.targets.forEach {
|
||||||
|
visitTarget(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NpmProjects(
|
||||||
|
project,
|
||||||
|
npmProjects,
|
||||||
|
byCompilation,
|
||||||
|
byNpmDependency,
|
||||||
|
taskRequirements
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun visitTasksRequiredDependencies() {
|
||||||
|
project.tasks.toList().forEach { task ->
|
||||||
|
if (task.enabled && task is RequiresNpmDependencies) {
|
||||||
|
addTaskRequirements(task)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun visitTarget(target: KotlinTarget) {
|
||||||
|
if (target.platformType == KotlinPlatformType.js) {
|
||||||
|
target.compilations.toList().forEach { compilation ->
|
||||||
|
compilation as KotlinJsCompilation
|
||||||
|
visitCompilation(compilation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun visitCompilation(compilation: KotlinJsCompilation) {
|
||||||
|
val project = compilation.target.project
|
||||||
|
val npmProject = compilation.npmProject
|
||||||
|
val name = npmProject.name
|
||||||
|
val packageJson = PackageJson(
|
||||||
|
name,
|
||||||
|
project.version.toString()
|
||||||
|
)
|
||||||
|
val npmDependencies = mutableSetOf<NpmDependency>()
|
||||||
|
val gradleDeps = NpmProjectGradleDeps()
|
||||||
|
|
||||||
|
compilation.allKotlinSourceSets.forEach { sourceSet ->
|
||||||
|
sourceSet.relatedConfigurationNames.forEach { configurationName ->
|
||||||
|
val configuration = project.configurations.getByName(configurationName)
|
||||||
|
visitConfiguration(configuration, npmDependencies, gradleDeps)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
packageJson.main = npmProject.main
|
||||||
|
|
||||||
|
val requiredByTasks = requiredFromTasksByCompilation[compilation]
|
||||||
|
if (requiredByTasks != null && requiredByTasks.isNotEmpty()) {
|
||||||
|
val configuration = project.configurations.create("$name-jsTools")
|
||||||
|
requiredByTasks.forEach {
|
||||||
|
configuration.dependencies.add(it)
|
||||||
|
}
|
||||||
|
configuration.resolve()
|
||||||
|
visitConfiguration(configuration, npmDependencies, gradleDeps)
|
||||||
|
}
|
||||||
|
|
||||||
|
npmDependencies.forEach {
|
||||||
|
packageJson.dependencies[it.key] = resolver.chooseVersion(packageJson.dependencies[it.key], it.version)
|
||||||
|
}
|
||||||
|
|
||||||
|
gradleDeps.externalModules.forEach {
|
||||||
|
val relativePath = it.path.relativeTo(npmProject.dir)
|
||||||
|
packageJson.dependencies[it.name] = "file:$relativePath"
|
||||||
|
}
|
||||||
|
|
||||||
|
gradleDeps.internalModules.forEach { target ->
|
||||||
|
val resolvedTarget = resolver.findDependentResolvedNpmProject(project, target)
|
||||||
|
if (resolvedTarget != null) {
|
||||||
|
packageJson.dependencies[resolvedTarget.packageJson.name] = resolvedTarget.packageJson.version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
project.nodeJs.packageJsonHandlers.forEach {
|
||||||
|
it(packageJson)
|
||||||
|
}
|
||||||
|
|
||||||
|
val npmPackage = NpmProjectPackage(project, npmProject, npmDependencies, packageJson)
|
||||||
|
npmPackage.packageJson.saveTo(npmProject.packageJsonFile)
|
||||||
|
|
||||||
|
resolver.packageManager.resolveProject(npmPackage)
|
||||||
|
|
||||||
|
addNpmProject(npmPackage)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun visitConfiguration(
|
||||||
|
configuration: Configuration,
|
||||||
|
npmDependencies: MutableSet<NpmDependency>,
|
||||||
|
gradleDeps: NpmProjectGradleDeps
|
||||||
|
) {
|
||||||
|
resolver.gradleNodeModules.collectDependenciesFromConfiguration(configuration, gradleDeps)
|
||||||
|
|
||||||
|
configuration.allDependencies.forEach { dependency ->
|
||||||
|
when (dependency) {
|
||||||
|
is NpmDependency -> npmDependencies.add(dependency)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* 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.plugin.mpp.KotlinJsCompilation
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.js.RequiredKotlinJsDependency
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Info about NPM projects inside particular gradle [project].
|
||||||
|
*/
|
||||||
|
class NpmProjects(
|
||||||
|
val project: Project,
|
||||||
|
|
||||||
|
val npmProjects: List<NpmProjectPackage>,
|
||||||
|
val npmProjectsByCompilation: Map<KotlinJsCompilation, NpmProjectPackage>,
|
||||||
|
val npmProjectsByNpmDependency: Map<NpmDependency, NpmProjectPackage>,
|
||||||
|
|
||||||
|
val taskRequirements: Map<RequiresNpmDependencies, Collection<RequiredKotlinJsDependency>>
|
||||||
|
)
|
||||||
+1
-1
@@ -11,7 +11,7 @@ import org.gradle.api.tasks.TaskAction
|
|||||||
open class NpmResolveTask : AbstractTask() {
|
open class NpmResolveTask : AbstractTask() {
|
||||||
@TaskAction
|
@TaskAction
|
||||||
fun resolve() {
|
fun resolve() {
|
||||||
NpmResolver.resolve(project)
|
NpmResolver.resolveIfNeeded(project)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
+69
-253
@@ -5,29 +5,14 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.gradle.targets.js.npm
|
package org.jetbrains.kotlin.gradle.targets.js.npm
|
||||||
|
|
||||||
import com.google.gson.Gson
|
|
||||||
import com.google.gson.GsonBuilder
|
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.gradle.api.artifacts.Configuration
|
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
|
||||||
import org.gradle.api.artifacts.Dependency
|
|
||||||
import org.gradle.api.file.CopySpec
|
|
||||||
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
|
||||||
import org.jetbrains.kotlin.gradle.dsl.KotlinSingleTargetExtension
|
|
||||||
import org.jetbrains.kotlin.gradle.dsl.kotlinExtensionOrNull
|
|
||||||
import org.jetbrains.kotlin.gradle.internal.ensureParentDirsCreated
|
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
|
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
|
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
|
|
||||||
import org.jetbrains.kotlin.gradle.plugin.whenEvaluated
|
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.internal.RewriteSourceMapFilterReader
|
|
||||||
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 org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates `package.json` file for projects with npm or js dependencies and
|
* Generates `package.json` file for [NpmProject] with npm or js dependencies and
|
||||||
* runs selected [NodeJsRootExtension.packageManager] to download and install all of it's dependencies.
|
* runs selected [NodeJsRootExtension.packageManager] to download and install all of it's dependencies.
|
||||||
*
|
*
|
||||||
* All [NpmDependency] for configurations related to kotlin/js will be added to `package.json`.
|
* All [NpmDependency] for configurations related to kotlin/js will be added to `package.json`.
|
||||||
@@ -36,44 +21,45 @@ import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile
|
|||||||
*/
|
*/
|
||||||
internal class NpmResolver private constructor(val rootProject: Project) : AutoCloseable {
|
internal class NpmResolver private constructor(val rootProject: Project) : AutoCloseable {
|
||||||
companion object {
|
companion object {
|
||||||
fun resolve(project: Project): ResolutionCallResult {
|
fun resolveIfNeeded(project: Project): ResolutionCallResult {
|
||||||
val rootProject = project.rootProject
|
val rootProject = project.rootProject
|
||||||
val process = ProjectData[rootProject]
|
val process = ProjectData[rootProject]
|
||||||
|
|
||||||
if (process != null && process.resolved == null) return AlreadyInProgress
|
if (process != null && process.visit == null) return AlreadyInProgress
|
||||||
|
|
||||||
val resolved = process?.resolved
|
val resolved = process?.visit
|
||||||
|
|
||||||
return if (resolved != null) AlreadyResolved(ProjectData[project]!!.resolved!!)
|
return if (resolved != null) AlreadyResolved(resolved)
|
||||||
else {
|
else {
|
||||||
val resolver = NpmResolver(rootProject)
|
run(rootProject)
|
||||||
resolver.resolve(rootProject)!!
|
ResolvedNow(ProjectData[project]!!.visit!!)
|
||||||
resolver.close()
|
|
||||||
ResolvedNow(ProjectData[project]!!.resolved!!)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun run(rootProject: Project) {
|
||||||
|
NpmResolver(rootProject).resolve()
|
||||||
|
}
|
||||||
|
|
||||||
fun getAlreadyResolvedOrNull(project: Project): ResolutionCallResult? {
|
fun getAlreadyResolvedOrNull(project: Project): ResolutionCallResult? {
|
||||||
val rootProject = project.rootProject
|
val rootProject = project.rootProject
|
||||||
val process = ProjectData[rootProject]
|
val process = ProjectData[rootProject]
|
||||||
if (process != null && process.resolved == null) return AlreadyInProgress
|
if (process != null && process.visit == null) return AlreadyInProgress
|
||||||
val resolved = process?.resolved
|
val resolved = process?.visit
|
||||||
if (resolved != null) return AlreadyResolved(ProjectData[project]!!.resolved!!)
|
if (resolved != null) return AlreadyResolved(ProjectData[project]!!.visit!!)
|
||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun requireResolved(project: Project, reason: String = ""): ResolvedProject =
|
fun requireResolved(project: Project, reason: String = ""): NpmProjects =
|
||||||
ProjectData[project.rootProject]?.resolved
|
ProjectData[project]?.visit ?: error("NPM dependencies should be resolved $reason")
|
||||||
?: error("NPM dependencies should be resolved$reason")
|
|
||||||
|
|
||||||
fun checkRequiredDependencies(project: Project, target: RequiresNpmDependencies) {
|
fun checkRequiredDependencies(project: Project, target: RequiresNpmDependencies) {
|
||||||
val required = requireResolved(project, "before $target execution").taskDependencies
|
val requestedTaskDependencies = requireResolved(project, "before $target execution").taskRequirements
|
||||||
val targetRequired = required[target]?.toSet() ?: setOf()
|
val targetRequired = requestedTaskDependencies[target]?.toSet() ?: setOf()
|
||||||
|
|
||||||
target.requiredNpmDependencies.forEach {
|
target.requiredNpmDependencies.forEach {
|
||||||
check(it in targetRequired) {
|
check(it in targetRequired) {
|
||||||
"$it required by $target after npm dependencies was resolved. " +
|
"$it required by $target was not found resolved at the time of nodejs package manager call. " +
|
||||||
"This may be caused by changing $target configuration after npm dependencies resolution."
|
"This may be caused by changing $target configuration after npm dependencies resolution."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -82,21 +68,21 @@ internal class NpmResolver private constructor(val rootProject: Project) : AutoC
|
|||||||
|
|
||||||
sealed class ResolutionCallResult {
|
sealed class ResolutionCallResult {
|
||||||
object AlreadyInProgress : ResolutionCallResult()
|
object AlreadyInProgress : ResolutionCallResult()
|
||||||
class AlreadyResolved(val resolution: ResolvedProject) : ResolutionCallResult()
|
class AlreadyResolved(val resolution: NpmProjects) : ResolutionCallResult()
|
||||||
class ResolvedNow(val resolution: ResolvedProject) : ResolutionCallResult()
|
class ResolvedNow(val resolution: NpmProjects) : ResolutionCallResult()
|
||||||
}
|
}
|
||||||
|
|
||||||
private val nodeJs = NodeJsPlugin.apply(rootProject).root
|
val gradleNodeModules = GradleNodeModulesCache(rootProject)
|
||||||
private val npmProject = rootProject.npmProject
|
val nodeJs = NodeJsPlugin.apply(rootProject).root
|
||||||
private val gradleNodeModules = GradleNodeModulesCache(rootProject)
|
val packageManager by lazy {
|
||||||
private val packageManager = nodeJs.packageManager
|
val packageManager = nodeJs.packageManager
|
||||||
private val npmPackages = mutableListOf<NpmPackage>()
|
packageManager.setup(rootProject)
|
||||||
private val requiredByTasks = mutableMapOf<RequiresNpmDependencies, Collection<RequiredKotlinJsDependency>>()
|
packageManager
|
||||||
private val gson = GsonBuilder()
|
}
|
||||||
.setPrettyPrinting()
|
|
||||||
.create()
|
|
||||||
|
|
||||||
class ProjectData(var resolved: ResolvedProject? = null) {
|
private val allNpmPackages = mutableListOf<NpmProjectPackage>()
|
||||||
|
|
||||||
|
class ProjectData(var visit: NpmProjects? = null) {
|
||||||
companion object {
|
companion object {
|
||||||
private const val KEY = "npmResolverData"
|
private const val KEY = "npmResolverData"
|
||||||
operator fun get(project: Project) = project.extensions.findByName(KEY) as ProjectData?
|
operator fun get(project: Project) = project.extensions.findByName(KEY) as ProjectData?
|
||||||
@@ -104,39 +90,31 @@ internal class NpmResolver private constructor(val rootProject: Project) : AutoC
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ResolvedProject(
|
fun resolve() {
|
||||||
val npmPackage: NpmPackage?,
|
resolve(rootProject)
|
||||||
val taskDependencies: Map<RequiresNpmDependencies, Collection<RequiredKotlinJsDependency>>
|
if (allNpmPackages.isNotEmpty()) {
|
||||||
)
|
removeOutdatedPackages()
|
||||||
|
packageManager.resolveRootProject(rootProject, allNpmPackages)
|
||||||
|
}
|
||||||
|
|
||||||
class NpmPackage(
|
close()
|
||||||
val project: Project,
|
}
|
||||||
val packageJson: PackageJson,
|
|
||||||
val npmDependencies: Set<NpmDependency>
|
private fun removeOutdatedPackages() {
|
||||||
) {
|
val packages = allNpmPackages.mapTo(mutableSetOf()) { it.npmProject.name }
|
||||||
fun savePackageJson(gson: Gson) {
|
nodeJs.projectPackagesDir.listFiles()?.forEach {
|
||||||
val packageJsonFile = NpmProject[project].packageJsonFile
|
if (it.name !in packages) {
|
||||||
packageJsonFile.ensureParentDirsCreated()
|
it.deleteRecursively()
|
||||||
packageJsonFile.writer().use {
|
|
||||||
gson.toJson(packageJson, it)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var packageManagerInstalled = false
|
private fun getOrResolve(project: Project): NpmProjects {
|
||||||
|
return ProjectData[project]?.visit ?: resolve(project)
|
||||||
private fun requirePackageManagerSetup() {
|
|
||||||
if (packageManagerInstalled) return
|
|
||||||
packageManager.setup(rootProject)
|
|
||||||
packageManagerInstalled = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getOrResolve(project: Project): ResolvedProject {
|
private fun resolve(project: Project): NpmProjects {
|
||||||
return (ProjectData[project] ?: resolve(project)!!).resolved!!
|
val data = ProjectData().also {
|
||||||
}
|
|
||||||
|
|
||||||
private fun resolve(project: Project): ProjectData? {
|
|
||||||
val result = ProjectData().also {
|
|
||||||
ProjectData[project] = it
|
ProjectData[project] = it
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,195 +122,33 @@ internal class NpmResolver private constructor(val rootProject: Project) : AutoC
|
|||||||
getOrResolve(it)
|
getOrResolve(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
val npmPackage = extractNpmPackage(project)
|
val visited = NpmProjectVisitor(this, project).visitProject()
|
||||||
if (npmPackage != null) {
|
data.visit = visited
|
||||||
npmPackage.savePackageJson(gson)
|
allNpmPackages.addAll(visited.npmProjects)
|
||||||
|
|
||||||
requirePackageManagerSetup()
|
return visited
|
||||||
packageManager.resolveProject(npmPackage)
|
|
||||||
|
|
||||||
npmPackages.add(npmPackage)
|
|
||||||
}
|
|
||||||
|
|
||||||
result.resolved = ResolvedProject(npmPackage, requiredByTasks)
|
|
||||||
|
|
||||||
if (project == rootProject) {
|
|
||||||
if (npmPackages.isNotEmpty()) {
|
|
||||||
requirePackageManagerSetup()
|
|
||||||
packageManager.resolveRootProject(rootProject, npmPackages)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun extractNpmPackage(project: Project): NpmPackage? {
|
fun findDependentResolvedNpmProject(src: Project, target: Project): NpmProjectPackage? {
|
||||||
val packageJson = PackageJson(project.name, project.version.toString())
|
// todo: proper finding using KotlinTargetComponent.findUsageContext
|
||||||
val npmDependencies = mutableSetOf<NpmDependency>()
|
val resolvedTarget = getOrResolve(target)
|
||||||
val gradleDeps = NpmProjectGradleDeps()
|
val mainCompilations = resolvedTarget.npmProjectsByCompilation.entries.filter { it.key.name == KotlinCompilation.MAIN_COMPILATION_NAME }
|
||||||
|
|
||||||
visitTasksRequiredDependencies(project, npmDependencies, gradleDeps)
|
return if (mainCompilations.isNotEmpty()) {
|
||||||
|
if (mainCompilations.size > 1) {
|
||||||
collectDependencies(project, npmDependencies, gradleDeps, packageJson)
|
error(
|
||||||
|
"Cannot resolve project dependency $src -> $target." +
|
||||||
gradleDeps.externalModules.forEach {
|
"Dependency to project with multiple js compilation not supported yet."
|
||||||
val relativePath = it.path.relativeTo(NpmProject[project].nodeWorkDir)
|
|
||||||
packageJson.dependencies[it.name] = "file:$relativePath"
|
|
||||||
}
|
|
||||||
|
|
||||||
gradleDeps.internalModules.forEach {
|
|
||||||
val npmPackage = getOrResolve(it).npmPackage
|
|
||||||
if (npmPackage != null) {
|
|
||||||
packageJson.dependencies[npmPackage.packageJson.name] = npmPackage.packageJson.version
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
project.nodeJs.packageJsonHandlers.forEach {
|
|
||||||
it(packageJson)
|
|
||||||
}
|
|
||||||
|
|
||||||
val packageJsonRequired =
|
|
||||||
if (project == rootProject) packageManager.hookRootPackage(rootProject, packageJson, npmPackages)
|
|
||||||
else false
|
|
||||||
|
|
||||||
return if (!packageJsonRequired && packageJson.empty) null
|
|
||||||
else NpmPackage(project, packageJson, npmDependencies)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun visitTasksRequiredDependencies(
|
|
||||||
project: Project,
|
|
||||||
npmDependencies: MutableSet<NpmDependency>,
|
|
||||||
gradleDeps: NpmProjectGradleDeps
|
|
||||||
) {
|
|
||||||
val requiredDependencies = mutableListOf<Dependency>()
|
|
||||||
|
|
||||||
project.tasks.toList().forEach { task ->
|
|
||||||
if (task.enabled && task is RequiresNpmDependencies) {
|
|
||||||
val list = task.requiredNpmDependencies.toList()
|
|
||||||
|
|
||||||
requiredByTasks[task] = list
|
|
||||||
list.forEach { requiredDependency ->
|
|
||||||
requiredDependencies.add(requiredDependency.createDependency(project))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (requiredDependencies.isNotEmpty()) {
|
|
||||||
val configuration = project.configurations.create("jsTools")
|
|
||||||
requiredDependencies.forEach {
|
|
||||||
configuration.dependencies.add(it)
|
|
||||||
}
|
|
||||||
configuration.resolve()
|
|
||||||
visitConfiguration(configuration, npmDependencies, gradleDeps)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun collectDependencies(
|
|
||||||
project: Project,
|
|
||||||
npmDependencies: MutableSet<NpmDependency>,
|
|
||||||
gradleDeps: NpmProjectGradleDeps,
|
|
||||||
packageJson: PackageJson
|
|
||||||
) {
|
|
||||||
val kotlin = project.kotlinExtensionOrNull
|
|
||||||
|
|
||||||
if (kotlin != null) {
|
|
||||||
when (kotlin) {
|
|
||||||
is KotlinSingleTargetExtension -> visitTarget(kotlin.target, project, npmDependencies, gradleDeps, packageJson)
|
|
||||||
is KotlinMultiplatformExtension -> kotlin.targets.forEach {
|
|
||||||
visitTarget(it, project, npmDependencies, gradleDeps, packageJson)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
npmDependencies.forEach {
|
|
||||||
packageJson.dependencies[it.key] = chooseVersion(packageJson.dependencies[it.key], it.version)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun chooseVersion(oldVersion: String?, newVersion: String): String =
|
|
||||||
oldVersion ?: newVersion // todo: real versions conflict resolution
|
|
||||||
|
|
||||||
private fun visitTarget(
|
|
||||||
target: KotlinTarget,
|
|
||||||
project: Project,
|
|
||||||
npmDependencies: MutableSet<NpmDependency>,
|
|
||||||
gradleDeps: NpmProjectGradleDeps,
|
|
||||||
packageJson: PackageJson
|
|
||||||
) {
|
|
||||||
if (target.platformType == KotlinPlatformType.js) {
|
|
||||||
target.compilations.toList().forEach { compilation ->
|
|
||||||
compilation.relatedConfigurationNames.forEach {
|
|
||||||
val configuration = project.configurations.getByName(it)
|
|
||||||
visitConfiguration(configuration, npmDependencies, gradleDeps)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (compilation is KotlinJsCompilation) {
|
|
||||||
visitKotlinJsCompilation(project, compilation)
|
|
||||||
|
|
||||||
if (compilation.name == "main") {
|
|
||||||
packageJson.main = compilation.compileKotlinTask.outputFile.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun visitConfiguration(
|
|
||||||
configuration: Configuration,
|
|
||||||
npmDependencies: MutableSet<NpmDependency>,
|
|
||||||
gradleDeps: NpmProjectGradleDeps
|
|
||||||
) {
|
|
||||||
gradleNodeModules.collectDependenciesFromConfiguration(configuration, gradleDeps)
|
|
||||||
|
|
||||||
configuration.allDependencies.forEach { dependency ->
|
|
||||||
when (dependency) {
|
|
||||||
is NpmDependency -> npmDependencies.add(dependency)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun visitKotlinJsCompilation(
|
|
||||||
project: Project,
|
|
||||||
compilation: KotlinJsCompilation
|
|
||||||
) {
|
|
||||||
val npmProject = project.npmProject
|
|
||||||
val kotlin2JsCompile = compilation.compileKotlinTask
|
|
||||||
if (npmProject.compileOutputCopyDest != null) {
|
|
||||||
project.whenEvaluated {
|
|
||||||
if (kotlin2JsCompile.outputFile.exists()) {
|
|
||||||
visitCompile(project.npmProject, kotlin2JsCompile)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
kotlin2JsCompile.doLast {
|
|
||||||
visitCompile(project.npmProject, kotlin2JsCompile)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun visitCompile(npmProject: NpmProject, kotlin2JsCompile: Kotlin2JsCompile) {
|
|
||||||
npmProject.project.copy { copy ->
|
|
||||||
copy.from(kotlin2JsCompile.outputFile)
|
|
||||||
copy.from(kotlin2JsCompile.outputFile.path + ".map")
|
|
||||||
copy.into(npmProject.compileOutputCopyDest!!)
|
|
||||||
copy.withSourceMapRewriter(npmProject)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun CopySpec.withSourceMapRewriter(npmProject: NpmProject) {
|
|
||||||
eachFile {
|
|
||||||
if (it.name.endsWith(".js.map")) {
|
|
||||||
it.filter(
|
|
||||||
mapOf(
|
|
||||||
"srcSourceRoot" to it.file.parentFile,
|
|
||||||
"targetSourceRoot" to npmProject.compileOutputCopyDest!!
|
|
||||||
),
|
|
||||||
RewriteSourceMapFilterReader::class.java
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
mainCompilations.single().value
|
||||||
|
} else null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun chooseVersion(oldVersion: String?, newVersion: String): String =
|
||||||
|
oldVersion ?: newVersion // todo: real versions conflict resolution
|
||||||
|
|
||||||
override fun close() {
|
override fun close() {
|
||||||
gradleNodeModules.close()
|
gradleNodeModules.close()
|
||||||
}
|
}
|
||||||
|
|||||||
+34
@@ -5,6 +5,10 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.gradle.targets.js.npm
|
package org.jetbrains.kotlin.gradle.targets.js.npm
|
||||||
|
|
||||||
|
import com.google.gson.GsonBuilder
|
||||||
|
import org.jetbrains.kotlin.gradle.internal.ensureParentDirsCreated
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
class PackageJson(
|
class PackageJson(
|
||||||
var name: String,
|
var name: String,
|
||||||
var version: String
|
var version: String
|
||||||
@@ -16,10 +20,40 @@ class PackageJson(
|
|||||||
dependencies.isEmpty() &&
|
dependencies.isEmpty() &&
|
||||||
devDependencies.isEmpty()
|
devDependencies.isEmpty()
|
||||||
|
|
||||||
|
val scopedName: ScopedName
|
||||||
|
get() = scopedName(name)
|
||||||
|
|
||||||
var private: Boolean? = null
|
var private: Boolean? = null
|
||||||
|
|
||||||
|
var main: String? = null
|
||||||
|
|
||||||
var workspaces: Collection<String>? = null
|
var workspaces: Collection<String>? = null
|
||||||
|
|
||||||
val devDependencies = mutableMapOf<String, String>()
|
val devDependencies = mutableMapOf<String, String>()
|
||||||
val dependencies = mutableMapOf<String, String>()
|
val dependencies = mutableMapOf<String, String>()
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun scopedName(name: String): ScopedName = if (name.contains("/")) ScopedName(
|
||||||
|
scope = name.substringBeforeLast("/").removePrefix("@"),
|
||||||
|
name = name.substringAfterLast("/")
|
||||||
|
) else ScopedName(scope = null, name = name)
|
||||||
|
|
||||||
|
operator fun invoke(scope: String, name: String, version: String) =
|
||||||
|
PackageJson(ScopedName(scope, name).toString(), version)
|
||||||
|
}
|
||||||
|
|
||||||
|
data class ScopedName(val scope: String?, val name: String) {
|
||||||
|
override fun toString() = if (scope == null) name else "@$scope/$name"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveTo(packageJsonFile: File) {
|
||||||
|
val gson = GsonBuilder()
|
||||||
|
.setPrettyPrinting()
|
||||||
|
.create()
|
||||||
|
|
||||||
|
packageJsonFile.ensureParentDirsCreated()
|
||||||
|
packageJsonFile.writer().use {
|
||||||
|
gson.toJson(this, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+4
@@ -5,6 +5,10 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.gradle.targets.js.npm
|
package org.jetbrains.kotlin.gradle.targets.js.npm
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.js.RequiredKotlinJsDependency
|
||||||
|
|
||||||
interface RequiresNpmDependencies {
|
interface RequiresNpmDependencies {
|
||||||
|
val compilation: KotlinJsCompilation
|
||||||
val requiredNpmDependencies: Collection<RequiredKotlinJsDependency>
|
val requiredNpmDependencies: Collection<RequiredKotlinJsDependency>
|
||||||
}
|
}
|
||||||
+2
-5
@@ -10,7 +10,6 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
|
|||||||
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsTarget
|
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsTarget
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsBrowserDsl
|
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsBrowserDsl
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.nodeJs
|
import org.jetbrains.kotlin.gradle.targets.js.nodejs.nodeJs
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject
|
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest
|
import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpack
|
import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpack
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfigWriter
|
import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfigWriter
|
||||||
@@ -20,7 +19,6 @@ class KotlinBrowserJs(target: KotlinJsTarget) :
|
|||||||
KotlinJsSubTarget(target, "browser"),
|
KotlinJsSubTarget(target, "browser"),
|
||||||
KotlinJsBrowserDsl {
|
KotlinJsBrowserDsl {
|
||||||
|
|
||||||
private val versions = project.nodeJs.versions
|
|
||||||
private val webpackTaskName = disambiguateCamelCased("webpack")
|
private val webpackTaskName = disambiguateCamelCased("webpack")
|
||||||
|
|
||||||
override fun configureDefaultTestFramework(it: KotlinJsTest) {
|
override fun configureDefaultTestFramework(it: KotlinJsTest) {
|
||||||
@@ -39,13 +37,12 @@ class KotlinBrowserJs(target: KotlinJsTarget) :
|
|||||||
|
|
||||||
override fun configureRun(compilation: KotlinJsCompilation) {
|
override fun configureRun(compilation: KotlinJsCompilation) {
|
||||||
val project = compilation.target.project
|
val project = compilation.target.project
|
||||||
val npmProject = project.npmProject
|
|
||||||
|
|
||||||
project.createOrRegisterTask<KotlinWebpack>(disambiguateCamelCased("webpack")) {
|
project.createOrRegisterTask<KotlinWebpack>(disambiguateCamelCased("webpack")) {
|
||||||
val compileKotlinTask = compilation.compileKotlinTask
|
val compileKotlinTask = compilation.compileKotlinTask
|
||||||
it.dependsOn(target.project.nodeJs.root.npmResolveTask, compileKotlinTask)
|
it.dependsOn(target.project.nodeJs.root.npmResolveTask, compileKotlinTask)
|
||||||
|
|
||||||
it.entry = npmProject.compileOutput(compileKotlinTask)
|
it.compilation = compilation
|
||||||
|
|
||||||
project.tasks.getByName(LifecycleBasePlugin.ASSEMBLE_TASK_NAME).dependsOn(it)
|
project.tasks.getByName(LifecycleBasePlugin.ASSEMBLE_TASK_NAME).dependsOn(it)
|
||||||
}
|
}
|
||||||
@@ -59,7 +56,7 @@ class KotlinBrowserJs(target: KotlinJsTarget) :
|
|||||||
)
|
)
|
||||||
|
|
||||||
it.bin = "webpack-dev-server"
|
it.bin = "webpack-dev-server"
|
||||||
it.entry = npmProject.compileOutput(compileKotlinTask)
|
it.compilation = compilation
|
||||||
|
|
||||||
it.devServer = KotlinWebpackConfigWriter.DevServer(
|
it.devServer = KotlinWebpackConfigWriter.DevServer(
|
||||||
open = true,
|
open = true,
|
||||||
|
|||||||
+7
-1
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.gradle.targets.js.KotlinJsTarget
|
|||||||
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsSubTargetDsl
|
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsSubTargetDsl
|
||||||
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.nodeJs
|
import org.jetbrains.kotlin.gradle.targets.js.nodejs.nodeJs
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest
|
import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest
|
||||||
import org.jetbrains.kotlin.gradle.tasks.createOrRegisterTask
|
import org.jetbrains.kotlin.gradle.tasks.createOrRegisterTask
|
||||||
import org.jetbrains.kotlin.gradle.testing.internal.configureConventions
|
import org.jetbrains.kotlin.gradle.testing.internal.configureConventions
|
||||||
@@ -32,6 +33,11 @@ abstract class KotlinJsSubTarget(
|
|||||||
fun configure() {
|
fun configure() {
|
||||||
configureTests()
|
configureTests()
|
||||||
configureRun()
|
configureRun()
|
||||||
|
|
||||||
|
target.compilations.all {
|
||||||
|
val npmProject = it.npmProject
|
||||||
|
it.compileKotlinTask.kotlinOptions.outputFile = npmProject.dir.resolve(npmProject.main).canonicalPath
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun disambiguate(name: String): MutableList<String> {
|
private fun disambiguate(name: String): MutableList<String> {
|
||||||
@@ -72,8 +78,8 @@ abstract class KotlinJsSubTarget(
|
|||||||
compileTask.outputFile.exists()
|
compileTask.outputFile.exists()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
testJs.compilation = compilation
|
||||||
testJs.targetName = target.disambiguationClassifier + "," + disambiguationClassifier
|
testJs.targetName = target.disambiguationClassifier + "," + disambiguationClassifier
|
||||||
testJs.nodeModulesToLoad.add(compileTask.outputFile.nameWithoutExtension)
|
|
||||||
|
|
||||||
testJs.configureConventions()
|
testJs.configureConventions()
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-7
@@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.gradle.targets.js.subtargets
|
package org.jetbrains.kotlin.gradle.targets.js.subtargets
|
||||||
|
|
||||||
import org.gradle.api.Project
|
|
||||||
import org.jetbrains.kotlin.gradle.plugin.TaskHolder
|
import org.jetbrains.kotlin.gradle.plugin.TaskHolder
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsTarget
|
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsTarget
|
||||||
@@ -35,19 +34,18 @@ class KotlinNodeJs(target: KotlinJsTarget) :
|
|||||||
val compileKotlinTask = compilation.compileKotlinTask
|
val compileKotlinTask = compilation.compileKotlinTask
|
||||||
runTask.dependsOn(target.project.nodeJs.root.npmResolveTask, compileKotlinTask)
|
runTask.dependsOn(target.project.nodeJs.root.npmResolveTask, compileKotlinTask)
|
||||||
|
|
||||||
val npmProject = project.npmProject
|
val npmProject = compilation.npmProject
|
||||||
runTask.args(npmProject.compileOutput(compileKotlinTask))
|
runTask.args(compileKotlinTask.outputFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
addSourceMapSupport(compilation, runTaskHolder, project)
|
addSourceMapSupport(compilation, runTaskHolder)
|
||||||
|
|
||||||
target.runTask.dependsOn(runTaskHolder.getTaskOrProvider())
|
target.runTask.dependsOn(runTaskHolder.getTaskOrProvider())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addSourceMapSupport(
|
private fun addSourceMapSupport(
|
||||||
compilation: KotlinJsCompilation,
|
compilation: KotlinJsCompilation,
|
||||||
runTaskHolder: TaskHolder<NodeJsExec>,
|
runTaskHolder: TaskHolder<NodeJsExec>
|
||||||
project: Project
|
|
||||||
) {
|
) {
|
||||||
compilation.dependencies {
|
compilation.dependencies {
|
||||||
runtimeOnly(kotlin("test-nodejs-runner"))
|
runtimeOnly(kotlin("test-nodejs-runner"))
|
||||||
@@ -57,7 +55,7 @@ class KotlinNodeJs(target: KotlinJsTarget) :
|
|||||||
runTaskHolder.configure { runTask ->
|
runTaskHolder.configure { runTask ->
|
||||||
runTask.args(
|
runTask.args(
|
||||||
"--require",
|
"--require",
|
||||||
project.npmProject.require("kotlin-test-nodejs-runner/kotlin-nodejs-source-map-support")
|
compilation.npmProject.require("kotlin-test-nodejs-runner/kotlin-nodejs-source-map-support")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-11
@@ -12,9 +12,12 @@ import org.gradle.api.tasks.SkipWhenEmpty
|
|||||||
import org.gradle.process.internal.DefaultProcessForkOptions
|
import org.gradle.process.internal.DefaultProcessForkOptions
|
||||||
import org.gradle.util.ConfigureUtil
|
import org.gradle.util.ConfigureUtil
|
||||||
import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutionSpec
|
import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutionSpec
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
|
||||||
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.npm.*
|
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmResolver
|
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmResolver
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.js.RequiredKotlinJsDependency
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.js.npm.RequiresNpmDependencies
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.testing.karma.KotlinKarma
|
import org.jetbrains.kotlin.gradle.targets.js.testing.karma.KotlinKarma
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.testing.mocha.KotlinMocha
|
import org.jetbrains.kotlin.gradle.targets.js.testing.mocha.KotlinMocha
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.testing.nodejs.KotlinNodeJsTestRunner
|
import org.jetbrains.kotlin.gradle.targets.js.testing.nodejs.KotlinNodeJsTestRunner
|
||||||
@@ -31,27 +34,36 @@ open class KotlinJsTest : KotlinTest(), RequiresNpmDependencies {
|
|||||||
@Input
|
@Input
|
||||||
var debug: Boolean = false
|
var debug: Boolean = false
|
||||||
|
|
||||||
@Input
|
@Internal
|
||||||
var nodeModulesToLoad: MutableList<String> = mutableListOf()
|
override lateinit var compilation: KotlinJsCompilation
|
||||||
|
|
||||||
|
val compilationId: String
|
||||||
|
@Input get() = compilation.let {
|
||||||
|
val target = it.target
|
||||||
|
target.project.path + "@" + target.name + ":" + it.compilationName
|
||||||
|
}
|
||||||
|
|
||||||
|
val nodeModulesToLoad: List<String>
|
||||||
|
@Internal get() = listOf("./" + compilation.npmProject.main)
|
||||||
|
|
||||||
override val requiredNpmDependencies: Collection<RequiredKotlinJsDependency>
|
override val requiredNpmDependencies: Collection<RequiredKotlinJsDependency>
|
||||||
get() = testFramework!!.requiredNpmDependencies
|
get() = testFramework!!.requiredNpmDependencies
|
||||||
|
|
||||||
fun useNodeJs(body: KotlinNodeJsTestRunner.() -> Unit) = use(KotlinNodeJsTestRunner(project), body)
|
fun useNodeJs(body: KotlinNodeJsTestRunner.() -> Unit) = use(KotlinNodeJsTestRunner(compilation), body)
|
||||||
fun useNodeJs(fn: Closure<*>) {
|
fun useNodeJs(fn: Closure<*>) {
|
||||||
useNodeJs {
|
useNodeJs {
|
||||||
ConfigureUtil.configure(fn, this)
|
ConfigureUtil.configure(fn, this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun useMocha(body: KotlinMocha.() -> Unit) = use(KotlinMocha(project), body)
|
fun useMocha(body: KotlinMocha.() -> Unit) = use(KotlinMocha(compilation), body)
|
||||||
fun useMocha(fn: Closure<*>) {
|
fun useMocha(fn: Closure<*>) {
|
||||||
useMocha {
|
useMocha {
|
||||||
ConfigureUtil.configure(fn, this)
|
ConfigureUtil.configure(fn, this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun useKarma(body: KotlinKarma.() -> Unit) = use(KotlinKarma(project), body)
|
fun useKarma(body: KotlinKarma.() -> Unit) = use(KotlinKarma(compilation), body)
|
||||||
fun useKarma(fn: Closure<*>) {
|
fun useKarma(fn: Closure<*>) {
|
||||||
useKarma {
|
useKarma {
|
||||||
ConfigureUtil.configure(fn, this)
|
ConfigureUtil.configure(fn, this)
|
||||||
@@ -70,17 +82,13 @@ open class KotlinJsTest : KotlinTest(), RequiresNpmDependencies {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun executeTests() {
|
override fun executeTests() {
|
||||||
NpmResolver.resolve(project)
|
|
||||||
NpmResolver.checkRequiredDependencies(project, this)
|
NpmResolver.checkRequiredDependencies(project, this)
|
||||||
super.executeTests()
|
super.executeTests()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createTestExecutionSpec(): TCServiceMessagesTestExecutionSpec {
|
override fun createTestExecutionSpec(): TCServiceMessagesTestExecutionSpec {
|
||||||
val forkOptions = DefaultProcessForkOptions(fileResolver)
|
val forkOptions = DefaultProcessForkOptions(fileResolver)
|
||||||
|
forkOptions.workingDir = compilation.npmProject.dir
|
||||||
NpmResolver.resolve(project)
|
|
||||||
|
|
||||||
forkOptions.workingDir = NpmProject[project].nodeWorkDir
|
|
||||||
forkOptions.executable = NodeJsPlugin.apply(project).root.environment.nodeExecutable
|
forkOptions.executable = NodeJsPlugin.apply(project).root.environment.nodeExecutable
|
||||||
|
|
||||||
val nodeJsArgs = mutableListOf<String>()
|
val nodeJsArgs = mutableListOf<String>()
|
||||||
|
|||||||
+9
-5
@@ -15,11 +15,12 @@ import org.jetbrains.kotlin.gradle.internal.operation
|
|||||||
import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesClient
|
import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesClient
|
||||||
import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesClientSettings
|
import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesClientSettings
|
||||||
import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutionSpec
|
import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutionSpec
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.appendConfigsFromDir
|
import org.jetbrains.kotlin.gradle.targets.js.appendConfigsFromDir
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.internal.parseNodeJsStackTraceAsJvm
|
import org.jetbrains.kotlin.gradle.targets.js.internal.parseNodeJsStackTraceAsJvm
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.nodeJs
|
import org.jetbrains.kotlin.gradle.targets.js.nodejs.nodeJs
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmPackageVersion
|
import org.jetbrains.kotlin.gradle.targets.js.NpmPackageVersion
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.npm.RequiredKotlinJsDependency
|
import org.jetbrains.kotlin.gradle.targets.js.RequiredKotlinJsDependency
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject
|
import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest
|
import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTestFramework
|
import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTestFramework
|
||||||
@@ -29,7 +30,10 @@ import org.jetbrains.kotlin.gradle.testing.internal.reportsDir
|
|||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class KotlinKarma(val project: Project) : KotlinJsTestFramework {
|
class KotlinKarma(override val compilation: KotlinJsCompilation) : KotlinJsTestFramework {
|
||||||
|
val project: Project
|
||||||
|
get() = compilation.target.project
|
||||||
|
|
||||||
private val config: KarmaConfig = KarmaConfig()
|
private val config: KarmaConfig = KarmaConfig()
|
||||||
private val requiredDependencies = mutableSetOf<NpmPackageVersion>()
|
private val requiredDependencies = mutableSetOf<NpmPackageVersion>()
|
||||||
|
|
||||||
@@ -183,7 +187,7 @@ class KotlinKarma(val project: Project) : KotlinJsTestFramework {
|
|||||||
ignoreOutOfRootNodes = true
|
ignoreOutOfRootNodes = true
|
||||||
)
|
)
|
||||||
|
|
||||||
val npmProject = task.project.npmProject
|
val npmProject = compilation.npmProject
|
||||||
|
|
||||||
val files = task.nodeModulesToLoad.map { npmProject.require(it) }
|
val files = task.nodeModulesToLoad.map { npmProject.require(it) }
|
||||||
config.files.addAll(files)
|
config.files.addAll(files)
|
||||||
@@ -194,7 +198,7 @@ class KotlinKarma(val project: Project) : KotlinJsTestFramework {
|
|||||||
it(task)
|
it(task)
|
||||||
}
|
}
|
||||||
|
|
||||||
val karmaConfJs = npmProject.nodeWorkDir.resolve("karma.conf.js")
|
val karmaConfJs = npmProject.dir.resolve("karma.conf.js")
|
||||||
karmaConfJs.printWriter().use { confWriter ->
|
karmaConfJs.printWriter().use { confWriter ->
|
||||||
confWriter.println("module.exports = function(config) {")
|
confWriter.println("module.exports = function(config) {")
|
||||||
confWriter.println()
|
confWriter.println()
|
||||||
|
|||||||
+10
-6
@@ -9,15 +9,19 @@ import org.gradle.api.Project
|
|||||||
import org.gradle.process.ProcessForkOptions
|
import org.gradle.process.ProcessForkOptions
|
||||||
import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesClientSettings
|
import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesClientSettings
|
||||||
import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutionSpec
|
import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutionSpec
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.internal.parseNodeJsStackTraceAsJvm
|
import org.jetbrains.kotlin.gradle.targets.js.internal.parseNodeJsStackTraceAsJvm
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.nodeJs
|
import org.jetbrains.kotlin.gradle.targets.js.nodejs.nodeJs
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.npm.KotlinGradleNpmPackage
|
import org.jetbrains.kotlin.gradle.targets.js.KotlinGradleNpmPackage
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProject
|
import org.jetbrains.kotlin.gradle.targets.js.RequiredKotlinJsDependency
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.npm.RequiredKotlinJsDependency
|
import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest
|
import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTestFramework
|
import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTestFramework
|
||||||
|
|
||||||
class KotlinMocha(val project: Project) : KotlinJsTestFramework {
|
class KotlinMocha(override val compilation: KotlinJsCompilation) : KotlinJsTestFramework {
|
||||||
|
val project: Project
|
||||||
|
get() = compilation.target.project
|
||||||
|
|
||||||
private val versions = project.nodeJs.versions
|
private val versions = project.nodeJs.versions
|
||||||
|
|
||||||
override val settingsState: String
|
override val settingsState: String
|
||||||
@@ -48,11 +52,11 @@ class KotlinMocha(val project: Project) : KotlinJsTestFramework {
|
|||||||
task.nodeModulesToLoad.single()
|
task.nodeModulesToLoad.single()
|
||||||
)
|
)
|
||||||
|
|
||||||
val npmProjectLayout = NpmProject[task.project]
|
val npmProject = compilation.npmProject
|
||||||
|
|
||||||
val args = nodeJsArgs +
|
val args = nodeJsArgs +
|
||||||
nodeModules.map {
|
nodeModules.map {
|
||||||
npmProjectLayout.nodeModulesDir.resolve(it).also { file ->
|
npmProject.nodeModulesDir.resolve(it).also { file ->
|
||||||
check(file.isFile) { "Cannot find ${file.canonicalPath}" }
|
check(file.isFile) { "Cannot find ${file.canonicalPath}" }
|
||||||
}.canonicalPath
|
}.canonicalPath
|
||||||
} +
|
} +
|
||||||
|
|||||||
+9
-10
@@ -6,21 +6,22 @@
|
|||||||
package org.jetbrains.kotlin.gradle.targets.js.testing.nodejs
|
package org.jetbrains.kotlin.gradle.targets.js.testing.nodejs
|
||||||
|
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.gradle.api.tasks.Input
|
|
||||||
import org.gradle.process.ProcessForkOptions
|
import org.gradle.process.ProcessForkOptions
|
||||||
import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesClientSettings
|
import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesClientSettings
|
||||||
import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutionSpec
|
import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutionSpec
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.internal.parseNodeJsStackTraceAsJvm
|
import org.jetbrains.kotlin.gradle.targets.js.internal.parseNodeJsStackTraceAsJvm
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.npm.KotlinGradleNpmPackage
|
import org.jetbrains.kotlin.gradle.targets.js.KotlinGradleNpmPackage
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProject
|
import org.jetbrains.kotlin.gradle.targets.js.RequiredKotlinJsDependency
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.npm.RequiredKotlinJsDependency
|
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject
|
import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTestFramework
|
import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTestFramework
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest
|
import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest
|
||||||
import org.jetbrains.kotlin.gradle.testing.IgnoredTestSuites
|
import org.jetbrains.kotlin.gradle.testing.IgnoredTestSuites
|
||||||
|
|
||||||
class KotlinNodeJsTestRunner(val project: Project) : KotlinJsTestFramework {
|
class KotlinNodeJsTestRunner(override val compilation: KotlinJsCompilation) : KotlinJsTestFramework {
|
||||||
@Input
|
val project: Project
|
||||||
|
get() = compilation.target.project
|
||||||
|
|
||||||
var ignoredTestSuites: IgnoredTestSuites = IgnoredTestSuites.showWithContents
|
var ignoredTestSuites: IgnoredTestSuites = IgnoredTestSuites.showWithContents
|
||||||
|
|
||||||
override val settingsState: String
|
override val settingsState: String
|
||||||
@@ -34,7 +35,7 @@ class KotlinNodeJsTestRunner(val project: Project) : KotlinJsTestFramework {
|
|||||||
forkOptions: ProcessForkOptions,
|
forkOptions: ProcessForkOptions,
|
||||||
nodeJsArgs: MutableList<String>
|
nodeJsArgs: MutableList<String>
|
||||||
): TCServiceMessagesTestExecutionSpec {
|
): TCServiceMessagesTestExecutionSpec {
|
||||||
val npmProject = project.npmProject
|
val npmProject = compilation.npmProject
|
||||||
|
|
||||||
val cliArgs = KotlinNodeJsTestRunnerCliArgs(
|
val cliArgs = KotlinNodeJsTestRunnerCliArgs(
|
||||||
task.nodeModulesToLoad.map { npmProject.require(it) },
|
task.nodeModulesToLoad.map { npmProject.require(it) },
|
||||||
@@ -55,11 +56,9 @@ class KotlinNodeJsTestRunner(val project: Project) : KotlinJsTestFramework {
|
|||||||
"kotlin-test-nodejs-runner/kotlin-nodejs-source-map-support.js"
|
"kotlin-test-nodejs-runner/kotlin-nodejs-source-map-support.js"
|
||||||
)
|
)
|
||||||
|
|
||||||
val npmProjectLayout = NpmProject[task.project]
|
|
||||||
|
|
||||||
val args = nodeJsArgs +
|
val args = nodeJsArgs +
|
||||||
testRuntimeNodeModules.map {
|
testRuntimeNodeModules.map {
|
||||||
npmProjectLayout.require(it)
|
npmProject.require(it)
|
||||||
} +
|
} +
|
||||||
cliArgs.toList()
|
cliArgs.toList()
|
||||||
|
|
||||||
|
|||||||
+15
-7
@@ -13,8 +13,9 @@ import org.gradle.deployment.internal.DeploymentHandle
|
|||||||
import org.gradle.deployment.internal.DeploymentRegistry
|
import org.gradle.deployment.internal.DeploymentRegistry
|
||||||
import org.gradle.process.internal.ExecHandle
|
import org.gradle.process.internal.ExecHandle
|
||||||
import org.gradle.process.internal.ExecHandleFactory
|
import org.gradle.process.internal.ExecHandleFactory
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.nodeJs
|
import org.jetbrains.kotlin.gradle.targets.js.nodejs.nodeJs
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmPackageVersion
|
import org.jetbrains.kotlin.gradle.targets.js.NpmPackageVersion
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmResolver
|
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmResolver
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.npm.RequiresNpmDependencies
|
import org.jetbrains.kotlin.gradle.targets.js.npm.RequiresNpmDependencies
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject
|
import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject
|
||||||
@@ -34,12 +35,20 @@ open class KotlinWebpack : DefaultTask(), RequiresNpmDependencies {
|
|||||||
open val execHandleFactory: ExecHandleFactory
|
open val execHandleFactory: ExecHandleFactory
|
||||||
get() = injected
|
get() = injected
|
||||||
|
|
||||||
@Input
|
@Internal
|
||||||
@SkipWhenEmpty
|
override lateinit var compilation: KotlinJsCompilation
|
||||||
open lateinit var entry: File
|
|
||||||
|
val compilationId: String
|
||||||
|
@Input get() = compilation.let {
|
||||||
|
val target = it.target
|
||||||
|
target.project.path + "@" + target.name + ":" + it.compilationName
|
||||||
|
}
|
||||||
|
|
||||||
|
val entry: File
|
||||||
|
get() = compilation.compileKotlinTask.outputFile
|
||||||
|
|
||||||
open val configFile: File
|
open val configFile: File
|
||||||
@OutputFile get() = project.npmProject.nodeWorkDir.resolve("webpack.config.js")
|
@OutputFile get() = compilation.npmProject.dir.resolve("webpack.config.js")
|
||||||
|
|
||||||
@Input
|
@Input
|
||||||
var saveEvaluatedConfigFile: Boolean = true
|
var saveEvaluatedConfigFile: Boolean = true
|
||||||
@@ -89,7 +98,7 @@ open class KotlinWebpack : DefaultTask(), RequiresNpmDependencies {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun createRunner() = KotlinWebpackRunner(
|
private fun createRunner() = KotlinWebpackRunner(
|
||||||
project,
|
compilation!!.npmProject,
|
||||||
configFile,
|
configFile,
|
||||||
execHandleFactory,
|
execHandleFactory,
|
||||||
bin,
|
bin,
|
||||||
@@ -107,7 +116,6 @@ open class KotlinWebpack : DefaultTask(), RequiresNpmDependencies {
|
|||||||
|
|
||||||
@TaskAction
|
@TaskAction
|
||||||
fun execute() {
|
fun execute() {
|
||||||
NpmResolver.resolve(project)
|
|
||||||
NpmResolver.checkRequiredDependencies(project, this)
|
NpmResolver.checkRequiredDependencies(project, this)
|
||||||
|
|
||||||
val runner = createRunner()
|
val runner = createRunner()
|
||||||
|
|||||||
+2
-7
@@ -12,7 +12,6 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.gradle.targets.js.webpack
|
package org.jetbrains.kotlin.gradle.targets.js.webpack
|
||||||
|
|
||||||
import org.gradle.api.Project
|
|
||||||
import org.gradle.process.ExecResult
|
import org.gradle.process.ExecResult
|
||||||
import org.gradle.process.internal.ExecHandle
|
import org.gradle.process.internal.ExecHandle
|
||||||
import org.gradle.process.internal.ExecHandleFactory
|
import org.gradle.process.internal.ExecHandleFactory
|
||||||
@@ -21,7 +20,7 @@ import org.jetbrains.kotlin.gradle.targets.js.npm.NpmResolver
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
internal class KotlinWebpackRunner(
|
internal class KotlinWebpackRunner(
|
||||||
val project: Project,
|
val npmProject: NpmProject,
|
||||||
val configFile: File,
|
val configFile: File,
|
||||||
val execHandleFactory: ExecHandleFactory,
|
val execHandleFactory: ExecHandleFactory,
|
||||||
val bin: String,
|
val bin: String,
|
||||||
@@ -41,10 +40,6 @@ internal class KotlinWebpackRunner(
|
|||||||
"${this}: Entry file not existed \"${configWriter.entry}\""
|
"${this}: Entry file not existed \"${configWriter.entry}\""
|
||||||
}
|
}
|
||||||
|
|
||||||
NpmResolver.resolve(project)
|
|
||||||
|
|
||||||
val npmProjectLayout = NpmProject[project]
|
|
||||||
|
|
||||||
configWriter.save(configFile)
|
configWriter.save(configFile)
|
||||||
|
|
||||||
val execFactory = execHandleFactory.newExec()
|
val execFactory = execHandleFactory.newExec()
|
||||||
@@ -54,7 +49,7 @@ internal class KotlinWebpackRunner(
|
|||||||
args.add("--progress")
|
args.add("--progress")
|
||||||
}
|
}
|
||||||
|
|
||||||
npmProjectLayout.useTool(execFactory, ".bin/$bin", *args.toTypedArray())
|
npmProject.useTool(execFactory, ".bin/$bin", *args.toTypedArray())
|
||||||
val exec = execFactory.build()
|
val exec = execFactory.build()
|
||||||
exec.start()
|
exec.start()
|
||||||
return exec
|
return exec
|
||||||
|
|||||||
+39
-48
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.gradle.targets.js.yarn
|
|||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.jetbrains.kotlin.gradle.internal.execWithProgress
|
import org.jetbrains.kotlin.gradle.internal.execWithProgress
|
||||||
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.nodeJs
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.npm.*
|
import org.jetbrains.kotlin.gradle.targets.js.npm.*
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
@@ -16,24 +17,22 @@ object Yarn : NpmApi {
|
|||||||
YarnPlugin.apply(project).executeSetup()
|
YarnPlugin.apply(project).executeSetup()
|
||||||
}
|
}
|
||||||
|
|
||||||
val Project.packageJsonHashFile: File
|
val NpmProject.packageJsonHashFile: File
|
||||||
get() = buildDir.resolve("package.json.hash")
|
get() = dir.resolve("package.json.hash")
|
||||||
|
|
||||||
fun yarnExec(
|
fun yarnExec(
|
||||||
project: Project,
|
project: Project,
|
||||||
|
dir: File,
|
||||||
description: String,
|
description: String,
|
||||||
vararg args: String,
|
vararg args: String
|
||||||
npmProject: NpmProject = NpmProject[project]
|
|
||||||
) {
|
) {
|
||||||
val nodeJsEnv = NodeJsPlugin.apply(project).root.environment
|
val nodeJsEnv = NodeJsPlugin.apply(project).root.environment
|
||||||
val yarnEnv = YarnPlugin.apply(project).environment
|
val yarnEnv = YarnPlugin.apply(project).environment
|
||||||
|
|
||||||
val nodeWorkDir = npmProject.nodeWorkDir
|
|
||||||
|
|
||||||
project.execWithProgress(description) { exec ->
|
project.execWithProgress(description) { exec ->
|
||||||
exec.executable = nodeJsEnv.nodeExecutable
|
exec.executable = nodeJsEnv.nodeExecutable
|
||||||
exec.args = listOf(yarnEnv.home.resolve("bin/yarn.js").absolutePath) + args
|
exec.args = listOf(yarnEnv.home.resolve("bin/yarn.js").absolutePath) + args
|
||||||
exec.workingDir = nodeWorkDir
|
exec.workingDir = dir
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -79,70 +78,62 @@ object Yarn : NpmApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("EXPOSED_PARAMETER_TYPE")
|
override fun resolveProject(resolvedNpmProject: NpmProjectPackage) {
|
||||||
override fun resolveProject(npmPackage: NpmResolver.NpmPackage) {
|
val project = resolvedNpmProject.project
|
||||||
val project = npmPackage.project
|
|
||||||
if (!project.yarn.useWorkspaces) {
|
if (!project.yarn.useWorkspaces) {
|
||||||
YarnAvoidance(project).updateIfNeeded {
|
YarnAvoidance(resolvedNpmProject.npmProject).updateIfNeeded {
|
||||||
yarnExec(project, NpmApi.resolveOperationDescription("yarn for ${project.path}"))
|
yarnExec(project, resolvedNpmProject.npmProject.dir, NpmApi.resolveOperationDescription("yarn for ${project.path}"))
|
||||||
yarnLockReadTransitiveDependencies(NpmProject[project].nodeWorkDir, npmPackage.npmDependencies)
|
yarnLockReadTransitiveDependencies(resolvedNpmProject.npmProject.dir, resolvedNpmProject.npmDependencies)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("EXPOSED_PARAMETER_TYPE")
|
override fun resolveRootProject(rootProject: Project, subProjects: MutableList<NpmProjectPackage>) {
|
||||||
override fun hookRootPackage(
|
|
||||||
rootProject: Project,
|
|
||||||
rootPackageJson: PackageJson,
|
|
||||||
allWorkspaces: Collection<NpmResolver.NpmPackage>
|
|
||||||
): Boolean {
|
|
||||||
if (rootProject.yarn.useWorkspaces) {
|
|
||||||
rootPackageJson.private = true
|
|
||||||
rootPackageJson.workspaces = allWorkspaces
|
|
||||||
.filter { it.project != rootProject }
|
|
||||||
.map { it.project.npmProject.nodeWorkDir.relativeTo(rootProject.npmProject.nodeWorkDir).path }
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// override fun shouldHoistGradleNodeModules(project: Project): Boolean =
|
|
||||||
// project.rootProject.yarn.useWorkspaces
|
|
||||||
|
|
||||||
@Suppress("EXPOSED_PARAMETER_TYPE")
|
|
||||||
override fun resolveRootProject(
|
|
||||||
rootProject: Project,
|
|
||||||
subprojects: MutableList<NpmResolver.NpmPackage>
|
|
||||||
) {
|
|
||||||
check(rootProject == rootProject.rootProject)
|
check(rootProject == rootProject.rootProject)
|
||||||
|
|
||||||
if (rootProject.yarn.useWorkspaces) {
|
if (rootProject.yarn.useWorkspaces) {
|
||||||
resolveWorkspaces(rootProject, subprojects)
|
resolveWorkspaces(rootProject, subProjects)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun resolveWorkspaces(
|
private fun resolveWorkspaces(
|
||||||
rootProject: Project,
|
rootProject: Project,
|
||||||
subprojects: MutableList<NpmResolver.NpmPackage>
|
npmProjects: MutableList<NpmProjectPackage>
|
||||||
) {
|
) {
|
||||||
val upToDateChecks = subprojects.map {
|
val upToDateChecks = npmProjects.map {
|
||||||
YarnAvoidance(it.project)
|
YarnAvoidance(it.npmProject)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (upToDateChecks.all { it.upToDate }) return
|
if (upToDateChecks.all { it.upToDate }) return
|
||||||
|
|
||||||
yarnExec(rootProject, NpmApi.resolveOperationDescription("yarn"))
|
val nodeJsWorldDir = rootProject.nodeJs.root.rootPackageDir
|
||||||
yarnLockReadTransitiveDependencies(NpmProject[rootProject].nodeWorkDir, subprojects.flatMap { it.npmDependencies })
|
|
||||||
|
saveRootProjectWorkspacesPackageJson(rootProject, npmProjects, nodeJsWorldDir)
|
||||||
|
|
||||||
|
yarnExec(rootProject, nodeJsWorldDir, NpmApi.resolveOperationDescription("yarn"))
|
||||||
|
yarnLockReadTransitiveDependencies(nodeJsWorldDir, npmProjects.flatMap { it.npmDependencies })
|
||||||
|
|
||||||
upToDateChecks.forEach {
|
upToDateChecks.forEach {
|
||||||
it.commit()
|
it.commit()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun cleanProject(project: Project) {
|
private fun saveRootProjectWorkspacesPackageJson(
|
||||||
super.cleanProject(project)
|
rootProject: Project,
|
||||||
project.packageJsonHashFile.delete()
|
npmProjects: MutableList<NpmProjectPackage>,
|
||||||
|
nodeJsWorldDir: File
|
||||||
|
) {
|
||||||
|
val rootPackageJson = PackageJson(rootProject.name, rootProject.version.toString())
|
||||||
|
rootPackageJson.private = true
|
||||||
|
rootPackageJson.workspaces = npmProjects
|
||||||
|
.map { it.npmProject.dir.relativeTo(nodeJsWorldDir).path }
|
||||||
|
|
||||||
|
rootProject.nodeJs.packageJsonHandlers.forEach {
|
||||||
|
it(rootPackageJson)
|
||||||
|
}
|
||||||
|
|
||||||
|
rootPackageJson.saveTo(
|
||||||
|
nodeJsWorldDir.resolve(NpmProject.PACKAGE_JSON)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+9
-4
@@ -10,16 +10,21 @@ import org.gradle.api.internal.project.ProjectInternal
|
|||||||
import org.gradle.internal.hash.FileHasher
|
import org.gradle.internal.hash.FileHasher
|
||||||
import org.jetbrains.kotlin.daemon.common.toHexString
|
import org.jetbrains.kotlin.daemon.common.toHexString
|
||||||
import org.jetbrains.kotlin.gradle.internal.ensureParentDirsCreated
|
import org.jetbrains.kotlin.gradle.internal.ensureParentDirsCreated
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProject
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject
|
import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.yarn.Yarn.packageJsonHashFile
|
import org.jetbrains.kotlin.gradle.targets.js.yarn.Yarn.packageJsonHashFile
|
||||||
|
import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile
|
||||||
|
|
||||||
|
class YarnAvoidance(val npmProject: NpmProject) {
|
||||||
|
val project: Project
|
||||||
|
get() = npmProject.project
|
||||||
|
|
||||||
class YarnAvoidance(val project: Project) {
|
|
||||||
private val prevHash by lazy {
|
private val prevHash by lazy {
|
||||||
val packageJsonHashFile = project.packageJsonHashFile
|
val packageJsonHashFile = npmProject.packageJsonHashFile
|
||||||
if (packageJsonHashFile.exists()) packageJsonHashFile.readText() else null
|
if (packageJsonHashFile.exists()) packageJsonHashFile.readText() else null
|
||||||
}
|
}
|
||||||
|
|
||||||
private val npmProject = project.npmProject
|
|
||||||
private val packageJsonFile = npmProject.packageJsonFile
|
private val packageJsonFile = npmProject.packageJsonFile
|
||||||
|
|
||||||
private val hash by lazy {
|
private val hash by lazy {
|
||||||
@@ -34,7 +39,7 @@ class YarnAvoidance(val project: Project) {
|
|||||||
|
|
||||||
fun commit() {
|
fun commit() {
|
||||||
if (!upToDate) {
|
if (!upToDate) {
|
||||||
val packageJsonHashFile = project.packageJsonHashFile
|
val packageJsonHashFile = npmProject.packageJsonHashFile
|
||||||
packageJsonHashFile.ensureParentDirsCreated()
|
packageJsonHashFile.ensureParentDirsCreated()
|
||||||
packageJsonHashFile.writeText(hash)
|
packageJsonHashFile.writeText(hash)
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -26,7 +26,7 @@ open class YarnRootExtension(val project: Project) {
|
|||||||
var disableWorkspaces: Boolean = false
|
var disableWorkspaces: Boolean = false
|
||||||
|
|
||||||
val useWorkspaces: Boolean
|
val useWorkspaces: Boolean
|
||||||
get() = !disableWorkspaces && project.nodeJs.root.layout.allowYarnWorkspaces
|
get() = !disableWorkspaces
|
||||||
|
|
||||||
internal fun executeSetup() {
|
internal fun executeSetup() {
|
||||||
NodeJsPlugin.apply(project).root.executeSetup()
|
NodeJsPlugin.apply(project).root.executeSetup()
|
||||||
|
|||||||
Reference in New Issue
Block a user