[Gradle, JS] Remove requireNodeModules
[Gradle, JS] Remove 4 major webpack [Gradle, JS] Remove webpack 4 related dependencies [Gradle, JS] How want to see npm dependency [JS IR] Object factory and remove forceResolve [Gradle, JS] Object factory to package json producer [Gradle, JS] Only npm dependencies as required [Gradle, JS] NodeJsRootPlugin applied once [Gradle, JS] NodeJsRootPlugin applied once #2 [Gradle, JS] Divide task providers from NodeJsRootExtension [Gradle, JS] Remove redundant [Gradle, JS] Fix #1 [Gradle, JS] Fix #2 [Gradle, JS] Fix #3 [Gradle, JS] Fix #4 [Gradle, JS] Fix #5 [Gradle, JS] Fix tests [Gradle, JS] No objectFactory [Gradle, JS] Remove archive compat and fs compat [Gradle, JS] Build service kotlin npm resolution manager [JS] Build servicify Build servicify Build servicify Fix internal Tasks requirements as build service ~ try to move from build service [JS] no nested [JS] Configuration resolver inside input files Revert "[JS] Configuration resolver inside input files" This reverts commit 48536e011a8a341e9cb62fbf8e03a09f2ba115ba. [JS] nested but only configuration [JS] packageJsonHandlers serializable [JS] packageJsonProducer as part of task inputs [JS] packageJsonProducer ~1 ~2 ~3 ~4 ~5 ~6 ~7 ~8 ~9 ~10 Remove comments [Gradle, JS] Remove comments [Gradle, JS] Fix internals and test [Gradle, JS] Input package json files for root package json [Gradle, JS] Kotlin npm install always tracked externally [Gradle, JS] Rename resolution items [Gradle, JS] Build service with new scheme
This commit is contained in:
committed by
Space Team
parent
7fa7118325
commit
b2f416dbbe
+1
-3
@@ -86,7 +86,6 @@ abstract class AbstractJsConfigurationCacheIT(protected val irBackend: Boolean)
|
||||
":packageJson",
|
||||
":publicPackageJson",
|
||||
":rootPackageJson",
|
||||
":kotlinNpmInstall",
|
||||
":compileKotlinJs",
|
||||
":nodeTest",
|
||||
) + if (irBackend) listOf(":compileProductionExecutableKotlinJs") else emptyList()
|
||||
@@ -109,7 +108,6 @@ abstract class AbstractJsConfigurationCacheIT(protected val irBackend: Boolean)
|
||||
":packageJson",
|
||||
":publicPackageJson",
|
||||
":rootPackageJson",
|
||||
":kotlinNpmInstall",
|
||||
":compileKotlinJs",
|
||||
":nodeTest",
|
||||
) + if (irBackend) listOf(":compileProductionExecutableKotlinJs") else emptyList()
|
||||
@@ -125,7 +123,7 @@ abstract class AbstractJsConfigurationCacheIT(protected val irBackend: Boolean)
|
||||
assertSimpleConfigurationCacheScenarioWorks(
|
||||
"assemble", "kotlinStoreYarnLock",
|
||||
buildOptions = defaultBuildOptions,
|
||||
executedTaskNames = listOf(":kotlinNpmInstall")
|
||||
executedTaskNames = listOf(":rootPackageJson")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -1575,6 +1575,7 @@ abstract class AbstractKotlin2JsGradlePluginIT(protected val irBackend: Boolean)
|
||||
project("kotlin-js-browser-project", gradleVersion) {
|
||||
buildGradleKts.modify { originalScript ->
|
||||
buildString {
|
||||
append("import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin.Companion.kotlinNpmResolutionManager")
|
||||
append(originalScript)
|
||||
append(
|
||||
"""
|
||||
@@ -1583,7 +1584,7 @@ abstract class AbstractKotlin2JsGradlePluginIT(protected val irBackend: Boolean)
|
||||
| val nodejs = the<org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension>()
|
||||
| tasks.named<org.jetbrains.kotlin.gradle.targets.js.npm.tasks.KotlinNpmInstallTask>("kotlinNpmInstall") {
|
||||
| doFirst {
|
||||
| nodejs.npmResolutionManager.state =
|
||||
| project.rootProject.kotlinNpmResolutionManager.get().state =
|
||||
| org.jetbrains.kotlin.gradle.targets.js.npm.KotlinNpmResolutionManager.ResolutionState.Error(GradleException("someSpecialException"))
|
||||
| }
|
||||
| }
|
||||
|
||||
-5
@@ -7,14 +7,9 @@ package org.jetbrains.kotlin.generators.gradle.targets.js
|
||||
|
||||
val npmPackages = listOf(
|
||||
NpmPackage("webpack"),
|
||||
NpmPackage("webpack", "4.46.0", "webpack4"),
|
||||
NpmPackage("webpack-cli"),
|
||||
NpmPackage("webpack-cli", "3.3.12", "webpackCli3"),
|
||||
NpmPackage("webpack-bundle-analyzer"),
|
||||
NpmPackage("webpack-dev-server"),
|
||||
NpmPackage("webpack-dev-server", "3.11.2", "webpackDevServer3"),
|
||||
NpmPackage("source-map-loader"),
|
||||
NpmPackage("source-map-loader", "1.1.0", "sourceMapLoader1"),
|
||||
NpmPackage("source-map-support"),
|
||||
NpmPackage("css-loader"),
|
||||
NpmPackage("style-loader"),
|
||||
|
||||
+1
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle.internal
|
||||
|
||||
import java.io.Serializable
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
abstract class ConfigurationPhaseAware<C : Any> {
|
||||
|
||||
-13
@@ -456,19 +456,6 @@ internal class PropertiesProvider private constructor(private val project: Proje
|
||||
val publishJsCompilerAttribute: Boolean
|
||||
get() = this.booleanProperty("$jsCompilerProperty.publish.attribute") ?: true
|
||||
|
||||
/**
|
||||
* Use Webpack 4 for compatibility
|
||||
*/
|
||||
val webpackMajorVersion: WebpackMajorVersion
|
||||
get() = this.property(WebpackMajorVersion.webpackMajorVersion)?.let { WebpackMajorVersion.byArgument(it) }
|
||||
?.also { version ->
|
||||
if (!WebpackMajorVersion.webpackVersionWarning && version != WebpackMajorVersion.DEFAULT) {
|
||||
WebpackMajorVersion.webpackVersionWarning = true
|
||||
project.logger.warn(WebpackMajorVersion.warningMessage)
|
||||
}
|
||||
}
|
||||
?: WebpackMajorVersion.DEFAULT
|
||||
|
||||
/**
|
||||
* Use Kotlin/JS backend compiler type
|
||||
*/
|
||||
|
||||
+5
-5
@@ -106,7 +106,7 @@ class DefaultKotlinDependencyHandler(
|
||||
version: String,
|
||||
): NpmDependency =
|
||||
NpmDependency(
|
||||
project = project,
|
||||
objectFactory = project.objects,
|
||||
name = name,
|
||||
version = version,
|
||||
)
|
||||
@@ -134,7 +134,7 @@ class DefaultKotlinDependencyHandler(
|
||||
version: String
|
||||
): NpmDependency =
|
||||
NpmDependency(
|
||||
project = project,
|
||||
objectFactory = project.objects,
|
||||
name = name,
|
||||
version = version,
|
||||
scope = NpmDependency.Scope.DEV
|
||||
@@ -161,7 +161,7 @@ class DefaultKotlinDependencyHandler(
|
||||
version: String,
|
||||
): NpmDependency =
|
||||
NpmDependency(
|
||||
project = project,
|
||||
objectFactory = project.objects,
|
||||
name = name,
|
||||
version = version,
|
||||
scope = NpmDependency.Scope.OPTIONAL,
|
||||
@@ -190,7 +190,7 @@ class DefaultKotlinDependencyHandler(
|
||||
version: String
|
||||
): NpmDependency =
|
||||
NpmDependency(
|
||||
project = project,
|
||||
objectFactory = project.objects,
|
||||
name = name,
|
||||
version = version,
|
||||
scope = NpmDependency.Scope.PEER
|
||||
@@ -202,7 +202,7 @@ class DefaultKotlinDependencyHandler(
|
||||
scope: NpmDependency.Scope,
|
||||
): NpmDependency =
|
||||
directoryNpmDependency(
|
||||
project = project,
|
||||
objectFactory = project.objects,
|
||||
name = name,
|
||||
directory = directory,
|
||||
scope = scope,
|
||||
|
||||
+3
-3
@@ -7,9 +7,9 @@ package org.jetbrains.kotlin.gradle.targets.js
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.Dependency
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmDependency
|
||||
import java.io.Serializable
|
||||
|
||||
data class KotlinGradleNpmPackage(val simpleModuleName: String) : RequiredKotlinJsDependency {
|
||||
override fun createDependency(project: Project, scope: NpmDependency.Scope): Dependency =
|
||||
data class KotlinGradleNpmPackage(val simpleModuleName: String) : Serializable {
|
||||
fun createDependency(project: Project): Dependency =
|
||||
project.dependencies.create("org.jetbrains.kotlin:kotlin-$simpleModuleName")
|
||||
}
|
||||
+12
-1
@@ -16,9 +16,14 @@ import org.jetbrains.kotlin.gradle.plugin.AbstractKotlinTargetConfigurator.Compa
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.MAIN_COMPILATION_NAME
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinJsCompilerType.LEGACY
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.*
|
||||
import org.jetbrains.kotlin.gradle.targets.js.dsl.*
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.PRIMARY_SINGLE_COMPONENT_NAME
|
||||
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsBrowserDsl
|
||||
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsNodeDsl
|
||||
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsSubTargetContainerDsl
|
||||
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsTargetDsl
|
||||
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsBinaryContainer
|
||||
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTarget
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmResolverPlugin
|
||||
import org.jetbrains.kotlin.gradle.targets.js.subtargets.KotlinBrowserJs
|
||||
import org.jetbrains.kotlin.gradle.targets.js.subtargets.KotlinNodeJs
|
||||
import org.jetbrains.kotlin.gradle.tasks.locateOrRegisterTask
|
||||
@@ -147,8 +152,13 @@ constructor(
|
||||
|
||||
private val propertiesProvider = PropertiesProvider(project)
|
||||
|
||||
private val commonLazy by lazy {
|
||||
NpmResolverPlugin.apply(project)
|
||||
}
|
||||
|
||||
//Browser
|
||||
private val browserLazyDelegate = lazy {
|
||||
commonLazy
|
||||
project.objects.newInstance(KotlinBrowserJs::class.java, this).also {
|
||||
it.configure()
|
||||
|
||||
@@ -177,6 +187,7 @@ constructor(
|
||||
|
||||
//node.js
|
||||
private val nodejsLazyDelegate = lazy {
|
||||
commonLazy
|
||||
project.objects.newInstance(KotlinNodeJs::class.java, this).also {
|
||||
it.configure()
|
||||
|
||||
|
||||
+3
-3
@@ -5,11 +5,11 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle.targets.js
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.Dependency
|
||||
import org.gradle.api.model.ObjectFactory
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmDependency
|
||||
|
||||
data class NpmPackageVersion(val name: String, var version: String) : RequiredKotlinJsDependency {
|
||||
override fun createDependency(project: Project, scope: NpmDependency.Scope): Dependency =
|
||||
NpmDependency(project, name, version, scope)
|
||||
override fun createDependency(objectFactory: ObjectFactory, scope: NpmDependency.Scope): Dependency =
|
||||
NpmDependency(objectFactory, scope, name, version)
|
||||
}
|
||||
+5
-10
@@ -12,24 +12,19 @@ import java.io.Serializable
|
||||
*/
|
||||
// DO NOT MODIFY DIRECTLY! Use org.jetbrains.kotlin.generators.gradle.targets.js.MainKt
|
||||
class NpmVersions : Serializable {
|
||||
val webpack4 = NpmPackageVersion("webpack", "4.46.0")
|
||||
val webpackCli3 = NpmPackageVersion("webpack-cli", "3.3.12")
|
||||
val webpackDevServer3 = NpmPackageVersion("webpack-dev-server", "3.11.2")
|
||||
val sourceMapLoader1 = NpmPackageVersion("source-map-loader", "1.1.0")
|
||||
val webpack = NpmPackageVersion("webpack", "5.74.0")
|
||||
val webpackCli = NpmPackageVersion("webpack-cli", "4.10.0")
|
||||
val webpackBundleAnalyzer = NpmPackageVersion("webpack-bundle-analyzer", "4.5.0")
|
||||
val webpackDevServer = NpmPackageVersion("webpack-dev-server", "4.9.3")
|
||||
val webpackDevServer = NpmPackageVersion("webpack-dev-server", "4.11.1")
|
||||
val sourceMapLoader = NpmPackageVersion("source-map-loader", "4.0.0")
|
||||
val sourceMapSupport = NpmPackageVersion("source-map-support", "0.5.21")
|
||||
val cssLoader = NpmPackageVersion("css-loader", "6.7.1")
|
||||
val styleLoader = NpmPackageVersion("style-loader", "3.3.1")
|
||||
val sassLoader = NpmPackageVersion("sass-loader", "13.0.2")
|
||||
val sass = NpmPackageVersion("sass", "1.54.3")
|
||||
val sassLoader = NpmPackageVersion("sass-loader", "13.1.0")
|
||||
val sass = NpmPackageVersion("sass", "1.55.0")
|
||||
val toStringLoader = NpmPackageVersion("to-string-loader", "1.2.0")
|
||||
val miniCssExtractPlugin = NpmPackageVersion("mini-css-extract-plugin", "2.6.1")
|
||||
val mocha = NpmPackageVersion("mocha", "10.0.0")
|
||||
val karma = NpmPackageVersion("karma", "6.4.0")
|
||||
val karma = NpmPackageVersion("karma", "6.4.1")
|
||||
val karmaChromeLauncher = NpmPackageVersion("karma-chrome-launcher", "3.1.1")
|
||||
val karmaPhantomjsLauncher = NpmPackageVersion("karma-phantomjs-launcher", "1.0.4")
|
||||
val karmaFirefoxLauncher = NpmPackageVersion("karma-firefox-launcher", "2.1.2")
|
||||
@@ -41,7 +36,7 @@ class NpmVersions : Serializable {
|
||||
val karmaCoverage = NpmPackageVersion("karma-coverage", "2.2.0")
|
||||
val karmaSourcemapLoader = NpmPackageVersion("karma-sourcemap-loader", "0.3.8")
|
||||
val formatUtil = NpmPackageVersion("format-util", "1.0.5")
|
||||
val typescript = NpmPackageVersion("typescript", "4.7.4")
|
||||
val typescript = NpmPackageVersion("typescript", "4.8.4")
|
||||
|
||||
val kotlinJsTestRunner = KotlinGradleNpmPackage("test-js-runner")
|
||||
}
|
||||
+2
-1
@@ -7,9 +7,10 @@ package org.jetbrains.kotlin.gradle.targets.js
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.Dependency
|
||||
import org.gradle.api.model.ObjectFactory
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmDependency
|
||||
import java.io.Serializable
|
||||
|
||||
interface RequiredKotlinJsDependency : Serializable {
|
||||
fun createDependency(project: Project, scope: NpmDependency.Scope = NpmDependency.Scope.DEV): Dependency
|
||||
fun createDependency(objectFactory: ObjectFactory, scope: NpmDependency.Scope = NpmDependency.Scope.DEV): Dependency
|
||||
}
|
||||
+15
-38
@@ -13,7 +13,6 @@ import org.gradle.api.tasks.Copy
|
||||
import org.gradle.language.base.plugins.LifecycleBasePlugin
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinJsDce
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
|
||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.archivesName
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.distsDirectory
|
||||
@@ -23,14 +22,13 @@ import org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalDceDsl
|
||||
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsBinaryMode
|
||||
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsBrowserDsl
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin.Companion.kotlinNodeJsExtension
|
||||
import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest
|
||||
import org.jetbrains.kotlin.gradle.targets.js.testing.karma.KotlinKarma
|
||||
import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpack
|
||||
import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig
|
||||
import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig.Mode
|
||||
import org.jetbrains.kotlin.gradle.targets.js.webpack.WebpackDevtool
|
||||
import org.jetbrains.kotlin.gradle.targets.js.webpack.WebpackMajorVersion.Companion.choose
|
||||
import org.jetbrains.kotlin.gradle.tasks.dependsOn
|
||||
import org.jetbrains.kotlin.gradle.utils.doNotTrackStateCompat
|
||||
import org.jetbrains.kotlin.gradle.utils.newFileProperty
|
||||
@@ -42,15 +40,11 @@ abstract class KotlinBrowserJsIr @Inject constructor(target: KotlinJsIrTarget) :
|
||||
KotlinJsIrSubTarget(target, "browser"),
|
||||
KotlinJsBrowserDsl {
|
||||
|
||||
private val nodeJs = NodeJsRootPlugin.apply(project.rootProject)
|
||||
private val nodeJs = project.rootProject.kotlinNodeJsExtension
|
||||
|
||||
private val webpackTaskConfigurations: MutableList<Action<KotlinWebpack>> = mutableListOf()
|
||||
private val runTaskConfigurations: MutableList<Action<KotlinWebpack>> = mutableListOf()
|
||||
|
||||
private val propertiesProvider = PropertiesProvider(project)
|
||||
private val webpackMajorVersion
|
||||
get() = propertiesProvider.webpackMajorVersion
|
||||
|
||||
override val testTaskDescription: String
|
||||
get() = "Run all ${target.name} tests inside browser using karma and webpack"
|
||||
|
||||
@@ -110,9 +104,6 @@ abstract class KotlinBrowserJsIr @Inject constructor(target: KotlinJsIrTarget) :
|
||||
override fun configureRun(
|
||||
compilation: KotlinJsIrCompilation
|
||||
) {
|
||||
val project = compilation.target.project
|
||||
val nodeJs = NodeJsRootPlugin.apply(project.rootProject)
|
||||
|
||||
val commonRunTask = registerSubTargetTask<Task>(disambiguateCamelCased(RUN_TASK_NAME)) {}
|
||||
|
||||
compilation.binaries
|
||||
@@ -134,10 +125,7 @@ abstract class KotlinBrowserJsIr @Inject constructor(target: KotlinJsIrTarget) :
|
||||
task.dependsOn(binary.linkSyncTask)
|
||||
task.outputDirectory.convention(distsDirectory).finalizeValueOnRead()
|
||||
|
||||
webpackMajorVersion.choose(
|
||||
{ task.args.add(0, "serve") },
|
||||
{ task.bin = "webpack-dev-server/bin/webpack-dev-server.js" }
|
||||
)()
|
||||
task.args.add(0, "serve")
|
||||
task.description = "start ${mode.name.toLowerCaseAsciiOnly()} webpack dev server"
|
||||
|
||||
val openValue = if (compilation.platformType == KotlinPlatformType.wasm) {
|
||||
@@ -156,29 +144,19 @@ abstract class KotlinBrowserJsIr @Inject constructor(target: KotlinJsIrTarget) :
|
||||
true
|
||||
}
|
||||
|
||||
webpackMajorVersion.choose(
|
||||
{
|
||||
task.devServer = KotlinWebpackConfig.DevServer(
|
||||
open = openValue,
|
||||
static = mutableListOf(
|
||||
"./kotlin",
|
||||
compilation.output.resourcesDir.canonicalPath,
|
||||
),
|
||||
client = KotlinWebpackConfig.DevServer.Client(
|
||||
KotlinWebpackConfig.DevServer.Client.Overlay(
|
||||
errors = true,
|
||||
warnings = false
|
||||
)
|
||||
)
|
||||
task.devServer = KotlinWebpackConfig.DevServer(
|
||||
open = openValue,
|
||||
static = mutableListOf(
|
||||
"./kotlin",
|
||||
compilation.output.resourcesDir.canonicalPath
|
||||
),
|
||||
client = KotlinWebpackConfig.DevServer.Client(
|
||||
KotlinWebpackConfig.DevServer.Client.Overlay(
|
||||
errors = true,
|
||||
warnings = false
|
||||
)
|
||||
},
|
||||
{
|
||||
task.devServer = KotlinWebpackConfig.DevServer(
|
||||
open = true,
|
||||
contentBase = mutableListOf(compilation.output.resourcesDir.canonicalPath)
|
||||
)
|
||||
}
|
||||
)()
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
task.doNotTrackStateCompat("Tracked by external webpack tool")
|
||||
@@ -205,7 +183,6 @@ abstract class KotlinBrowserJsIr @Inject constructor(target: KotlinJsIrTarget) :
|
||||
compilation: KotlinJsIrCompilation
|
||||
) {
|
||||
val project = compilation.target.project
|
||||
val nodeJs = NodeJsRootPlugin.apply(project.rootProject)
|
||||
|
||||
val processResourcesTask = target.project.tasks.named(compilation.processResourcesTaskName)
|
||||
|
||||
|
||||
+3
-4
@@ -12,7 +12,9 @@ import org.gradle.api.plugins.ExtensionAware
|
||||
import org.gradle.api.tasks.Copy
|
||||
import org.gradle.api.tasks.TaskProvider
|
||||
import org.gradle.language.base.plugins.LifecycleBasePlugin
|
||||
import org.jetbrains.kotlin.gradle.plugin.*
|
||||
import org.jetbrains.kotlin.gradle.plugin.AbstractKotlinTargetConfigurator
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetWithTests
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.isMain
|
||||
import org.jetbrains.kotlin.gradle.plugin.whenEvaluated
|
||||
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsPlatformTestRun
|
||||
@@ -20,7 +22,6 @@ import org.jetbrains.kotlin.gradle.targets.js.dsl.Distribution
|
||||
import org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalDistributionDsl
|
||||
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsBinaryMode
|
||||
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsSubTargetDsl
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmResolverPlugin
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject
|
||||
import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest
|
||||
import org.jetbrains.kotlin.gradle.tasks.dependsOn
|
||||
@@ -52,8 +53,6 @@ abstract class KotlinJsIrSubTarget(
|
||||
}
|
||||
|
||||
internal fun configure() {
|
||||
NpmResolverPlugin.apply(project)
|
||||
|
||||
target.compilations.all {
|
||||
val npmProject = it.npmProject
|
||||
it.kotlinOptions {
|
||||
|
||||
+2
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.gradle.targets.js.KotlinJsReportAggregatingTestRun
|
||||
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsTarget
|
||||
import org.jetbrains.kotlin.gradle.targets.js.binaryen.BinaryenExec
|
||||
import org.jetbrains.kotlin.gradle.targets.js.dsl.*
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmResolverPlugin
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject
|
||||
import org.jetbrains.kotlin.gradle.targets.js.typescript.TypeScriptValidationTask
|
||||
import org.jetbrains.kotlin.gradle.tasks.locateOrRegisterTask
|
||||
@@ -110,6 +111,7 @@ constructor(
|
||||
}
|
||||
|
||||
private val commonLazy by lazy {
|
||||
NpmResolverPlugin.apply(project)
|
||||
compilations.all { compilation ->
|
||||
compilation.binaries
|
||||
.withType(JsIrBinary::class.java)
|
||||
|
||||
+6
-5
@@ -9,7 +9,7 @@ import org.gradle.api.Action
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
|
||||
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsNodeDsl
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsExec
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin.Companion.kotlinNodeJsExtension
|
||||
import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest
|
||||
import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinWasmNode
|
||||
import org.jetbrains.kotlin.gradle.tasks.dependsOn
|
||||
@@ -21,7 +21,8 @@ abstract class KotlinNodeJsIr @Inject constructor(target: KotlinJsIrTarget) :
|
||||
KotlinJsIrSubTargetBase(target, "node"),
|
||||
KotlinJsNodeDsl {
|
||||
|
||||
private val nodeJs = NodeJsRootPlugin.apply(project.rootProject)
|
||||
private val nodeJs = project.rootProject.kotlinNodeJsExtension
|
||||
private val nodeJsTaskProviders = project.rootProject.kotlinNodeJsExtension
|
||||
|
||||
override val testTaskDescription: String
|
||||
get() = "Run all ${target.name} tests inside nodejs using the builtin test framework"
|
||||
@@ -51,9 +52,9 @@ abstract class KotlinNodeJsIr @Inject constructor(target: KotlinJsIrTarget) :
|
||||
|
||||
override fun configureTestDependencies(test: KotlinJsTest) {
|
||||
test.dependsOn(
|
||||
nodeJs.npmInstallTaskProvider,
|
||||
nodeJs.storeYarnLockTaskProvider,
|
||||
nodeJs.nodeJsSetupTaskProvider
|
||||
nodeJsTaskProviders.npmInstallTaskProvider,
|
||||
nodeJsTaskProviders.storeYarnLockTaskProvider,
|
||||
nodeJsTaskProviders.nodeJsSetupTaskProvider
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+5
-1
@@ -1,10 +1,12 @@
|
||||
package org.jetbrains.kotlin.gradle.targets.js.nodejs
|
||||
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmApi
|
||||
import org.jetbrains.kotlin.gradle.tasks.internal.CleanableStore
|
||||
import java.io.File
|
||||
|
||||
data class NodeJsEnv(
|
||||
val cleanableStore: CleanableStore,
|
||||
val rootPackageDir: File,
|
||||
val nodeDir: File,
|
||||
val nodeBinDir: File,
|
||||
val nodeExecutable: String,
|
||||
@@ -12,7 +14,9 @@ data class NodeJsEnv(
|
||||
val platformName: String,
|
||||
val architectureName: String,
|
||||
val ivyDependency: String,
|
||||
val downloadBaseUrl: String
|
||||
val downloadBaseUrl: String,
|
||||
|
||||
val packageManager: NpmApi,
|
||||
) {
|
||||
val isWindows: Boolean
|
||||
get() = platformName == "win"
|
||||
|
||||
+6
-7
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
|
||||
import org.jetbrains.kotlin.gradle.targets.js.RequiredKotlinJsDependency
|
||||
import org.jetbrains.kotlin.gradle.targets.js.addWasmExperimentalArguments
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin.Companion.kotlinNodeJsExtension
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.RequiresNpmDependencies
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject
|
||||
import org.jetbrains.kotlin.gradle.tasks.registerTask
|
||||
@@ -48,10 +49,6 @@ constructor(
|
||||
@NormalizeLineEndings
|
||||
val inputFileProperty: RegularFileProperty = project.newFileProperty()
|
||||
|
||||
@get:Internal
|
||||
override val nodeModulesRequired: Boolean
|
||||
get() = true
|
||||
|
||||
@get:Internal
|
||||
override val requiredNpmDependencies: Set<RequiredKotlinJsDependency> by lazy {
|
||||
mutableSetOf<RequiredKotlinJsDependency>().also {
|
||||
@@ -92,7 +89,9 @@ constructor(
|
||||
): TaskProvider<NodeJsExec> {
|
||||
val target = compilation.target
|
||||
val project = target.project
|
||||
val nodeJs = NodeJsRootPlugin.apply(project.rootProject)
|
||||
NodeJsRootPlugin.apply(project.rootProject)
|
||||
val nodeJs = project.rootProject.kotlinNodeJsExtension
|
||||
val nodeJsTaskProviders = project.rootProject.kotlinNodeJsExtension
|
||||
val npmProject = compilation.npmProject
|
||||
|
||||
return project.registerTask(
|
||||
@@ -103,8 +102,8 @@ constructor(
|
||||
it.executable = nodeJs.requireConfigured().nodeExecutable
|
||||
it.workingDir = npmProject.dir
|
||||
it.dependsOn(
|
||||
nodeJs.npmInstallTaskProvider,
|
||||
nodeJs.storeYarnLockTaskProvider,
|
||||
nodeJsTaskProviders.npmInstallTaskProvider,
|
||||
nodeJsTaskProviders.storeYarnLockTaskProvider,
|
||||
)
|
||||
it.dependsOn(compilation.compileKotlinTaskProvider)
|
||||
if (compilation.platformType == KotlinPlatformType.wasm) {
|
||||
|
||||
+49
-82
@@ -12,29 +12,45 @@ import org.jetbrains.kotlin.gradle.internal.ConfigurationPhaseAware
|
||||
import org.jetbrains.kotlin.gradle.logging.kotlinInfo
|
||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
|
||||
import org.jetbrains.kotlin.gradle.targets.js.NpmVersions
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.KotlinNpmResolutionManager
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmApi
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.resolver.KotlinRootNpmResolver
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.resolver.PACKAGE_JSON_UMBRELLA_TASK_NAME
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.KotlinNpmCachesSetup
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.KotlinNpmInstallTask
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.RootPackageJsonTask
|
||||
import org.jetbrains.kotlin.gradle.targets.js.yarn.Yarn
|
||||
import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnLockCopyTask
|
||||
import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnLockCopyTask.Companion.RESTORE_YARN_LOCK_NAME
|
||||
import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnLockCopyTask.Companion.STORE_YARN_LOCK_NAME
|
||||
import org.jetbrains.kotlin.gradle.tasks.internal.CleanableStore
|
||||
import java.io.File
|
||||
import java.io.Serializable
|
||||
|
||||
open class NodeJsRootExtension(@Transient val rootProject: Project) : ConfigurationPhaseAware<NodeJsEnv>(), Serializable {
|
||||
open class NodeJsRootExtension(
|
||||
val project: Project
|
||||
) : ConfigurationPhaseAware<NodeJsEnv>() {
|
||||
|
||||
init {
|
||||
check(rootProject.rootProject == rootProject)
|
||||
check(project.rootProject == project)
|
||||
|
||||
val projectProperties = PropertiesProvider(project)
|
||||
|
||||
if (projectProperties.errorJsGenerateExternals != null) {
|
||||
project.logger.warn(
|
||||
"""
|
||||
|
|
||||
|==========
|
||||
|Please note, Dukat integration in Gradle plugin does not work now, it was removed.
|
||||
|We rethink how we can integrate properly.
|
||||
|==========
|
||||
|
|
||||
""".trimMargin()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private val logger = rootProject.logger
|
||||
val rootProjectDir
|
||||
get() = project.projectDir
|
||||
|
||||
private val gradleHome = rootProject.gradle.gradleUserHomeDir.also {
|
||||
logger.kotlinInfo("Storing cached files in $it")
|
||||
private val gradleHome = project.gradle.gradleUserHomeDir.also {
|
||||
project.logger.kotlinInfo("Storing cached files in $it")
|
||||
}
|
||||
|
||||
var installationDir by Property(gradleHome.resolve("nodejs"))
|
||||
@@ -52,70 +68,12 @@ open class NodeJsRootExtension(@Transient val rootProject: Project) : Configurat
|
||||
|
||||
var packageManager: NpmApi by Property(Yarn())
|
||||
|
||||
@Transient
|
||||
private val projectProperties = PropertiesProvider(rootProject)
|
||||
val taskRequirements: TasksRequirements
|
||||
get() = resolver.tasksRequirements
|
||||
|
||||
private val errorGenerateExternals = run {
|
||||
if (projectProperties.errorJsGenerateExternals != null) {
|
||||
logger.warn(
|
||||
"""
|
||||
|
|
||||
|==========
|
||||
|Please note, Dukat integration in Gradle plugin does not work now, it was removed.
|
||||
|We rethink how we can integrate properly.
|
||||
|==========
|
||||
|
|
||||
""".trimMargin()
|
||||
)
|
||||
}
|
||||
}
|
||||
lateinit var resolver: KotlinRootNpmResolver
|
||||
|
||||
val taskRequirements: TasksRequirements = TasksRequirements()
|
||||
|
||||
val nodeJsSetupTaskProvider: TaskProvider<out NodeJsSetupTask>
|
||||
get() = rootProject.tasks.withType(NodeJsSetupTask::class.java).named(NodeJsSetupTask.NAME)
|
||||
|
||||
@Suppress(
|
||||
"UNNECESSARY_SAFE_CALL",
|
||||
"SAFE_CALL_WILL_CHANGE_NULLABILITY"
|
||||
) // TODO: investigate this warning; fixing it breaks integration tests.
|
||||
val npmInstallTaskProvider: TaskProvider<out KotlinNpmInstallTask>?
|
||||
get() = rootProject?.tasks?.withType(KotlinNpmInstallTask::class.java)?.named(KotlinNpmInstallTask.NAME)
|
||||
|
||||
val packageJsonUmbrellaTaskProvider: TaskProvider<Task>
|
||||
get() = rootProject.tasks.named(PACKAGE_JSON_UMBRELLA_TASK_NAME)
|
||||
|
||||
@Suppress(
|
||||
"UNNECESSARY_SAFE_CALL",
|
||||
"SAFE_CALL_WILL_CHANGE_NULLABILITY"
|
||||
) // TODO: investigate this warning; fixing it breaks integration tests.
|
||||
val rootPackageJsonTaskProvider: TaskProvider<RootPackageJsonTask>?
|
||||
get() = rootProject?.tasks?.withType(RootPackageJsonTask::class.java)?.named(RootPackageJsonTask.NAME)
|
||||
|
||||
@Suppress(
|
||||
"UNNECESSARY_SAFE_CALL",
|
||||
"SAFE_CALL_WILL_CHANGE_NULLABILITY"
|
||||
) // TODO: investigate this warning; fixing it breaks integration tests.
|
||||
val npmCachesSetupTaskProvider: TaskProvider<out KotlinNpmCachesSetup>?
|
||||
get() = rootProject?.tasks?.withType(KotlinNpmCachesSetup::class.java)?.named(KotlinNpmCachesSetup.NAME)
|
||||
|
||||
@Suppress(
|
||||
"UNNECESSARY_SAFE_CALL",
|
||||
"SAFE_CALL_WILL_CHANGE_NULLABILITY"
|
||||
) // TODO: investigate this warning; fixing it breaks integration tests.
|
||||
val storeYarnLockTaskProvider: TaskProvider<out YarnLockCopyTask>?
|
||||
get() = rootProject?.tasks?.withType(YarnLockCopyTask::class.java)?.named(STORE_YARN_LOCK_NAME)
|
||||
|
||||
@Suppress(
|
||||
"UNNECESSARY_SAFE_CALL",
|
||||
"SAFE_CALL_WILL_CHANGE_NULLABILITY"
|
||||
) // TODO: investigate this warning; fixing it breaks integration tests.
|
||||
val restoreYarnLockTaskProvider: TaskProvider<out YarnLockCopyTask>?
|
||||
get() = rootProject?.tasks?.withType(YarnLockCopyTask::class.java)?.named(RESTORE_YARN_LOCK_NAME)
|
||||
|
||||
val rootPackageDir: File by lazy {
|
||||
rootProject.buildDir.resolve("js")
|
||||
}
|
||||
val rootPackageDir: File = project.buildDir.resolve("js")
|
||||
|
||||
val projectPackagesDir: File
|
||||
get() = rootPackageDir.resolve("packages")
|
||||
@@ -123,6 +81,8 @@ open class NodeJsRootExtension(@Transient val rootProject: Project) : Configurat
|
||||
val nodeModulesGradleCacheDir: File
|
||||
get() = rootPackageDir.resolve("packages_imported")
|
||||
|
||||
val versions = NpmVersions()
|
||||
|
||||
override fun finalizeConfiguration(): NodeJsEnv {
|
||||
val platformHelper = PlatformHelper
|
||||
val platform = platformHelper.osName
|
||||
@@ -146,28 +106,35 @@ open class NodeJsRootExtension(@Transient val rootProject: Project) : Configurat
|
||||
|
||||
return NodeJsEnv(
|
||||
cleanableStore = cleanableStore,
|
||||
rootPackageDir = rootPackageDir,
|
||||
nodeDir = nodeDir,
|
||||
nodeBinDir = nodeBinDir,
|
||||
nodeExecutable = getExecutable("node", nodeCommand, "exe"),
|
||||
platformName = platform,
|
||||
architectureName = architecture,
|
||||
ivyDependency = getIvyDependency(),
|
||||
downloadBaseUrl = nodeDownloadBaseUrl
|
||||
downloadBaseUrl = nodeDownloadBaseUrl,
|
||||
packageManager = packageManager
|
||||
)
|
||||
}
|
||||
|
||||
internal fun executeSetup() {
|
||||
if (download) {
|
||||
val nodeJsSetupTask = nodeJsSetupTaskProvider.get()
|
||||
nodeJsSetupTask.actions.forEach {
|
||||
it.execute(nodeJsSetupTask)
|
||||
}
|
||||
}
|
||||
}
|
||||
val nodeJsSetupTaskProvider: TaskProvider<out NodeJsSetupTask>
|
||||
get() = project.tasks.withType(NodeJsSetupTask::class.java).named(NodeJsSetupTask.NAME)
|
||||
|
||||
val versions = NpmVersions()
|
||||
val npmInstallTaskProvider: TaskProvider<out KotlinNpmInstallTask>
|
||||
get() = project.tasks.withType(KotlinNpmInstallTask::class.java).named(KotlinNpmInstallTask.NAME)
|
||||
|
||||
val npmResolutionManager = KotlinNpmResolutionManager(this)
|
||||
val rootPackageJsonTaskProvider: TaskProvider<RootPackageJsonTask>
|
||||
get() = project.tasks.withType(RootPackageJsonTask::class.java).named(RootPackageJsonTask.NAME)
|
||||
|
||||
val packageJsonUmbrellaTaskProvider: TaskProvider<Task>
|
||||
get() = project.tasks.named(PACKAGE_JSON_UMBRELLA_TASK_NAME)
|
||||
|
||||
val npmCachesSetupTaskProvider: TaskProvider<out KotlinNpmCachesSetup>
|
||||
get() = project.tasks.withType(KotlinNpmCachesSetup::class.java).named(KotlinNpmCachesSetup.NAME)
|
||||
|
||||
val storeYarnLockTaskProvider: TaskProvider<out YarnLockCopyTask>
|
||||
get() = project.tasks.withType(YarnLockCopyTask::class.java).named(YarnLockCopyTask.STORE_YARN_LOCK_NAME)
|
||||
|
||||
companion object {
|
||||
const val EXTENSION_NAME: String = "kotlinNodeJs"
|
||||
|
||||
+105
-14
@@ -9,18 +9,25 @@ import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.plugins.BasePlugin
|
||||
import org.jetbrains.kotlin.gradle.utils.markResolvable
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.jetbrains.kotlin.gradle.targets.js.MultiplePluginDeclarationDetector
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension.Companion.EXTENSION_NAME
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.CompositeNodeModulesCache
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.GradleNodeModulesCache
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.KotlinNpmResolutionManager
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.resolver.KotlinRootNpmResolver
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.resolver.PACKAGE_JSON_UMBRELLA_TASK_NAME
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.KotlinNpmInstallTask
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.KotlinNpmCachesSetup
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.KotlinNpmInstallTask
|
||||
import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnPlugin
|
||||
import org.jetbrains.kotlin.gradle.tasks.CleanDataTask
|
||||
import org.jetbrains.kotlin.gradle.tasks.registerTask
|
||||
import org.jetbrains.kotlin.gradle.utils.castIsolatedKotlinPluginClassLoaderAware
|
||||
import org.jetbrains.kotlin.gradle.utils.doNotTrackStateCompat
|
||||
import org.jetbrains.kotlin.gradle.utils.markResolvable
|
||||
import org.jetbrains.kotlin.gradle.utils.providerWithLazyConvention
|
||||
|
||||
open class NodeJsRootPlugin : Plugin<Project> {
|
||||
override fun apply(project: Project): Unit = project.run {
|
||||
override fun apply(project: Project) {
|
||||
MultiplePluginDeclarationDetector.detect(project)
|
||||
|
||||
project.plugins.apply(BasePlugin::class.java)
|
||||
@@ -29,35 +36,93 @@ open class NodeJsRootPlugin : Plugin<Project> {
|
||||
"NodeJsRootPlugin can be applied only to root project"
|
||||
}
|
||||
|
||||
val settings = this.extensions.create(EXTENSION_NAME, NodeJsRootExtension::class.java, this)
|
||||
val nodeJs = project.extensions.create(
|
||||
NodeJsRootExtension.EXTENSION_NAME,
|
||||
NodeJsRootExtension::class.java,
|
||||
project
|
||||
)
|
||||
|
||||
val setupTask = registerTask<NodeJsSetupTask>(NodeJsSetupTask.NAME) {
|
||||
val setupTask = project.registerTask<NodeJsSetupTask>(NodeJsSetupTask.NAME) {
|
||||
it.group = TASKS_GROUP_NAME
|
||||
it.description = "Download and install a local node/npm version"
|
||||
it.configuration = provider {
|
||||
this.project.configurations.detachedConfiguration(this.project.dependencies.create(it.ivyDependency))
|
||||
it.configuration = project.provider {
|
||||
project.configurations.detachedConfiguration(project.dependencies.create(it.ivyDependency))
|
||||
.markResolvable()
|
||||
.also { conf -> conf.isTransitive = false }
|
||||
}
|
||||
}
|
||||
|
||||
val setupFileHasherTask = registerTask<KotlinNpmCachesSetup>(KotlinNpmCachesSetup.NAME) {
|
||||
val gradleNodeModulesProvider: Provider<GradleNodeModulesCache> = GradleNodeModulesCache.registerIfAbsent(
|
||||
project,
|
||||
project.projectDir,
|
||||
nodeJs.nodeModulesGradleCacheDir
|
||||
)
|
||||
|
||||
val compositeNodeModulesProvider: Provider<CompositeNodeModulesCache> = CompositeNodeModulesCache.registerIfAbsent(
|
||||
project,
|
||||
project.projectDir,
|
||||
nodeJs.nodeModulesGradleCacheDir
|
||||
)
|
||||
|
||||
val setupFileHasherTask = project.registerTask<KotlinNpmCachesSetup>(KotlinNpmCachesSetup.NAME) {
|
||||
it.description = "Setup file hasher for caches"
|
||||
|
||||
it.gradleNodeModules.set(gradleNodeModulesProvider)
|
||||
it.compositeNodeModules.set(compositeNodeModulesProvider)
|
||||
}
|
||||
|
||||
registerTask<KotlinNpmInstallTask>(KotlinNpmInstallTask.NAME) {
|
||||
val npmInstall = project.registerTask<KotlinNpmInstallTask>(KotlinNpmInstallTask.NAME) {
|
||||
it.dependsOn(setupTask)
|
||||
it.dependsOn(setupFileHasherTask)
|
||||
it.group = TASKS_GROUP_NAME
|
||||
it.description = "Find, download and link NPM dependencies and projects"
|
||||
|
||||
it.onlyIf { task ->
|
||||
task as KotlinNpmInstallTask
|
||||
task.preparedFiles.all { file ->
|
||||
file.exists()
|
||||
}
|
||||
}
|
||||
|
||||
it.doNotTrackStateCompat("NPM package manager track by its own")
|
||||
}
|
||||
|
||||
registerTask<Task>(PACKAGE_JSON_UMBRELLA_TASK_NAME)
|
||||
project.registerTask<Task>(PACKAGE_JSON_UMBRELLA_TASK_NAME)
|
||||
|
||||
YarnPlugin.apply(project)
|
||||
|
||||
tasks.register("node" + CleanDataTask.NAME_SUFFIX, CleanDataTask::class.java) {
|
||||
it.cleanableStoreProvider = provider { settings.requireConfigured().cleanableStore }
|
||||
nodeJs.resolver = KotlinRootNpmResolver(
|
||||
project.name,
|
||||
project.version.toString(),
|
||||
TasksRequirements(),
|
||||
nodeJs.versions,
|
||||
nodeJs.projectPackagesDir,
|
||||
nodeJs.rootProjectDir,
|
||||
)
|
||||
|
||||
val objectFactory = project.objects
|
||||
|
||||
val npmResolutionManager = KotlinNpmResolutionManager.registerIfAbsent(
|
||||
project,
|
||||
objectFactory.providerWithLazyConvention {
|
||||
nodeJs.resolver.close()
|
||||
},
|
||||
objectFactory.providerWithLazyConvention {
|
||||
nodeJs.resolver.compilations.associate { compilation ->
|
||||
"${compilation.project.path}:${compilation.disambiguatedName}" to compilation.packageJsonHandlers
|
||||
}
|
||||
},
|
||||
gradleNodeModulesProvider,
|
||||
compositeNodeModulesProvider
|
||||
)
|
||||
|
||||
npmInstall.configure {
|
||||
it.npmResolutionManager.set(npmResolutionManager)
|
||||
it.npmResolutionManager.disallowChanges()
|
||||
}
|
||||
|
||||
project.tasks.register("node" + CleanDataTask.NAME_SUFFIX, CleanDataTask::class.java) {
|
||||
it.cleanableStoreProvider = project.provider { nodeJs.requireConfigured().cleanableStore }
|
||||
it.group = TASKS_GROUP_NAME
|
||||
it.description = "Clean unused local node version"
|
||||
}
|
||||
@@ -69,7 +134,33 @@ open class NodeJsRootPlugin : Plugin<Project> {
|
||||
fun apply(rootProject: Project): NodeJsRootExtension {
|
||||
check(rootProject == rootProject.rootProject)
|
||||
rootProject.plugins.apply(NodeJsRootPlugin::class.java)
|
||||
return rootProject.extensions.getByName(EXTENSION_NAME) as NodeJsRootExtension
|
||||
return rootProject.extensions.getByName(NodeJsRootExtension.EXTENSION_NAME) as NodeJsRootExtension
|
||||
}
|
||||
|
||||
val Project.kotlinNodeJsExtension: NodeJsRootExtension
|
||||
get() = extensions.getByName(NodeJsRootExtension.EXTENSION_NAME).castIsolatedKotlinPluginClassLoaderAware()
|
||||
|
||||
private val Project.gradleNodeModules
|
||||
get() = GradleNodeModulesCache.registerIfAbsent(
|
||||
this,
|
||||
null,
|
||||
null
|
||||
)
|
||||
|
||||
private val Project.compositeNodeModules
|
||||
get() = CompositeNodeModulesCache.registerIfAbsent(
|
||||
this,
|
||||
null,
|
||||
null
|
||||
)
|
||||
|
||||
val Project.kotlinNpmResolutionManager
|
||||
get() = KotlinNpmResolutionManager.registerIfAbsent(
|
||||
this,
|
||||
null,
|
||||
null,
|
||||
gradleNodeModules,
|
||||
compositeNodeModules
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+6
-5
@@ -2,6 +2,7 @@ package org.jetbrains.kotlin.gradle.targets.js.nodejs
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.artifacts.Configuration
|
||||
import org.gradle.api.file.ArchiveOperations
|
||||
import org.gradle.api.file.FileSystemOperations
|
||||
import org.gradle.api.model.ObjectFactory
|
||||
import org.gradle.api.provider.Provider
|
||||
@@ -9,8 +10,8 @@ import org.gradle.api.tasks.*
|
||||
import org.gradle.internal.hash.FileHasher
|
||||
import org.jetbrains.kotlin.gradle.logging.kotlinInfo
|
||||
import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin.Companion.kotlinNodeJsExtension
|
||||
import org.jetbrains.kotlin.gradle.targets.js.extractWithUpToDate
|
||||
import org.jetbrains.kotlin.gradle.utils.ArchiveOperationsCompat
|
||||
import org.jetbrains.kotlin.statistics.metrics.NumericalMetrics
|
||||
import java.io.File
|
||||
import java.net.URI
|
||||
@@ -21,12 +22,13 @@ import javax.inject.Inject
|
||||
|
||||
abstract class NodeJsSetupTask : DefaultTask() {
|
||||
@Transient
|
||||
private val settings = NodeJsRootPlugin.apply(project.rootProject)
|
||||
private val settings = project.rootProject.kotlinNodeJsExtension
|
||||
private val env by lazy { settings.requireConfigured() }
|
||||
|
||||
private val shouldDownload = settings.download
|
||||
|
||||
private val archiveOperations = ArchiveOperationsCompat(project)
|
||||
@get:Inject
|
||||
abstract internal val archiveOperations: ArchiveOperations
|
||||
|
||||
@get:Inject
|
||||
internal open val fileHasher: FileHasher
|
||||
@@ -36,8 +38,7 @@ abstract class NodeJsSetupTask : DefaultTask() {
|
||||
internal abstract val objects: ObjectFactory
|
||||
|
||||
@get:Inject
|
||||
internal open val fs: FileSystemOperations
|
||||
get() = error("Should be injected")
|
||||
abstract internal val fs: FileSystemOperations
|
||||
|
||||
val ivyDependency: String
|
||||
@Input get() = env.ivyDependency
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ class TasksRequirements : Serializable {
|
||||
|
||||
val requiredNpmDependencies = requirements
|
||||
.asSequence()
|
||||
.map { it.createDependency(task.compilation.target.project) }
|
||||
.map { it.createDependency(task.compilation.target.project.objects) }
|
||||
.filterIsInstance<NpmDependency>()
|
||||
.toMutableSet()
|
||||
|
||||
|
||||
+2
-2
@@ -16,8 +16,8 @@ import java.io.File
|
||||
/**
|
||||
* Cache for storing already created [GradleNodeModule]s
|
||||
*/
|
||||
internal abstract class AbstractNodeModulesCache : AutoCloseable, BuildService<AbstractNodeModulesCache.Parameters> {
|
||||
internal interface Parameters : BuildServiceParameters {
|
||||
abstract class AbstractNodeModulesCache : AutoCloseable, BuildService<AbstractNodeModulesCache.Parameters> {
|
||||
interface Parameters : BuildServiceParameters {
|
||||
val rootProjectDir: DirectoryProperty
|
||||
val cacheDir: DirectoryProperty
|
||||
}
|
||||
|
||||
+52
-2
@@ -5,14 +5,24 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle.targets.js.npm
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension
|
||||
import org.gradle.api.tasks.Internal
|
||||
import org.jetbrains.kotlin.gradle.tasks.withType
|
||||
import org.jetbrains.kotlin.gradle.utils.SingleActionPerProject
|
||||
import java.io.File
|
||||
|
||||
internal interface UsesCompositeNodeModulesCache : Task {
|
||||
@get:Internal
|
||||
val compositeNodeModules: Property<CompositeNodeModulesCache>
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache for storing already created [GradleNodeModule]s
|
||||
*/
|
||||
internal abstract class CompositeNodeModulesCache : AbstractNodeModulesCache() {
|
||||
abstract class CompositeNodeModulesCache : AbstractNodeModulesCache() {
|
||||
override val type: String
|
||||
get() = "composite"
|
||||
|
||||
@@ -24,4 +34,44 @@ internal abstract class CompositeNodeModulesCache : AbstractNodeModulesCache() {
|
||||
val module = CompositeNodeModuleBuilder(file, parameters.cacheDir.get().asFile)
|
||||
return module.rebuild()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val serviceClass = CompositeNodeModulesCache::class.java
|
||||
private val serviceName = serviceClass.name
|
||||
|
||||
private fun registerIfAbsentImpl(
|
||||
project: Project,
|
||||
rootProjectDir: File?,
|
||||
cacheDir: File?
|
||||
): Provider<CompositeNodeModulesCache> {
|
||||
project.gradle.sharedServices.registrations.findByName(serviceName)?.let {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return it.service as Provider<CompositeNodeModulesCache>
|
||||
}
|
||||
|
||||
val message = {
|
||||
"Build service Composite Node Modules should be already registered"
|
||||
}
|
||||
|
||||
requireNotNull(rootProjectDir, message)
|
||||
requireNotNull(cacheDir, message)
|
||||
|
||||
return project.gradle.sharedServices.registerIfAbsent(serviceName, serviceClass) {
|
||||
it.parameters.rootProjectDir.set(rootProjectDir)
|
||||
it.parameters.cacheDir.set(cacheDir)
|
||||
}
|
||||
}
|
||||
|
||||
fun registerIfAbsent(
|
||||
project: Project,
|
||||
rootProjectDir: File?,
|
||||
cacheDir: File?
|
||||
) = registerIfAbsentImpl(project, rootProjectDir, cacheDir).also { serviceProvider ->
|
||||
SingleActionPerProject.run(project, UsesCompositeNodeModulesCache::class.java.name) {
|
||||
project.tasks.withType<UsesCompositeNodeModulesCache>().configureEach { task ->
|
||||
task.usesService(serviceProvider)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -5,22 +5,22 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle.targets.js.npm
|
||||
|
||||
import org.gradle.api.file.ArchiveOperations
|
||||
import org.gradle.api.file.FileSystemOperations
|
||||
import org.gradle.api.file.FileTree
|
||||
import org.jetbrains.kotlin.gradle.targets.js.HTML
|
||||
import org.jetbrains.kotlin.gradle.targets.js.JS
|
||||
import org.jetbrains.kotlin.gradle.targets.js.JS_MAP
|
||||
import org.jetbrains.kotlin.gradle.targets.js.META_JS
|
||||
import org.jetbrains.kotlin.gradle.targets.js.ir.KLIB_TYPE
|
||||
import org.jetbrains.kotlin.gradle.utils.ArchiveOperationsCompat
|
||||
import org.jetbrains.kotlin.gradle.utils.FileSystemOperationsCompat
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* Creates fake NodeJS module directory from given gradle [dependency].
|
||||
*/
|
||||
internal class GradleNodeModuleBuilder(
|
||||
val fs: FileSystemOperationsCompat,
|
||||
val archiveOperations: ArchiveOperationsCompat,
|
||||
val fs: FileSystemOperations,
|
||||
val archiveOperations: ArchiveOperations,
|
||||
val moduleName: String,
|
||||
val moduleVersion: String,
|
||||
val srcFiles: Collection<File>,
|
||||
|
||||
+62
-10
@@ -5,28 +5,40 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle.targets.js.npm
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.file.ArchiveOperations
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.file.FileSystemOperations
|
||||
import org.jetbrains.kotlin.gradle.utils.ArchiveOperationsCompat
|
||||
import org.jetbrains.kotlin.gradle.utils.FileSystemOperationsCompat
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.tasks.Internal
|
||||
import org.jetbrains.kotlin.gradle.report.BuildMetricsService
|
||||
import org.jetbrains.kotlin.gradle.report.UsesBuildMetricsService
|
||||
import org.jetbrains.kotlin.gradle.report.reportingSettings
|
||||
import org.jetbrains.kotlin.gradle.tasks.withType
|
||||
import org.jetbrains.kotlin.gradle.utils.SingleActionPerProject
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
internal interface UsesGradleNodeModulesCache : Task {
|
||||
@get:Internal
|
||||
val gradleNodeModules: Property<GradleNodeModulesCache>
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache for storing already created [GradleNodeModule]s
|
||||
*/
|
||||
internal abstract class GradleNodeModulesCache : AbstractNodeModulesCache() {
|
||||
abstract class GradleNodeModulesCache : AbstractNodeModulesCache() {
|
||||
|
||||
// TODO: replace by injected service org.gradle.api.file.FileSystemOperations once min support Gradle is 6.2
|
||||
// https://github.com/gradle/gradle/commit/d02b9d84c08dba64775fb9581e3280f88d319a21
|
||||
@Transient
|
||||
lateinit var fs: FileSystemOperationsCompat
|
||||
@get:Inject
|
||||
abstract val fs: FileSystemOperations
|
||||
|
||||
override val type: String
|
||||
get() = "gradle"
|
||||
|
||||
// TODO: replace by injected service org.gradle.api.file.ArchiveOperations once min supported Gradle is 6.6
|
||||
@Transient
|
||||
lateinit var archiveOperations: ArchiveOperationsCompat
|
||||
@get:Inject
|
||||
abstract val archiveOperations: ArchiveOperations
|
||||
|
||||
override fun buildImportedPackage(
|
||||
name: String,
|
||||
@@ -37,4 +49,44 @@ internal abstract class GradleNodeModulesCache : AbstractNodeModulesCache() {
|
||||
module.visitArtifacts()
|
||||
return module.rebuild()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val serviceClass = GradleNodeModulesCache::class.java
|
||||
private val serviceName = serviceClass.name
|
||||
|
||||
private fun registerIfAbsentImpl(
|
||||
project: Project,
|
||||
rootProjectDir: File?,
|
||||
cacheDir: File?
|
||||
): Provider<GradleNodeModulesCache> {
|
||||
project.gradle.sharedServices.registrations.findByName(serviceName)?.let {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return it.service as Provider<GradleNodeModulesCache>
|
||||
}
|
||||
|
||||
val message = {
|
||||
"Build service Gradle Node Modules should be already registered"
|
||||
}
|
||||
|
||||
requireNotNull(rootProjectDir, message)
|
||||
requireNotNull(cacheDir, message)
|
||||
|
||||
return project.gradle.sharedServices.registerIfAbsent(serviceName, serviceClass) {
|
||||
it.parameters.rootProjectDir.set(rootProjectDir)
|
||||
it.parameters.cacheDir.set(cacheDir)
|
||||
}
|
||||
}
|
||||
|
||||
fun registerIfAbsent(
|
||||
project: Project,
|
||||
rootProjectDir: File?,
|
||||
cacheDir: File?
|
||||
) = registerIfAbsentImpl(project, rootProjectDir, cacheDir).also { serviceProvider ->
|
||||
SingleActionPerProject.run(project, UsesGradleNodeModulesCache::class.java.name) {
|
||||
project.tasks.withType<UsesGradleNodeModulesCache>().configureEach { task ->
|
||||
task.usesService(serviceProvider)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+108
-204
@@ -5,169 +5,74 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle.targets.js.npm
|
||||
|
||||
import org.gradle.api.Incubating
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.internal.project.ProjectInternal
|
||||
import org.gradle.api.logging.Logger
|
||||
import org.gradle.api.provider.MapProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.services.BuildService
|
||||
import org.gradle.api.services.BuildServiceParameters
|
||||
import org.gradle.api.tasks.Internal
|
||||
import org.gradle.internal.service.ServiceRegistry
|
||||
import org.jetbrains.kotlin.gradle.internal.isInIdeaSync
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinCompilationNpmResolution
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinProjectNpmResolution
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.Installation
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinRootNpmResolution
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.resolver.KotlinCompilationNpmResolver
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.resolver.KotlinProjectNpmResolver
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.resolver.KotlinRootNpmResolver
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.KotlinPackageJsonTask
|
||||
import org.jetbrains.kotlin.gradle.utils.unavailableValueError
|
||||
import java.io.File
|
||||
import org.jetbrains.kotlin.gradle.tasks.withType
|
||||
import org.jetbrains.kotlin.gradle.utils.SingleActionPerProject
|
||||
|
||||
/**
|
||||
* # NPM resolution state manager
|
||||
*
|
||||
* ## Resolving process from Gradle
|
||||
*
|
||||
* **configuring**. Global initial state. [NpmResolverPlugin] should be applied for each project
|
||||
* that requires NPM resolution. When applied, [KotlinProjectNpmResolver] will be created for the
|
||||
* corresponding project and will subscribe to all js compilations. [NpmResolverPlugin] requires
|
||||
* kotlin mulitplatform or plaform plugin applied first.
|
||||
*
|
||||
* **up-to-date-checked**. This state is compilation local: one compilation may be in up-to-date-checked
|
||||
* state, while another may be steel in configuring state. New compilations may be added in this
|
||||
* state, but compilations that are already up-to-date-checked cannot be changed.
|
||||
* Initiated by calling [KotlinPackageJsonTask.producerInputs] getter (will be called by Gradle).
|
||||
* [KotlinCompilationNpmResolver] will create and **resolve** aggregated compilation configuration,
|
||||
* which contains all related compilation configuration and NPM tools configuration.
|
||||
* NPM tools configuration contains all dependencies that is required for all enabled
|
||||
* tasks related to this compilation. It is important to resolve this configuration inside particular
|
||||
* project and not globally. Aggregated configuration will be analyzed for gradle internal dependencies
|
||||
* (project dependencies), gradle external dependencies and npm dependencies. This collections will
|
||||
* be treated as `packageJson` task inputs.
|
||||
*
|
||||
* **package-json-created**. This state also compilation local. Initiated by executing `packageJson`
|
||||
* task for particular compilation. If `packageJson` task is up-to-date, this state is reached by
|
||||
* first calling [KotlinCompilationNpmResolver.getResolutionOrResolveIfForced] which may be called
|
||||
* by compilation that depends on this compilation. Note that package.json will be executed only for
|
||||
* required compilations, while other may be missed.
|
||||
*
|
||||
* **Prepared**.
|
||||
* Global final state. Initiated by executing global `rootPackageJson` task.
|
||||
*
|
||||
* **Installed**.
|
||||
* All created package.json files will be gathered and package manager will be executed.
|
||||
* Package manager will create lock file, that will be parsed for transitive npm dependencies
|
||||
* that will be added to the root [NpmDependency] objects. `kotlinNpmInstall` task may be up-to-date.
|
||||
* In this case, installed state will be reached by first call of [installIfNeeded] without executing
|
||||
* package manager.
|
||||
*
|
||||
* Resolution will be used from [NpmDependency] by calling [getNpmDependencyResolvedCompilation].
|
||||
* Also resolution will be checked before calling [NpmProject.require] and executing any task
|
||||
* that requires npm dependencies or node_modules.
|
||||
*
|
||||
* User can call [requireInstalled] to get resolution info.
|
||||
*
|
||||
* ## Resolving process during Idea import
|
||||
*
|
||||
* In this case [forceFullResolve] will be set, and all compilations will be resolved
|
||||
* even without `packageJson` task execution.
|
||||
*
|
||||
* During building gradle project model, all [NpmDependency] will be asked for there files,
|
||||
* and [getNpmDependencyResolvedCompilation] will be called. In the [forceFullResolve] mode
|
||||
* project will be fully resolved: all `package.json` files will be created, and package manager
|
||||
* will be called. We are manually tracking package.json files contents to avoid calling package manager
|
||||
* if nothing was changes.
|
||||
*
|
||||
* Note that in this case resolution process will be performed outside of task execution.
|
||||
*/
|
||||
class KotlinNpmResolutionManager(@Transient private val nodeJsSettings: NodeJsRootExtension?) {
|
||||
private val forceFullResolve: Boolean by lazy {
|
||||
(nodeJsSettings ?: unavailableValueError("nodeJsSettings")).rootProject.isInIdeaSync
|
||||
internal interface UsesKotlinNpmResolutionManager : Task {
|
||||
@get:Internal
|
||||
val npmResolutionManager: Property<KotlinNpmResolutionManager>
|
||||
}
|
||||
|
||||
abstract class KotlinNpmResolutionManager : BuildService<KotlinNpmResolutionManager.Parameters> {
|
||||
|
||||
interface Parameters : BuildServiceParameters {
|
||||
val resolution: Property<KotlinRootNpmResolution>
|
||||
|
||||
// pulled up from compilation resolver since it was failing with ClassNotFoundException on deserialization, see KT-49061
|
||||
val packageJsonHandlers: MapProperty<String, List<PackageJson.() -> Unit>>
|
||||
|
||||
val gradleNodeModulesProvider: Property<GradleNodeModulesCache>
|
||||
val compositeNodeModulesProvider: Property<CompositeNodeModulesCache>
|
||||
}
|
||||
|
||||
val resolver = KotlinRootNpmResolver(nodeJsSettings, forceFullResolve)
|
||||
val resolution
|
||||
get() = parameters.resolution
|
||||
|
||||
internal abstract class KotlinNpmResolutionManagerStateHolder : BuildService<BuildServiceParameters.None> {
|
||||
@Volatile
|
||||
internal var state: ResolutionState? = null
|
||||
}
|
||||
|
||||
private val stateHolderProvider = (nodeJsSettings ?: unavailableValueError("nodeJsSettings"))
|
||||
.rootProject.gradle.sharedServices.registerIfAbsent(
|
||||
"npm-resolution-manager-state-holder", KotlinNpmResolutionManagerStateHolder::class.java
|
||||
) {
|
||||
}.also {
|
||||
resolver.declareBuildServiceForRootProjectJsTasks(it)
|
||||
resolver.declareBuildServiceForAllProjectsJsTasks(it)
|
||||
}
|
||||
|
||||
private val stateHolder get() = stateHolderProvider.get()
|
||||
|
||||
var state: ResolutionState
|
||||
get() = stateHolder.state ?: ResolutionState.Configuring(resolver)
|
||||
set(value) {
|
||||
stateHolder.state = value
|
||||
}
|
||||
@Volatile
|
||||
var state: ResolutionState = ResolutionState.Configuring(resolution.get())
|
||||
|
||||
sealed class ResolutionState {
|
||||
abstract val npmProjects: List<NpmProject>
|
||||
|
||||
class Configuring(val resolver: KotlinRootNpmResolver) : ResolutionState() {
|
||||
override val npmProjects: List<NpmProject>
|
||||
get() = resolver.compilations.map { it.npmProject }
|
||||
}
|
||||
class Configuring(val resolution: KotlinRootNpmResolution) : ResolutionState()
|
||||
|
||||
open class Prepared(val preparedInstallation: KotlinRootNpmResolver.Installation) : ResolutionState() {
|
||||
override val npmProjects: List<NpmProject>
|
||||
get() = npmProjectsByProjectResolutions(preparedInstallation.projectResolutions)
|
||||
}
|
||||
open class Prepared(val preparedInstallation: Installation) : ResolutionState()
|
||||
|
||||
class Installed internal constructor(internal val resolved: KotlinRootNpmResolution) : ResolutionState() {
|
||||
override val npmProjects: List<NpmProject>
|
||||
get() = npmProjectsByProjectResolutions(resolved.projects)
|
||||
}
|
||||
class Installed() : ResolutionState()
|
||||
|
||||
class Error(val wrappedException: Throwable) : ResolutionState() {
|
||||
override val npmProjects: List<NpmProject>
|
||||
get() = emptyList()
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun npmProjectsByProjectResolutions(
|
||||
resolutions: Map<String, KotlinProjectNpmResolution>
|
||||
): List<NpmProject> {
|
||||
return resolutions
|
||||
.values
|
||||
.flatMap { it.npmProjects.map { it.npmProject } }
|
||||
}
|
||||
}
|
||||
class Error(val wrappedException: Throwable) : ResolutionState()
|
||||
}
|
||||
|
||||
@Incubating
|
||||
internal fun requireInstalled(
|
||||
services: ServiceRegistry,
|
||||
logger: Logger,
|
||||
reason: String = ""
|
||||
) = installIfNeeded(reason = reason, services = services, logger = logger)
|
||||
|
||||
internal fun requireConfiguringState(): KotlinRootNpmResolver =
|
||||
(this.state as? ResolutionState.Configuring ?: error("NPM Dependencies already resolved and installed")).resolver
|
||||
|
||||
internal fun isConfiguringState(): Boolean =
|
||||
this.state is ResolutionState.Configuring
|
||||
|
||||
internal fun prepare(logger: Logger) = prepareIfNeeded(requireNotPrepared = true, logger = logger)
|
||||
internal fun prepare(
|
||||
logger: Logger,
|
||||
npmEnvironment: NpmEnvironment,
|
||||
yarnEnvironment: YarnEnvironment,
|
||||
) = prepareIfNeeded(logger = logger, npmEnvironment, yarnEnvironment)
|
||||
|
||||
internal fun installIfNeeded(
|
||||
reason: String? = "",
|
||||
args: List<String> = emptyList(),
|
||||
services: ServiceRegistry,
|
||||
logger: Logger
|
||||
): KotlinRootNpmResolution? {
|
||||
synchronized(stateHolder) {
|
||||
logger: Logger,
|
||||
npmEnvironment: NpmEnvironment,
|
||||
yarnEnvironment: YarnEnvironment,
|
||||
): Unit? {
|
||||
synchronized(this) {
|
||||
if (state is ResolutionState.Installed) {
|
||||
return (state as ResolutionState.Installed).resolved
|
||||
return Unit
|
||||
}
|
||||
|
||||
if (state is ResolutionState.Error) {
|
||||
@@ -175,14 +80,9 @@ class KotlinNpmResolutionManager(@Transient private val nodeJsSettings: NodeJsRo
|
||||
}
|
||||
|
||||
return try {
|
||||
val installUpToDate = nodeJsSettings?.npmInstallTaskProvider?.get()?.state?.upToDate ?: false
|
||||
val forceUpToDate = installUpToDate && !forceFullResolve
|
||||
|
||||
val installation = prepareIfNeeded(requireUpToDateReason = reason, logger = logger)
|
||||
val resolution = installation
|
||||
.install(forceUpToDate, args, services, logger)
|
||||
state = ResolutionState.Installed(resolution)
|
||||
resolution
|
||||
val installation: Installation = prepareIfNeeded(logger = logger, npmEnvironment, yarnEnvironment)
|
||||
installation.install(args, services, logger, npmEnvironment, yarnEnvironment)
|
||||
state = ResolutionState.Installed()
|
||||
} catch (e: Exception) {
|
||||
state = ResolutionState.Error(e)
|
||||
throw e
|
||||
@@ -190,93 +90,97 @@ class KotlinNpmResolutionManager(@Transient private val nodeJsSettings: NodeJsRo
|
||||
}
|
||||
}
|
||||
|
||||
internal val packageJsonFiles: Collection<File>
|
||||
get() = state.npmProjects.map { it.packageJsonFile }
|
||||
// internal val packageJsonFiles: Collection<File>
|
||||
// get() = state.npmProjects.map { it.packageJsonFile }
|
||||
|
||||
/**
|
||||
* @param requireUpToDateReason Check that project already resolved,
|
||||
* or it is up-to-date but just not closed. Show given message if it is not.
|
||||
* @param requireNotPrepared Check that project is not prepared
|
||||
*/
|
||||
private fun prepareIfNeeded(
|
||||
requireUpToDateReason: String? = null,
|
||||
requireNotPrepared: Boolean = false,
|
||||
logger: Logger
|
||||
): KotlinRootNpmResolver.Installation {
|
||||
fun alreadyResolved(installation: KotlinRootNpmResolver.Installation): KotlinRootNpmResolver.Installation {
|
||||
if (requireNotPrepared) error("Project already prepared")
|
||||
return installation
|
||||
}
|
||||
|
||||
logger: Logger,
|
||||
npmEnvironment: NpmEnvironment,
|
||||
yarnEnvironment: YarnEnvironment,
|
||||
): Installation {
|
||||
val state0 = this.state
|
||||
return when (state0) {
|
||||
is ResolutionState.Prepared -> {
|
||||
alreadyResolved(state0.preparedInstallation)
|
||||
state0.preparedInstallation
|
||||
}
|
||||
|
||||
is ResolutionState.Configuring -> {
|
||||
synchronized(stateHolder) {
|
||||
synchronized(this) {
|
||||
val state1 = this.state
|
||||
when (state1) {
|
||||
is ResolutionState.Prepared -> alreadyResolved(state1.preparedInstallation)
|
||||
is ResolutionState.Prepared -> state1.preparedInstallation
|
||||
is ResolutionState.Configuring -> {
|
||||
val upToDate = nodeJsSettings?.rootPackageJsonTaskProvider?.get()?.state?.upToDate ?: true
|
||||
if (requireUpToDateReason != null && !upToDate) {
|
||||
error("NPM dependencies should be resolved $requireUpToDateReason")
|
||||
}
|
||||
|
||||
state1.resolver.prepareInstallation(logger).also {
|
||||
state1.resolution.prepareInstallation(
|
||||
logger,
|
||||
npmEnvironment,
|
||||
yarnEnvironment,
|
||||
this
|
||||
).also {
|
||||
this.state = ResolutionState.Prepared(it)
|
||||
}
|
||||
}
|
||||
|
||||
is ResolutionState.Installed -> error("Project already installed")
|
||||
is ResolutionState.Error -> throw state1.wrappedException
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is ResolutionState.Installed -> error("Project already installed")
|
||||
is ResolutionState.Error -> throw state0.wrappedException
|
||||
}
|
||||
}
|
||||
|
||||
internal fun getNpmDependencyResolvedCompilation(npmDependency: NpmDependency): KotlinCompilationNpmResolution? {
|
||||
val project = npmDependency.project!!
|
||||
val projectPath = project.path
|
||||
val services = (project as ProjectInternal).services
|
||||
val logger = project.logger
|
||||
companion object {
|
||||
private val serviceClass = KotlinNpmResolutionManager::class.java
|
||||
private val serviceName = serviceClass.name
|
||||
|
||||
val resolvedProject =
|
||||
if (forceFullResolve) {
|
||||
installIfNeeded(reason = null, services = services, logger = logger)?.get(projectPath) ?: return null
|
||||
} else {
|
||||
// may return null only during npm resolution
|
||||
// (it can be called since NpmDependency added to configuration that
|
||||
// requires resolve to build package.json, in this case we should just skip this call)
|
||||
val state0 = state
|
||||
when (state0) {
|
||||
is ResolutionState.Prepared -> state0.preparedInstallation[projectPath]
|
||||
is ResolutionState.Configuring -> {
|
||||
return null
|
||||
//error("Cannot use NpmDependency before :kotlinNpmInstall task execution")
|
||||
}
|
||||
is ResolutionState.Installed -> state0.resolved[projectPath]
|
||||
is ResolutionState.Error -> {
|
||||
return null
|
||||
}
|
||||
}
|
||||
private fun registerIfAbsentImpl(
|
||||
project: Project,
|
||||
resolution: Provider<KotlinRootNpmResolution>?,
|
||||
packageJsonHandlers: Provider<Map<String, MutableList<PackageJson.() -> Unit>>>?,
|
||||
gradleNodeModulesProvider: Provider<GradleNodeModulesCache>,
|
||||
compositeNodeModulesProvider: Provider<CompositeNodeModulesCache>
|
||||
): Provider<KotlinNpmResolutionManager> {
|
||||
project.gradle.sharedServices.registrations.findByName(serviceName)?.let {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return it.service as Provider<KotlinNpmResolutionManager>
|
||||
}
|
||||
|
||||
return resolvedProject.npmProjectsByNpmDependency[npmDependency] ?: error("NPM project resolved without $this")
|
||||
}
|
||||
val message = {
|
||||
"Build service KotlinNpmResolutionManager should be already registered"
|
||||
}
|
||||
|
||||
internal fun <T> checkRequiredDependencies(task: T)
|
||||
where T : RequiresNpmDependencies,
|
||||
T : Task {
|
||||
val targetRequired = resolver.taskRequirements.byTask[task.path]?.toSet() ?: setOf()
|
||||
requireNotNull(resolution, message)
|
||||
requireNotNull(packageJsonHandlers, message)
|
||||
|
||||
task.requiredNpmDependencies.forEach {
|
||||
check(it in targetRequired) {
|
||||
"${it.createDependency(task.project)} required by $task was not found resolved at the time of nodejs package manager call. " +
|
||||
"This may be caused by changing $task configuration after npm dependencies resolution."
|
||||
return project.gradle.sharedServices.registerIfAbsent(serviceName, serviceClass) {
|
||||
it.parameters.resolution.set(resolution)
|
||||
it.parameters.packageJsonHandlers.set(packageJsonHandlers)
|
||||
it.parameters.gradleNodeModulesProvider.set(gradleNodeModulesProvider)
|
||||
it.parameters.compositeNodeModulesProvider.set(compositeNodeModulesProvider)
|
||||
}
|
||||
}
|
||||
|
||||
fun registerIfAbsent(
|
||||
project: Project,
|
||||
resolution: Provider<KotlinRootNpmResolution>?,
|
||||
packageJsonHandlers: Provider<Map<String, MutableList<PackageJson.() -> Unit>>>?,
|
||||
gradleNodeModulesProvider: Provider<GradleNodeModulesCache>,
|
||||
compositeNodeModulesProvider: Provider<CompositeNodeModulesCache>
|
||||
) = registerIfAbsentImpl(
|
||||
project,
|
||||
resolution,
|
||||
packageJsonHandlers,
|
||||
gradleNodeModulesProvider,
|
||||
compositeNodeModulesProvider
|
||||
).also { serviceProvider ->
|
||||
SingleActionPerProject.run(project, UsesKotlinNpmResolutionManager::class.java.name) {
|
||||
project.tasks.withType<UsesKotlinNpmResolutionManager>().configureEach { task ->
|
||||
task.usesService(serviceProvider)
|
||||
task.usesService(gradleNodeModulesProvider)
|
||||
task.usesService(compositeNodeModulesProvider)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+27
-20
@@ -5,12 +5,12 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle.targets.js.npm
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.logging.Logger
|
||||
import org.gradle.internal.service.ServiceRegistry
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinCompilationNpmResolution
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsEnv
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.PreparedKotlinCompilationNpmResolution
|
||||
import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnEnv
|
||||
import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnResolution
|
||||
import java.io.File
|
||||
import java.io.Serializable
|
||||
|
||||
@@ -18,36 +18,26 @@ import java.io.Serializable
|
||||
* NodeJS package manager API
|
||||
*/
|
||||
interface NpmApi : Serializable {
|
||||
fun setup(project: Project)
|
||||
|
||||
fun preparedFiles(nodeJs: NpmEnvironment): Collection<File>
|
||||
|
||||
fun prepareRootProject(
|
||||
rootProject: Project?,
|
||||
nodeJs: NpmEnvironment,
|
||||
rootProjectName: String,
|
||||
rootProjectVersion: String,
|
||||
logger: Logger,
|
||||
subProjects: Collection<KotlinCompilationNpmResolution>,
|
||||
subProjects: Collection<PreparedKotlinCompilationNpmResolution>,
|
||||
resolutions: Map<String, String>,
|
||||
forceFullResolve: Boolean
|
||||
)
|
||||
|
||||
fun resolveRootProject(
|
||||
services: ServiceRegistry,
|
||||
logger: Logger,
|
||||
nodeJs: NpmEnvironment,
|
||||
yarn: YarnEnv,
|
||||
npmProjects: Collection<KotlinCompilationNpmResolution>,
|
||||
yarn: YarnEnvironment,
|
||||
npmProjects: Collection<PreparedKotlinCompilationNpmResolution>,
|
||||
cliArgs: List<String>
|
||||
)
|
||||
|
||||
fun resolveDependency(
|
||||
npmResolution: KotlinCompilationNpmResolution,
|
||||
dependency: NpmDependency,
|
||||
transitive: Boolean
|
||||
): Set<File>
|
||||
|
||||
companion object {
|
||||
fun resolveOperationDescription(packageManagerTitle: String): String =
|
||||
"Resolving NPM dependencies using $packageManagerTitle"
|
||||
@@ -57,12 +47,29 @@ interface NpmApi : Serializable {
|
||||
data class NpmEnvironment(
|
||||
val rootPackageDir: File,
|
||||
val nodeExecutable: String,
|
||||
val isWindows: Boolean
|
||||
val isWindows: Boolean,
|
||||
val packageManager: NpmApi
|
||||
) : Serializable
|
||||
|
||||
internal val NodeJsRootExtension.asNpmEnvironment
|
||||
internal val NodeJsEnv.asNpmEnvironment
|
||||
get() = NpmEnvironment(
|
||||
rootPackageDir,
|
||||
requireConfigured().nodeExecutable,
|
||||
requireConfigured().isWindows
|
||||
nodeExecutable,
|
||||
isWindows,
|
||||
packageManager
|
||||
)
|
||||
|
||||
data class YarnEnvironment(
|
||||
val executable: String,
|
||||
val standalone: Boolean,
|
||||
val ignoreScripts: Boolean,
|
||||
val yarnResolutions: List<YarnResolution>
|
||||
) : Serializable
|
||||
|
||||
internal val YarnEnv.asYarnEnvironment
|
||||
get() = YarnEnvironment(
|
||||
executable,
|
||||
standalone,
|
||||
ignoreScripts,
|
||||
yarnResolutions
|
||||
)
|
||||
+20
-68
@@ -5,31 +5,23 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle.targets.js.npm
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.Dependency
|
||||
import org.gradle.api.artifacts.FileCollectionDependency
|
||||
import org.gradle.api.artifacts.SelfResolvingDependency
|
||||
import org.gradle.api.artifacts.component.ComponentIdentifier
|
||||
import org.gradle.api.file.FileCollection
|
||||
import org.gradle.api.internal.artifacts.DependencyResolveContext
|
||||
import org.gradle.api.internal.artifacts.ResolvableDependency
|
||||
import org.gradle.api.internal.artifacts.dependencies.SelfResolvingDependencyInternal
|
||||
import org.gradle.api.model.ObjectFactory
|
||||
import org.gradle.api.tasks.TaskDependency
|
||||
import org.gradle.internal.component.local.model.DefaultLibraryBinaryIdentifier
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProject.Companion.PACKAGE_JSON
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinCompilationNpmResolution
|
||||
import java.io.File
|
||||
|
||||
data class NpmDependency(
|
||||
@Transient
|
||||
internal val project: Project?,
|
||||
val objectFactory: ObjectFactory,
|
||||
val scope: Scope = Scope.NORMAL,
|
||||
private val name: String,
|
||||
private val version: String,
|
||||
val scope: Scope = Scope.NORMAL,
|
||||
) : SelfResolvingDependency,
|
||||
SelfResolvingDependencyInternal,
|
||||
ResolvableDependency,
|
||||
FileCollectionDependency {
|
||||
) : FileCollectionDependency,
|
||||
SelfResolvingDependencyInternal {
|
||||
|
||||
enum class Scope {
|
||||
NORMAL,
|
||||
@@ -38,73 +30,33 @@ data class NpmDependency(
|
||||
PEER
|
||||
}
|
||||
|
||||
private var reason: String? = null
|
||||
|
||||
override fun getGroup(): String? = null
|
||||
|
||||
override fun getName() = name
|
||||
|
||||
override fun getVersion() = version
|
||||
|
||||
internal var parent: NpmDependency? = null
|
||||
internal val dependencies = mutableSetOf<NpmDependency>()
|
||||
internal var resolvedVersion: String? = null
|
||||
internal var integrity: String? = null
|
||||
|
||||
override fun resolve(transitive: Boolean): Set<File> =
|
||||
resolveProject()
|
||||
?.let {
|
||||
it
|
||||
.npmProject
|
||||
.nodeJs
|
||||
.packageManager
|
||||
.resolveDependency(
|
||||
it,
|
||||
this,
|
||||
transitive
|
||||
)
|
||||
}
|
||||
?: mutableSetOf()
|
||||
resolve()
|
||||
|
||||
override fun resolve(): MutableSet<File> {
|
||||
val npmPackage = parent?.resolveProject()
|
||||
?: resolveProject()
|
||||
?: return mutableSetOf()
|
||||
return mutableSetOf(npmPackage.npmProject.resolve(key)!!)
|
||||
}
|
||||
override fun getTargetComponentId(): ComponentIdentifier? = null
|
||||
override fun resolve(): MutableSet<File> = mutableSetOf()
|
||||
|
||||
override fun resolve(context: DependencyResolveContext) {
|
||||
val npmPackage = resolveProject()
|
||||
if (npmPackage != null) {
|
||||
npmPackage.project.files(npmPackage.npmProject.resolve(key))
|
||||
dependencies.forEach {
|
||||
context.add(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// may return null only during npm resolution
|
||||
// (it can be called since NpmDependency added to configuration that
|
||||
// requires resolve to build package.json, in this case we should just skip this call)
|
||||
private fun resolveProject(): KotlinCompilationNpmResolution? {
|
||||
val nodeJs = NodeJsRootPlugin.apply(project!!.rootProject)
|
||||
return nodeJs.npmResolutionManager.getNpmDependencyResolvedCompilation(this)
|
||||
}
|
||||
|
||||
val key: String = name
|
||||
|
||||
override fun toString() = "$key: $version"
|
||||
|
||||
override fun getFiles(): FileCollection = project!!.files(resolve(true))
|
||||
|
||||
override fun getName() = name
|
||||
|
||||
override fun getVersion() = version
|
||||
override fun getFiles(): FileCollection = objectFactory.fileCollection()
|
||||
|
||||
override fun getBuildDependencies(): TaskDependency = TaskDependency { mutableSetOf() }
|
||||
|
||||
override fun contentEquals(dependency: Dependency) = this == dependency
|
||||
|
||||
override fun getTargetComponentId() = DefaultLibraryBinaryIdentifier(project!!.path, key, "npm")
|
||||
|
||||
override fun copy(): Dependency = this.copy(name = name)
|
||||
|
||||
private var reason: String? = null
|
||||
|
||||
override fun because(reason: String?) {
|
||||
this.reason = reason
|
||||
}
|
||||
@@ -113,20 +65,20 @@ data class NpmDependency(
|
||||
}
|
||||
|
||||
internal fun directoryNpmDependency(
|
||||
project: Project,
|
||||
objectFactory: ObjectFactory,
|
||||
scope: NpmDependency.Scope,
|
||||
name: String,
|
||||
directory: File,
|
||||
scope: NpmDependency.Scope,
|
||||
): NpmDependency {
|
||||
check(directory.isDirectory) {
|
||||
"Dependency on local path should point on directory but $directory found"
|
||||
}
|
||||
|
||||
return NpmDependency(
|
||||
project = project,
|
||||
objectFactory = objectFactory,
|
||||
scope = scope,
|
||||
name = name,
|
||||
version = fileVersion(directory),
|
||||
scope = scope,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -118,7 +118,7 @@ private abstract class NpmDependencyExtensionDelegate(
|
||||
version: String,
|
||||
): NpmDependency =
|
||||
NpmDependency(
|
||||
project = project,
|
||||
objectFactory = project.objects,
|
||||
name = name,
|
||||
version = version,
|
||||
scope = scope,
|
||||
@@ -289,10 +289,10 @@ private fun defaultNpmDependencyDelegate(
|
||||
directory: File,
|
||||
): NpmDependency =
|
||||
directoryNpmDependency(
|
||||
project = project,
|
||||
objectFactory = project.objects,
|
||||
scope = scope,
|
||||
name = name,
|
||||
directory = directory,
|
||||
scope = scope,
|
||||
)
|
||||
|
||||
override fun processNonStringFirstArgument(arg: Any?, vararg args: Any?): NpmDependency {
|
||||
|
||||
+2
-1
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.disambiguateName
|
||||
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsTargetDsl
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin.Companion.kotlinNodeJsExtension
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.KotlinPackageJsonTask
|
||||
import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly
|
||||
import java.io.File
|
||||
@@ -37,7 +38,7 @@ open class NpmProject(@Transient val compilation: KotlinJsCompilation) : Seriali
|
||||
}
|
||||
|
||||
@Transient
|
||||
val nodeJs = NodeJsRootPlugin.apply(project.rootProject)
|
||||
val nodeJs = project.rootProject.kotlinNodeJsExtension
|
||||
|
||||
val dir: File by lazy {
|
||||
nodeJs.projectPackagesDir.resolve(name)
|
||||
|
||||
+24
-3
@@ -7,13 +7,34 @@ package org.jetbrains.kotlin.gradle.targets.js.npm
|
||||
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.jetbrains.kotlin.gradle.plugin.whenEvaluated
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin.Companion.kotlinNodeJsExtension
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.resolver.implementing
|
||||
import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest
|
||||
|
||||
class NpmResolverPlugin : Plugin<Project> {
|
||||
override fun apply(target: Project) {
|
||||
val project = target
|
||||
override fun apply(project: Project) {
|
||||
val nodeJs = NodeJsRootPlugin.apply(project.rootProject)
|
||||
nodeJs.npmResolutionManager.requireConfiguringState().addProject(project)
|
||||
project.rootProject.kotlinNodeJsExtension.resolver.addProject(project)
|
||||
val kotlinNodeJsTaskProvidersExtension = project.rootProject.kotlinNodeJsExtension
|
||||
project.whenEvaluated {
|
||||
project.tasks.implementing(RequiresNpmDependencies::class)
|
||||
.configureEach { task ->
|
||||
if (task.enabled) {
|
||||
task as RequiresNpmDependencies
|
||||
// KotlinJsTest delegates npm dependencies to testFramework,
|
||||
// which can be defined after this configure action
|
||||
if (task !is KotlinJsTest) {
|
||||
nodeJs.taskRequirements.addTaskRequirements(task)
|
||||
}
|
||||
task.dependsOn(
|
||||
kotlinNodeJsTaskProvidersExtension.npmInstallTaskProvider,
|
||||
kotlinNodeJsTaskProvidersExtension.storeYarnLockTaskProvider,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
+41
-41
@@ -6,33 +6,40 @@
|
||||
package org.jetbrains.kotlin.gradle.targets.js.npm
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.Nested
|
||||
import org.gradle.api.tasks.Internal
|
||||
import org.gradle.api.tasks.OutputFile
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
|
||||
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrCompilation
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProject.Companion.PACKAGE_JSON
|
||||
import org.jetbrains.kotlin.gradle.utils.property
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
open class PublicPackageJsonTask
|
||||
@Inject
|
||||
constructor(
|
||||
@Transient
|
||||
private val compilation: KotlinJsCompilation
|
||||
) : DefaultTask() {
|
||||
private val npmProject = compilation.npmProject
|
||||
abstract class PublicPackageJsonTask :
|
||||
DefaultTask(),
|
||||
UsesKotlinNpmResolutionManager {
|
||||
|
||||
@Transient
|
||||
private val nodeJs = npmProject.nodeJs
|
||||
private val resolutionManager = nodeJs.npmResolutionManager
|
||||
@get:Internal
|
||||
abstract val compilationDisambiguatedName: Property<String>
|
||||
|
||||
private val compilationName = compilation.disambiguatedName
|
||||
private val projectPath = project.path
|
||||
|
||||
private val packageJsonHandlers = compilation.packageJsonHandlers
|
||||
@get:Input
|
||||
val projectVersion = project.version.toString()
|
||||
|
||||
@get:Input
|
||||
abstract val jsIrCompilation: Property<Boolean>
|
||||
|
||||
@get:Input
|
||||
abstract val npmProjectName: Property<String>
|
||||
|
||||
@get:Internal
|
||||
abstract val npmProjectMain: Property<String>
|
||||
|
||||
private val packageJsonHandlers: List<PackageJson.() -> Unit>
|
||||
get() = npmResolutionManager.get().parameters.packageJsonHandlers.get()
|
||||
.getValue("$projectPath:${compilationDisambiguatedName.get()}")
|
||||
|
||||
|
||||
@get:Input
|
||||
val packageJsonCustomFields: Map<String, Any?>
|
||||
@@ -41,47 +48,40 @@ constructor(
|
||||
packageJsonHandlers.forEach { it() }
|
||||
}.customFields
|
||||
|
||||
private val compilationResolver
|
||||
get() = resolutionManager.resolver[projectPath][compilationName]
|
||||
|
||||
private val compilationResolution
|
||||
get() = compilationResolver.getResolutionOrResolveIfForced() ?: error("Compilation resolution isn't available")
|
||||
get() = npmResolutionManager.get().resolution.get()[projectPath][compilationDisambiguatedName.get()]
|
||||
.getResolutionOrResolve(
|
||||
npmResolutionManager.get(),
|
||||
logger
|
||||
)
|
||||
|
||||
@get:Nested
|
||||
internal val externalDependencies: Collection<NpmDependencyDeclaration>
|
||||
@get:Input
|
||||
val externalDependencies: Collection<NpmDependencyDeclaration>
|
||||
get() = compilationResolution.externalNpmDependencies
|
||||
.map {
|
||||
NpmDependencyDeclaration(
|
||||
scope = it.scope,
|
||||
name = it.name,
|
||||
version = it.version,
|
||||
)
|
||||
}
|
||||
|
||||
private val publicPackageJsonTaskName by lazy {
|
||||
npmProject.publicPackageJsonTaskName
|
||||
}
|
||||
|
||||
private val defaultPackageJsonFile by lazy {
|
||||
project.buildDir
|
||||
.resolve("tmp")
|
||||
.resolve(publicPackageJsonTaskName)
|
||||
.resolve(name)
|
||||
.resolve(PACKAGE_JSON)
|
||||
}
|
||||
|
||||
@get:OutputFile
|
||||
var packageJsonFile: File by property { defaultPackageJsonFile }
|
||||
|
||||
private val isJrIrCompilation = compilation is KotlinJsIrCompilation
|
||||
private val projectVersion = project.version.toString()
|
||||
|
||||
@TaskAction
|
||||
fun resolve() {
|
||||
packageJson(npmProject.name, projectVersion, npmProject.main, externalDependencies, packageJsonHandlers).let { packageJson ->
|
||||
packageJson.main = "${npmProject.name}.js"
|
||||
packageJson(
|
||||
npmProjectName.get(),
|
||||
projectVersion,
|
||||
npmProjectMain.get(),
|
||||
externalDependencies,
|
||||
packageJsonHandlers
|
||||
).let { packageJson ->
|
||||
packageJson.main = "${npmProjectName}.js"
|
||||
|
||||
if (isJrIrCompilation) {
|
||||
packageJson.types = "${npmProject.name}.d.ts"
|
||||
if (jsIrCompilation.get()) {
|
||||
packageJson.types = "${npmProjectName}.d.ts"
|
||||
}
|
||||
|
||||
packageJson.apply {
|
||||
|
||||
-1
@@ -11,7 +11,6 @@ import org.jetbrains.kotlin.gradle.targets.js.RequiredKotlinJsDependency
|
||||
|
||||
interface RequiresNpmDependencies {
|
||||
val compilation: KotlinJsCompilation
|
||||
val nodeModulesRequired: Boolean
|
||||
val requiredNpmDependencies: Set<RequiredKotlinJsDependency>
|
||||
|
||||
@Internal
|
||||
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.resolved
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.*
|
||||
import java.io.Serializable
|
||||
|
||||
/**
|
||||
* Resolved [NpmProject]
|
||||
*/
|
||||
class KotlinCompilationNpmResolution(
|
||||
@Transient
|
||||
private val _project: Project?,
|
||||
val npmProject: NpmProject,
|
||||
val internalCompositeDependencies: Collection<GradleNodeModule>,
|
||||
val externalGradleDependencies: Collection<GradleNodeModule>,
|
||||
private val _externalNpmDependencies: Collection<NpmDependencyDeclaration>,
|
||||
val packageJson: PackageJson
|
||||
) : Serializable {
|
||||
val project
|
||||
get() = _project!!
|
||||
|
||||
val externalNpmDependencies
|
||||
get() = _externalNpmDependencies
|
||||
.map {
|
||||
NpmDependency(
|
||||
project = _project,
|
||||
name = it.name,
|
||||
version = it.version,
|
||||
scope = it.scope,
|
||||
)
|
||||
}
|
||||
}
|
||||
+7
-22
@@ -5,35 +5,20 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle.targets.js.npm.resolved
|
||||
|
||||
import org.jetbrains.kotlin.gradle.targets.js.RequiredKotlinJsDependency
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmDependency
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.resolver.KotlinCompilationNpmResolution
|
||||
import java.io.Serializable
|
||||
|
||||
/**
|
||||
* Info about NPM projects inside particular gradle [project].
|
||||
*/
|
||||
class KotlinProjectNpmResolution(
|
||||
val project: String,
|
||||
val npmProjects: List<KotlinCompilationNpmResolution>,
|
||||
val taskRequirements: Map<String, Collection<RequiredKotlinJsDependency>>
|
||||
) {
|
||||
val npmProjectsByNpmDependency: Map<NpmDependency, KotlinCompilationNpmResolution> by lazy {
|
||||
mutableMapOf<NpmDependency, KotlinCompilationNpmResolution>().also { result ->
|
||||
npmProjects.forEach { npmPackage ->
|
||||
npmPackage.externalNpmDependencies.forEach { npmDependency ->
|
||||
result[npmDependency] = npmPackage
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val byCompilation by lazy { npmProjects.associateBy { it.npmProject.compilationName } }
|
||||
val byCompilation: Map<String, KotlinCompilationNpmResolution>,
|
||||
) : Serializable {
|
||||
val npmProjects: Collection<KotlinCompilationNpmResolution>
|
||||
get() = byCompilation.values
|
||||
|
||||
operator fun get(compilationName: String): KotlinCompilationNpmResolution {
|
||||
// check(compilation.target.project.path == project)
|
||||
return byCompilation.getValue(compilationName)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun empty(project: String) = KotlinProjectNpmResolution(project, listOf(), mapOf())
|
||||
fun empty() = KotlinProjectNpmResolution(emptyMap())
|
||||
}
|
||||
}
|
||||
+64
-6
@@ -5,11 +5,69 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle.targets.js.npm.resolved
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.logging.Logger
|
||||
import org.gradle.internal.service.ServiceRegistry
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.KotlinNpmResolutionManager
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmEnvironment
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.YarnEnvironment
|
||||
import org.jetbrains.kotlin.gradle.targets.js.yarn.toVersionString
|
||||
import java.io.Serializable
|
||||
|
||||
internal class KotlinRootNpmResolution(
|
||||
val rootProject: Project?,
|
||||
internal val projects: Map<String, KotlinProjectNpmResolution>
|
||||
) {
|
||||
operator fun get(project: String) = projects[project] ?: KotlinProjectNpmResolution.empty(project)
|
||||
class KotlinRootNpmResolution(
|
||||
val projects: Map<String, KotlinProjectNpmResolution>,
|
||||
val rootProjectName: String,
|
||||
val rootProjectVersion: String
|
||||
) : Serializable {
|
||||
operator fun get(project: String) = projects[project] ?: KotlinProjectNpmResolution.empty()
|
||||
|
||||
/**
|
||||
* Don't use directly, use [KotlinNpmResolutionManager.installIfNeeded] instead.
|
||||
*/
|
||||
internal fun prepareInstallation(
|
||||
logger: Logger,
|
||||
npmEnvironment: NpmEnvironment,
|
||||
yarnEnvironment: YarnEnvironment,
|
||||
npmResolutionManager: KotlinNpmResolutionManager
|
||||
): Installation {
|
||||
synchronized(projects) {
|
||||
npmResolutionManager.parameters.gradleNodeModulesProvider.get().close()
|
||||
npmResolutionManager.parameters.compositeNodeModulesProvider.get().close()
|
||||
|
||||
val projectResolutions: List<PreparedKotlinCompilationNpmResolution> = projects.values.flatMap { it.npmProjects }.map { it.close(npmResolutionManager, logger) }
|
||||
npmEnvironment.packageManager.prepareRootProject(
|
||||
npmEnvironment,
|
||||
rootProjectName,
|
||||
rootProjectVersion,
|
||||
logger,
|
||||
projectResolutions,
|
||||
yarnEnvironment.yarnResolutions
|
||||
.associate { it.path to it.toVersionString() },
|
||||
)
|
||||
|
||||
return Installation(
|
||||
projectResolutions
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Installation(val compilationResolutions: Collection<PreparedKotlinCompilationNpmResolution>) {
|
||||
internal fun install(
|
||||
args: List<String>,
|
||||
services: ServiceRegistry,
|
||||
logger: Logger,
|
||||
npmEnvironment: NpmEnvironment,
|
||||
yarnEnvironment: YarnEnvironment,
|
||||
) {
|
||||
synchronized(compilationResolutions) {
|
||||
npmEnvironment.packageManager.resolveRootProject(
|
||||
services,
|
||||
logger,
|
||||
npmEnvironment,
|
||||
yarnEnvironment,
|
||||
compilationResolutions,
|
||||
args
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.resolved
|
||||
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.*
|
||||
import java.io.File
|
||||
import java.io.Serializable
|
||||
|
||||
/**
|
||||
* Resolved [NpmProject]
|
||||
*/
|
||||
class PreparedKotlinCompilationNpmResolution(
|
||||
val npmProjectDir: File,
|
||||
val internalCompositeDependencies: Collection<GradleNodeModule>,
|
||||
val externalGradleDependencies: Collection<GradleNodeModule>,
|
||||
val externalNpmDependencies: Collection<NpmDependencyDeclaration>,
|
||||
) : Serializable
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.resolver
|
||||
|
||||
import org.gradle.api.artifacts.ResolvedArtifact
|
||||
import org.gradle.api.artifacts.ResolvedDependency
|
||||
import org.gradle.api.initialization.IncludedBuild
|
||||
import java.io.File
|
||||
import java.io.Serializable
|
||||
|
||||
data class ExternalGradleDependency(
|
||||
val dependency: ResolvedDependency,
|
||||
val artifact: ResolvedArtifact
|
||||
) : Serializable
|
||||
|
||||
data class FileCollectionExternalGradleDependency(
|
||||
val files: Collection<File>,
|
||||
val dependencyVersion: String?
|
||||
) : Serializable
|
||||
|
||||
data class FileExternalGradleDependency(
|
||||
val dependencyName: String,
|
||||
val dependencyVersion: String,
|
||||
val file: File
|
||||
) : Serializable
|
||||
|
||||
data class CompositeDependency(
|
||||
val dependencyName: String,
|
||||
val dependencyVersion: String,
|
||||
val includedBuildDir: File,
|
||||
@Transient
|
||||
val includedBuild: IncludedBuild?
|
||||
) : Serializable
|
||||
|
||||
data class InternalDependency(
|
||||
val projectPath: String,
|
||||
val compilationName: String,
|
||||
val projectName: String
|
||||
) : Serializable
|
||||
+201
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.resolver
|
||||
|
||||
import org.gradle.api.logging.Logger
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.TasksRequirements
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.*
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProject.Companion.PACKAGE_JSON
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.PreparedKotlinCompilationNpmResolution
|
||||
import java.io.Serializable
|
||||
import java.io.File
|
||||
|
||||
class KotlinCompilationNpmResolution(
|
||||
var internalDependencies: Collection<InternalDependency>,
|
||||
var internalCompositeDependencies: Collection<CompositeDependency>,
|
||||
var externalGradleDependencies: Collection<FileExternalGradleDependency>,
|
||||
var externalNpmDependencies: Collection<NpmDependencyDeclaration>,
|
||||
var fileCollectionDependencies: Collection<FileCollectionExternalGradleDependency>,
|
||||
val projectPath: String,
|
||||
val projectPackagesDir: File,
|
||||
val rootDir: File,
|
||||
val compilationDisambiguatedName: String,
|
||||
val npmProjectName: String,
|
||||
val npmProjectVersion: String,
|
||||
val npmProjectMain: String,
|
||||
val npmProjectPackageJsonFile: File,
|
||||
val npmProjectDir: File,
|
||||
val tasksRequirements: TasksRequirements
|
||||
) : Serializable {
|
||||
|
||||
val inputs: PackageJsonProducerInputs
|
||||
get() = PackageJsonProducerInputs(
|
||||
internalDependencies.map { it.projectName },
|
||||
internalCompositeDependencies.flatMap { it.getPackages() },
|
||||
externalGradleDependencies.map { it.file },
|
||||
externalNpmDependencies.map { it.uniqueRepresentation() },
|
||||
fileCollectionDependencies.flatMap { it.files }
|
||||
)
|
||||
|
||||
private var closed = false
|
||||
private var resolution: PreparedKotlinCompilationNpmResolution? = null
|
||||
|
||||
@Synchronized
|
||||
fun resolve(
|
||||
skipWriting: Boolean = false,
|
||||
npmResolutionManager: KotlinNpmResolutionManager,
|
||||
logger: Logger
|
||||
): PreparedKotlinCompilationNpmResolution {
|
||||
check(resolution == null) { "$this already resolved" }
|
||||
|
||||
return createPackageJson(
|
||||
skipWriting,
|
||||
npmResolutionManager,
|
||||
logger
|
||||
).also {
|
||||
resolution = it
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun getResolutionOrResolve(
|
||||
npmResolutionManager: KotlinNpmResolutionManager,
|
||||
logger: Logger,
|
||||
): PreparedKotlinCompilationNpmResolution {
|
||||
|
||||
return resolution ?: resolve(
|
||||
skipWriting = true,
|
||||
npmResolutionManager,
|
||||
logger
|
||||
)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun close(
|
||||
npmResolutionManager: KotlinNpmResolutionManager,
|
||||
logger: Logger,
|
||||
): PreparedKotlinCompilationNpmResolution {
|
||||
check(!closed) { "$this already closed" }
|
||||
closed = true
|
||||
return getResolutionOrResolve(npmResolutionManager, logger)
|
||||
}
|
||||
|
||||
fun createPackageJson(
|
||||
skipWriting: Boolean,
|
||||
npmResolutionManager: KotlinNpmResolutionManager,
|
||||
logger: Logger
|
||||
): PreparedKotlinCompilationNpmResolution {
|
||||
val rootResolver = npmResolutionManager.parameters.resolution.get()
|
||||
|
||||
internalDependencies.map {
|
||||
val compilationNpmResolution: KotlinCompilationNpmResolution = rootResolver[it.projectPath][it.compilationName]
|
||||
compilationNpmResolution.getResolutionOrResolve(
|
||||
npmResolutionManager,
|
||||
logger
|
||||
)
|
||||
}
|
||||
val importedExternalGradleDependencies = externalGradleDependencies.mapNotNull {
|
||||
npmResolutionManager.parameters.gradleNodeModulesProvider.get().get(it.dependencyName, it.dependencyVersion, it.file)
|
||||
} + fileCollectionDependencies.flatMap { dependency ->
|
||||
dependency.files
|
||||
// Gradle can hash with FileHasher only files and only existed files
|
||||
.filter { it.isFile }
|
||||
.map { file ->
|
||||
npmResolutionManager.parameters.gradleNodeModulesProvider.get().get(
|
||||
file.name,
|
||||
dependency.dependencyVersion ?: "0.0.1",
|
||||
file
|
||||
)
|
||||
}
|
||||
}.filterNotNull()
|
||||
val transitiveNpmDependencies = importedExternalGradleDependencies.flatMap {
|
||||
it.dependencies
|
||||
}.filter { it.scope != NpmDependency.Scope.DEV }
|
||||
|
||||
val compositeDependencies = internalCompositeDependencies.flatMap { dependency ->
|
||||
dependency.getPackages()
|
||||
.map { file ->
|
||||
npmResolutionManager.parameters.compositeNodeModulesProvider.get().get(
|
||||
dependency.dependencyName,
|
||||
dependency.dependencyVersion,
|
||||
file
|
||||
)
|
||||
}
|
||||
}.filterNotNull()
|
||||
|
||||
val toolsNpmDependencies = tasksRequirements
|
||||
.getCompilationNpmRequirements(projectPath, compilationDisambiguatedName)
|
||||
|
||||
val otherNpmDependencies = toolsNpmDependencies + transitiveNpmDependencies
|
||||
val allNpmDependencies = disambiguateDependencies(externalNpmDependencies, otherNpmDependencies, logger)
|
||||
val packageJsonHandlers =
|
||||
npmResolutionManager.parameters.packageJsonHandlers.get()["$projectPath:${compilationDisambiguatedName}"]
|
||||
?: emptyList()
|
||||
|
||||
val packageJson = packageJson(
|
||||
npmProjectName,
|
||||
npmProjectVersion,
|
||||
npmProjectMain,
|
||||
allNpmDependencies,
|
||||
packageJsonHandlers
|
||||
)
|
||||
|
||||
compositeDependencies.forEach {
|
||||
packageJson.dependencies[it.name] = it.version
|
||||
}
|
||||
|
||||
packageJsonHandlers.forEach {
|
||||
it(packageJson)
|
||||
}
|
||||
|
||||
if (!skipWriting) {
|
||||
packageJson.saveTo(npmProjectPackageJsonFile)
|
||||
}
|
||||
|
||||
return PreparedKotlinCompilationNpmResolution(
|
||||
npmProjectDir,
|
||||
compositeDependencies,
|
||||
importedExternalGradleDependencies,
|
||||
allNpmDependencies,
|
||||
)
|
||||
}
|
||||
|
||||
private fun disambiguateDependencies(
|
||||
direct: Collection<NpmDependencyDeclaration>,
|
||||
others: Collection<NpmDependencyDeclaration>,
|
||||
logger: Logger,
|
||||
): Collection<NpmDependencyDeclaration> {
|
||||
val unique = others.groupBy(NpmDependencyDeclaration::name)
|
||||
.filterKeys { k -> direct.none { it.name == k } }
|
||||
.mapNotNull { (name, dependencies) ->
|
||||
dependencies.maxByOrNull { dep ->
|
||||
SemVer.from(dep.version, true)
|
||||
}?.also { selected ->
|
||||
if (dependencies.size > 1) {
|
||||
logger.warn(
|
||||
"""
|
||||
Transitive npm dependency version clash for compilation "${compilationDisambiguatedName}"
|
||||
Candidates:
|
||||
${dependencies.joinToString("\n") { "\t\t" + it.name + "@" + it.version }}
|
||||
Selected:
|
||||
${selected.name}@${selected.version}
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
return direct + unique
|
||||
}
|
||||
|
||||
internal fun CompositeDependency.getPackages(): List<File> {
|
||||
val packages = includedBuildDir.resolve(projectPackagesDir.relativeTo(rootDir))
|
||||
return packages
|
||||
.list()
|
||||
?.map { packages.resolve(it) }
|
||||
?.map { it.resolve(PACKAGE_JSON) }
|
||||
?: emptyList()
|
||||
}
|
||||
}
|
||||
+48
-268
@@ -12,12 +12,9 @@ import org.gradle.api.artifacts.ResolvedDependency
|
||||
import org.gradle.api.artifacts.component.ProjectComponentIdentifier
|
||||
import org.gradle.api.attributes.Category
|
||||
import org.gradle.api.attributes.Usage
|
||||
import org.gradle.api.initialization.IncludedBuild
|
||||
import org.gradle.api.internal.artifacts.DefaultProjectComponentIdentifier
|
||||
import org.gradle.api.tasks.*
|
||||
import org.gradle.api.tasks.TaskProvider
|
||||
import org.gradle.api.tasks.bundling.Zip
|
||||
import org.gradle.configurationcache.extensions.serviceOf
|
||||
import org.gradle.work.NormalizeLineEndings
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
|
||||
import org.jetbrains.kotlin.gradle.plugin.categoryByName
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
|
||||
@@ -28,29 +25,24 @@ import org.jetbrains.kotlin.gradle.plugin.sources.KotlinDependencyScope
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.compilationDependencyConfigurationByScope
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.sourceSetDependencyConfigurationByScope
|
||||
import org.jetbrains.kotlin.gradle.plugin.usesPlatformOf
|
||||
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrCompilation
|
||||
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTarget
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin.Companion.kotlinNpmResolutionManager
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.*
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProject.Companion.PACKAGE_JSON
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinCompilationNpmResolution
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.KotlinPackageJsonTask
|
||||
import org.jetbrains.kotlin.gradle.tasks.registerTask
|
||||
import org.jetbrains.kotlin.gradle.utils.CompositeProjectComponentArtifactMetadata
|
||||
import org.jetbrains.kotlin.gradle.utils.`is`
|
||||
import org.jetbrains.kotlin.gradle.utils.topRealPath
|
||||
import org.jetbrains.kotlin.gradle.utils.unavailableValueError
|
||||
import java.io.File
|
||||
import java.io.Serializable
|
||||
|
||||
/**
|
||||
* See [KotlinNpmResolutionManager] for details about resolution process.
|
||||
*/
|
||||
internal class KotlinCompilationNpmResolver(
|
||||
@Transient
|
||||
class KotlinCompilationNpmResolver(
|
||||
val projectResolver: KotlinProjectNpmResolver,
|
||||
@Transient
|
||||
val compilation: KotlinJsCompilation
|
||||
) : Serializable {
|
||||
@Transient
|
||||
var rootResolver = projectResolver.resolver
|
||||
|
||||
val npmProject = compilation.npmProject
|
||||
@@ -61,26 +53,32 @@ internal class KotlinCompilationNpmResolver(
|
||||
project.version.toString()
|
||||
}
|
||||
|
||||
val nodeJs get() = rootResolver.nodeJs
|
||||
private val nodeJs_ get() = nodeJs ?: unavailableValueError("nodeJs")
|
||||
|
||||
val target get() = compilation.target
|
||||
|
||||
val project get() = target.project
|
||||
|
||||
val projectPath = project.path
|
||||
val projectPath: String = project.path
|
||||
|
||||
@Transient
|
||||
val packageJsonTaskHolder: TaskProvider<KotlinPackageJsonTask>? =
|
||||
val packageJsonTaskHolder: TaskProvider<KotlinPackageJsonTask> =
|
||||
KotlinPackageJsonTask.create(compilation)
|
||||
|
||||
@Transient
|
||||
val publicPackageJsonTaskHolder: TaskProvider<PublicPackageJsonTask> =
|
||||
val publicPackageJsonTaskHolder: TaskProvider<PublicPackageJsonTask> = run {
|
||||
val npmResolutionManager = project.kotlinNpmResolutionManager
|
||||
project.registerTask<PublicPackageJsonTask>(
|
||||
npmProject.publicPackageJsonTaskName,
|
||||
listOf(compilation)
|
||||
npmProject.publicPackageJsonTaskName
|
||||
) {
|
||||
it.dependsOn(packageJsonTaskHolder)
|
||||
|
||||
it.compilationDisambiguatedName.set(compilation.disambiguatedName)
|
||||
|
||||
it.npmResolutionManager.apply {
|
||||
set(npmResolutionManager)
|
||||
disallowChanges()
|
||||
}
|
||||
|
||||
it.jsIrCompilation.set(compilation is KotlinJsIrCompilation)
|
||||
it.npmProjectName.set(npmProject.name)
|
||||
it.npmProjectMain.set(npmProject.main)
|
||||
}.also { packageJsonTask ->
|
||||
if (compilation.isMain()) {
|
||||
project.tasks
|
||||
@@ -91,66 +89,29 @@ internal class KotlinCompilationNpmResolver(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String = "KotlinCompilationNpmResolver(${npmProject.name})"
|
||||
|
||||
@delegate:Transient
|
||||
private val aggregatedConfiguration: Configuration by lazy {
|
||||
createAggregatedConfiguration()
|
||||
}
|
||||
private var _compilationNpmResolution: KotlinCompilationNpmResolution? = null
|
||||
|
||||
private val packageJsonProducer_: PackageJsonProducer by lazy {
|
||||
val visitor = ConfigurationVisitor()
|
||||
visitor.visit(aggregatedConfiguration)
|
||||
visitor.toPackageJsonProducer().also { it.compilationResolver = this }
|
||||
}
|
||||
|
||||
val packageJsonProducer: PackageJsonProducer
|
||||
val compilationNpmResolution: KotlinCompilationNpmResolution
|
||||
get() {
|
||||
val packageJsonProducer = packageJsonProducer_
|
||||
packageJsonProducer.compilationResolver = this
|
||||
return packageJsonProducer
|
||||
return _compilationNpmResolution ?: run {
|
||||
val visitor = ConfigurationVisitor()
|
||||
visitor.visit(createAggregatedConfiguration())
|
||||
visitor.toPackageJsonProducer()
|
||||
}.also {
|
||||
_compilationNpmResolution = it
|
||||
}
|
||||
}
|
||||
|
||||
private var closed = false
|
||||
private var resolution: KotlinCompilationNpmResolution? = null
|
||||
|
||||
@Synchronized
|
||||
fun resolve(skipWriting: Boolean = false): KotlinCompilationNpmResolution {
|
||||
check(!closed) { "$this already closed" }
|
||||
check(resolution == null) { "$this already resolved" }
|
||||
|
||||
return packageJsonProducer.createPackageJson(skipWriting).also {
|
||||
resolution = it
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun getResolutionOrResolveIfForced(): KotlinCompilationNpmResolution? {
|
||||
if (resolution != null) return resolution
|
||||
if (rootResolver.mayBeUpToDateTasksRegistry.get().shouldResolveNpmDependenciesFor(npmProject.packageJsonTaskPath)) {
|
||||
// when we need to resolve the compilation but the task is UP-TO-DATE, so we don't have ready resolution yet
|
||||
return resolve(skipWriting = true)
|
||||
}
|
||||
if (rootResolver.forceFullResolve) {
|
||||
// need to force all NPM tasks to be configured in IDEA import
|
||||
rootResolver.gradleNodeModules.fileHasher = project.serviceOf()
|
||||
rootResolver.compositeNodeModules.fileHasher = project.serviceOf()
|
||||
project.tasks.implementing(RequiresNpmDependencies::class).all {}
|
||||
return resolve()
|
||||
}
|
||||
return null // we don't need to resolve NPM dependencies for the compilation
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun close(): KotlinCompilationNpmResolution? {
|
||||
check(!closed) { "$this already closed" }
|
||||
val resolution = getResolutionOrResolveIfForced()
|
||||
closed = true
|
||||
return resolution
|
||||
return _compilationNpmResolution
|
||||
}
|
||||
|
||||
private fun createAggregatedConfiguration(): Configuration {
|
||||
fun createAggregatedConfiguration(): Configuration {
|
||||
val all = project.configurations.create(compilation.disambiguateName("npm"))
|
||||
|
||||
all.usesPlatformOf(target)
|
||||
@@ -174,46 +135,16 @@ internal class KotlinCompilationNpmResolver(
|
||||
}
|
||||
|
||||
// We don't have `kotlin-js-test-runner` in NPM yet
|
||||
all.dependencies.add(nodeJs_.versions.kotlinJsTestRunner.createDependency(project))
|
||||
all.dependencies.add(rootResolver.versions.kotlinJsTestRunner.createDependency(project))
|
||||
|
||||
return all
|
||||
}
|
||||
|
||||
data class ExternalGradleDependency(
|
||||
val dependency: ResolvedDependency,
|
||||
val artifact: ResolvedArtifact
|
||||
) : Serializable
|
||||
|
||||
data class FileCollectionExternalGradleDependency(
|
||||
val files: Collection<File>,
|
||||
val dependencyVersion: String?
|
||||
) : Serializable
|
||||
|
||||
data class FileExternalGradleDependency(
|
||||
val dependencyName: String,
|
||||
val dependencyVersion: String,
|
||||
val file: File
|
||||
) : Serializable
|
||||
|
||||
data class CompositeDependency(
|
||||
val dependencyName: String,
|
||||
val dependencyVersion: String,
|
||||
val includedBuildDir: File,
|
||||
@Transient
|
||||
val includedBuild: IncludedBuild?
|
||||
) : Serializable
|
||||
|
||||
data class InternalDependency(
|
||||
val projectPath: String,
|
||||
val compilationName: String,
|
||||
val projectName: String
|
||||
) : Serializable
|
||||
|
||||
inner class ConfigurationVisitor {
|
||||
private val internalDependencies = mutableSetOf<InternalDependency>()
|
||||
private val internalCompositeDependencies = mutableSetOf<CompositeDependency>()
|
||||
private val externalGradleDependencies = mutableSetOf<ExternalGradleDependency>()
|
||||
private val externalNpmDependencies = mutableSetOf<NpmDependency>()
|
||||
private val externalNpmDependencies = mutableSetOf<NpmDependencyDeclaration>()
|
||||
private val fileCollectionDependencies = mutableSetOf<FileCollectionExternalGradleDependency>()
|
||||
|
||||
private val visitedDependencies = mutableSetOf<ResolvedDependency>()
|
||||
@@ -225,7 +156,7 @@ internal class KotlinCompilationNpmResolver(
|
||||
|
||||
configuration.allDependencies.forEach { dependency ->
|
||||
when (dependency) {
|
||||
is NpmDependency -> externalNpmDependencies.add(dependency)
|
||||
is NpmDependency -> externalNpmDependencies.add(dependency.toDeclaration())
|
||||
is FileCollectionDependency -> fileCollectionDependencies.add(
|
||||
FileCollectionExternalGradleDependency(
|
||||
dependency.files.files,
|
||||
@@ -240,7 +171,7 @@ internal class KotlinCompilationNpmResolver(
|
||||
val main = compilation.target.compilations.findByName(KotlinCompilation.MAIN_COMPILATION_NAME) as KotlinJsCompilation
|
||||
internalDependencies.add(
|
||||
InternalDependency(
|
||||
projectResolver.project.path,
|
||||
projectResolver.projectPath,
|
||||
main.disambiguatedName,
|
||||
projectResolver[main].npmProject.name
|
||||
)
|
||||
@@ -336,7 +267,7 @@ internal class KotlinCompilationNpmResolver(
|
||||
}
|
||||
}
|
||||
|
||||
fun toPackageJsonProducer() = PackageJsonProducer(
|
||||
fun toPackageJsonProducer() = KotlinCompilationNpmResolution(
|
||||
internalDependencies,
|
||||
internalCompositeDependencies,
|
||||
externalGradleDependencies.map {
|
||||
@@ -346,169 +277,18 @@ internal class KotlinCompilationNpmResolver(
|
||||
it.artifact.file
|
||||
)
|
||||
},
|
||||
externalNpmDependencies.map { it.toDeclaration() },
|
||||
externalNpmDependencies,
|
||||
fileCollectionDependencies,
|
||||
projectPath
|
||||
projectPath,
|
||||
rootResolver.projectPackagesDir,
|
||||
rootResolver.rootProjectDir,
|
||||
compilationDisambiguatedName,
|
||||
npmProject.name,
|
||||
npmVersion,
|
||||
npmProject.main,
|
||||
npmProject.packageJsonFile,
|
||||
npmProject.dir,
|
||||
rootResolver.tasksRequirements
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
class PackageJsonProducerInputs(
|
||||
@get:Input
|
||||
val internalDependencies: Collection<String>,
|
||||
|
||||
@get:PathSensitive(PathSensitivity.ABSOLUTE)
|
||||
@get:IgnoreEmptyDirectories
|
||||
@get:NormalizeLineEndings
|
||||
@get:InputFiles
|
||||
val internalCompositeDependencies: Collection<File>,
|
||||
|
||||
@get:PathSensitive(PathSensitivity.ABSOLUTE)
|
||||
@get:IgnoreEmptyDirectories
|
||||
@get:NormalizeLineEndings
|
||||
@get:InputFiles
|
||||
val externalGradleDependencies: Collection<File>,
|
||||
|
||||
@get:Input
|
||||
val externalDependencies: Collection<String>,
|
||||
|
||||
@get:Input
|
||||
val fileCollectionDependencies: Collection<File>
|
||||
)
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
class PackageJsonProducer(
|
||||
var internalDependencies: Collection<InternalDependency>,
|
||||
var internalCompositeDependencies: Collection<CompositeDependency>,
|
||||
var externalGradleDependencies: Collection<FileExternalGradleDependency>,
|
||||
var externalNpmDependencies: Collection<NpmDependencyDeclaration>,
|
||||
var fileCollectionDependencies: Collection<FileCollectionExternalGradleDependency>,
|
||||
val projectPath: String
|
||||
) : Serializable {
|
||||
private val projectPackagesDir by lazy { compilationResolver.nodeJs_.projectPackagesDir }
|
||||
private val rootDir by lazy { compilationResolver.nodeJs_.rootProject.rootDir }
|
||||
|
||||
@Transient
|
||||
internal lateinit var compilationResolver: KotlinCompilationNpmResolver
|
||||
|
||||
val inputs: PackageJsonProducerInputs
|
||||
get() = PackageJsonProducerInputs(
|
||||
internalDependencies.map { it.projectName },
|
||||
internalCompositeDependencies.flatMap { it.getPackages() },
|
||||
externalGradleDependencies.map { it.file },
|
||||
externalNpmDependencies.map { it.uniqueRepresentation() },
|
||||
fileCollectionDependencies.flatMap { it.files }
|
||||
)
|
||||
|
||||
fun createPackageJson(skipWriting: Boolean): KotlinCompilationNpmResolution {
|
||||
internalDependencies.map {
|
||||
compilationResolver.rootResolver[it.projectPath][it.compilationName].getResolutionOrResolveIfForced()
|
||||
?: error("Unresolved dependent npm package: ${compilationResolver} -> $it")
|
||||
}
|
||||
val importedExternalGradleDependencies = externalGradleDependencies.mapNotNull {
|
||||
compilationResolver.rootResolver.gradleNodeModules.get(it.dependencyName, it.dependencyVersion, it.file)
|
||||
} + fileCollectionDependencies.flatMap { dependency ->
|
||||
dependency.files
|
||||
// Gradle can hash with FileHasher only files and only existed files
|
||||
.filter { it.isFile }
|
||||
.map { file ->
|
||||
compilationResolver.rootResolver.gradleNodeModules.get(
|
||||
file.name,
|
||||
dependency.dependencyVersion ?: "0.0.1",
|
||||
file
|
||||
)
|
||||
}
|
||||
}.filterNotNull()
|
||||
val transitiveNpmDependencies = importedExternalGradleDependencies.flatMap {
|
||||
it.dependencies
|
||||
}.filter { it.scope != NpmDependency.Scope.DEV }
|
||||
|
||||
val compositeDependencies = internalCompositeDependencies.flatMap { dependency ->
|
||||
dependency.getPackages()
|
||||
.map { file ->
|
||||
compilationResolver.rootResolver.compositeNodeModules.get(
|
||||
dependency.dependencyName,
|
||||
dependency.dependencyVersion,
|
||||
file
|
||||
)
|
||||
}
|
||||
}.filterNotNull()
|
||||
|
||||
val toolsNpmDependencies = compilationResolver.rootResolver.taskRequirements
|
||||
.getCompilationNpmRequirements(projectPath, compilationResolver.compilationDisambiguatedName)
|
||||
|
||||
val otherNpmDependencies = toolsNpmDependencies + transitiveNpmDependencies
|
||||
val allNpmDependencies = disambiguateDependencies(externalNpmDependencies, otherNpmDependencies)
|
||||
val packageJsonHandlers = if (compilationResolver.compilation != null) {
|
||||
compilationResolver.compilation.packageJsonHandlers
|
||||
} else {
|
||||
compilationResolver.rootResolver.getPackageJsonHandlers(projectPath, compilationResolver.compilationDisambiguatedName)
|
||||
}
|
||||
|
||||
val packageJson = packageJson(
|
||||
compilationResolver.npmProject.name,
|
||||
compilationResolver.npmVersion,
|
||||
compilationResolver.npmProject.main,
|
||||
allNpmDependencies,
|
||||
packageJsonHandlers
|
||||
)
|
||||
|
||||
compositeDependencies.forEach {
|
||||
packageJson.dependencies[it.name] = it.version
|
||||
}
|
||||
|
||||
packageJsonHandlers.forEach {
|
||||
it(packageJson)
|
||||
}
|
||||
|
||||
if (!skipWriting) {
|
||||
packageJson.saveTo(compilationResolver.npmProject.packageJsonFile)
|
||||
}
|
||||
|
||||
return KotlinCompilationNpmResolution(
|
||||
@Suppress("SENSELESS_COMPARISON")
|
||||
if (compilationResolver.compilation != null) compilationResolver.project else null,
|
||||
compilationResolver.npmProject,
|
||||
compositeDependencies,
|
||||
importedExternalGradleDependencies,
|
||||
allNpmDependencies,
|
||||
packageJson
|
||||
)
|
||||
}
|
||||
|
||||
private fun disambiguateDependencies(
|
||||
direct: Collection<NpmDependencyDeclaration>,
|
||||
others: Collection<NpmDependencyDeclaration>,
|
||||
): Collection<NpmDependencyDeclaration> {
|
||||
val unique = others.groupBy(NpmDependencyDeclaration::name)
|
||||
.filterKeys { k -> direct.none { it.name == k } }
|
||||
.mapNotNull { (name, dependencies) ->
|
||||
dependencies.maxByOrNull { dep ->
|
||||
SemVer.from(dep.version, true)
|
||||
}?.also { selected ->
|
||||
if (dependencies.size > 1) {
|
||||
compilationResolver.project.logger.warn(
|
||||
"""
|
||||
Transitive npm dependency version clash for compilation "${compilationResolver.compilation.name}"
|
||||
Candidates:
|
||||
${dependencies.joinToString("\n") { "\t\t" + it.name + "@" + it.version }}
|
||||
Selected:
|
||||
${selected.name}@${selected.version}
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
return direct + unique
|
||||
}
|
||||
|
||||
private fun CompositeDependency.getPackages(): List<File> {
|
||||
val packages = includedBuildDir.resolve(projectPackagesDir.relativeTo(rootDir))
|
||||
return packages
|
||||
.list()
|
||||
?.map { packages.resolve(it) }
|
||||
?.map { it.resolve(PACKAGE_JSON) }
|
||||
?: emptyList()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+24
-48
@@ -14,32 +14,24 @@ 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.plugin.whenEvaluated
|
||||
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsTarget
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.RequiresNpmDependencies
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.KotlinNpmResolutionManager
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinProjectNpmResolution
|
||||
import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest
|
||||
import org.jetbrains.kotlin.gradle.utils.unavailableValueError
|
||||
import java.io.Serializable
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* See [KotlinNpmResolutionManager] for details about resolution process.
|
||||
*/
|
||||
internal class KotlinProjectNpmResolver(
|
||||
@Transient
|
||||
val project: Project,
|
||||
@Transient
|
||||
class KotlinProjectNpmResolver(
|
||||
project: Project,
|
||||
var resolver: KotlinRootNpmResolver
|
||||
) : Serializable {
|
||||
override fun toString(): String = "ProjectNpmResolver($project)"
|
||||
|
||||
private val projectPath by lazy { project.path }
|
||||
val projectPath by lazy { project.path }
|
||||
|
||||
private val byCompilation = mutableMapOf<String, KotlinCompilationNpmResolver>()
|
||||
|
||||
operator fun get(compilation: KotlinJsCompilation): KotlinCompilationNpmResolver {
|
||||
check(compilation.target.project == project)
|
||||
return byCompilation[compilation.disambiguatedName] ?: error("$compilation was not registered in $this")
|
||||
}
|
||||
|
||||
@@ -47,38 +39,17 @@ internal class KotlinProjectNpmResolver(
|
||||
return byCompilation[compilationName] ?: error("$compilationName was not registered in $this")
|
||||
}
|
||||
|
||||
private var closed = false
|
||||
private var resolution: KotlinProjectNpmResolution? = null
|
||||
|
||||
val compilationResolvers: Collection<KotlinCompilationNpmResolver>
|
||||
get() = byCompilation.values
|
||||
|
||||
init {
|
||||
addContainerListeners()
|
||||
|
||||
project.whenEvaluated {
|
||||
val nodeJs = resolver.nodeJs ?: unavailableValueError("resolver.nodeJs")
|
||||
project.tasks.implementing(RequiresNpmDependencies::class)
|
||||
.configureEach { task ->
|
||||
if (task.enabled) {
|
||||
task as RequiresNpmDependencies
|
||||
// KotlinJsTest delegates npm dependencies to testFramework,
|
||||
// which can be defined after this configure action
|
||||
val packageJsonTaskHolder = get(task.compilation).packageJsonTaskHolder
|
||||
if (task !is KotlinJsTest) {
|
||||
nodeJs.taskRequirements.addTaskRequirements(task)
|
||||
}
|
||||
task.dependsOn(packageJsonTaskHolder)
|
||||
task.dependsOn(
|
||||
nodeJs.npmInstallTaskProvider,
|
||||
nodeJs.storeYarnLockTaskProvider,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
project.addContainerListeners()
|
||||
}
|
||||
|
||||
private fun addContainerListeners() {
|
||||
val kotlin = project.kotlinExtensionOrNull
|
||||
private fun Project.addContainerListeners() {
|
||||
val kotlin = kotlinExtensionOrNull
|
||||
?: error("NpmResolverPlugin should be applied after kotlin plugin")
|
||||
|
||||
when (kotlin) {
|
||||
@@ -91,10 +62,11 @@ internal class KotlinProjectNpmResolver(
|
||||
}
|
||||
|
||||
private fun addTargetListeners(target: KotlinTarget) {
|
||||
check(!closed) { resolver.alreadyResolvedMessage("add target $target") }
|
||||
check(resolution == null) { resolver.alreadyResolvedMessage("add target $target") }
|
||||
|
||||
if (target.platformType == KotlinPlatformType.js ||
|
||||
target.platformType == KotlinPlatformType.wasm) {
|
||||
target.platformType == KotlinPlatformType.wasm
|
||||
) {
|
||||
target.compilations.all { compilation ->
|
||||
if (compilation is KotlinJsCompilation) {
|
||||
// compilation may be KotlinWithJavaTarget for old Kotlin2JsPlugin
|
||||
@@ -115,19 +87,23 @@ internal class KotlinProjectNpmResolver(
|
||||
|
||||
@Synchronized
|
||||
private fun addCompilation(compilation: KotlinJsCompilation) {
|
||||
check(!closed) { resolver.alreadyResolvedMessage("add compilation $compilation") }
|
||||
check(resolution == null) { resolver.alreadyResolvedMessage("add compilation $compilation") }
|
||||
|
||||
byCompilation[compilation.disambiguatedName] = KotlinCompilationNpmResolver(this, compilation)
|
||||
byCompilation[compilation.disambiguatedName] =
|
||||
KotlinCompilationNpmResolver(
|
||||
this,
|
||||
compilation
|
||||
)
|
||||
}
|
||||
|
||||
fun close(): KotlinProjectNpmResolution {
|
||||
check(!closed)
|
||||
closed = true
|
||||
|
||||
return KotlinProjectNpmResolution(
|
||||
projectPath,
|
||||
byCompilation.values.mapNotNull { it.close() },
|
||||
resolver.taskRequirements.byTask
|
||||
return resolution ?: KotlinProjectNpmResolution(
|
||||
byCompilation
|
||||
.map { (key, value) ->
|
||||
value.close()?.let { key to it }
|
||||
}
|
||||
.filterNotNull()
|
||||
.toMap(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+25
-282
@@ -6,204 +6,45 @@
|
||||
package org.jetbrains.kotlin.gradle.targets.js.npm.resolver
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.logging.Logger
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.services.BuildService
|
||||
import org.gradle.internal.service.ServiceRegistry
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.isMain
|
||||
import org.jetbrains.kotlin.gradle.targets.js.NpmVersions
|
||||
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrCompilation
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.TasksRequirements
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.*
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinCompilationNpmResolution
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinProjectNpmResolution
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinRootNpmResolution
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.KotlinNpmCachesSetup
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.KotlinNpmInstallTask
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.KotlinPackageJsonTask
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.RootPackageJsonTask
|
||||
import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnEnv
|
||||
import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnPlugin
|
||||
import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnResolution
|
||||
import org.jetbrains.kotlin.gradle.targets.js.yarn.toVersionString
|
||||
import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile
|
||||
import org.jetbrains.kotlin.gradle.tasks.withType
|
||||
import org.jetbrains.kotlin.gradle.utils.ArchiveOperationsCompat
|
||||
import org.jetbrains.kotlin.gradle.utils.FileSystemOperationsCompat
|
||||
import org.jetbrains.kotlin.gradle.utils.unavailableValueError
|
||||
import java.io.File
|
||||
import java.io.Serializable
|
||||
|
||||
/**
|
||||
* See [KotlinNpmResolutionManager] for details about resolution process.
|
||||
*
|
||||
* This class contains many transient properties to deduplicate data when configuration cache is used.
|
||||
* Regularly tasks share the same instance of this class, but with configuration cache each task that holds a reference to the instance will
|
||||
* create an own copy. We use build services as a single storage for the heavy state of this class.
|
||||
*/
|
||||
class KotlinRootNpmResolver internal constructor(
|
||||
@Transient
|
||||
val nodeJs: NodeJsRootExtension?,
|
||||
val forceFullResolve: Boolean
|
||||
) {
|
||||
private val nodeJs_
|
||||
get() = nodeJs ?: unavailableValueError("nodeJs")
|
||||
val rootProjectName: String,
|
||||
val rootProjectVersion: String,
|
||||
val tasksRequirements: TasksRequirements,
|
||||
val versions: NpmVersions,
|
||||
val projectPackagesDir: File,
|
||||
val rootProjectDir: File,
|
||||
) : Serializable {
|
||||
|
||||
private val rootProject: Project?
|
||||
get() = nodeJs?.rootProject
|
||||
internal var resolution: KotlinRootNpmResolution? = null
|
||||
|
||||
private val rootProject_: Project
|
||||
get() = rootProject ?: unavailableValueError("rootProject")
|
||||
|
||||
private val rootProjectName by lazy {
|
||||
rootProject_.name
|
||||
}
|
||||
|
||||
private val rootProjectVersion by lazy {
|
||||
rootProject_.version.toString()
|
||||
}
|
||||
|
||||
@Transient
|
||||
@Volatile
|
||||
private var state_: RootResolverState? = RootResolverState.CONFIGURING
|
||||
|
||||
var state
|
||||
get() = state_ ?: resolverStateHolder.get().state
|
||||
set(value) {
|
||||
if (state_ != null) {
|
||||
state_ = value
|
||||
} else {
|
||||
resolverStateHolder.get().state = value
|
||||
}
|
||||
}
|
||||
|
||||
private val archiveOperations by lazy { ArchiveOperationsCompat(rootProject_) }
|
||||
private val fs by lazy { FileSystemOperationsCompat(rootProject_) }
|
||||
|
||||
internal val gradleNodeModulesProvider: Provider<GradleNodeModulesCache> =
|
||||
rootProject_
|
||||
.gradle.sharedServices.registerIfAbsent("gradle-node-modules", GradleNodeModulesCache::class.java) {
|
||||
it.parameters.cacheDir.set(nodeJs_.nodeModulesGradleCacheDir)
|
||||
it.parameters.rootProjectDir.set(rootProject_.projectDir)
|
||||
}.also {
|
||||
declareBuildServiceForRootProjectJsTasks(it)
|
||||
declareBuildServiceForAllProjectsJsTasks(it)
|
||||
}
|
||||
|
||||
internal val gradleNodeModules: GradleNodeModulesCache
|
||||
get() = gradleNodeModulesProvider.get().also {
|
||||
it.archiveOperations = archiveOperations
|
||||
it.fs = fs
|
||||
}
|
||||
|
||||
internal val compositeNodeModulesProvider: Provider<CompositeNodeModulesCache> =
|
||||
rootProject_
|
||||
.gradle.sharedServices.registerIfAbsent("composite-node-modules", CompositeNodeModulesCache::class.java) {
|
||||
it.parameters.cacheDir.set(nodeJs_.nodeModulesGradleCacheDir)
|
||||
it.parameters.rootProjectDir.set(rootProject_.projectDir)
|
||||
}.also {
|
||||
declareBuildServiceForRootProjectJsTasks(it)
|
||||
declareBuildServiceForAllProjectsJsTasks(it)
|
||||
}
|
||||
|
||||
internal val compositeNodeModules: CompositeNodeModulesCache
|
||||
get() = compositeNodeModulesProvider.get()
|
||||
|
||||
@Transient
|
||||
private val projectResolvers_: MutableMap<String, KotlinProjectNpmResolver>? = mutableMapOf()
|
||||
|
||||
@Transient
|
||||
private val yarnEnvironment_: Provider<YarnEnv>? = rootProject_.provider {
|
||||
YarnPlugin.apply(rootProject_).requireConfigured()
|
||||
}
|
||||
|
||||
@Transient
|
||||
private val npmEnvironment_: Provider<NpmEnvironment>? = rootProject_.provider {
|
||||
nodeJs_.asNpmEnvironment
|
||||
}
|
||||
|
||||
@Transient
|
||||
private val yarnResolutions_: Provider<List<YarnResolution>>? = rootProject_.provider {
|
||||
YarnPlugin.apply(rootProject_).resolutions
|
||||
}
|
||||
|
||||
@Transient
|
||||
private val taskRequirements_: TasksRequirements? = nodeJs_.taskRequirements
|
||||
|
||||
private val resolverStateHolder by lazy {
|
||||
rootProject_.gradle.sharedServices.registerIfAbsent(
|
||||
KotlinRootNpmResolverStateHolder::class.qualifiedName,
|
||||
KotlinRootNpmResolverStateHolder::class.java
|
||||
) { service ->
|
||||
service.parameters.projectResolvers.set(projectResolvers_)
|
||||
service.parameters.packageManager.set(nodeJs_.packageManager)
|
||||
service.parameters.yarnEnvironment.set(yarnEnvironment_?.get())
|
||||
service.parameters.npmEnvironment.set(npmEnvironment_?.get())
|
||||
service.parameters.yarnResolutions.set(yarnResolutions_?.get())
|
||||
service.parameters.taskRequirements.set(taskRequirements_)
|
||||
service.parameters.packageJsonHandlers.set(compilations.associate { compilation ->
|
||||
"${compilation.project.path}:${compilation.disambiguatedName}" to compilation.packageJsonHandlers
|
||||
}.filter { it.value.isNotEmpty() })
|
||||
}.also {
|
||||
declareBuildServiceForRootProjectJsTasks(it)
|
||||
declareBuildServiceForAllProjectsJsTasks(it)
|
||||
}
|
||||
}
|
||||
|
||||
private val configurationCacheProjectResolvers: MutableMap<String, KotlinProjectNpmResolver>
|
||||
get() {
|
||||
val stateHolder = resolverStateHolder.get()
|
||||
val projResolvers = stateHolder.parameters.projectResolvers.get()
|
||||
if (stateHolder.initialized) return projResolvers
|
||||
projResolvers.forEach { (_, value) ->
|
||||
value.resolver = this
|
||||
value.compilationResolvers.forEach { compResolver ->
|
||||
compResolver.rootResolver = this
|
||||
}
|
||||
}
|
||||
stateHolder.initialized = true
|
||||
return projResolvers
|
||||
}
|
||||
|
||||
private val projectResolvers
|
||||
get() = projectResolvers_ ?: configurationCacheProjectResolvers
|
||||
|
||||
private val packageManager
|
||||
get() = nodeJs?.packageManager ?: resolverStateHolder.get().parameters.packageManager.get()
|
||||
|
||||
private val yarnEnvironment
|
||||
get() = yarnEnvironment_?.get() ?: resolverStateHolder.get().parameters.yarnEnvironment.get()
|
||||
|
||||
private val npmEnvironment
|
||||
get() = npmEnvironment_?.get() ?: resolverStateHolder.get().parameters.npmEnvironment.get()
|
||||
|
||||
private val yarnResolutions
|
||||
get() = yarnResolutions_?.get() ?: resolverStateHolder.get().parameters.yarnResolutions.get()
|
||||
|
||||
internal val taskRequirements
|
||||
get() = taskRequirements_ ?: resolverStateHolder.get().parameters.taskRequirements.get()
|
||||
|
||||
internal val mayBeUpToDateTasksRegistry =
|
||||
MayBeUpToDatePackageJsonTasksRegistry.registerIfAbsent(rootProject_)
|
||||
val projectResolvers: MutableMap<String, KotlinProjectNpmResolver> = mutableMapOf()
|
||||
|
||||
fun alreadyResolvedMessage(action: String) = "Cannot $action. NodeJS projects already resolved."
|
||||
|
||||
fun addProject(target: Project) {
|
||||
synchronized(projectResolvers) {
|
||||
check(state == RootResolverState.CONFIGURING) { alreadyResolvedMessage("add new project: $target") }
|
||||
projectResolvers[target.path] = KotlinProjectNpmResolver(target, this)
|
||||
check(resolution == null) { alreadyResolvedMessage("add new project: $target") }
|
||||
val kotlinProjectNpmResolver = KotlinProjectNpmResolver(target, this)
|
||||
projectResolvers[target.path] = kotlinProjectNpmResolver
|
||||
}
|
||||
}
|
||||
|
||||
internal operator fun get(projectPath: String) = projectResolvers[projectPath] ?: error("$projectPath is not configured for JS usage")
|
||||
internal operator fun get(projectPath: String) =
|
||||
projectResolvers[projectPath] ?: error("$projectPath is not configured for JS usage")
|
||||
|
||||
val compilations: Collection<KotlinJsCompilation>
|
||||
get() = projectResolvers.values.flatMap { it.compilationResolvers.map { it.compilation } }
|
||||
|
||||
internal fun getPackageJsonHandlers(projectPath: String, compilationDisambiguatedName: String): List<PackageJson.() -> Unit> =
|
||||
resolverStateHolder.get().parameters.packageJsonHandlers.get()["$projectPath:$compilationDisambiguatedName"] ?: emptyList()
|
||||
|
||||
internal fun findDependentResolver(src: Project, target: Project): List<KotlinCompilationNpmResolver>? {
|
||||
// todo: proper finding using KotlinTargetComponent.findUsageContext
|
||||
val targetResolver = this[target.path]
|
||||
@@ -242,113 +83,15 @@ class KotlinRootNpmResolver internal constructor(
|
||||
return mainCompilations
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't use directly, use [KotlinNpmResolutionManager.installIfNeeded] instead.
|
||||
*/
|
||||
internal fun prepareInstallation(logger: Logger): Installation {
|
||||
synchronized(projectResolvers) {
|
||||
state = RootResolverState.PROJECTS_CLOSED
|
||||
|
||||
val projectResolutions = projectResolvers.values
|
||||
.map { it.close() }
|
||||
.associateBy { it.project }
|
||||
val allNpmPackages = projectResolutions.values.flatMap { it.npmProjects }
|
||||
|
||||
gradleNodeModules.close()
|
||||
compositeNodeModules.close()
|
||||
|
||||
packageManager.prepareRootProject(
|
||||
rootProject,
|
||||
npmEnvironment,
|
||||
rootProjectName,
|
||||
rootProjectVersion,
|
||||
logger,
|
||||
allNpmPackages,
|
||||
yarnResolutions
|
||||
.associate { it.path to it.toVersionString() },
|
||||
forceFullResolve
|
||||
)
|
||||
|
||||
return Installation(
|
||||
projectResolutions
|
||||
)
|
||||
}
|
||||
internal fun close(): KotlinRootNpmResolution {
|
||||
return resolution ?: KotlinRootNpmResolution(
|
||||
projectResolvers
|
||||
.map { (key, value) -> key to value.close() }
|
||||
.toMap(),
|
||||
rootProjectName,
|
||||
rootProjectVersion
|
||||
)
|
||||
}
|
||||
|
||||
open inner class Installation(val projectResolutions: Map<String, KotlinProjectNpmResolution>) {
|
||||
operator fun get(project: String) =
|
||||
projectResolutions[project] ?: KotlinProjectNpmResolution.empty(project)
|
||||
|
||||
internal fun install(
|
||||
forceUpToDate: Boolean,
|
||||
args: List<String>,
|
||||
services: ServiceRegistry,
|
||||
logger: Logger
|
||||
): KotlinRootNpmResolution {
|
||||
synchronized(projectResolvers) {
|
||||
if (state == RootResolverState.INSTALLED) {
|
||||
return KotlinRootNpmResolution(rootProject, projectResolutions)
|
||||
}
|
||||
check(state == RootResolverState.PROJECTS_CLOSED) {
|
||||
"Projects must be closed"
|
||||
}
|
||||
state = RootResolverState.INSTALLED
|
||||
|
||||
val allNpmPackages = projectResolutions
|
||||
.values
|
||||
.flatMap { it.npmProjects }
|
||||
|
||||
packageManager.resolveRootProject(
|
||||
services,
|
||||
logger,
|
||||
npmEnvironment,
|
||||
yarnEnvironment,
|
||||
allNpmPackages,
|
||||
args
|
||||
)
|
||||
|
||||
return KotlinRootNpmResolution(rootProject, projectResolutions)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeOutdatedPackages(nodeJs: NodeJsRootExtension, allNpmPackages: List<KotlinCompilationNpmResolution>) {
|
||||
val packages = allNpmPackages.mapTo(mutableSetOf()) { it.npmProject.name }
|
||||
nodeJs.projectPackagesDir.listFiles()?.forEach {
|
||||
if (it.name !in packages) {
|
||||
it.deleteRecursively()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun declareBuildServiceForRootProjectJsTasks(serviceProvider: Provider<out BuildService<*>>) {
|
||||
rootProject_.tasks.withType<RootPackageJsonTask>().configureEach {
|
||||
it.usesService(serviceProvider)
|
||||
}
|
||||
rootProject_.tasks.withType<KotlinNpmInstallTask>().configureEach {
|
||||
it.usesService(serviceProvider)
|
||||
}
|
||||
rootProject_.tasks.withType<KotlinNpmCachesSetup>().configureEach {
|
||||
it.usesService(serviceProvider)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun declareBuildServiceForAllProjectsJsTasks(serviceProvider: Provider<out BuildService<*>>) {
|
||||
rootProject_.allprojects { project ->
|
||||
project.tasks.withType<Kotlin2JsCompile>().configureEach {
|
||||
it.usesService(serviceProvider)
|
||||
}
|
||||
project.tasks.withType<KotlinPackageJsonTask>().configureEach {
|
||||
it.usesService(serviceProvider)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class RootResolverState {
|
||||
CONFIGURING,
|
||||
PROJECTS_CLOSED,
|
||||
INSTALLED
|
||||
}
|
||||
|
||||
const val PACKAGE_JSON_UMBRELLA_TASK_NAME = "packageJsonUmbrella"
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.resolver
|
||||
|
||||
import org.gradle.api.provider.ListProperty
|
||||
import org.gradle.api.provider.MapProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.services.BuildService
|
||||
import org.gradle.api.services.BuildServiceParameters
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.TasksRequirements
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmApi
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmEnvironment
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.PackageJson
|
||||
import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnEnv
|
||||
import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnResolution
|
||||
|
||||
// We use this service as a single storage for duplicated data in configuration cache
|
||||
abstract class KotlinRootNpmResolverStateHolder : BuildService<KotlinRootNpmResolverStateHolder.Parameters> {
|
||||
internal interface Parameters : BuildServiceParameters {
|
||||
val projectResolvers: MapProperty<String, KotlinProjectNpmResolver>
|
||||
val packageManager: Property<NpmApi>
|
||||
val yarnEnvironment: Property<YarnEnv>
|
||||
val npmEnvironment: Property<NpmEnvironment>
|
||||
val yarnResolutions: ListProperty<YarnResolution>
|
||||
val taskRequirements: Property<TasksRequirements>
|
||||
|
||||
// pulled up from compilation resolver since it was failing with ClassNotFoundException on deserialization, see KT-49061
|
||||
val packageJsonHandlers: MapProperty<String, List<PackageJson.() -> Unit>>
|
||||
}
|
||||
|
||||
var initialized = false
|
||||
|
||||
@Volatile
|
||||
var state = RootResolverState.CONFIGURING
|
||||
}
|
||||
-31
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.resolver
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.services.BuildService
|
||||
import org.gradle.api.services.BuildServiceParameters
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.KotlinPackageJsonTask
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
internal abstract class MayBeUpToDatePackageJsonTasksRegistry : BuildService<BuildServiceParameters.None> {
|
||||
private val mayBeUpToDateTasks = ConcurrentHashMap.newKeySet<String>()
|
||||
|
||||
fun markForNpmDependenciesResolve(task: KotlinPackageJsonTask) {
|
||||
mayBeUpToDateTasks.add(task.path)
|
||||
}
|
||||
|
||||
fun shouldResolveNpmDependenciesFor(taskPath: String) = taskPath in mayBeUpToDateTasks
|
||||
|
||||
companion object {
|
||||
fun registerIfAbsent(project: Project): Provider<MayBeUpToDatePackageJsonTasksRegistry> =
|
||||
project.rootProject.gradle.sharedServices.registerIfAbsent(
|
||||
MayBeUpToDatePackageJsonTasksRegistry::class.qualifiedName,
|
||||
MayBeUpToDatePackageJsonTasksRegistry::class.java
|
||||
) {}
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.resolver
|
||||
|
||||
import org.gradle.api.tasks.*
|
||||
import org.gradle.work.NormalizeLineEndings
|
||||
import java.io.File
|
||||
|
||||
class PackageJsonProducerInputs(
|
||||
@get:Input
|
||||
val internalDependencies: Collection<String>,
|
||||
|
||||
@get:PathSensitive(PathSensitivity.ABSOLUTE)
|
||||
@get:IgnoreEmptyDirectories
|
||||
@get:NormalizeLineEndings
|
||||
@get:InputFiles
|
||||
val internalCompositeDependencies: Collection<File>,
|
||||
|
||||
@get:PathSensitive(PathSensitivity.ABSOLUTE)
|
||||
@get:IgnoreEmptyDirectories
|
||||
@get:NormalizeLineEndings
|
||||
@get:InputFiles
|
||||
val externalGradleDependencies: Collection<File>,
|
||||
|
||||
@get:Input
|
||||
val externalDependencies: Collection<String>,
|
||||
|
||||
@get:Input
|
||||
val fileCollectionDependencies: Collection<File>
|
||||
)
|
||||
+10
-7
@@ -6,21 +6,24 @@
|
||||
package org.jetbrains.kotlin.gradle.targets.js.npm.tasks
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.Internal
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.internal.hash.FileHasher
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.CompositeNodeModulesCache
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.GradleNodeModulesCache
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.UsesCompositeNodeModulesCache
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.UsesGradleNodeModulesCache
|
||||
import javax.inject.Inject
|
||||
|
||||
abstract class KotlinNpmCachesSetup : DefaultTask() {
|
||||
abstract class KotlinNpmCachesSetup :
|
||||
DefaultTask(),
|
||||
UsesGradleNodeModulesCache,
|
||||
UsesCompositeNodeModulesCache {
|
||||
@get:Inject
|
||||
open val fileHasher: FileHasher
|
||||
get() = throw UnsupportedOperationException()
|
||||
|
||||
@Transient
|
||||
private val nodeJs = NodeJsRootPlugin.apply(project.rootProject)
|
||||
private val gradleNodeModules = nodeJs.npmResolutionManager.resolver.gradleNodeModulesProvider
|
||||
private val compositeNodeModules = nodeJs.npmResolutionManager.resolver.compositeNodeModulesProvider
|
||||
|
||||
@TaskAction
|
||||
fun setup() {
|
||||
gradleNodeModules.get().fileHasher = fileHasher
|
||||
|
||||
+35
-41
@@ -9,72 +9,66 @@ import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.tasks.*
|
||||
import org.gradle.work.NormalizeLineEndings
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin.Companion.kotlinNodeJsExtension
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.KotlinNpmResolutionManager
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.UsesKotlinNpmResolutionManager
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.asNpmEnvironment
|
||||
import org.jetbrains.kotlin.gradle.utils.unavailableValueError
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.asYarnEnvironment
|
||||
import org.jetbrains.kotlin.gradle.targets.js.yarn.yarn
|
||||
import java.io.File
|
||||
|
||||
open class KotlinNpmInstallTask : DefaultTask() {
|
||||
abstract class KotlinNpmInstallTask :
|
||||
DefaultTask(),
|
||||
UsesKotlinNpmResolutionManager {
|
||||
init {
|
||||
check(project == project.rootProject)
|
||||
|
||||
onlyIf {
|
||||
preparedFiles.all {
|
||||
it.exists()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Transient
|
||||
private val nodeJs: NodeJsRootExtension? = NodeJsRootPlugin.apply(project.rootProject)
|
||||
private val resolutionManager = (nodeJs ?: unavailableValueError("nodeJs")).npmResolutionManager
|
||||
// Only in configuration phase
|
||||
// Not part of configuration caching
|
||||
|
||||
private val nodeJs: NodeJsRootExtension
|
||||
get() = project.rootProject.kotlinNodeJsExtension
|
||||
|
||||
private val yarn
|
||||
get() = project.rootProject.yarn
|
||||
|
||||
// -----
|
||||
|
||||
private val npmEnvironment by lazy {
|
||||
nodeJs.requireConfigured().asNpmEnvironment
|
||||
}
|
||||
|
||||
private val yarnEnv by lazy {
|
||||
yarn.requireConfigured().asYarnEnvironment
|
||||
}
|
||||
|
||||
@Input
|
||||
val args: MutableList<String> = mutableListOf()
|
||||
|
||||
@get:Internal
|
||||
val nodeModulesDir: File by lazy {
|
||||
(nodeJs ?: unavailableValueError("nodeJs"))
|
||||
.rootPackageDir
|
||||
.resolve("node_modules")
|
||||
}
|
||||
|
||||
init {
|
||||
outputs.upToDateWhen {
|
||||
nodeModulesDir.isDirectory
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
@get:PathSensitive(PathSensitivity.ABSOLUTE)
|
||||
@get:IgnoreEmptyDirectories
|
||||
@get:NormalizeLineEndings
|
||||
@get:InputFiles
|
||||
val packageJsonFiles: Collection<File> by lazy {
|
||||
resolutionManager.packageJsonFiles
|
||||
}
|
||||
|
||||
@get:PathSensitive(PathSensitivity.ABSOLUTE)
|
||||
@get:IgnoreEmptyDirectories
|
||||
@get:NormalizeLineEndings
|
||||
@get:InputFiles
|
||||
val preparedFiles: Collection<File> by lazy {
|
||||
(nodeJs ?: unavailableValueError("nodeJs")).packageManager.preparedFiles(nodeJs.asNpmEnvironment)
|
||||
nodeJs.packageManager.preparedFiles(npmEnvironment)
|
||||
}
|
||||
|
||||
@get:OutputFile
|
||||
val yarnLock: File by lazy {
|
||||
(nodeJs ?: unavailableValueError("nodeJs")).rootPackageDir.resolve("yarn.lock")
|
||||
nodeJs.rootPackageDir.resolve("yarn.lock")
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
fun resolve() {
|
||||
resolutionManager.installIfNeeded(
|
||||
args = args,
|
||||
services = services,
|
||||
logger = logger
|
||||
) ?: throw (resolutionManager.state as KotlinNpmResolutionManager.ResolutionState.Error).wrappedException
|
||||
npmResolutionManager.get()
|
||||
.installIfNeeded(
|
||||
args = args,
|
||||
services = services,
|
||||
logger = logger,
|
||||
npmEnvironment,
|
||||
yarnEnv
|
||||
) ?: throw (npmResolutionManager.get().state as KotlinNpmResolutionManager.ResolutionState.Error).wrappedException
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
+75
-60
@@ -11,92 +11,86 @@ import org.gradle.api.tasks.*
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.PackageJson
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.fakePackageJsonValue
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.resolver.MayBeUpToDatePackageJsonTasksRegistry
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin.Companion.kotlinNodeJsExtension
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin.Companion.kotlinNpmResolutionManager
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.*
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.resolver.KotlinCompilationNpmResolver
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.resolver.KotlinRootNpmResolver
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.resolver.PACKAGE_JSON_UMBRELLA_TASK_NAME
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.resolver.PackageJsonProducerInputs
|
||||
import org.jetbrains.kotlin.gradle.tasks.registerTask
|
||||
import org.jetbrains.kotlin.gradle.utils.chainedDisallowChanges
|
||||
import org.jetbrains.kotlin.gradle.utils.getValue
|
||||
import java.io.File
|
||||
|
||||
abstract class KotlinPackageJsonTask : DefaultTask() {
|
||||
abstract class KotlinPackageJsonTask :
|
||||
DefaultTask(),
|
||||
UsesKotlinNpmResolutionManager,
|
||||
UsesGradleNodeModulesCache,
|
||||
UsesCompositeNodeModulesCache {
|
||||
// Only in configuration phase
|
||||
// Not part of configuration caching
|
||||
|
||||
init {
|
||||
onlyIf {
|
||||
npmResolutionManager.isConfiguringState()
|
||||
private val nodeJs: NodeJsRootExtension
|
||||
get() = project.rootProject.kotlinNodeJsExtension
|
||||
|
||||
private val rootResolver: KotlinRootNpmResolver
|
||||
get() = nodeJs.resolver
|
||||
|
||||
private val compilationResolver: KotlinCompilationNpmResolver
|
||||
get() = rootResolver[projectPath][compilationDisambiguatedName.get()]
|
||||
|
||||
private fun findDependentTasks(): Collection<Any> =
|
||||
compilationResolver.compilationNpmResolution.internalDependencies.map { dependency ->
|
||||
nodeJs.resolver[dependency.projectPath][dependency.compilationName].npmProject.packageJsonTaskPath
|
||||
} + compilationResolver.compilationNpmResolution.internalCompositeDependencies.map { dependency ->
|
||||
dependency.includedBuild?.task(":$PACKAGE_JSON_UMBRELLA_TASK_NAME") ?: error("includedBuild instance is not available")
|
||||
dependency.includedBuild.task(":${RootPackageJsonTask.NAME}")
|
||||
}
|
||||
outputs.upToDateWhen {
|
||||
// this way we will ensure that we need to resolve dependencies for the compilation in case of UP-TO-DATE task
|
||||
// used in KotlinCompilationNpmResolver#getResolutionOrResolveIfForced
|
||||
mayBeUpToDateTasksRegistry.get().markForNpmDependenciesResolve(it as KotlinPackageJsonTask)
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
@Transient
|
||||
private lateinit var nodeJs: NodeJsRootExtension
|
||||
// -----
|
||||
|
||||
private val npmResolutionManager by project.provider { nodeJs.npmResolutionManager }
|
||||
|
||||
@Transient
|
||||
private lateinit var compilation: KotlinJsCompilation
|
||||
private val projectPath = project.path
|
||||
|
||||
@get:Internal
|
||||
internal abstract val mayBeUpToDateTasksRegistry: Property<MayBeUpToDatePackageJsonTasksRegistry>
|
||||
abstract val compilationDisambiguatedName: Property<String>
|
||||
|
||||
private val compilationDisambiguatedName by lazy {
|
||||
compilation.disambiguatedName
|
||||
}
|
||||
|
||||
@Input
|
||||
val projectPath = project.path
|
||||
|
||||
private val compilationResolver
|
||||
get() = npmResolutionManager.resolver[projectPath][compilationDisambiguatedName]
|
||||
|
||||
private val producer: KotlinCompilationNpmResolver.PackageJsonProducer
|
||||
get() = compilationResolver.packageJsonProducer
|
||||
private val packageJsonHandlers: List<PackageJson.() -> Unit>
|
||||
get() = npmResolutionManager.get().parameters.packageJsonHandlers.get()
|
||||
.getValue("$projectPath:${compilationDisambiguatedName.get()}")
|
||||
|
||||
@get:Input
|
||||
val packageJsonCustomFields: Map<String, Any?> by lazy {
|
||||
PackageJson(fakePackageJsonValue, fakePackageJsonValue)
|
||||
.apply {
|
||||
compilation.packageJsonHandlers.forEach { it() }
|
||||
packageJsonHandlers.forEach { it() }
|
||||
}.customFields
|
||||
}
|
||||
|
||||
private fun findDependentTasks(): Collection<Any> =
|
||||
producer.internalDependencies.map { dependency ->
|
||||
npmResolutionManager.resolver[dependency.projectPath][dependency.compilationName].npmProject.packageJsonTaskPath
|
||||
} + producer.internalCompositeDependencies.map { dependency ->
|
||||
dependency.includedBuild?.task(":$PACKAGE_JSON_UMBRELLA_TASK_NAME") ?: error("includedBuild instance is not available")
|
||||
dependency.includedBuild.task(":${RootPackageJsonTask.NAME}")
|
||||
}
|
||||
|
||||
@get:Input
|
||||
internal val toolsNpmDependencies: List<String> by lazy {
|
||||
nodeJs.taskRequirements
|
||||
.getCompilationNpmRequirements(projectPath, compilationDisambiguatedName)
|
||||
.getCompilationNpmRequirements(projectPath, compilationDisambiguatedName.get())
|
||||
.map { it.toString() }
|
||||
.sorted()
|
||||
}
|
||||
|
||||
// nested inputs are processed in configuration phase
|
||||
// so npmResolutionManager must not be used
|
||||
@get:Nested
|
||||
internal val producerInputs: KotlinCompilationNpmResolver.PackageJsonProducerInputs by lazy {
|
||||
producer.inputs
|
||||
internal val producerInputs: PackageJsonProducerInputs by lazy {
|
||||
compilationResolver.compilationNpmResolution.inputs
|
||||
}
|
||||
|
||||
@get:OutputFile
|
||||
val packageJson: File by lazy {
|
||||
compilationResolver.npmProject.packageJsonFile
|
||||
}
|
||||
abstract val packageJson: Property<File>
|
||||
|
||||
@TaskAction
|
||||
fun resolve() {
|
||||
compilationResolver.resolve()
|
||||
npmResolutionManager.get().resolution.get()[projectPath][compilationDisambiguatedName.get()]
|
||||
.resolve(
|
||||
npmResolutionManager = npmResolutionManager.get(),
|
||||
logger = logger
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@@ -104,29 +98,50 @@ abstract class KotlinPackageJsonTask : DefaultTask() {
|
||||
val target = compilation.target
|
||||
val project = target.project
|
||||
val npmProject = compilation.npmProject
|
||||
val nodeJs = NodeJsRootPlugin.apply(project.rootProject)
|
||||
val nodeJsTaskProviders = project.rootProject.kotlinNodeJsExtension
|
||||
|
||||
val npmCachesSetupTask = nodeJs.npmCachesSetupTaskProvider
|
||||
val npmCachesSetupTask = nodeJsTaskProviders.npmCachesSetupTaskProvider
|
||||
val packageJsonTaskName = npmProject.packageJsonTaskName
|
||||
val packageJsonUmbrella = nodeJs.packageJsonUmbrellaTaskProvider
|
||||
val packageJsonUmbrella = nodeJsTaskProviders.packageJsonUmbrellaTaskProvider
|
||||
val npmResolutionManager = project.kotlinNpmResolutionManager
|
||||
val gradleNodeModules = GradleNodeModulesCache.registerIfAbsent(project, null, null)
|
||||
val compositeNodeModules = CompositeNodeModulesCache.registerIfAbsent(project, null, null)
|
||||
val packageJsonTask = project.registerTask<KotlinPackageJsonTask>(packageJsonTaskName) { task ->
|
||||
task.nodeJs = nodeJs
|
||||
task.compilation = compilation
|
||||
task.compilationDisambiguatedName.set(compilation.disambiguatedName)
|
||||
task.description = "Create package.json file for $compilation"
|
||||
task.group = NodeJsRootPlugin.TASKS_GROUP_NAME
|
||||
val packageJsonStateService = MayBeUpToDatePackageJsonTasksRegistry.registerIfAbsent(project)
|
||||
task.mayBeUpToDateTasksRegistry.value(packageJsonStateService).chainedDisallowChanges().also {
|
||||
task.usesService(packageJsonStateService)
|
||||
|
||||
task.npmResolutionManager.apply {
|
||||
set(npmResolutionManager)
|
||||
disallowChanges()
|
||||
}
|
||||
|
||||
task.gradleNodeModules.apply {
|
||||
set(gradleNodeModules)
|
||||
disallowChanges()
|
||||
}
|
||||
|
||||
task.compositeNodeModules.apply {
|
||||
set(compositeNodeModules)
|
||||
disallowChanges()
|
||||
}
|
||||
|
||||
task.packageJson.set(compilation.npmProject.packageJsonFile)
|
||||
|
||||
task.onlyIf {
|
||||
it as KotlinPackageJsonTask
|
||||
it.npmResolutionManager.get().isConfiguringState()
|
||||
}
|
||||
|
||||
task.dependsOn(target.project.provider { task.findDependentTasks() })
|
||||
task.dependsOn(npmCachesSetupTask)
|
||||
}
|
||||
|
||||
packageJsonUmbrella.configure { task ->
|
||||
task.inputs.file(packageJsonTask.map { it.packageJson })
|
||||
}
|
||||
|
||||
nodeJs.rootPackageJsonTaskProvider!!.configure { it.mustRunAfter(packageJsonTask) }
|
||||
nodeJsTaskProviders.rootPackageJsonTaskProvider.configure { it.mustRunAfter(packageJsonTask) }
|
||||
|
||||
return packageJsonTask
|
||||
}
|
||||
|
||||
+33
-12
@@ -8,22 +8,40 @@ package org.jetbrains.kotlin.gradle.targets.js.npm.tasks
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.tasks.*
|
||||
import org.gradle.work.NormalizeLineEndings
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProject
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin.Companion.kotlinNodeJsExtension
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.*
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.resolver.KotlinRootNpmResolver
|
||||
import org.jetbrains.kotlin.gradle.targets.js.yarn.yarn
|
||||
import java.io.File
|
||||
|
||||
open class RootPackageJsonTask : DefaultTask() {
|
||||
abstract class RootPackageJsonTask :
|
||||
DefaultTask(),
|
||||
UsesKotlinNpmResolutionManager {
|
||||
init {
|
||||
check(project == project.rootProject)
|
||||
|
||||
onlyIf {
|
||||
resolutionManager.isConfiguringState()
|
||||
}
|
||||
}
|
||||
|
||||
@Transient
|
||||
private val nodeJs = NodeJsRootPlugin.apply(project.rootProject)
|
||||
private val resolutionManager = nodeJs.npmResolutionManager
|
||||
// Only in configuration phase
|
||||
// Not part of configuration caching
|
||||
|
||||
private val nodeJs
|
||||
get() = project.rootProject.kotlinNodeJsExtension
|
||||
|
||||
private val yarn
|
||||
get() = project.rootProject.yarn
|
||||
|
||||
private val rootResolver: KotlinRootNpmResolver
|
||||
get() = nodeJs.resolver
|
||||
|
||||
// -----
|
||||
|
||||
private val npmEnvironment by lazy {
|
||||
nodeJs.requireConfigured().asNpmEnvironment
|
||||
}
|
||||
|
||||
private val yarnEnv by lazy {
|
||||
yarn.requireConfigured().asYarnEnvironment
|
||||
}
|
||||
|
||||
@get:OutputFile
|
||||
val rootPackageJson: File by lazy {
|
||||
@@ -35,12 +53,15 @@ open class RootPackageJsonTask : DefaultTask() {
|
||||
@get:NormalizeLineEndings
|
||||
@get:InputFiles
|
||||
val packageJsonFiles: Collection<File> by lazy {
|
||||
resolutionManager.packageJsonFiles
|
||||
rootResolver.projectResolvers.values
|
||||
.flatMap { it.compilationResolvers }
|
||||
.map { it.compilationNpmResolution }
|
||||
.map { it.npmProjectPackageJsonFile }
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
fun resolve() {
|
||||
resolutionManager.prepare(logger)
|
||||
npmResolutionManager.get().prepare(logger, npmEnvironment, yarnEnv)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
+13
-31
@@ -14,7 +14,6 @@ import org.gradle.language.base.plugins.LifecycleBasePlugin
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinJsDce
|
||||
import org.jetbrains.kotlin.gradle.plugin.COMPILER_CLASSPATH_CONFIGURATION_NAME
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
|
||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.isMain
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.isTest
|
||||
@@ -25,7 +24,7 @@ import org.jetbrains.kotlin.gradle.targets.js.KotlinJsTarget
|
||||
import org.jetbrains.kotlin.gradle.targets.js.dsl.*
|
||||
import org.jetbrains.kotlin.gradle.targets.js.ir.executeTaskBaseName
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin.Companion.kotlinNodeJsExtension
|
||||
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.karma.KotlinKarma
|
||||
@@ -33,7 +32,6 @@ import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpack
|
||||
import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig
|
||||
import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig.Mode
|
||||
import org.jetbrains.kotlin.gradle.targets.js.webpack.WebpackDevtool
|
||||
import org.jetbrains.kotlin.gradle.targets.js.webpack.WebpackMajorVersion.Companion.choose
|
||||
import org.jetbrains.kotlin.gradle.tasks.dependsOn
|
||||
import org.jetbrains.kotlin.gradle.tasks.registerTask
|
||||
import org.jetbrains.kotlin.gradle.utils.doNotTrackStateCompat
|
||||
@@ -51,9 +49,6 @@ abstract class KotlinBrowserJs @Inject constructor(target: KotlinJsTarget) :
|
||||
private val runTaskConfigurations: MutableList<Action<KotlinWebpack>> = mutableListOf()
|
||||
private val dceConfigurations: MutableList<Action<KotlinJsDce>> = mutableListOf()
|
||||
private val distribution: Distribution = createDefaultDistribution(project)
|
||||
private val propertiesProvider = PropertiesProvider(project)
|
||||
private val webpackMajorVersion
|
||||
get() = propertiesProvider.webpackMajorVersion
|
||||
|
||||
override val testTaskDescription: String
|
||||
get() = "Run all ${target.name} tests inside browser using karma and webpack"
|
||||
@@ -138,7 +133,7 @@ abstract class KotlinBrowserJs @Inject constructor(target: KotlinJsTarget) :
|
||||
devDceTaskProvider: TaskProvider<KotlinJsDceTask>
|
||||
) {
|
||||
val project = compilation.target.project
|
||||
val nodeJs = NodeJsRootPlugin.apply(project.rootProject)
|
||||
val nodeJs = project.rootProject.kotlinNodeJsExtension
|
||||
|
||||
val commonRunTask = registerSubTargetTask<Task>(disambiguateCamelCased(RUN_TASK_NAME)) {}
|
||||
|
||||
@@ -156,33 +151,20 @@ abstract class KotlinBrowserJs @Inject constructor(target: KotlinJsTarget) :
|
||||
listOf(compilation)
|
||||
) { task ->
|
||||
task.outputDirectory.convention(distsDirectory).finalizeValueOnRead()
|
||||
webpackMajorVersion.choose(
|
||||
{ task.args.add(0, "serve") },
|
||||
{ task.bin = "webpack-dev-server/bin/webpack-dev-server.js" }
|
||||
)()
|
||||
task.args.add(0, "serve")
|
||||
|
||||
task.description = "start ${type.name.toLowerCaseAsciiOnly()} webpack dev server"
|
||||
|
||||
webpackMajorVersion.choose(
|
||||
{
|
||||
task.devServer = KotlinWebpackConfig.DevServer(
|
||||
open = true,
|
||||
static = mutableListOf(compilation.output.resourcesDir.canonicalPath),
|
||||
client = KotlinWebpackConfig.DevServer.Client(
|
||||
KotlinWebpackConfig.DevServer.Client.Overlay(
|
||||
errors = true,
|
||||
warnings = false
|
||||
)
|
||||
)
|
||||
task.devServer = KotlinWebpackConfig.DevServer(
|
||||
open = true,
|
||||
static = mutableListOf(compilation.output.resourcesDir.canonicalPath),
|
||||
client = KotlinWebpackConfig.DevServer.Client(
|
||||
KotlinWebpackConfig.DevServer.Client.Overlay(
|
||||
errors = true,
|
||||
warnings = false
|
||||
)
|
||||
},
|
||||
{
|
||||
task.devServer = KotlinWebpackConfig.DevServer(
|
||||
open = true,
|
||||
contentBase = mutableListOf(compilation.output.resourcesDir.canonicalPath)
|
||||
)
|
||||
}
|
||||
)()
|
||||
)
|
||||
)
|
||||
|
||||
task.doNotTrackStateCompat("Tracked by external webpack tool")
|
||||
|
||||
@@ -212,7 +194,7 @@ abstract class KotlinBrowserJs @Inject constructor(target: KotlinJsTarget) :
|
||||
devDceTaskProvider: TaskProvider<KotlinJsDceTask>
|
||||
) {
|
||||
val project = compilation.target.project
|
||||
val nodeJs = NodeJsRootPlugin.apply(project.rootProject)
|
||||
val nodeJs = project.rootProject.kotlinNodeJsExtension
|
||||
|
||||
val processResourcesTask = target.project.tasks.named(compilation.processResourcesTaskName)
|
||||
|
||||
|
||||
+6
-8
@@ -20,8 +20,7 @@ import org.jetbrains.kotlin.gradle.plugin.whenEvaluated
|
||||
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsPlatformTestRun
|
||||
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsTarget
|
||||
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsSubTargetDsl
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmResolverPlugin
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin.Companion.kotlinNodeJsExtension
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject
|
||||
import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest
|
||||
import org.jetbrains.kotlin.gradle.tasks.registerTask
|
||||
@@ -35,7 +34,8 @@ abstract class KotlinJsSubTarget(
|
||||
) : KotlinJsSubTargetDsl {
|
||||
val project get() = target.project
|
||||
|
||||
private val nodeJs = NodeJsRootPlugin.apply(project.rootProject)
|
||||
private val nodeJs = project.rootProject.kotlinNodeJsExtension
|
||||
private val nodeJsTaskProviders = project.rootProject.kotlinNodeJsExtension
|
||||
|
||||
abstract val testTaskDescription: String
|
||||
|
||||
@@ -53,8 +53,6 @@ abstract class KotlinJsSubTarget(
|
||||
}
|
||||
|
||||
internal fun configure() {
|
||||
NpmResolverPlugin.apply(project)
|
||||
|
||||
configureTests()
|
||||
|
||||
target.compilations.all {
|
||||
@@ -108,10 +106,10 @@ abstract class KotlinJsSubTarget(
|
||||
testJs.inputFileProperty.fileProvider(compileOutputFile)
|
||||
|
||||
testJs.dependsOn(
|
||||
nodeJs.npmInstallTaskProvider,
|
||||
nodeJs.storeYarnLockTaskProvider,
|
||||
nodeJsTaskProviders.npmInstallTaskProvider,
|
||||
nodeJsTaskProviders.storeYarnLockTaskProvider,
|
||||
compileTask,
|
||||
nodeJs.nodeJsSetupTaskProvider
|
||||
nodeJsTaskProviders.nodeJsSetupTaskProvider
|
||||
)
|
||||
|
||||
testJs.onlyIf {
|
||||
|
||||
+2
-14
@@ -14,7 +14,7 @@ import org.gradle.work.NormalizeLineEndings
|
||||
import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutionSpec
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
|
||||
import org.jetbrains.kotlin.gradle.targets.js.RequiredKotlinJsDependency
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin.Companion.kotlinNodeJsExtension
|
||||
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
|
||||
@@ -33,16 +33,12 @@ constructor(
|
||||
) : KotlinTest(),
|
||||
RequiresNpmDependencies {
|
||||
@Transient
|
||||
private val nodeJs = NodeJsRootPlugin.apply(project.rootProject)
|
||||
|
||||
private val npmResolutionManager by project.provider { nodeJs.npmResolutionManager }
|
||||
private val nodeJs = project.rootProject.kotlinNodeJsExtension
|
||||
|
||||
private val nodeExecutable by project.provider { nodeJs.requireConfigured().nodeExecutable }
|
||||
|
||||
private val npmProjectDir by project.provider { compilation.npmProject.dir }
|
||||
|
||||
private val projectPath = project.path
|
||||
|
||||
@Input
|
||||
var environment = mutableMapOf<String, String>()
|
||||
|
||||
@@ -110,9 +106,6 @@ constructor(
|
||||
val nodeJsArgs: MutableList<String> =
|
||||
mutableListOf()
|
||||
|
||||
override val nodeModulesRequired: Boolean
|
||||
@Internal get() = testFramework!!.nodeModulesRequired
|
||||
|
||||
override val requiredNpmDependencies: Set<RequiredKotlinJsDependency>
|
||||
@Internal get() = testFramework!!.requiredNpmDependencies
|
||||
|
||||
@@ -164,11 +157,6 @@ constructor(
|
||||
return testFramework
|
||||
}
|
||||
|
||||
override fun executeTests() {
|
||||
npmResolutionManager.checkRequiredDependencies(task = this)
|
||||
super.executeTests()
|
||||
}
|
||||
|
||||
override fun createTestExecutionSpec(): TCServiceMessagesTestExecutionSpec {
|
||||
val forkOptions = DefaultProcessForkOptions(fileResolver)
|
||||
forkOptions.workingDir = npmProjectDir
|
||||
|
||||
-3
@@ -18,7 +18,4 @@ interface KotlinJsTestFramework : RequiresNpmDependencies {
|
||||
nodeJsArgs: MutableList<String>,
|
||||
debug: Boolean
|
||||
): TCServiceMessagesTestExecutionSpec
|
||||
|
||||
override val nodeModulesRequired: Boolean
|
||||
get() = true
|
||||
}
|
||||
+11
-27
@@ -32,11 +32,10 @@ import org.jetbrains.kotlin.gradle.targets.js.dsl.WebpackRulesDsl.Companion.webp
|
||||
import org.jetbrains.kotlin.gradle.targets.js.internal.parseNodeJsStackTraceAsJvm
|
||||
import org.jetbrains.kotlin.gradle.targets.js.jsQuoted
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin.Companion.kotlinNodeJsExtension
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject
|
||||
import org.jetbrains.kotlin.gradle.targets.js.testing.*
|
||||
import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig
|
||||
import org.jetbrains.kotlin.gradle.targets.js.webpack.WebpackMajorVersion
|
||||
import org.jetbrains.kotlin.gradle.targets.js.webpack.WebpackMajorVersion.Companion.choose
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinTest
|
||||
import org.jetbrains.kotlin.gradle.testing.internal.reportsDir
|
||||
import org.jetbrains.kotlin.gradle.utils.appendLine
|
||||
@@ -56,7 +55,7 @@ class KotlinKarma(
|
||||
private val npmProject = compilation.npmProject
|
||||
|
||||
@Transient
|
||||
private val nodeJs = NodeJsRootPlugin.apply(project.rootProject)
|
||||
private val nodeJs = project.rootProject.kotlinNodeJsExtension
|
||||
private val nodeRootPackageDir by lazy { nodeJs.rootPackageDir }
|
||||
private val versions = nodeJs.versions
|
||||
|
||||
@@ -81,8 +80,6 @@ class KotlinKarma(
|
||||
override val settingsState: String
|
||||
get() = "KotlinKarma($config)"
|
||||
|
||||
private val webpackMajorVersion = PropertiesProvider(project).webpackMajorVersion
|
||||
|
||||
val webpackConfig = KotlinWebpackConfig(
|
||||
configDirectory = project.projectDir.resolve("webpack.config.d"),
|
||||
optimization = KotlinWebpackConfig.Optimization(
|
||||
@@ -94,13 +91,11 @@ class KotlinKarma(
|
||||
export = false,
|
||||
progressReporter = true,
|
||||
progressReporterPathFilter = nodeRootPackageDir,
|
||||
webpackMajorVersion = webpackMajorVersion,
|
||||
rules = project.objects.webpackRulesContainer(),
|
||||
experiments = mutableSetOf("topLevelAwait")
|
||||
)
|
||||
|
||||
init {
|
||||
requiredDependencies.add(versions.kotlinJsTestRunner)
|
||||
requiredDependencies.add(versions.karma)
|
||||
|
||||
useKotlinReporter()
|
||||
@@ -266,23 +261,14 @@ class KotlinKarma(
|
||||
config.frameworks.add("webpack")
|
||||
requiredDependencies.add(versions.karmaWebpack)
|
||||
requiredDependencies.add(
|
||||
webpackMajorVersion.choose(
|
||||
versions.webpack,
|
||||
versions.webpack4
|
||||
)
|
||||
versions.webpack
|
||||
)
|
||||
requiredDependencies.add(
|
||||
webpackMajorVersion.choose(
|
||||
versions.webpackCli,
|
||||
versions.webpackCli3
|
||||
)
|
||||
versions.webpackCli
|
||||
)
|
||||
requiredDependencies.add(versions.formatUtil)
|
||||
requiredDependencies.add(
|
||||
webpackMajorVersion.choose(
|
||||
versions.sourceMapLoader,
|
||||
versions.sourceMapLoader1
|
||||
)
|
||||
versions.sourceMapLoader
|
||||
)
|
||||
|
||||
addPreprocessor("webpack")
|
||||
@@ -298,14 +284,12 @@ class KotlinKarma(
|
||||
// noinspection JSUnnecessarySemicolon
|
||||
;(function(config) {
|
||||
const webpack = require('webpack');
|
||||
${
|
||||
if (webpackMajorVersion != WebpackMajorVersion.V4) {
|
||||
"""
|
||||
// https://github.com/webpack/webpack/issues/12951
|
||||
const PatchSourceMapSource = require('kotlin-test-js-runner/webpack-5-debug');
|
||||
config.plugins.push(new PatchSourceMapSource())
|
||||
"""
|
||||
} else ""
|
||||
${
|
||||
"""
|
||||
// https://github.com/webpack/webpack/issues/12951
|
||||
const PatchSourceMapSource = require('kotlin-test-js-runner/webpack-5-debug');
|
||||
config.plugins.push(new PatchSourceMapSource())
|
||||
"""
|
||||
}
|
||||
config.plugins.push(new webpack.SourceMapDevToolPlugin({
|
||||
moduleFilenameTemplate: "[absolute-resource-path]"
|
||||
|
||||
+2
-2
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
|
||||
import org.jetbrains.kotlin.gradle.targets.js.RequiredKotlinJsDependency
|
||||
import org.jetbrains.kotlin.gradle.targets.js.internal.parseNodeJsStackTraceAsJvm
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin.Companion.kotlinNodeJsExtension
|
||||
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.KotlinJsTestFramework
|
||||
@@ -25,7 +26,7 @@ class KotlinMocha(@Transient override val compilation: KotlinJsCompilation, priv
|
||||
@Transient
|
||||
private val project: Project = compilation.target.project
|
||||
private val npmProject = compilation.npmProject
|
||||
private val versions = NodeJsRootPlugin.apply(project.rootProject).versions
|
||||
private val versions = project.rootProject.kotlinNodeJsExtension.versions
|
||||
private val isTeamCity = project.providers.gradleProperty(TCServiceMessagesTestExecutor.TC_PROJECT_PROPERTY)
|
||||
|
||||
override val settingsState: String
|
||||
@@ -33,7 +34,6 @@ class KotlinMocha(@Transient override val compilation: KotlinJsCompilation, priv
|
||||
|
||||
override val requiredNpmDependencies: Set<RequiredKotlinJsDependency>
|
||||
get() = setOf(
|
||||
versions.kotlinJsTestRunner,
|
||||
versions.mocha,
|
||||
versions.sourceMapSupport,
|
||||
versions.formatUtil
|
||||
|
||||
+8
-10
@@ -6,15 +6,15 @@
|
||||
package org.jetbrains.kotlin.gradle.targets.js.typescript
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.tasks.*
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.*
|
||||
import org.gradle.work.NormalizeLineEndings
|
||||
import org.jetbrains.kotlin.gradle.internal.execWithProgress
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
|
||||
import org.jetbrains.kotlin.gradle.targets.js.RequiredKotlinJsDependency
|
||||
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinIrJsGeneratedTSValidationStrategy
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin.Companion.kotlinNodeJsExtension
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.RequiresNpmDependencies
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject
|
||||
import javax.inject.Inject
|
||||
@@ -30,14 +30,13 @@ constructor(
|
||||
|
||||
@get:Internal
|
||||
@Transient
|
||||
protected val nodeJs = NodeJsRootPlugin.apply(project.rootProject)
|
||||
protected val nodeJs = project.rootProject.kotlinNodeJsExtension
|
||||
|
||||
@get:Internal
|
||||
override val nodeModulesRequired: Boolean get() = false
|
||||
private val versions = nodeJs.versions
|
||||
|
||||
@get:Internal
|
||||
override val requiredNpmDependencies: Set<RequiredKotlinJsDependency>
|
||||
get() = setOf(nodeJs.versions.typescript)
|
||||
get() = setOf(versions.typescript)
|
||||
|
||||
@get:SkipWhenEmpty
|
||||
@get:NormalizeLineEndings
|
||||
@@ -69,9 +68,8 @@ constructor(
|
||||
|
||||
val message = "Oops, Kotlin/JS compiler generated invalid d.ts files."
|
||||
|
||||
when (validationStrategy) {
|
||||
KotlinIrJsGeneratedTSValidationStrategy.ERROR -> error(message)
|
||||
KotlinIrJsGeneratedTSValidationStrategy.IGNORE -> {}
|
||||
if (validationStrategy == KotlinIrJsGeneratedTSValidationStrategy.ERROR) {
|
||||
error(message)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-11
@@ -35,6 +35,7 @@ import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinWebpackRulesContainer
|
||||
import org.jetbrains.kotlin.gradle.targets.js.dsl.WebpackRulesDsl
|
||||
import org.jetbrains.kotlin.gradle.targets.js.dsl.WebpackRulesDsl.Companion.webpackRulesContainer
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin.Companion.kotlinNodeJsExtension
|
||||
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.webpack.KotlinWebpackConfig.Mode
|
||||
@@ -55,9 +56,8 @@ constructor(
|
||||
private val objects: ObjectFactory
|
||||
) : DefaultTask(), RequiresNpmDependencies, WebpackRulesDsl, UsesBuildMetricsService {
|
||||
@Transient
|
||||
private val nodeJs = NodeJsRootPlugin.apply(project.rootProject)
|
||||
private val nodeJs = project.rootProject.kotlinNodeJsExtension
|
||||
private val versions = nodeJs.versions
|
||||
private val resolutionManager = nodeJs.npmResolutionManager
|
||||
private val rootPackageDir by lazy { nodeJs.rootPackageDir }
|
||||
|
||||
private val npmProject = compilation.npmProject
|
||||
@@ -202,9 +202,6 @@ constructor(
|
||||
@Internal
|
||||
var generateConfigOnly: Boolean = false
|
||||
|
||||
@Input
|
||||
val webpackMajorVersion = PropertiesProvider(project).webpackMajorVersion
|
||||
|
||||
fun webpackConfigApplier(body: Action<KotlinWebpackConfig>) {
|
||||
webpackConfigAppliers.add(body)
|
||||
}
|
||||
@@ -234,7 +231,6 @@ constructor(
|
||||
devtool = devtool,
|
||||
sourceMaps = sourceMaps,
|
||||
resolveFromModulesFirst = resolveFromModulesFirst,
|
||||
webpackMajorVersion = webpackMajorVersion
|
||||
)
|
||||
|
||||
private fun createRunner(): KotlinWebpackRunner {
|
||||
@@ -262,9 +258,6 @@ constructor(
|
||||
)
|
||||
}
|
||||
|
||||
override val nodeModulesRequired: Boolean
|
||||
@Internal get() = true
|
||||
|
||||
override val requiredNpmDependencies: Set<RequiredKotlinJsDependency>
|
||||
@Internal get() = createWebpackConfig(true).getRequiredDependencies(versions)
|
||||
|
||||
@@ -272,8 +265,6 @@ constructor(
|
||||
|
||||
@TaskAction
|
||||
fun doExecute() {
|
||||
resolutionManager.checkRequiredDependencies(task = this)
|
||||
|
||||
val runner = createRunner()
|
||||
|
||||
if (generateConfigOnly) {
|
||||
|
||||
+9
-31
@@ -20,7 +20,6 @@ import org.jetbrains.kotlin.gradle.targets.js.appendConfigsFromDir
|
||||
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinWebpackRulesContainer
|
||||
import org.jetbrains.kotlin.gradle.targets.js.dsl.WebpackRulesDsl
|
||||
import org.jetbrains.kotlin.gradle.targets.js.jsQuoted
|
||||
import org.jetbrains.kotlin.gradle.targets.js.webpack.WebpackMajorVersion.Companion.choose
|
||||
import org.jetbrains.kotlin.gradle.utils.appendLine
|
||||
import org.jetbrains.kotlin.gradle.utils.relativeOrAbsolute
|
||||
import java.io.File
|
||||
@@ -49,6 +48,8 @@ data class KotlinWebpackConfig(
|
||||
@get:NormalizeLineEndings
|
||||
@get:InputDirectory
|
||||
var configDirectory: File? = null,
|
||||
@Internal
|
||||
var reportEvaluatedConfigFile: File? = null,
|
||||
@Input
|
||||
@Optional
|
||||
var devServer: DevServer? = null,
|
||||
@@ -72,9 +73,7 @@ data class KotlinWebpackConfig(
|
||||
@Optional
|
||||
var progressReporterPathFilter: File? = null,
|
||||
@Input
|
||||
var resolveFromModulesFirst: Boolean = false,
|
||||
@Input
|
||||
val webpackMajorVersion: WebpackMajorVersion = WebpackMajorVersion.V5
|
||||
var resolveFromModulesFirst: Boolean = false
|
||||
) : WebpackRulesDsl {
|
||||
|
||||
@get:Input
|
||||
@@ -94,36 +93,23 @@ data class KotlinWebpackConfig(
|
||||
|
||||
fun getRequiredDependencies(versions: NpmVersions) =
|
||||
mutableSetOf<RequiredKotlinJsDependency>().also {
|
||||
it.add(versions.kotlinJsTestRunner)
|
||||
it.add(
|
||||
webpackMajorVersion.choose(
|
||||
versions.webpack,
|
||||
versions.webpack4
|
||||
)
|
||||
versions.webpack
|
||||
)
|
||||
it.add(
|
||||
webpackMajorVersion.choose(
|
||||
versions.webpackCli,
|
||||
versions.webpackCli3
|
||||
)
|
||||
versions.webpackCli
|
||||
)
|
||||
it.add(versions.formatUtil)
|
||||
|
||||
if (sourceMaps) {
|
||||
it.add(
|
||||
webpackMajorVersion.choose(
|
||||
versions.sourceMapLoader,
|
||||
versions.sourceMapLoader1
|
||||
)
|
||||
versions.sourceMapLoader
|
||||
)
|
||||
}
|
||||
|
||||
if (devServer != null) {
|
||||
it.add(
|
||||
webpackMajorVersion.choose(
|
||||
versions.webpackDevServer,
|
||||
versions.webpackDevServer3
|
||||
)
|
||||
versions.webpackDevServer
|
||||
)
|
||||
}
|
||||
|
||||
@@ -294,16 +280,8 @@ data class KotlinWebpackConfig(
|
||||
enforce: "pre"
|
||||
});
|
||||
config.devtool = ${devtool?.let { "'$it'" } ?: false};
|
||||
${
|
||||
webpackMajorVersion.choose(
|
||||
"config.ignoreWarnings = [/Failed to parse source map/]",
|
||||
"""
|
||||
config.stats = config.stats || {}
|
||||
Object.assign(config.stats, config.stats, {
|
||||
warningsFilter: [/Failed to parse source map/]
|
||||
})
|
||||
"""
|
||||
)
|
||||
${
|
||||
"config.ignoreWarnings = [/Failed to parse source map/]"
|
||||
}
|
||||
|
||||
""".trimIndent()
|
||||
|
||||
+5
-28
@@ -5,55 +5,43 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle.targets.js.yarn
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.logging.Logger
|
||||
import org.gradle.internal.service.ServiceRegistry
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmApi
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmDependency
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmEnvironment
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinCompilationNpmResolution
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.YarnEnvironment
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.PreparedKotlinCompilationNpmResolution
|
||||
import java.io.File
|
||||
|
||||
class Yarn : NpmApi {
|
||||
private val yarnWorkspaces = YarnWorkspaces()
|
||||
|
||||
private fun getDelegate(project: Project): NpmApi =
|
||||
yarnWorkspaces
|
||||
|
||||
override fun setup(project: Project) =
|
||||
getDelegate(project.rootProject).setup(project)
|
||||
|
||||
override fun preparedFiles(nodeJs: NpmEnvironment): Collection<File> =
|
||||
yarnWorkspaces.preparedFiles(nodeJs)
|
||||
|
||||
override fun prepareRootProject(
|
||||
rootProject: Project?,
|
||||
nodeJs: NpmEnvironment,
|
||||
rootProjectName: String,
|
||||
rootProjectVersion: String,
|
||||
logger: Logger,
|
||||
subProjects: Collection<KotlinCompilationNpmResolution>,
|
||||
subProjects: Collection<PreparedKotlinCompilationNpmResolution>,
|
||||
resolutions: Map<String, String>,
|
||||
forceFullResolve: Boolean
|
||||
) = yarnWorkspaces
|
||||
.prepareRootProject(
|
||||
rootProject,
|
||||
nodeJs,
|
||||
rootProjectName,
|
||||
rootProjectVersion,
|
||||
logger,
|
||||
subProjects,
|
||||
resolutions,
|
||||
forceFullResolve
|
||||
)
|
||||
|
||||
override fun resolveRootProject(
|
||||
services: ServiceRegistry,
|
||||
logger: Logger,
|
||||
nodeJs: NpmEnvironment,
|
||||
yarn: YarnEnv,
|
||||
npmProjects: Collection<KotlinCompilationNpmResolution>,
|
||||
yarn: YarnEnvironment,
|
||||
npmProjects: Collection<PreparedKotlinCompilationNpmResolution>,
|
||||
cliArgs: List<String>
|
||||
) {
|
||||
yarnWorkspaces
|
||||
@@ -66,15 +54,4 @@ class Yarn : NpmApi {
|
||||
cliArgs
|
||||
)
|
||||
}
|
||||
|
||||
override fun resolveDependency(
|
||||
npmResolution: KotlinCompilationNpmResolution,
|
||||
dependency: NpmDependency,
|
||||
transitive: Boolean
|
||||
) = getDelegate(npmResolution.project)
|
||||
.resolveDependency(
|
||||
npmResolution,
|
||||
dependency,
|
||||
transitive
|
||||
)
|
||||
}
|
||||
+2
-115
@@ -5,31 +5,21 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle.targets.js.yarn
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.logging.Logger
|
||||
import org.gradle.internal.service.ServiceRegistry
|
||||
import org.jetbrains.kotlin.gradle.internal.execWithProgress
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmApi
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmDependency
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmDependency.Scope.PEER
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmEnvironment
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinCompilationNpmResolution
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.YarnEnvironment
|
||||
import java.io.File
|
||||
|
||||
abstract class YarnBasics : NpmApi {
|
||||
|
||||
private val nonTransitiveResolvedDependencies = mutableMapOf<NpmDependency, Set<File>>()
|
||||
private val transitiveResolvedDependencies = mutableMapOf<NpmDependency, Set<File>>()
|
||||
|
||||
override fun setup(project: Project) {
|
||||
YarnPlugin.apply(project).executeSetup()
|
||||
}
|
||||
|
||||
fun yarnExec(
|
||||
services: ServiceRegistry,
|
||||
logger: Logger,
|
||||
nodeJs: NpmEnvironment,
|
||||
yarn: YarnEnv,
|
||||
yarn: YarnEnvironment,
|
||||
dir: File,
|
||||
description: String,
|
||||
args: List<String>
|
||||
@@ -69,107 +59,4 @@ abstract class YarnBasics : NpmApi {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun resolveDependency(
|
||||
npmResolution: KotlinCompilationNpmResolution,
|
||||
dependency: NpmDependency,
|
||||
transitive: Boolean
|
||||
): Set<File> {
|
||||
val files = (if (transitive) {
|
||||
transitiveResolvedDependencies
|
||||
} else {
|
||||
nonTransitiveResolvedDependencies
|
||||
})[dependency]
|
||||
|
||||
if (files != null) {
|
||||
return files
|
||||
}
|
||||
|
||||
val npmProject = npmResolution.npmProject
|
||||
|
||||
val all = mutableSetOf<File>()
|
||||
|
||||
npmProject.resolve(dependency.key)?.let {
|
||||
if (it.isFile) all.add(it)
|
||||
if (it.path.endsWith(".js")) {
|
||||
val baseName = it.path.removeSuffix(".js")
|
||||
val metaJs = File(baseName + ".meta.js")
|
||||
if (metaJs.isFile) all.add(metaJs)
|
||||
val kjsmDir = File(baseName)
|
||||
if (kjsmDir.isDirectory) {
|
||||
kjsmDir.walkTopDown()
|
||||
.filter { it.extension == "kjsm" }
|
||||
.forEach { all.add(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nonTransitiveResolvedDependencies[dependency] = all
|
||||
|
||||
if (transitive) {
|
||||
dependency.dependencies.forEach {
|
||||
resolveDependency(
|
||||
npmResolution,
|
||||
it,
|
||||
transitive
|
||||
).also { files ->
|
||||
all.addAll(files)
|
||||
}
|
||||
}
|
||||
transitiveResolvedDependencies[dependency] = all
|
||||
}
|
||||
|
||||
return all
|
||||
}
|
||||
|
||||
protected fun yarnLockReadTransitiveDependencies(
|
||||
nodeWorkDir: File,
|
||||
srcDependenciesList: Collection<NpmDependency>
|
||||
) {
|
||||
val yarnLock = nodeWorkDir
|
||||
.resolve("yarn.lock")
|
||||
.takeIf { it.isFile }
|
||||
?: return
|
||||
|
||||
val entryRegistry = YarnEntryRegistry(yarnLock)
|
||||
val visited = mutableMapOf<NpmDependency, NpmDependency>()
|
||||
|
||||
fun resolveRecursively(src: NpmDependency) {
|
||||
if (src.scope == PEER) {
|
||||
return
|
||||
}
|
||||
|
||||
val copy = visited[src]
|
||||
if (copy != null) {
|
||||
src.resolvedVersion = copy.resolvedVersion
|
||||
src.integrity = copy.integrity
|
||||
src.dependencies.addAll(copy.dependencies)
|
||||
return
|
||||
}
|
||||
visited[src] = src
|
||||
|
||||
val deps = entryRegistry.find(src.key, src.version)
|
||||
|
||||
src.resolvedVersion = deps.version
|
||||
src.integrity = deps.integrity
|
||||
|
||||
deps.dependencies.mapTo(src.dependencies) { dep ->
|
||||
val scopedName = dep.scopedName
|
||||
val child = NpmDependency(
|
||||
project = src.project,
|
||||
name = scopedName.toString(),
|
||||
version = dep.version ?: "*"
|
||||
)
|
||||
child.parent = src
|
||||
|
||||
resolveRecursively(child)
|
||||
|
||||
child
|
||||
}
|
||||
}
|
||||
|
||||
srcDependenciesList.forEach { src ->
|
||||
resolveRecursively(src)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-50
@@ -11,56 +11,6 @@ import org.jetbrains.kotlin.gradle.targets.js.npm.includedRange
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.intersect
|
||||
import java.io.File
|
||||
|
||||
internal class YarnEntryRegistry(private val lockFile: File) {
|
||||
private val entryMap = YarnLock.parse(lockFile)
|
||||
.entries
|
||||
.associateBy { it.dependencyKey }
|
||||
|
||||
fun find(packageKey: String, version: String): YarnLock.Entry {
|
||||
val key = dependencyKey(packageKey, version)
|
||||
val entry = entryMap[key]
|
||||
|
||||
if (entry != null) {
|
||||
return entry
|
||||
}
|
||||
|
||||
entryMap.entries
|
||||
.firstOrNull { (_, entry) ->
|
||||
if (entry.version == null) {
|
||||
false
|
||||
} else {
|
||||
(includedRange(version) intersect includedRange(entry.version)) != null
|
||||
}
|
||||
}
|
||||
?.let { return it.value }
|
||||
|
||||
throw GradleException(
|
||||
"Cannot find $key in yarn.lock"
|
||||
)
|
||||
}
|
||||
|
||||
private val YarnLock.Entry.dependencyKey: String
|
||||
get() = key.correctDependencyKey()
|
||||
|
||||
private fun dependencyKey(packageKey: String, version: String) =
|
||||
YarnLock.dependencyKey(packageKey, version).correctDependencyKey()
|
||||
|
||||
private fun String.correctDependencyKey(): String =
|
||||
when {
|
||||
GITHUB_MARKER in this -> replace(GITHUB_MARKER, SEPARATOR)
|
||||
FILE_MARKER in this -> {
|
||||
val location = substringAfter(FILE_MARKER)
|
||||
val path = lockFile
|
||||
.parentFile
|
||||
.resolve(location)
|
||||
.canonicalPath
|
||||
|
||||
replaceAfter(FILE_MARKER, path)
|
||||
}
|
||||
else -> this
|
||||
}
|
||||
}
|
||||
|
||||
private const val SEPARATOR = "@"
|
||||
|
||||
private const val FILE_MARKER = "${SEPARATOR}$FILE_VERSION_PREFIX"
|
||||
|
||||
+2
-2
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.gradle.targets.js.yarn
|
||||
|
||||
import org.jetbrains.kotlin.gradle.tasks.internal.CleanableStore
|
||||
import java.io.File
|
||||
import java.io.Serializable
|
||||
|
||||
data class YarnEnv(
|
||||
val downloadUrl: String,
|
||||
@@ -20,4 +19,5 @@ data class YarnEnv(
|
||||
val yarnLockMismatchReport: YarnLockMismatchReport,
|
||||
val reportNewYarnLock: Boolean,
|
||||
val yarnLockAutoReplace: Boolean,
|
||||
) : Serializable
|
||||
val yarnResolutions: List<YarnResolution>
|
||||
)
|
||||
|
||||
+2
-2
@@ -11,12 +11,12 @@ import org.jetbrains.kotlin.gradle.targets.js.npm.GradleNodeModule
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProject
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.PackageJson
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.fileVersion
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinCompilationNpmResolution
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.PreparedKotlinCompilationNpmResolution
|
||||
import java.io.File
|
||||
|
||||
class YarnImportedPackagesVersionResolver(
|
||||
private val logger: Logger,
|
||||
private val npmProjects: Collection<KotlinCompilationNpmResolution>,
|
||||
npmProjects: Collection<PreparedKotlinCompilationNpmResolution>,
|
||||
private val nodeJsWorldDir: File
|
||||
) {
|
||||
private val resolvedVersion = mutableMapOf<String, ResolvedNpmDependency>()
|
||||
|
||||
-154
@@ -1,154 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.gradle.targets.js.yarn
|
||||
|
||||
import com.google.gson.stream.JsonReader
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.PackageJson
|
||||
import java.io.File
|
||||
import java.io.StringReader
|
||||
|
||||
data class YarnLock(val entries: List<Entry>) {
|
||||
data class Entry(
|
||||
val key: String,
|
||||
val version: String?,
|
||||
val resolved: String?,
|
||||
val integrity: String?,
|
||||
val dependencies: List<Dependency>
|
||||
)
|
||||
|
||||
data class Dependency(val key: String, val version: String?) {
|
||||
val scopedName: PackageJson.ScopedName
|
||||
get() = PackageJson.scopedName(key)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun dependencyKey(packageKey: String, version: String) = "$packageKey@$version"
|
||||
|
||||
private class Node(val parent: Node?, val value: String? = null) {
|
||||
var indent: String? = null
|
||||
val children = mutableMapOf<String, Node>()
|
||||
}
|
||||
|
||||
fun parse(yarnLock: File): YarnLock {
|
||||
val root = parseTree(yarnLock)
|
||||
|
||||
return YarnLock(root.children.map {
|
||||
val values = it.value.children
|
||||
Entry(
|
||||
it.key,
|
||||
values["version"]?.value,
|
||||
values["resolved"]?.value,
|
||||
values["integrity"]?.value,
|
||||
values["dependencies"]?.children?.map { dep ->
|
||||
Dependency(dep.key, dep.value.value)
|
||||
} ?: listOf()
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
private fun parseTree(yarnLock: File): Node {
|
||||
val root = Node(null)
|
||||
var parent = root
|
||||
var onNewLevel = true
|
||||
yarnLock.useLines {
|
||||
it.forEach { line ->
|
||||
if (!line.startsWith("#")) {
|
||||
var i = 0
|
||||
while (i < line.length && line[i].isWhitespace()) i++
|
||||
val indentPos = i
|
||||
val indent = line.substring(0, indentPos)
|
||||
|
||||
val key = line.endsWith(":")
|
||||
|
||||
if (line.isNotEmpty()) {
|
||||
val values = parseLine(line, indentPos)
|
||||
|
||||
if (onNewLevel) {
|
||||
parent.indent = indent
|
||||
onNewLevel = false
|
||||
} else {
|
||||
while (indent != parent.indent!!) {
|
||||
parent = parent.parent!!
|
||||
}
|
||||
}
|
||||
|
||||
val child = Node(parent, if (values.size > 1) values[1] else null)
|
||||
if (key) {
|
||||
values.forEach {
|
||||
parent.children[it] = child
|
||||
}
|
||||
parent = child
|
||||
onNewLevel = true
|
||||
} else {
|
||||
parent.children[values[0]] = child
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return root
|
||||
}
|
||||
|
||||
private fun parseLine(line: String, indentPos: Int): List<String> {
|
||||
val quotedLineResult = replaceQuoted(line.removeSuffix(":"))
|
||||
|
||||
return quotedLineResult
|
||||
.parse(indentPos)
|
||||
}
|
||||
|
||||
private fun replaceQuoted(line: String): QuotedLineResult {
|
||||
var result: String = line
|
||||
val quotedValues = QUOTED_VALUE.findAll(line)
|
||||
.flatMap { it.groupValues.drop(1).asSequence() }
|
||||
.toList()
|
||||
|
||||
quotedValues.forEachIndexed { index, item ->
|
||||
result = result.replace(
|
||||
"""
|
||||
"$item"
|
||||
""".trimIndent(),
|
||||
"""
|
||||
"$$index"
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
return QuotedLineResult(
|
||||
result,
|
||||
quotedValues
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private data class QuotedLineResult(
|
||||
val value: String,
|
||||
val quotedValues: List<String>
|
||||
)
|
||||
|
||||
private fun QuotedLineResult.parse(indentPos: Int): List<String> {
|
||||
return value
|
||||
.substring(indentPos)
|
||||
.split(" ")
|
||||
.map { value ->
|
||||
val withoutComma = value.removeSuffix(",")
|
||||
if (withoutComma.startsWith("\"")) {
|
||||
val (index) = QUOTED_PLACEHOLDER.find(withoutComma)!!.destructured
|
||||
val restoredValue = """
|
||||
"${quotedValues[index.toInt()]}"
|
||||
""".trimIndent()
|
||||
|
||||
try {
|
||||
JsonReader(StringReader(restoredValue)).nextString()
|
||||
} catch (e: Throwable) {
|
||||
restoredValue.removePrefix("\"").removeSuffix("\"")
|
||||
}
|
||||
} else withoutComma
|
||||
}
|
||||
}
|
||||
|
||||
private val QUOTED_VALUE = """"(.+?)"""".toRegex()
|
||||
private val QUOTED_PLACEHOLDER = """\$(\d+)""".toRegex()
|
||||
+18
-4
@@ -11,6 +11,8 @@ import org.gradle.api.tasks.TaskProvider
|
||||
import org.jetbrains.kotlin.gradle.utils.markResolvable
|
||||
import org.jetbrains.kotlin.gradle.targets.js.MultiplePluginDeclarationDetector
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin.Companion.kotlinNodeJsExtension
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin.Companion.kotlinNpmResolutionManager
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.RequiresNpmDependencies
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.resolver.implementing
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.KotlinNpmInstallTask
|
||||
@@ -30,10 +32,12 @@ open class YarnPlugin : Plugin<Project> {
|
||||
}
|
||||
|
||||
val yarnRootExtension = this.extensions.create(YarnRootExtension.YARN, YarnRootExtension::class.java, this)
|
||||
val nodeJs = NodeJsRootPlugin.apply(this)
|
||||
NodeJsRootPlugin.apply(project)
|
||||
val nodeJs = this.kotlinNodeJsExtension
|
||||
val nodeJsTaskProviders = this.kotlinNodeJsExtension
|
||||
|
||||
val setupTask = registerTask<YarnSetupTask>(YarnSetupTask.NAME) {
|
||||
it.dependsOn(nodeJs.nodeJsSetupTaskProvider)
|
||||
it.dependsOn(nodeJsTaskProviders.nodeJsSetupTaskProvider)
|
||||
|
||||
it.configuration = provider {
|
||||
this.project.configurations.detachedConfiguration(this.project.dependencies.create(it.ivyDependency))
|
||||
@@ -43,9 +47,19 @@ open class YarnPlugin : Plugin<Project> {
|
||||
}
|
||||
|
||||
val rootPackageJson = tasks.register(RootPackageJsonTask.NAME, RootPackageJsonTask::class.java) { task ->
|
||||
task.dependsOn(nodeJs.npmCachesSetupTaskProvider)
|
||||
task.dependsOn(nodeJsTaskProviders.npmCachesSetupTaskProvider)
|
||||
task.group = NodeJsRootPlugin.TASKS_GROUP_NAME
|
||||
task.description = "Create root package.json"
|
||||
|
||||
task.npmResolutionManager.apply {
|
||||
set(project.kotlinNpmResolutionManager)
|
||||
disallowChanges()
|
||||
}
|
||||
|
||||
task.onlyIf {
|
||||
it as RootPackageJsonTask
|
||||
it.npmResolutionManager.get().isConfiguringState()
|
||||
}
|
||||
}
|
||||
|
||||
configureRequiresNpmDependencies(project, rootPackageJson)
|
||||
@@ -62,7 +76,7 @@ open class YarnPlugin : Plugin<Project> {
|
||||
it.description = "Clean unused local yarn version"
|
||||
}
|
||||
|
||||
val packageJsonUmbrella = nodeJs
|
||||
val packageJsonUmbrella = nodeJsTaskProviders
|
||||
.packageJsonUmbrellaTaskProvider
|
||||
|
||||
yarnRootExtension.rootPackageJsonTaskProvider.configure {
|
||||
|
||||
+2
-29
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.gradle.targets.js.yarn
|
||||
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.PlatformHelper
|
||||
import org.gradle.api.Action
|
||||
import org.gradle.api.Incubating
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.tasks.TaskProvider
|
||||
import org.jetbrains.kotlin.gradle.internal.ConfigurationPhaseAware
|
||||
@@ -20,7 +19,6 @@ import org.jetbrains.kotlin.gradle.tasks.internal.CleanableStore
|
||||
import java.io.File
|
||||
|
||||
open class YarnRootExtension(
|
||||
@Transient
|
||||
val project: Project
|
||||
) : ConfigurationPhaseAware<YarnEnv>() {
|
||||
init {
|
||||
@@ -60,7 +58,7 @@ open class YarnRootExtension(
|
||||
.withType(RootPackageJsonTask::class.java)
|
||||
.named(RootPackageJsonTask.NAME)
|
||||
|
||||
var resolutions: MutableList<YarnResolution> = mutableListOf()
|
||||
var resolutions: MutableList<YarnResolution> by Property(mutableListOf())
|
||||
|
||||
fun resolution(path: String, configure: Action<YarnResolution>) {
|
||||
resolutions.add(
|
||||
@@ -75,21 +73,6 @@ open class YarnRootExtension(
|
||||
})
|
||||
}
|
||||
|
||||
@Incubating
|
||||
fun disableGranularWorkspaces() {
|
||||
val packageJsonUmbrella = NodeJsRootPlugin.apply(project)
|
||||
.packageJsonUmbrellaTaskProvider
|
||||
|
||||
rootPackageJsonTaskProvider.configure {
|
||||
it.dependsOn(packageJsonUmbrella)
|
||||
}
|
||||
|
||||
project.allprojects
|
||||
.forEach {
|
||||
it.tasks.implementing(RequiresNpmDependencies::class).all {}
|
||||
}
|
||||
}
|
||||
|
||||
override fun finalizeConfiguration(): YarnEnv {
|
||||
val cleanableStore = CleanableStore[installationDir.path]
|
||||
|
||||
@@ -116,20 +99,10 @@ open class YarnRootExtension(
|
||||
yarnLockMismatchReport = yarnLockMismatchReport,
|
||||
reportNewYarnLock = reportNewYarnLock,
|
||||
yarnLockAutoReplace = yarnLockAutoReplace,
|
||||
yarnResolutions = resolutions
|
||||
)
|
||||
}
|
||||
|
||||
internal fun executeSetup() {
|
||||
NodeJsRootPlugin.apply(project).executeSetup()
|
||||
|
||||
if (!download) return
|
||||
|
||||
val yarnSetupTask = yarnSetupTaskProvider.get()
|
||||
yarnSetupTask.actions.forEach {
|
||||
it.execute(yarnSetupTask)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val YARN: String = "kotlinYarn"
|
||||
|
||||
|
||||
+5
-5
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.gradle.targets.js.yarn
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.artifacts.Configuration
|
||||
import org.gradle.api.file.ArchiveOperations
|
||||
import org.gradle.api.file.FileSystemOperations
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.tasks.*
|
||||
@@ -15,24 +16,23 @@ import org.jetbrains.kotlin.gradle.logging.kotlinInfo
|
||||
import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService
|
||||
import org.jetbrains.kotlin.gradle.targets.js.extractWithUpToDate
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
|
||||
import org.jetbrains.kotlin.gradle.utils.ArchiveOperationsCompat
|
||||
import org.jetbrains.kotlin.statistics.metrics.NumericalMetrics
|
||||
import java.io.File
|
||||
import java.net.URI
|
||||
import javax.inject.Inject
|
||||
|
||||
open class YarnSetupTask : DefaultTask() {
|
||||
abstract class YarnSetupTask : DefaultTask() {
|
||||
@Transient
|
||||
private val settings = project.yarn
|
||||
private val env by lazy { settings.requireConfigured() }
|
||||
|
||||
private val shouldDownload = settings.download
|
||||
|
||||
private val archiveOperations = ArchiveOperationsCompat(project)
|
||||
@get:Inject
|
||||
abstract internal val archiveOperations: ArchiveOperations
|
||||
|
||||
@get:Inject
|
||||
internal open val fileHasher: FileHasher
|
||||
get() = error("Should be injected")
|
||||
abstract internal val fileHasher: FileHasher
|
||||
|
||||
@get:Inject
|
||||
internal open val fs: FileSystemOperations
|
||||
|
||||
+8
-19
@@ -5,14 +5,10 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle.targets.js.yarn
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.logging.Logger
|
||||
import org.gradle.internal.service.ServiceRegistry
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmApi
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmEnvironment
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProject
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.PackageJson
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinCompilationNpmResolution
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.*
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.PreparedKotlinCompilationNpmResolution
|
||||
import java.io.File
|
||||
|
||||
class YarnWorkspaces : YarnBasics() {
|
||||
@@ -25,18 +21,13 @@ class YarnWorkspaces : YarnBasics() {
|
||||
}
|
||||
|
||||
override fun prepareRootProject(
|
||||
rootProject: Project?,
|
||||
nodeJs: NpmEnvironment,
|
||||
rootProjectName: String,
|
||||
rootProjectVersion: String,
|
||||
logger: Logger,
|
||||
subProjects: Collection<KotlinCompilationNpmResolution>,
|
||||
subProjects: Collection<PreparedKotlinCompilationNpmResolution>,
|
||||
resolutions: Map<String, String>,
|
||||
forceFullResolve: Boolean
|
||||
) {
|
||||
if (forceFullResolve) {
|
||||
rootProject?.let { setup(it) }
|
||||
}
|
||||
return prepareRootPackageJson(
|
||||
nodeJs,
|
||||
rootProjectName,
|
||||
@@ -52,7 +43,7 @@ class YarnWorkspaces : YarnBasics() {
|
||||
rootProjectName: String,
|
||||
rootProjectVersion: String,
|
||||
logger: Logger,
|
||||
npmProjects: Collection<KotlinCompilationNpmResolution>,
|
||||
npmProjects: Collection<PreparedKotlinCompilationNpmResolution>,
|
||||
resolutions: Map<String, String>
|
||||
) {
|
||||
val rootPackageJsonFile = preparedFiles(nodeJs).single()
|
||||
@@ -71,8 +62,8 @@ class YarnWorkspaces : YarnBasics() {
|
||||
services: ServiceRegistry,
|
||||
logger: Logger,
|
||||
nodeJs: NpmEnvironment,
|
||||
yarn: YarnEnv,
|
||||
npmProjects: Collection<KotlinCompilationNpmResolution>,
|
||||
yarn: YarnEnvironment,
|
||||
npmProjects: Collection<PreparedKotlinCompilationNpmResolution>,
|
||||
cliArgs: List<String>
|
||||
) {
|
||||
val nodeJsWorldDir = nodeJs.rootPackageDir
|
||||
@@ -86,15 +77,13 @@ class YarnWorkspaces : YarnBasics() {
|
||||
NpmApi.resolveOperationDescription("yarn"),
|
||||
cliArgs
|
||||
)
|
||||
|
||||
yarnLockReadTransitiveDependencies(nodeJsWorldDir, npmProjects.flatMap { it.externalNpmDependencies })
|
||||
}
|
||||
|
||||
private fun saveRootProjectWorkspacesPackageJson(
|
||||
rootProjectName: String,
|
||||
rootProjectVersion: String,
|
||||
logger: Logger,
|
||||
npmProjects: Collection<KotlinCompilationNpmResolution>,
|
||||
npmProjects: Collection<PreparedKotlinCompilationNpmResolution>,
|
||||
resolutions: Map<String, String>,
|
||||
rootPackageJsonFile: File
|
||||
) {
|
||||
@@ -102,7 +91,7 @@ class YarnWorkspaces : YarnBasics() {
|
||||
val rootPackageJson = PackageJson(rootProjectName, rootProjectVersion)
|
||||
rootPackageJson.private = true
|
||||
|
||||
val npmProjectWorkspaces = npmProjects.map { it.npmProject.dir.relativeTo(nodeJsWorldDir).path }
|
||||
val npmProjectWorkspaces = npmProjects.map { it.npmProjectDir.relativeTo(nodeJsWorldDir).path }
|
||||
val importedProjectWorkspaces =
|
||||
YarnImportedPackagesVersionResolver(logger, npmProjects, nodeJsWorldDir).resolveAndUpdatePackages()
|
||||
|
||||
|
||||
-39
@@ -53,45 +53,6 @@ internal fun checkGradleCompatibility(
|
||||
internal val AbstractArchiveTask.archivePathCompatible: File
|
||||
get() = archiveFile.get().asFile
|
||||
|
||||
internal class ArchiveOperationsCompat(@Transient private val project: Project) : Serializable {
|
||||
private val archiveOperations: Any? = try {
|
||||
(project as ProjectInternal).services.get(ArchiveOperations::class.java)
|
||||
} catch (e: NoClassDefFoundError) {
|
||||
// Gradle version < 6.6
|
||||
null
|
||||
}
|
||||
|
||||
fun zipTree(obj: Any): FileTree {
|
||||
return when (archiveOperations) {
|
||||
is ArchiveOperations -> archiveOperations.zipTree(obj)
|
||||
else -> project.zipTree(obj)
|
||||
}
|
||||
}
|
||||
|
||||
fun tarTree(obj: Any): FileTree {
|
||||
return when (archiveOperations) {
|
||||
is ArchiveOperations -> archiveOperations.tarTree(obj)
|
||||
else -> project.tarTree(obj)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class FileSystemOperationsCompat(@Transient private val project: Project) : Serializable {
|
||||
private val fileSystemOperations: Any? = try {
|
||||
(project as ProjectInternal).services.get(FileSystemOperations::class.java)
|
||||
} catch (e: NoClassDefFoundError) {
|
||||
// Gradle version < 6.0
|
||||
null
|
||||
}
|
||||
|
||||
fun copy(action: (CopySpec) -> Unit): WorkResult? {
|
||||
return when (fileSystemOperations) {
|
||||
is FileSystemOperations -> fileSystemOperations.copy(action)
|
||||
else -> project.copy(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Gradle dropped out getOwnerBuildOperationId. Workaround to build correct plugin for Gradle < 6.8
|
||||
// See https://github.com/gradle/gradle/commit/0296f4441ae69ad608cfef6a90fef3fdf314fa2c
|
||||
internal interface LegacyTestDescriptorInternal : TestDescriptor {
|
||||
|
||||
Reference in New Issue
Block a user