All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsSetupTask.kt Maven / Gradle / Ivy

There is a newer version: 2.1.0-Beta1
Show newest version
package org.jetbrains.kotlin.gradle.targets.js.nodejs

import org.gradle.api.DefaultTask
import org.gradle.api.artifacts.Configuration
import org.gradle.api.file.FileSystemOperations
import org.gradle.api.file.FileTree
import org.gradle.api.provider.Provider
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.calculateDirHash
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

abstract class NodeJsSetupTask : DefaultTask() {
    @Transient
    private val settings = NodeJsRootPlugin.apply(project.rootProject)
    private val env by lazy { settings.requireConfigured() }

    private val shouldDownload = settings.download

    private val archiveOperations = ArchiveOperationsCompat(project)

    @get:Inject
    internal open val fileHasher: FileHasher
        get() = error("Should be injected")

    @get:Inject
    internal open val fs: FileSystemOperations
        get() = error("Should be injected")

    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")

    @Transient
    @get:Internal
    internal lateinit var configuration: Provider

    @get:Classpath
    val nodeJsDist: File by lazy {
        val repo = project.repositories.ivy { repo ->
            repo.name = "Node Distributions at ${downloadBaseUrl}"
            repo.url = URI(downloadBaseUrl)

            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
    }

    init {
        onlyIf {
            shouldDownload
        }
    }

    @Suppress("unused")
    @TaskAction
    fun exec() {
        logger.kotlinInfo("Using node distribution from '$nodeJsDist'")

        var dirHash: String? = null
        val upToDate = destinationHashFile.let { file ->
            if (file.exists()) {
                file.useLines {
                    it.single() == (fileHasher.calculateDirHash(destination).also { dirHash = it })
                }
            } else false
        }

        val tmpDir = temporaryDir
        unpackNodeArchive(nodeJsDist, tmpDir)

        if (upToDate && fileHasher.calculateDirHash(tmpDir.resolve(destination.name))!! == dirHash) return

        if (destination.isDirectory) {
            destination.deleteRecursively()
        }

        fs.copy {
            it.from(tmpDir)
            it.into(destination.parentFile)
        }

        tmpDir.deleteRecursively()

        if (!env.isWindows) {
            File(env.nodeExecutable).setExecutable(true)
        }

        destinationHashFile.writeText(
            fileHasher.calculateDirHash(destination)!!
        )
    }

    private fun unpackNodeArchive(archive: File, destination: File) {
        logger.kotlinInfo("Unpacking $archive to $destination")

        fs.copy {
            it.from(fileTree(archive))
            it.into(destination)
        }
    }

    private fun fileTree(archive: File): FileTree =
        when {
            archive.name.endsWith("zip") -> archiveOperations.zipTree(archive)
            else -> archiveOperations.tarTree(archive)
        }

    companion object {
        const val NAME: String = "kotlinNodeJsSetup"
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy