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
|
||||
|
||||
import org.jetbrains.kotlin.gradle.tasks.internal.CleanableStore
|
||||
import java.io.File
|
||||
|
||||
internal data class NodeJsEnv(
|
||||
data class NodeJsEnv(
|
||||
val cleanableStore: CleanableStore,
|
||||
val nodeDir: File,
|
||||
val nodeBinDir: File,
|
||||
val nodeExecutable: String,
|
||||
|
||||
+1
-1
@@ -72,7 +72,7 @@ open class NodeJsExec : AbstractExecTask<NodeJsExec>(NodeJsExec::class.java), Re
|
||||
return project.registerTask(name) {
|
||||
it.nodeJs = nodeJs
|
||||
it.compilation = compilation
|
||||
it.executable = nodeJs.environment.nodeExecutable
|
||||
it.executable = nodeJs.requireConfigured().nodeExecutable
|
||||
it.dependsOn(nodeJs.npmInstallTask)
|
||||
|
||||
val compileKotlinTask = compilation.compileKotlinTask
|
||||
|
||||
+37
-35
@@ -1,6 +1,7 @@
|
||||
package org.jetbrains.kotlin.gradle.targets.js.nodejs
|
||||
|
||||
import org.gradle.api.Project
|
||||
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
|
||||
@@ -11,7 +12,7 @@ import org.jetbrains.kotlin.gradle.targets.js.yarn.Yarn
|
||||
import org.jetbrains.kotlin.gradle.tasks.internal.CleanableStore
|
||||
import java.io.File
|
||||
|
||||
open class NodeJsRootExtension(val rootProject: Project) {
|
||||
open class NodeJsRootExtension(val rootProject: Project) : ConfigurationPhaseAware<NodeJsEnv>() {
|
||||
init {
|
||||
check(rootProject.rootProject == rootProject)
|
||||
}
|
||||
@@ -20,16 +21,16 @@ open class NodeJsRootExtension(val rootProject: Project) {
|
||||
rootProject.logger.kotlinInfo("Storing cached files in $it")
|
||||
}
|
||||
|
||||
var installationDir = gradleHome.resolve("nodejs")
|
||||
var cleanableStore = CleanableStore[installationDir.absolutePath]
|
||||
var installationDir by Property(gradleHome.resolve("nodejs"))
|
||||
|
||||
var download = true
|
||||
var nodeDownloadBaseUrl = "https://nodejs.org/dist"
|
||||
var nodeVersion = "12.14.0"
|
||||
var download by Property(true)
|
||||
|
||||
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)
|
||||
|
||||
@@ -61,38 +62,39 @@ open class NodeJsRootExtension(val rootProject: Project) {
|
||||
val nodeModulesGradleCacheDir: File
|
||||
get() = rootPackageDir.resolve("packages_imported")
|
||||
|
||||
internal val environment: NodeJsEnv
|
||||
get() {
|
||||
val platform = NodeJsPlatform.name
|
||||
val architecture = NodeJsPlatform.architecture
|
||||
override fun finalizeConfiguration(): NodeJsEnv {
|
||||
val platform = NodeJsPlatform.name
|
||||
val architecture = NodeJsPlatform.architecture
|
||||
|
||||
val nodeDirName = "node-v$nodeVersion-$platform-$architecture"
|
||||
val nodeDir = cleanableStore[nodeDirName].use()
|
||||
val isWindows = NodeJsPlatform.name == NodeJsPlatform.WIN
|
||||
val nodeBinDir = if (isWindows) nodeDir else nodeDir.resolve("bin")
|
||||
val nodeDirName = "node-v$nodeVersion-$platform-$architecture"
|
||||
val cleanableStore = CleanableStore[installationDir.absolutePath]
|
||||
val nodeDir = cleanableStore[nodeDirName].use()
|
||||
val isWindows = NodeJsPlatform.name == NodeJsPlatform.WIN
|
||||
val nodeBinDir = if (isWindows) nodeDir else nodeDir.resolve("bin")
|
||||
|
||||
fun getExecutable(command: String, customCommand: String, windowsExtension: String): String {
|
||||
val finalCommand = if (isWindows && customCommand == command) "$command.$windowsExtension" else customCommand
|
||||
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 getExecutable(command: String, customCommand: String, windowsExtension: String): String {
|
||||
val finalCommand = if (isWindows && customCommand == command) "$command.$windowsExtension" else customCommand
|
||||
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(
|
||||
cleanableStore = cleanableStore,
|
||||
nodeDir = nodeDir,
|
||||
nodeBinDir = nodeBinDir,
|
||||
nodeExecutable = getExecutable("node", nodeCommand, "exe"),
|
||||
platformName = platform,
|
||||
architectureName = architecture,
|
||||
ivyDependency = getIvyDependency()
|
||||
)
|
||||
}
|
||||
|
||||
internal fun executeSetup() {
|
||||
val nodeJsEnv = environment
|
||||
val nodeJsEnv = requireConfigured()
|
||||
if (download) {
|
||||
if (!nodeJsEnv.nodeBinDir.isDirectory) {
|
||||
nodeJsSetupTask.exec()
|
||||
|
||||
+3
-3
@@ -22,14 +22,14 @@ open class NodeJsRootPlugin : Plugin<Project> {
|
||||
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.group = TASKS_GROUP_NAME
|
||||
it.description = "Find, download and link NPM dependencies and projects"
|
||||
}
|
||||
|
||||
tasks.create("node" + CleanDataTask.NAME, CleanDataTask::class.java) {
|
||||
it.cleanableStore = settings.cleanableStore
|
||||
tasks.register("node" + CleanDataTask.NAME_SUFFIX, CleanDataTask::class.java) {
|
||||
it.cleanableStore = settings.requireConfigured().cleanableStore
|
||||
it.group = TASKS_GROUP_NAME
|
||||
it.description = "Clean unused local node version"
|
||||
}
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ import java.net.URI
|
||||
@CacheableTask
|
||||
open class NodeJsSetupTask : DefaultTask() {
|
||||
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
|
||||
@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) {
|
||||
exec.workingDir = dir
|
||||
exec.executable = nodeJs.environment.nodeExecutable
|
||||
exec.executable = nodeJs.requireConfigured().nodeExecutable
|
||||
exec.args = listOf(require(tool)) + args
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -110,7 +110,7 @@ open class KotlinJsTest : KotlinTest(), RequiresNpmDependencies {
|
||||
override fun createTestExecutionSpec(): TCServiceMessagesTestExecutionSpec {
|
||||
val forkOptions = DefaultProcessForkOptions(fileResolver)
|
||||
forkOptions.workingDir = compilation.npmProject.dir
|
||||
forkOptions.executable = nodeJs.environment.nodeExecutable
|
||||
forkOptions.executable = nodeJs.requireConfigured().nodeExecutable
|
||||
|
||||
val nodeJsArgs = mutableListOf<String>()
|
||||
|
||||
|
||||
+2
-4
@@ -24,13 +24,11 @@ abstract class YarnBasics : NpmApi {
|
||||
vararg args: String
|
||||
) {
|
||||
val nodeJs = NodeJsRootPlugin.apply(project)
|
||||
val nodeJsEnv = nodeJs.environment
|
||||
val yarnPlugin = YarnPlugin.apply(project)
|
||||
val yarnEnv = yarnPlugin.environment
|
||||
|
||||
project.execWithProgress(description) { exec ->
|
||||
exec.executable = nodeJsEnv.nodeExecutable
|
||||
exec.args = listOf(yarnEnv.home.resolve("bin/yarn.js").absolutePath) +
|
||||
exec.executable = nodeJs.requireConfigured().nodeExecutable
|
||||
exec.args = listOf(yarnPlugin.requireConfigured().home.resolve("bin/yarn.js").absolutePath) +
|
||||
args +
|
||||
if (project.logger.isDebugEnabled) "--verbose" else ""
|
||||
exec.workingDir = dir
|
||||
|
||||
+3
-1
@@ -5,9 +5,11 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle.targets.js.yarn
|
||||
|
||||
import org.jetbrains.kotlin.gradle.tasks.internal.CleanableStore
|
||||
import java.io.File
|
||||
|
||||
internal data class YarnEnv(
|
||||
data class YarnEnv(
|
||||
val downloadUrl: String,
|
||||
val cleanableStore: CleanableStore,
|
||||
val home: File
|
||||
)
|
||||
|
||||
+2
-3
@@ -9,7 +9,6 @@ import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
|
||||
import org.jetbrains.kotlin.gradle.tasks.CleanDataTask
|
||||
import org.jetbrains.kotlin.gradle.tasks.internal.CleanableStore
|
||||
|
||||
open class YarnPlugin : Plugin<Project> {
|
||||
override fun apply(project: Project): Unit = project.run {
|
||||
@@ -25,8 +24,8 @@ open class YarnPlugin : Plugin<Project> {
|
||||
it.dependsOn(nodeJs.nodeJsSetupTask)
|
||||
}
|
||||
|
||||
tasks.create("yarn" + CleanDataTask.NAME, CleanDataTask::class.java) {
|
||||
it.cleanableStore = yarnRootExtension.cleanableStore
|
||||
tasks.create("yarn" + CleanDataTask.NAME_SUFFIX, CleanDataTask::class.java) {
|
||||
it.cleanableStore = yarnRootExtension.requireConfigured().cleanableStore
|
||||
it.description = "Clean unused local yarn version"
|
||||
}
|
||||
}
|
||||
|
||||
+16
-14
@@ -6,11 +6,12 @@
|
||||
package org.jetbrains.kotlin.gradle.targets.js.yarn
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.jetbrains.kotlin.gradle.internal.ConfigurationPhaseAware
|
||||
import org.jetbrains.kotlin.gradle.logging.kotlinInfo
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
|
||||
import org.jetbrains.kotlin.gradle.tasks.internal.CleanableStore
|
||||
|
||||
open class YarnRootExtension(val project: Project) {
|
||||
open class YarnRootExtension(val project: Project) : ConfigurationPhaseAware<YarnEnv>() {
|
||||
init {
|
||||
check(project == project.rootProject)
|
||||
}
|
||||
@@ -19,32 +20,33 @@ open class YarnRootExtension(val project: Project) {
|
||||
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
|
||||
val cleanableStore = CleanableStore[installationDir.path]
|
||||
|
||||
var downloadBaseUrl = "https://github.com/yarnpkg/yarn/releases/download"
|
||||
var version = "1.21.1"
|
||||
var downloadBaseUrl by Property("https://github.com/yarnpkg/yarn/releases/download")
|
||||
var version by Property("1.21.1")
|
||||
|
||||
val yarnSetupTask: YarnSetupTask
|
||||
get() = project.tasks.getByName(YarnSetupTask.NAME) as YarnSetupTask
|
||||
|
||||
var disableWorkspaces: Boolean = false
|
||||
var disableWorkspaces: Boolean by Property(false)
|
||||
|
||||
val useWorkspaces: Boolean
|
||||
get() = !disableWorkspaces
|
||||
|
||||
// TODO: Split configuration and execution phases to support changed settings
|
||||
internal val environment = YarnEnv(
|
||||
downloadUrl = "$downloadBaseUrl/v$version/yarn-v$version.tar.gz",
|
||||
home = cleanableStore["yarn-v$version"].use()
|
||||
)
|
||||
override fun finalizeConfiguration(): YarnEnv {
|
||||
val cleanableStore = CleanableStore[installationDir.path]
|
||||
|
||||
return YarnEnv(
|
||||
downloadUrl = "$downloadBaseUrl/v$version/yarn-v$version.tar.gz",
|
||||
cleanableStore = cleanableStore,
|
||||
home = cleanableStore["yarn-v$version"].use()
|
||||
)
|
||||
}
|
||||
|
||||
internal fun executeSetup() {
|
||||
NodeJsRootPlugin.apply(project).executeSetup()
|
||||
|
||||
if (!environment.home.isDirectory) {
|
||||
if (!finalizeConfiguration().home.isDirectory) {
|
||||
yarnSetupTask.setup()
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ import java.io.File
|
||||
@CacheableTask
|
||||
open class YarnSetupTask : DefaultTask() {
|
||||
private val settings = project.yarn
|
||||
private val env by lazy { settings.environment }
|
||||
private val env by lazy { settings.requireConfigured() }
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
val downloadUrl
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ open class CleanDataTask : DefaultTask() {
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val NAME: String = "KotlinClean"
|
||||
const val NAME_SUFFIX: String = "KotlinClean"
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user