NodeJsRootExtension, YarnRootExtension: introduce configuration phase
Some properties were calculated based on yarn and nodeJs version. So, when version is changed properties were not updated. This change moves calculation to the end of configuration phase and adds assertion to ensure that version and other poperties are not changed after configuration was done.
This commit is contained in:
committed by
nataliya.valtman
parent
9c08ea3bf1
commit
6ac21856cc
+37
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* 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.internal
|
||||||
|
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
|
abstract class ConfigurationPhaseAware<C : Any> {
|
||||||
|
|
||||||
|
private var configured: C? = null
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
fun requireConfigured(): C {
|
||||||
|
if (configured == null) {
|
||||||
|
configured = finalizeConfiguration()
|
||||||
|
}
|
||||||
|
|
||||||
|
return configured!!
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun requireNotConfigured() {
|
||||||
|
check(configured == null) { "Configuration already finalized for previous property values" }
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class Property<T>(var value: T) {
|
||||||
|
operator fun getValue(receiver: Any, property: KProperty<*>): T = value
|
||||||
|
|
||||||
|
operator fun setValue(receiver: Any, property: KProperty<*>, value: T) {
|
||||||
|
requireNotConfigured()
|
||||||
|
this.value = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract fun finalizeConfiguration(): C
|
||||||
|
}
|
||||||
+3
-1
@@ -1,8 +1,10 @@
|
|||||||
package org.jetbrains.kotlin.gradle.targets.js.nodejs
|
package org.jetbrains.kotlin.gradle.targets.js.nodejs
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.gradle.tasks.internal.CleanableStore
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
internal data class NodeJsEnv(
|
data class NodeJsEnv(
|
||||||
|
val cleanableStore: CleanableStore,
|
||||||
val nodeDir: File,
|
val nodeDir: File,
|
||||||
val nodeBinDir: File,
|
val nodeBinDir: File,
|
||||||
val nodeExecutable: String,
|
val nodeExecutable: String,
|
||||||
|
|||||||
+1
-1
@@ -72,7 +72,7 @@ open class NodeJsExec : AbstractExecTask<NodeJsExec>(NodeJsExec::class.java), Re
|
|||||||
return project.registerTask(name) {
|
return project.registerTask(name) {
|
||||||
it.nodeJs = nodeJs
|
it.nodeJs = nodeJs
|
||||||
it.compilation = compilation
|
it.compilation = compilation
|
||||||
it.executable = nodeJs.environment.nodeExecutable
|
it.executable = nodeJs.requireConfigured().nodeExecutable
|
||||||
it.dependsOn(nodeJs.npmInstallTask)
|
it.dependsOn(nodeJs.npmInstallTask)
|
||||||
|
|
||||||
val compileKotlinTask = compilation.compileKotlinTask
|
val compileKotlinTask = compilation.compileKotlinTask
|
||||||
|
|||||||
+37
-35
@@ -1,6 +1,7 @@
|
|||||||
package org.jetbrains.kotlin.gradle.targets.js.nodejs
|
package org.jetbrains.kotlin.gradle.targets.js.nodejs
|
||||||
|
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
|
import org.jetbrains.kotlin.gradle.internal.ConfigurationPhaseAware
|
||||||
import org.jetbrains.kotlin.gradle.logging.kotlinInfo
|
import org.jetbrains.kotlin.gradle.logging.kotlinInfo
|
||||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
|
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.NpmVersions
|
import org.jetbrains.kotlin.gradle.targets.js.NpmVersions
|
||||||
@@ -11,7 +12,7 @@ import org.jetbrains.kotlin.gradle.targets.js.yarn.Yarn
|
|||||||
import org.jetbrains.kotlin.gradle.tasks.internal.CleanableStore
|
import org.jetbrains.kotlin.gradle.tasks.internal.CleanableStore
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
open class NodeJsRootExtension(val rootProject: Project) {
|
open class NodeJsRootExtension(val rootProject: Project) : ConfigurationPhaseAware<NodeJsEnv>() {
|
||||||
init {
|
init {
|
||||||
check(rootProject.rootProject == rootProject)
|
check(rootProject.rootProject == rootProject)
|
||||||
}
|
}
|
||||||
@@ -20,16 +21,16 @@ open class NodeJsRootExtension(val rootProject: Project) {
|
|||||||
rootProject.logger.kotlinInfo("Storing cached files in $it")
|
rootProject.logger.kotlinInfo("Storing cached files in $it")
|
||||||
}
|
}
|
||||||
|
|
||||||
var installationDir = gradleHome.resolve("nodejs")
|
var installationDir by Property(gradleHome.resolve("nodejs"))
|
||||||
var cleanableStore = CleanableStore[installationDir.absolutePath]
|
|
||||||
|
|
||||||
var download = true
|
var download by Property(true)
|
||||||
var nodeDownloadBaseUrl = "https://nodejs.org/dist"
|
|
||||||
var nodeVersion = "12.14.0"
|
|
||||||
|
|
||||||
var nodeCommand = "node"
|
var nodeDownloadBaseUrl by Property("https://nodejs.org/dist")
|
||||||
|
var nodeVersion by Property("12.14.0")
|
||||||
|
|
||||||
var packageManager: NpmApi = Yarn
|
var nodeCommand by Property("node")
|
||||||
|
|
||||||
|
var packageManager: NpmApi by Property(Yarn)
|
||||||
|
|
||||||
private val projectProperties = PropertiesProvider(rootProject)
|
private val projectProperties = PropertiesProvider(rootProject)
|
||||||
|
|
||||||
@@ -61,38 +62,39 @@ open class NodeJsRootExtension(val rootProject: Project) {
|
|||||||
val nodeModulesGradleCacheDir: File
|
val nodeModulesGradleCacheDir: File
|
||||||
get() = rootPackageDir.resolve("packages_imported")
|
get() = rootPackageDir.resolve("packages_imported")
|
||||||
|
|
||||||
internal val environment: NodeJsEnv
|
override fun finalizeConfiguration(): NodeJsEnv {
|
||||||
get() {
|
val platform = NodeJsPlatform.name
|
||||||
val platform = NodeJsPlatform.name
|
val architecture = NodeJsPlatform.architecture
|
||||||
val architecture = NodeJsPlatform.architecture
|
|
||||||
|
|
||||||
val nodeDirName = "node-v$nodeVersion-$platform-$architecture"
|
val nodeDirName = "node-v$nodeVersion-$platform-$architecture"
|
||||||
val nodeDir = cleanableStore[nodeDirName].use()
|
val cleanableStore = CleanableStore[installationDir.absolutePath]
|
||||||
val isWindows = NodeJsPlatform.name == NodeJsPlatform.WIN
|
val nodeDir = cleanableStore[nodeDirName].use()
|
||||||
val nodeBinDir = if (isWindows) nodeDir else nodeDir.resolve("bin")
|
val isWindows = NodeJsPlatform.name == NodeJsPlatform.WIN
|
||||||
|
val nodeBinDir = if (isWindows) nodeDir else nodeDir.resolve("bin")
|
||||||
|
|
||||||
fun getExecutable(command: String, customCommand: String, windowsExtension: String): String {
|
fun getExecutable(command: String, customCommand: String, windowsExtension: String): String {
|
||||||
val finalCommand = if (isWindows && customCommand == command) "$command.$windowsExtension" else customCommand
|
val finalCommand = if (isWindows && customCommand == command) "$command.$windowsExtension" else customCommand
|
||||||
return if (download) File(nodeBinDir, finalCommand).absolutePath else finalCommand
|
return if (download) File(nodeBinDir, finalCommand).absolutePath else finalCommand
|
||||||
}
|
|
||||||
|
|
||||||
fun getIvyDependency(): String {
|
|
||||||
val type = if (isWindows) "zip" else "tar.gz"
|
|
||||||
return "org.nodejs:node:$nodeVersion:$platform-$architecture@$type"
|
|
||||||
}
|
|
||||||
|
|
||||||
return NodeJsEnv(
|
|
||||||
nodeDir = nodeDir,
|
|
||||||
nodeBinDir = nodeBinDir,
|
|
||||||
nodeExecutable = getExecutable("node", nodeCommand, "exe"),
|
|
||||||
platformName = platform,
|
|
||||||
architectureName = architecture,
|
|
||||||
ivyDependency = getIvyDependency()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getIvyDependency(): String {
|
||||||
|
val type = if (isWindows) "zip" else "tar.gz"
|
||||||
|
return "org.nodejs:node:$nodeVersion:$platform-$architecture@$type"
|
||||||
|
}
|
||||||
|
|
||||||
|
return NodeJsEnv(
|
||||||
|
cleanableStore = cleanableStore,
|
||||||
|
nodeDir = nodeDir,
|
||||||
|
nodeBinDir = nodeBinDir,
|
||||||
|
nodeExecutable = getExecutable("node", nodeCommand, "exe"),
|
||||||
|
platformName = platform,
|
||||||
|
architectureName = architecture,
|
||||||
|
ivyDependency = getIvyDependency()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
internal fun executeSetup() {
|
internal fun executeSetup() {
|
||||||
val nodeJsEnv = environment
|
val nodeJsEnv = requireConfigured()
|
||||||
if (download) {
|
if (download) {
|
||||||
if (!nodeJsEnv.nodeBinDir.isDirectory) {
|
if (!nodeJsEnv.nodeBinDir.isDirectory) {
|
||||||
nodeJsSetupTask.exec()
|
nodeJsSetupTask.exec()
|
||||||
|
|||||||
+3
-3
@@ -22,14 +22,14 @@ open class NodeJsRootPlugin : Plugin<Project> {
|
|||||||
it.description = "Download and install a local node/npm version"
|
it.description = "Download and install a local node/npm version"
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.create(KotlinNpmInstallTask.NAME, KotlinNpmInstallTask::class.java) {
|
tasks.register(KotlinNpmInstallTask.NAME, KotlinNpmInstallTask::class.java) {
|
||||||
it.dependsOn(setupTask)
|
it.dependsOn(setupTask)
|
||||||
it.group = TASKS_GROUP_NAME
|
it.group = TASKS_GROUP_NAME
|
||||||
it.description = "Find, download and link NPM dependencies and projects"
|
it.description = "Find, download and link NPM dependencies and projects"
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.create("node" + CleanDataTask.NAME, CleanDataTask::class.java) {
|
tasks.register("node" + CleanDataTask.NAME_SUFFIX, CleanDataTask::class.java) {
|
||||||
it.cleanableStore = settings.cleanableStore
|
it.cleanableStore = settings.requireConfigured().cleanableStore
|
||||||
it.group = TASKS_GROUP_NAME
|
it.group = TASKS_GROUP_NAME
|
||||||
it.description = "Clean unused local node version"
|
it.description = "Clean unused local node version"
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@ import java.net.URI
|
|||||||
@CacheableTask
|
@CacheableTask
|
||||||
open class NodeJsSetupTask : DefaultTask() {
|
open class NodeJsSetupTask : DefaultTask() {
|
||||||
private val settings get() = NodeJsRootPlugin.apply(project.rootProject)
|
private val settings get() = NodeJsRootPlugin.apply(project.rootProject)
|
||||||
private val env by lazy { settings.environment }
|
private val env by lazy { settings.requireConfigured() }
|
||||||
|
|
||||||
val ivyDependency: String
|
val ivyDependency: String
|
||||||
@Input get() = env.ivyDependency
|
@Input get() = env.ivyDependency
|
||||||
|
|||||||
+1
-1
@@ -70,7 +70,7 @@ open class NpmProject(val compilation: KotlinJsCompilation) {
|
|||||||
|
|
||||||
fun useTool(exec: ExecSpec, tool: String, vararg args: String) {
|
fun useTool(exec: ExecSpec, tool: String, vararg args: String) {
|
||||||
exec.workingDir = dir
|
exec.workingDir = dir
|
||||||
exec.executable = nodeJs.environment.nodeExecutable
|
exec.executable = nodeJs.requireConfigured().nodeExecutable
|
||||||
exec.args = listOf(require(tool)) + args
|
exec.args = listOf(require(tool)) + args
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -110,7 +110,7 @@ open class KotlinJsTest : KotlinTest(), RequiresNpmDependencies {
|
|||||||
override fun createTestExecutionSpec(): TCServiceMessagesTestExecutionSpec {
|
override fun createTestExecutionSpec(): TCServiceMessagesTestExecutionSpec {
|
||||||
val forkOptions = DefaultProcessForkOptions(fileResolver)
|
val forkOptions = DefaultProcessForkOptions(fileResolver)
|
||||||
forkOptions.workingDir = compilation.npmProject.dir
|
forkOptions.workingDir = compilation.npmProject.dir
|
||||||
forkOptions.executable = nodeJs.environment.nodeExecutable
|
forkOptions.executable = nodeJs.requireConfigured().nodeExecutable
|
||||||
|
|
||||||
val nodeJsArgs = mutableListOf<String>()
|
val nodeJsArgs = mutableListOf<String>()
|
||||||
|
|
||||||
|
|||||||
+2
-4
@@ -24,13 +24,11 @@ abstract class YarnBasics : NpmApi {
|
|||||||
vararg args: String
|
vararg args: String
|
||||||
) {
|
) {
|
||||||
val nodeJs = NodeJsRootPlugin.apply(project)
|
val nodeJs = NodeJsRootPlugin.apply(project)
|
||||||
val nodeJsEnv = nodeJs.environment
|
|
||||||
val yarnPlugin = YarnPlugin.apply(project)
|
val yarnPlugin = YarnPlugin.apply(project)
|
||||||
val yarnEnv = yarnPlugin.environment
|
|
||||||
|
|
||||||
project.execWithProgress(description) { exec ->
|
project.execWithProgress(description) { exec ->
|
||||||
exec.executable = nodeJsEnv.nodeExecutable
|
exec.executable = nodeJs.requireConfigured().nodeExecutable
|
||||||
exec.args = listOf(yarnEnv.home.resolve("bin/yarn.js").absolutePath) +
|
exec.args = listOf(yarnPlugin.requireConfigured().home.resolve("bin/yarn.js").absolutePath) +
|
||||||
args +
|
args +
|
||||||
if (project.logger.isDebugEnabled) "--verbose" else ""
|
if (project.logger.isDebugEnabled) "--verbose" else ""
|
||||||
exec.workingDir = dir
|
exec.workingDir = dir
|
||||||
|
|||||||
+3
-1
@@ -5,9 +5,11 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.gradle.targets.js.yarn
|
package org.jetbrains.kotlin.gradle.targets.js.yarn
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.gradle.tasks.internal.CleanableStore
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
internal data class YarnEnv(
|
data class YarnEnv(
|
||||||
val downloadUrl: String,
|
val downloadUrl: String,
|
||||||
|
val cleanableStore: CleanableStore,
|
||||||
val home: File
|
val home: File
|
||||||
)
|
)
|
||||||
|
|||||||
+2
-3
@@ -9,7 +9,6 @@ import org.gradle.api.Plugin
|
|||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
|
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
|
||||||
import org.jetbrains.kotlin.gradle.tasks.CleanDataTask
|
import org.jetbrains.kotlin.gradle.tasks.CleanDataTask
|
||||||
import org.jetbrains.kotlin.gradle.tasks.internal.CleanableStore
|
|
||||||
|
|
||||||
open class YarnPlugin : Plugin<Project> {
|
open class YarnPlugin : Plugin<Project> {
|
||||||
override fun apply(project: Project): Unit = project.run {
|
override fun apply(project: Project): Unit = project.run {
|
||||||
@@ -25,8 +24,8 @@ open class YarnPlugin : Plugin<Project> {
|
|||||||
it.dependsOn(nodeJs.nodeJsSetupTask)
|
it.dependsOn(nodeJs.nodeJsSetupTask)
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.create("yarn" + CleanDataTask.NAME, CleanDataTask::class.java) {
|
tasks.create("yarn" + CleanDataTask.NAME_SUFFIX, CleanDataTask::class.java) {
|
||||||
it.cleanableStore = yarnRootExtension.cleanableStore
|
it.cleanableStore = yarnRootExtension.requireConfigured().cleanableStore
|
||||||
it.description = "Clean unused local yarn version"
|
it.description = "Clean unused local yarn version"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-14
@@ -6,11 +6,12 @@
|
|||||||
package org.jetbrains.kotlin.gradle.targets.js.yarn
|
package org.jetbrains.kotlin.gradle.targets.js.yarn
|
||||||
|
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
|
import org.jetbrains.kotlin.gradle.internal.ConfigurationPhaseAware
|
||||||
import org.jetbrains.kotlin.gradle.logging.kotlinInfo
|
import org.jetbrains.kotlin.gradle.logging.kotlinInfo
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
|
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
|
||||||
import org.jetbrains.kotlin.gradle.tasks.internal.CleanableStore
|
import org.jetbrains.kotlin.gradle.tasks.internal.CleanableStore
|
||||||
|
|
||||||
open class YarnRootExtension(val project: Project) {
|
open class YarnRootExtension(val project: Project) : ConfigurationPhaseAware<YarnEnv>() {
|
||||||
init {
|
init {
|
||||||
check(project == project.rootProject)
|
check(project == project.rootProject)
|
||||||
}
|
}
|
||||||
@@ -19,32 +20,33 @@ open class YarnRootExtension(val project: Project) {
|
|||||||
project.logger.kotlinInfo("Storing cached files in $it")
|
project.logger.kotlinInfo("Storing cached files in $it")
|
||||||
}
|
}
|
||||||
|
|
||||||
var installationDir = gradleHome.resolve("yarn")
|
var installationDir by Property(gradleHome.resolve("yarn"))
|
||||||
|
|
||||||
// TODO: Split configuration and execution phases to support changed installationDir
|
var downloadBaseUrl by Property("https://github.com/yarnpkg/yarn/releases/download")
|
||||||
val cleanableStore = CleanableStore[installationDir.path]
|
var version by Property("1.21.1")
|
||||||
|
|
||||||
var downloadBaseUrl = "https://github.com/yarnpkg/yarn/releases/download"
|
|
||||||
var version = "1.21.1"
|
|
||||||
|
|
||||||
val yarnSetupTask: YarnSetupTask
|
val yarnSetupTask: YarnSetupTask
|
||||||
get() = project.tasks.getByName(YarnSetupTask.NAME) as YarnSetupTask
|
get() = project.tasks.getByName(YarnSetupTask.NAME) as YarnSetupTask
|
||||||
|
|
||||||
var disableWorkspaces: Boolean = false
|
var disableWorkspaces: Boolean by Property(false)
|
||||||
|
|
||||||
val useWorkspaces: Boolean
|
val useWorkspaces: Boolean
|
||||||
get() = !disableWorkspaces
|
get() = !disableWorkspaces
|
||||||
|
|
||||||
// TODO: Split configuration and execution phases to support changed settings
|
override fun finalizeConfiguration(): YarnEnv {
|
||||||
internal val environment = YarnEnv(
|
val cleanableStore = CleanableStore[installationDir.path]
|
||||||
downloadUrl = "$downloadBaseUrl/v$version/yarn-v$version.tar.gz",
|
|
||||||
home = cleanableStore["yarn-v$version"].use()
|
return YarnEnv(
|
||||||
)
|
downloadUrl = "$downloadBaseUrl/v$version/yarn-v$version.tar.gz",
|
||||||
|
cleanableStore = cleanableStore,
|
||||||
|
home = cleanableStore["yarn-v$version"].use()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
internal fun executeSetup() {
|
internal fun executeSetup() {
|
||||||
NodeJsRootPlugin.apply(project).executeSetup()
|
NodeJsRootPlugin.apply(project).executeSetup()
|
||||||
|
|
||||||
if (!environment.home.isDirectory) {
|
if (!finalizeConfiguration().home.isDirectory) {
|
||||||
yarnSetupTask.setup()
|
yarnSetupTask.setup()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -17,7 +17,7 @@ import java.io.File
|
|||||||
@CacheableTask
|
@CacheableTask
|
||||||
open class YarnSetupTask : DefaultTask() {
|
open class YarnSetupTask : DefaultTask() {
|
||||||
private val settings = project.yarn
|
private val settings = project.yarn
|
||||||
private val env by lazy { settings.environment }
|
private val env by lazy { settings.requireConfigured() }
|
||||||
|
|
||||||
@Suppress("MemberVisibilityCanBePrivate")
|
@Suppress("MemberVisibilityCanBePrivate")
|
||||||
val downloadUrl
|
val downloadUrl
|
||||||
|
|||||||
+1
-1
@@ -41,7 +41,7 @@ open class CleanDataTask : DefaultTask() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val NAME: String = "KotlinClean"
|
const val NAME_SUFFIX: String = "KotlinClean"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user