[Gradle,JS]make downloadBaseUrl nullable to work with FAIL_ON_PROJECT_REPOS
^KT-56300 fixed ^KT-55620 fixed
This commit is contained in:
committed by
Space Team
parent
f4d18da6a0
commit
c9e328528e
+71
@@ -1782,4 +1782,75 @@ class Kotlin2JsIrGradlePluginIT : KGPBaseTest() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@DisplayName("test FAIL_ON_PROJECT_REPOS using custom repository")
|
||||
@GradleTest
|
||||
fun testFailOnProjectReposUsingCustomRepo(gradleVersion: GradleVersion) {
|
||||
project("js-project-repos", gradleVersion) {
|
||||
settingsGradleKts.modify {
|
||||
it + """
|
||||
|
||||
dependencyResolutionManagement {
|
||||
repositories {
|
||||
ivy {
|
||||
name = "Node.JS dist"
|
||||
url = URI("https://nodejs.org/dist")
|
||||
patternLayout {
|
||||
artifact("v[revision]/[artifact](-v[revision]-[classifier]).[ext]")
|
||||
}
|
||||
metadataSources {
|
||||
artifact()
|
||||
}
|
||||
content {
|
||||
includeModule("org.nodejs", "node")
|
||||
}
|
||||
}
|
||||
ivy {
|
||||
name = "Yarn dist"
|
||||
url = URI("https://github.com/yarnpkg/yarn/releases/download")
|
||||
patternLayout {
|
||||
artifact("v[revision]/[artifact](-v[revision]).[ext]")
|
||||
}
|
||||
metadataSources {
|
||||
artifact()
|
||||
}
|
||||
content {
|
||||
includeModule("com.yarnpkg", "yarn")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
}
|
||||
|
||||
build("kotlinNodeJsSetup", "kotlinYarnSetup") {
|
||||
assertTasksExecuted(":kotlinNodeJsSetup")
|
||||
assertTasksExecuted(":kotlinYarnSetup")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@DisplayName("test FAIL_ON_PROJECT_REPOS no download")
|
||||
@GradleTest
|
||||
fun testFailOnProjectReposNoDownload(gradleVersion: GradleVersion) {
|
||||
project("js-project-repos", gradleVersion) {
|
||||
buildGradleKts.modify {
|
||||
it + """
|
||||
|
||||
rootProject.plugins.withType<org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin> {
|
||||
rootProject.the<org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension>().download = false
|
||||
}
|
||||
|
||||
rootProject.plugins.withType<org.jetbrains.kotlin.gradle.targets.js.yarn.YarnPlugin> {
|
||||
rootProject.the<org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension>().download = false
|
||||
}
|
||||
""".trimIndent()
|
||||
}
|
||||
|
||||
build("kotlinNodeJsSetup", "kotlinYarnSetup") {
|
||||
assertTasksSkipped(":kotlinNodeJsSetup")
|
||||
assertTasksSkipped(":kotlinYarnSetup")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
plugins {
|
||||
kotlin("js")
|
||||
}
|
||||
|
||||
kotlin {
|
||||
js(IR) {
|
||||
binaries.executable()
|
||||
nodejs {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.plugins.withType<org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin> {
|
||||
rootProject.the<org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension>().downloadBaseUrl = null
|
||||
}
|
||||
|
||||
rootProject.plugins.withType<org.jetbrains.kotlin.gradle.targets.js.yarn.YarnPlugin> {
|
||||
rootProject.the<org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension>().downloadBaseUrl = null
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import java.net.URI
|
||||
|
||||
dependencyResolutionManagement {
|
||||
repositories {
|
||||
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* 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 example
|
||||
|
||||
@JsExport
|
||||
class Child {
|
||||
val name: String = "Child"
|
||||
}
|
||||
|
||||
fun main() {
|
||||
println("Hello there!")
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package org.jetbrains.kotlin.gradle.targets.js
|
||||
|
||||
import java.io.File
|
||||
|
||||
interface AbstractEnv {
|
||||
|
||||
val download: Boolean
|
||||
|
||||
val downloadBaseUrl: String?
|
||||
|
||||
val ivyDependency: String
|
||||
|
||||
val dir: File
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package org.jetbrains.kotlin.gradle.targets.js
|
||||
|
||||
import org.gradle.work.DisableCachingByDefault
|
||||
import org.jetbrains.kotlin.gradle.internal.ConfigurationPhaseAware
|
||||
import java.io.File
|
||||
|
||||
abstract class AbstractSettings<Env : AbstractEnv> : ConfigurationPhaseAware<Env>() {
|
||||
|
||||
abstract var download: Boolean
|
||||
|
||||
abstract var downloadBaseUrl: String?
|
||||
|
||||
abstract var installationDir: File
|
||||
|
||||
abstract var version: String
|
||||
|
||||
abstract var command: String
|
||||
}
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
package org.jetbrains.kotlin.gradle.targets.js
|
||||
|
||||
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
|
||||
import org.gradle.api.tasks.*
|
||||
import org.gradle.internal.hash.FileHasher
|
||||
import org.gradle.work.DisableCachingByDefault
|
||||
import org.jetbrains.kotlin.gradle.logging.kotlinInfo
|
||||
import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService
|
||||
import org.jetbrains.kotlin.statistics.metrics.NumericalMetrics
|
||||
import java.io.File
|
||||
import java.net.URI
|
||||
import javax.inject.Inject
|
||||
|
||||
@DisableCachingByDefault
|
||||
abstract class AbstractSetupTask<Env : AbstractEnv, Settings : AbstractSettings<Env>> : DefaultTask() {
|
||||
@get:Internal
|
||||
protected abstract val settings: Settings
|
||||
|
||||
@get:Internal
|
||||
protected abstract val artifactPattern: String
|
||||
|
||||
@get:Internal
|
||||
protected abstract val artifactModule: String
|
||||
|
||||
@get:Internal
|
||||
protected abstract val artifactName: String
|
||||
|
||||
@get:Internal
|
||||
protected val env: Env by lazy { settings.requireConfigured() }
|
||||
|
||||
private val shouldDownload by lazy {
|
||||
env.download
|
||||
}
|
||||
|
||||
@get:Inject
|
||||
internal abstract val archiveOperations: ArchiveOperations
|
||||
|
||||
@get:Inject
|
||||
internal abstract val fileHasher: FileHasher
|
||||
|
||||
@get:Inject
|
||||
internal abstract val objects: ObjectFactory
|
||||
|
||||
@get:Inject
|
||||
internal abstract val fs: FileSystemOperations
|
||||
|
||||
val ivyDependency: String
|
||||
@Input get() = env.ivyDependency
|
||||
|
||||
val downloadBaseUrl: String?
|
||||
@Input
|
||||
@Optional
|
||||
get() = env.downloadBaseUrl
|
||||
|
||||
val destination: File
|
||||
@OutputDirectory get() = env.dir
|
||||
|
||||
val destinationHashFile: File
|
||||
@OutputFile get() = destination.parentFile.resolve("${destination.name}.hash")
|
||||
|
||||
@Transient
|
||||
@get:Internal
|
||||
internal var configuration: Provider<Configuration>? = null
|
||||
|
||||
@get:Classpath
|
||||
@get:Optional
|
||||
val dist: File? by lazy {
|
||||
if (!shouldDownload) return@lazy null
|
||||
|
||||
withUrlRepo {
|
||||
val startDownloadTime = System.currentTimeMillis()
|
||||
configuration!!.get().files.single().also {
|
||||
val downloadDuration = System.currentTimeMillis() - startDownloadTime
|
||||
if (downloadDuration > 0) {
|
||||
KotlinBuildStatsService.getInstance()
|
||||
?.report(NumericalMetrics.ARTIFACTS_DOWNLOAD_SPEED, it.length() * 1000 / downloadDuration)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
onlyIf {
|
||||
shouldDownload
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
@TaskAction
|
||||
fun exec() {
|
||||
if (!shouldDownload) return
|
||||
|
||||
logger.kotlinInfo("Using distribution from '$dist'")
|
||||
|
||||
extractWithUpToDate(
|
||||
destination,
|
||||
destinationHashFile,
|
||||
dist!!,
|
||||
fileHasher,
|
||||
::extract
|
||||
)
|
||||
}
|
||||
|
||||
private fun <T> withUrlRepo(action: () -> T): T {
|
||||
val repo = downloadBaseUrl?.let {
|
||||
project.repositories.ivy { repo ->
|
||||
repo.name = "Distributions at ${it}"
|
||||
repo.url = URI(it)
|
||||
|
||||
repo.patternLayout {
|
||||
it.artifact(artifactPattern)
|
||||
}
|
||||
repo.metadataSources { it.artifact() }
|
||||
repo.content { it.includeModule(artifactModule, artifactName) }
|
||||
}
|
||||
}
|
||||
|
||||
return action().also {
|
||||
repo?.let { project.repositories.remove(it) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun extractWithUpToDate(
|
||||
destination: File,
|
||||
destinationHashFile: File,
|
||||
dist: File,
|
||||
fileHasher: FileHasher,
|
||||
extract: (File, File) -> Unit,
|
||||
) {
|
||||
var distHash: String? = null
|
||||
val upToDate = destinationHashFile.let { file ->
|
||||
if (file.exists()) {
|
||||
file.useLines { seq ->
|
||||
val list = seq.first().split(" ")
|
||||
list.size == 2 &&
|
||||
list[0] == fileHasher.calculateDirHash(destination) &&
|
||||
list[1] == fileHasher.hash(dist).toByteArray().toHex().also { distHash = it }
|
||||
}
|
||||
} else false
|
||||
}
|
||||
|
||||
if (upToDate) {
|
||||
return
|
||||
}
|
||||
|
||||
if (destination.isDirectory) {
|
||||
destination.deleteRecursively()
|
||||
}
|
||||
|
||||
extract(dist, destination.parentFile)
|
||||
|
||||
destinationHashFile.writeText(
|
||||
fileHasher.calculateDirHash(destination)!! +
|
||||
" " +
|
||||
(distHash ?: fileHasher.hash(dist).toByteArray().toHex())
|
||||
)
|
||||
}
|
||||
|
||||
abstract fun extract(archive: File, destination: File)
|
||||
}
|
||||
+6
-5
@@ -1,23 +1,24 @@
|
||||
package org.jetbrains.kotlin.gradle.targets.js.nodejs
|
||||
|
||||
import org.jetbrains.kotlin.gradle.targets.js.AbstractEnv
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmApi
|
||||
import org.jetbrains.kotlin.gradle.tasks.internal.CleanableStore
|
||||
import java.io.File
|
||||
|
||||
data class NodeJsEnv(
|
||||
override val download: Boolean,
|
||||
val cleanableStore: CleanableStore,
|
||||
val rootPackageDir: File,
|
||||
val nodeDir: File,
|
||||
override val dir: File,
|
||||
val nodeBinDir: File,
|
||||
val nodeExecutable: String,
|
||||
|
||||
val platformName: String,
|
||||
val architectureName: String,
|
||||
val ivyDependency: String,
|
||||
val downloadBaseUrl: String,
|
||||
override val ivyDependency: String,
|
||||
override val downloadBaseUrl: String?,
|
||||
|
||||
val packageManager: NpmApi,
|
||||
) {
|
||||
) : AbstractEnv {
|
||||
val isWindows: Boolean
|
||||
get() = platformName == "win"
|
||||
}
|
||||
|
||||
+33
-8
@@ -8,9 +8,9 @@ package org.jetbrains.kotlin.gradle.targets.js.nodejs
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.tasks.TaskProvider
|
||||
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.AbstractSettings
|
||||
import org.jetbrains.kotlin.gradle.targets.js.NpmVersions
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmApi
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.resolver.KotlinRootNpmResolver
|
||||
@@ -26,7 +26,7 @@ import java.io.File
|
||||
|
||||
open class NodeJsRootExtension(
|
||||
val project: Project,
|
||||
) : ConfigurationPhaseAware<NodeJsEnv>() {
|
||||
) : AbstractSettings<NodeJsEnv>() {
|
||||
|
||||
init {
|
||||
check(project.rootProject == project)
|
||||
@@ -54,18 +54,42 @@ open class NodeJsRootExtension(
|
||||
project.logger.kotlinInfo("Storing cached files in $it")
|
||||
}
|
||||
|
||||
var installationDir by Property(gradleHome.resolve("nodejs"))
|
||||
override var installationDir by Property(gradleHome.resolve("nodejs"))
|
||||
|
||||
var download by Property(true)
|
||||
override var download by Property(true)
|
||||
|
||||
var nodeDownloadBaseUrl by Property("https://nodejs.org/dist")
|
||||
// deprecate after bootstrap
|
||||
// @Deprecated("Use downloadBaseUrl instead", ReplaceWith("downloadBaseUrl"))
|
||||
var nodeDownloadBaseUrl
|
||||
get() = downloadBaseUrl
|
||||
set(value) {
|
||||
downloadBaseUrl = value
|
||||
}
|
||||
|
||||
override var downloadBaseUrl: String? by Property("https://nodejs.org/dist")
|
||||
|
||||
// deprecate after bootstrap
|
||||
// @Deprecated("Use version instead", ReplaceWith("version"))
|
||||
var nodeVersion
|
||||
get() = version
|
||||
set(value) {
|
||||
version = value
|
||||
}
|
||||
|
||||
// Release schedule: https://github.com/nodejs/Release
|
||||
// Actual LTS and Current versions: https://nodejs.org/en/download/
|
||||
// Older versions and more information, e.g. V8 version inside: https://nodejs.org/en/download/releases/
|
||||
var nodeVersion by Property("18.12.1")
|
||||
override var version by Property("18.12.1")
|
||||
|
||||
var nodeCommand by Property("node")
|
||||
override var command by Property("node")
|
||||
|
||||
// deprecate after bootstrap
|
||||
// @Deprecated("Use command instead", ReplaceWith("command"))
|
||||
var nodeCommand
|
||||
get() = command
|
||||
set(value) {
|
||||
command = value
|
||||
}
|
||||
|
||||
var packageManager: NpmApi by Property(Yarn())
|
||||
|
||||
@@ -107,9 +131,10 @@ open class NodeJsRootExtension(
|
||||
}
|
||||
|
||||
return NodeJsEnv(
|
||||
download = download,
|
||||
cleanableStore = cleanableStore,
|
||||
rootPackageDir = rootPackageDir,
|
||||
nodeDir = nodeDir,
|
||||
dir = nodeDir,
|
||||
nodeBinDir = nodeBinDir,
|
||||
nodeExecutable = getExecutable("node", nodeCommand, "exe"),
|
||||
platformName = name,
|
||||
|
||||
-1
@@ -10,7 +10,6 @@ import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.plugins.BasePlugin
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.util.GradleVersion
|
||||
import org.jetbrains.kotlin.gradle.plugin.internal.configurationTimePropertiesAccessor
|
||||
import org.jetbrains.kotlin.gradle.plugin.internal.usedAtConfigurationTime
|
||||
import org.jetbrains.kotlin.gradle.plugin.variantImplementationFactory
|
||||
|
||||
+30
-105
@@ -1,127 +1,52 @@
|
||||
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
|
||||
import org.gradle.api.tasks.*
|
||||
import org.gradle.internal.hash.FileHasher
|
||||
import org.gradle.api.tasks.Internal
|
||||
import org.gradle.work.DisableCachingByDefault
|
||||
import org.jetbrains.kotlin.gradle.logging.kotlinInfo
|
||||
import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService
|
||||
import org.jetbrains.kotlin.gradle.targets.js.AbstractSetupTask
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin.Companion.kotlinNodeJsExtension
|
||||
import org.jetbrains.kotlin.gradle.targets.js.extractWithUpToDate
|
||||
import org.jetbrains.kotlin.statistics.metrics.NumericalMetrics
|
||||
import java.io.File
|
||||
import java.net.URI
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
import javax.inject.Inject
|
||||
|
||||
@DisableCachingByDefault
|
||||
abstract class NodeJsSetupTask : DefaultTask() {
|
||||
@Transient
|
||||
private val settings = project.rootProject.kotlinNodeJsExtension
|
||||
private val env by lazy { settings.requireConfigured() }
|
||||
|
||||
private val shouldDownload = settings.download
|
||||
|
||||
@get:Inject
|
||||
abstract internal val archiveOperations: ArchiveOperations
|
||||
|
||||
@get:Inject
|
||||
internal open val fileHasher: FileHasher
|
||||
get() = error("Should be injected")
|
||||
|
||||
@get:Inject
|
||||
internal abstract val objects: ObjectFactory
|
||||
|
||||
@get:Inject
|
||||
abstract internal val fs: FileSystemOperations
|
||||
|
||||
val ivyDependency: String
|
||||
@Input get() = env.ivyDependency
|
||||
|
||||
val downloadBaseUrl: String
|
||||
@Input get() = env.downloadBaseUrl
|
||||
|
||||
val destination: File
|
||||
@OutputDirectory get() = env.nodeDir
|
||||
|
||||
val destinationHashFile: File
|
||||
@OutputFile get() = destination.parentFile.resolve("${destination.name}.hash")
|
||||
|
||||
abstract class NodeJsSetupTask : AbstractSetupTask<NodeJsEnv, NodeJsRootExtension>() {
|
||||
@Transient
|
||||
@get:Internal
|
||||
internal lateinit var configuration: Provider<Configuration>
|
||||
override val settings = project.rootProject.kotlinNodeJsExtension
|
||||
|
||||
@get:Classpath
|
||||
@get:Optional
|
||||
val nodeJsDist: File? by lazy {
|
||||
if (shouldDownload) {
|
||||
val repo = project.repositories.ivy { repo ->
|
||||
repo.name = "Node Distributions at ${downloadBaseUrl}"
|
||||
repo.url = URI(downloadBaseUrl)
|
||||
@get:Internal
|
||||
override val artifactPattern: String
|
||||
get() = "v[revision]/[artifact](-v[revision]-[classifier]).[ext]"
|
||||
|
||||
repo.patternLayout {
|
||||
it.artifact("v[revision]/[artifact](-v[revision]-[classifier]).[ext]")
|
||||
}
|
||||
repo.metadataSources { it.artifact() }
|
||||
repo.content { it.includeModule("org.nodejs", "node") }
|
||||
}
|
||||
val startDownloadTime = System.currentTimeMillis()
|
||||
val dist = configuration.get().files.single()
|
||||
val downloadDuration = System.currentTimeMillis() - startDownloadTime
|
||||
if (downloadDuration > 0) {
|
||||
KotlinBuildStatsService.getInstance()
|
||||
?.report(NumericalMetrics.ARTIFACTS_DOWNLOAD_SPEED, dist.length() * 1000 / downloadDuration)
|
||||
}
|
||||
project.repositories.remove(repo)
|
||||
dist
|
||||
} else null
|
||||
}
|
||||
@get:Internal
|
||||
override val artifactModule: String
|
||||
get() = "org.nodejs"
|
||||
|
||||
init {
|
||||
onlyIf {
|
||||
shouldDownload
|
||||
}
|
||||
}
|
||||
@get:Internal
|
||||
override val artifactName: String
|
||||
get() = "node"
|
||||
|
||||
@Suppress("unused")
|
||||
@TaskAction
|
||||
fun exec() {
|
||||
if (!shouldDownload) return
|
||||
logger.kotlinInfo("Using node distribution from '$nodeJsDist'")
|
||||
override fun extract(archive: File, destination: File) {
|
||||
var fixBrokenSymLinks = false
|
||||
|
||||
extractWithUpToDate(
|
||||
destination,
|
||||
destinationHashFile,
|
||||
nodeJsDist!!,
|
||||
fileHasher
|
||||
) { dist, destination ->
|
||||
var fixBrokenSymLinks = false
|
||||
|
||||
fs.copy {
|
||||
it.from(
|
||||
when {
|
||||
dist.name.endsWith("zip") -> archiveOperations.zipTree(dist)
|
||||
else -> {
|
||||
fixBrokenSymLinks = true
|
||||
archiveOperations.tarTree(dist)
|
||||
}
|
||||
fs.copy {
|
||||
it.from(
|
||||
when {
|
||||
archive.name.endsWith("zip") -> archiveOperations.zipTree(archive)
|
||||
else -> {
|
||||
fixBrokenSymLinks = true
|
||||
archiveOperations.tarTree(archive)
|
||||
}
|
||||
)
|
||||
it.into(destination)
|
||||
}
|
||||
}
|
||||
)
|
||||
it.into(destination)
|
||||
}
|
||||
|
||||
fixBrokenSymlinks(destination, env.isWindows, fixBrokenSymLinks)
|
||||
fixBrokenSymlinks(destination, env.isWindows, fixBrokenSymLinks)
|
||||
|
||||
if (!env.isWindows) {
|
||||
File(env.nodeExecutable).setExecutable(true)
|
||||
}
|
||||
if (!env.isWindows) {
|
||||
File(env.nodeExecutable).setExecutable(true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,7 +62,7 @@ abstract class NodeJsSetupTask : DefaultTask() {
|
||||
name: String,
|
||||
nodeBinDirPath: Path,
|
||||
nodeDirProvider: File,
|
||||
isWindows: Boolean
|
||||
isWindows: Boolean,
|
||||
) {
|
||||
val script = nodeBinDirPath.resolve(name)
|
||||
val scriptFile = computeNpmScriptFile(nodeDirProvider, name, isWindows)
|
||||
|
||||
-36
@@ -37,42 +37,6 @@ fun ByteArray.toHex(): String {
|
||||
return String(result)
|
||||
}
|
||||
|
||||
fun extractWithUpToDate(
|
||||
destination: File,
|
||||
destinationHashFile: File,
|
||||
dist: File,
|
||||
fileHasher: FileHasher,
|
||||
extract: (File, File) -> Unit
|
||||
) {
|
||||
var distHash: String? = null
|
||||
val upToDate = destinationHashFile.let { file ->
|
||||
if (file.exists()) {
|
||||
file.useLines { seq ->
|
||||
val list = seq.first().split(" ")
|
||||
list.size == 2 &&
|
||||
list[0] == fileHasher.calculateDirHash(destination) &&
|
||||
list[1] == fileHasher.hash(dist).toByteArray().toHex().also { distHash = it }
|
||||
}
|
||||
} else false
|
||||
}
|
||||
|
||||
if (upToDate) {
|
||||
return
|
||||
}
|
||||
|
||||
if (destination.isDirectory) {
|
||||
destination.deleteRecursively()
|
||||
}
|
||||
|
||||
extract(dist, destination.parentFile)
|
||||
|
||||
destinationHashFile.writeText(
|
||||
fileHasher.calculateDirHash(destination)!! +
|
||||
" " +
|
||||
(distHash ?: fileHasher.hash(dist).toByteArray().toHex())
|
||||
)
|
||||
}
|
||||
|
||||
fun FileHasher.calculateDirHash(
|
||||
dir: File
|
||||
): String? {
|
||||
|
||||
+6
-4
@@ -5,19 +5,21 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle.targets.js.yarn
|
||||
|
||||
import org.jetbrains.kotlin.gradle.targets.js.AbstractEnv
|
||||
import org.jetbrains.kotlin.gradle.tasks.internal.CleanableStore
|
||||
import java.io.File
|
||||
|
||||
data class YarnEnv(
|
||||
val downloadUrl: String,
|
||||
override val download: Boolean,
|
||||
override val downloadBaseUrl: String?,
|
||||
val cleanableStore: CleanableStore,
|
||||
val home: File,
|
||||
override val dir: File,
|
||||
val executable: String,
|
||||
val ivyDependency: String,
|
||||
override val ivyDependency: String,
|
||||
val standalone: Boolean,
|
||||
val ignoreScripts: Boolean,
|
||||
val yarnLockMismatchReport: YarnLockMismatchReport,
|
||||
val reportNewYarnLock: Boolean,
|
||||
val yarnLockAutoReplace: Boolean,
|
||||
val yarnResolutions: List<YarnResolution>
|
||||
)
|
||||
) : AbstractEnv
|
||||
|
||||
+5
-4
@@ -7,14 +7,11 @@ package org.jetbrains.kotlin.gradle.targets.js.yarn
|
||||
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.provider.Provider
|
||||
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.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
|
||||
@@ -24,6 +21,7 @@ import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnLockCopyTask.Companion.ST
|
||||
import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnLockCopyTask.Companion.UPGRADE_YARN_LOCK
|
||||
import org.jetbrains.kotlin.gradle.tasks.CleanDataTask
|
||||
import org.jetbrains.kotlin.gradle.tasks.registerTask
|
||||
import org.jetbrains.kotlin.gradle.utils.markResolvable
|
||||
import org.jetbrains.kotlin.gradle.utils.onlyIfCompat
|
||||
|
||||
open class YarnPlugin : Plugin<Project> {
|
||||
@@ -45,6 +43,9 @@ open class YarnPlugin : Plugin<Project> {
|
||||
val setupTask = registerTask<YarnSetupTask>(YarnSetupTask.NAME) {
|
||||
it.dependsOn(nodeJsTaskProviders.nodeJsSetupTaskProvider)
|
||||
|
||||
it.group = NodeJsRootPlugin.TASKS_GROUP_NAME
|
||||
it.description = "Download and install a local yarn version"
|
||||
|
||||
it.configuration = provider {
|
||||
this.project.configurations.detachedConfiguration(this.project.dependencies.create(it.ivyDependency))
|
||||
.markResolvable()
|
||||
@@ -131,7 +132,7 @@ open class YarnPlugin : Plugin<Project> {
|
||||
// https://youtrack.jetbrains.com/issue/KT-48241
|
||||
private fun configureRequiresNpmDependencies(
|
||||
project: Project,
|
||||
rootPackageJson: TaskProvider<RootPackageJsonTask>
|
||||
rootPackageJson: TaskProvider<RootPackageJsonTask>,
|
||||
) {
|
||||
val fn: (Project) -> Unit = {
|
||||
it.tasks.implementing(RequiresNpmDependencies::class)
|
||||
|
||||
+10
-9
@@ -8,8 +8,8 @@ package org.jetbrains.kotlin.gradle.targets.js.yarn
|
||||
import org.gradle.api.Action
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.tasks.TaskProvider
|
||||
import org.jetbrains.kotlin.gradle.internal.ConfigurationPhaseAware
|
||||
import org.jetbrains.kotlin.gradle.logging.kotlinInfo
|
||||
import org.jetbrains.kotlin.gradle.targets.js.AbstractSettings
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.Platform
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.RootPackageJsonTask
|
||||
import org.jetbrains.kotlin.gradle.tasks.internal.CleanableStore
|
||||
@@ -17,7 +17,7 @@ import java.io.File
|
||||
|
||||
open class YarnRootExtension(
|
||||
val project: Project
|
||||
) : ConfigurationPhaseAware<YarnEnv>() {
|
||||
) : AbstractSettings<YarnEnv>() {
|
||||
init {
|
||||
check(project == project.rootProject)
|
||||
}
|
||||
@@ -26,14 +26,14 @@ open class YarnRootExtension(
|
||||
project.logger.kotlinInfo("Storing cached files in $it")
|
||||
}
|
||||
|
||||
var installationDir by Property(gradleHome.resolve("yarn"))
|
||||
override var installationDir by Property(gradleHome.resolve("yarn"))
|
||||
|
||||
var downloadBaseUrl by Property("https://github.com/yarnpkg/yarn/releases/download")
|
||||
var version by Property("1.22.17")
|
||||
override var downloadBaseUrl: String? by Property("https://github.com/yarnpkg/yarn/releases/download")
|
||||
override var version by Property("1.22.17")
|
||||
|
||||
var command by Property("yarn")
|
||||
override var command by Property("yarn")
|
||||
|
||||
var download by Property(true)
|
||||
override var download by Property(true)
|
||||
var lockFileName by Property("yarn.lock")
|
||||
var lockFileDirectory: File by Property(project.rootDir.resolve("kotlin-js-store"))
|
||||
|
||||
@@ -88,9 +88,10 @@ open class YarnRootExtension(
|
||||
finalCommand
|
||||
}
|
||||
return YarnEnv(
|
||||
downloadUrl = downloadBaseUrl,
|
||||
download = download,
|
||||
downloadBaseUrl = downloadBaseUrl,
|
||||
cleanableStore = cleanableStore,
|
||||
home = home,
|
||||
dir = home,
|
||||
executable = getExecutable("yarn", command, "cmd"),
|
||||
standalone = !download,
|
||||
ivyDependency = "com.yarnpkg:yarn:$version@tar.gz",
|
||||
|
||||
+14
-93
@@ -5,109 +5,30 @@
|
||||
|
||||
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.*
|
||||
import org.gradle.internal.hash.FileHasher
|
||||
import org.gradle.api.tasks.Internal
|
||||
import org.gradle.work.DisableCachingByDefault
|
||||
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.statistics.metrics.NumericalMetrics
|
||||
import org.jetbrains.kotlin.gradle.targets.js.AbstractSetupTask
|
||||
import java.io.File
|
||||
import java.net.URI
|
||||
import javax.inject.Inject
|
||||
|
||||
@DisableCachingByDefault
|
||||
abstract class YarnSetupTask : DefaultTask() {
|
||||
abstract class YarnSetupTask : AbstractSetupTask<YarnEnv, YarnRootExtension>() {
|
||||
@Transient
|
||||
private val settings = project.yarn
|
||||
private val env by lazy { settings.requireConfigured() }
|
||||
@Internal
|
||||
override val settings = project.yarn
|
||||
|
||||
private val shouldDownload = settings.download
|
||||
|
||||
@get:Inject
|
||||
internal abstract val archiveOperations: ArchiveOperations
|
||||
|
||||
@get:Inject
|
||||
internal abstract val fileHasher: FileHasher
|
||||
|
||||
@get:Inject
|
||||
internal abstract val fs: FileSystemOperations
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
val downloadUrl
|
||||
@Input get() = env.downloadUrl
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
val destination: File
|
||||
@OutputDirectory get() = env.home
|
||||
|
||||
val destinationHashFile: File
|
||||
@OutputFile get() = destination.parentFile.resolve("${destination.name}.hash")
|
||||
|
||||
init {
|
||||
group = NodeJsRootPlugin.TASKS_GROUP_NAME
|
||||
description = "Download and install a local yarn version"
|
||||
}
|
||||
|
||||
val ivyDependency: String
|
||||
@Input get() = env.ivyDependency
|
||||
|
||||
@Transient
|
||||
@get:Internal
|
||||
internal lateinit var configuration: Provider<Configuration>
|
||||
override val artifactPattern: String
|
||||
get() = "v[revision]/[artifact](-v[revision]).[ext]"
|
||||
|
||||
@get:Classpath
|
||||
@get:Optional
|
||||
val yarnDist: File? by lazy {
|
||||
if (shouldDownload) {
|
||||
val repo = project.repositories.ivy { repo ->
|
||||
repo.name = "Yarn Distributions at ${downloadUrl}"
|
||||
repo.url = URI(downloadUrl)
|
||||
repo.patternLayout {
|
||||
it.artifact("v[revision]/[artifact](-v[revision]).[ext]")
|
||||
}
|
||||
repo.metadataSources { it.artifact() }
|
||||
repo.content { it.includeModule("com.yarnpkg", "yarn") }
|
||||
}
|
||||
val startDownloadTime = System.currentTimeMillis()
|
||||
val dist = configuration.get().files.single()
|
||||
val downloadDuration = System.currentTimeMillis() - startDownloadTime
|
||||
if (downloadDuration > 0) {
|
||||
KotlinBuildStatsService.getInstance()
|
||||
?.report(NumericalMetrics.ARTIFACTS_DOWNLOAD_SPEED, dist.length() * 1000 / downloadDuration)
|
||||
}
|
||||
project.repositories.remove(repo)
|
||||
dist
|
||||
} else null
|
||||
}
|
||||
@get:Internal
|
||||
override val artifactModule: String
|
||||
get() = "com.yarnpkg"
|
||||
|
||||
init {
|
||||
onlyIf {
|
||||
shouldDownload
|
||||
}
|
||||
}
|
||||
@get:Internal
|
||||
override val artifactName: String
|
||||
get() = "yarn"
|
||||
|
||||
@TaskAction
|
||||
fun setup() {
|
||||
if (!shouldDownload) return
|
||||
logger.kotlinInfo("Using yarn distribution from '$yarnDist'")
|
||||
|
||||
extractWithUpToDate(
|
||||
destination,
|
||||
destinationHashFile,
|
||||
yarnDist!!,
|
||||
fileHasher,
|
||||
::extract
|
||||
)
|
||||
}
|
||||
|
||||
private fun extract(archive: File, destination: File) {
|
||||
override fun extract(archive: File, destination: File) {
|
||||
val dirInTar = archive.name.removeSuffix(".tar.gz")
|
||||
fs.copy {
|
||||
it.from(archiveOperations.tarTree(archive))
|
||||
|
||||
Reference in New Issue
Block a user