Gradle, js, npm: remove hoisted gradle node modules. Split results collection from shared cache.

#KT-30530
This commit is contained in:
Sergey Rostov
2019-05-15 19:25:58 +03:00
parent eb3c701040
commit 8166cfb054
7 changed files with 75 additions and 71 deletions
@@ -82,14 +82,16 @@ internal class ProcessedFilesCache(
internal fun getOrCompute(
file: File,
compute: () -> String?
) {
): String? {
val hash = hasher.hash(file).toByteArray()
val old = old[hash]
if (old != null) {
new[hash] = old
return old.target
} else {
val key = compute()
new[hash] = Element(file.canonicalPath, key)
return key
}
}
@@ -16,7 +16,7 @@ internal class GradleNodeModuleBuilder(
val project: Project,
val dependency: ResolvedDependency,
val artifacts: Set<ResolvedArtifact>,
val cache: GradleNodeModulesBuilder
val cache: GradleNodeModulesCache
) {
var srcPackageJsonFile: File? = null
val files = mutableListOf<File>()
@@ -12,7 +12,7 @@ import org.gradle.api.artifacts.ResolvedDependency
import org.gradle.api.artifacts.component.ProjectComponentIdentifier
import org.jetbrains.kotlin.gradle.internal.ProcessedFilesCache
internal class GradleNodeModulesBuilder(val project: Project) : AutoCloseable {
internal class GradleNodeModulesCache(val project: Project) : AutoCloseable {
companion object {
const val STATE_FILE_NAME = ".visited"
}
@@ -21,34 +21,28 @@ internal class GradleNodeModulesBuilder(val project: Project) : AutoCloseable {
private val cache = ProcessedFilesCache(project, dir, STATE_FILE_NAME, "5")
private val visited = mutableSetOf<ResolvedDependency>()
val modules
get() = cache.targets.map {
GradleNodeModule(it, dir.resolve(it))
}
val projects = mutableSetOf<Project>()
fun visitConfiguration(configuration: Configuration) {
fun collectDependenciesFromConfiguration(configuration: Configuration, result: NpmProjectGradleDeps) {
if (configuration.isCanBeResolved) {
configuration.resolvedConfiguration.firstLevelModuleDependencies.forEach {
visitDependency(it)
visitDependency(it, result)
}
}
}
private fun visitDependency(dependency: ResolvedDependency) {
private fun visitDependency(dependency: ResolvedDependency, result: NpmProjectGradleDeps) {
if (!visited.add(dependency)) return
visitArtifacts(dependency, dependency.moduleArtifacts)
visitArtifacts(dependency, dependency.moduleArtifacts, result)
dependency.children.forEach {
visitDependency(it)
visitDependency(it, result)
}
}
private fun visitArtifacts(
dependency: ResolvedDependency,
artifacts: MutableSet<ResolvedArtifact>
artifacts: MutableSet<ResolvedArtifact>,
result: NpmProjectGradleDeps
) {
val lazyDirName: String? by lazy {
val module = GradleNodeModuleBuilder(project, dependency, artifacts, this)
@@ -62,11 +56,15 @@ internal class GradleNodeModulesBuilder(val project: Project) : AutoCloseable {
val dependentProject = project.findProject(componentIdentifier.projectPath)
?: error("Cannot find project ${componentIdentifier.projectPath}")
projects.add(dependentProject)
result.internalModules.add(dependentProject)
} else {
cache.getOrCompute(artifact.file) {
val key = cache.getOrCompute(artifact.file) {
lazyDirName
}
if (key != null) {
result.externalModules.add(GradleNodeModule(key, dir.resolve(key)))
}
}
}
}
@@ -30,7 +30,12 @@ interface NpmApi {
allWorkspaces: Collection<NpmResolver.NpmPackage>
): Boolean = false
open fun shouldHoistGradleNodeModules(project: Project) = false
fun cleanProject(project: Project) {
val npmProject = project.npmProject
npmProject.nodeModulesDir.deleteRecursively()
npmProject.packageJsonFile.delete()
}
companion object {
fun resolveOperationDescription(packageManagerTitle: String): String =
@@ -33,13 +33,8 @@ open class NpmProject(
private val parentModules: NpmProjectModules?
get() = project.parent?.npmProject?.modules
val hoistGradleNodeModules: Boolean
get() = project.nodeJs.root.packageManager.shouldHoistGradleNodeModules(project)
val gradleNodeModulesDir: File
get() =
if (hoistGradleNodeModules) project.rootProject.npmProject.nodeModulesDir
else nodeModulesDir
get() = project.rootProject.npmProject.nodeModulesDir
open fun compileOutput(compilationTask: Kotlin2JsCompile): File {
return compileOutputCopyDest?.resolve(compilationTask.outputFile.name) ?: compilationTask.outputFile
@@ -0,0 +1,13 @@
/*
* Copyright 2010-2019 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
import org.gradle.api.Project
class NpmProjectGradleDeps {
val internalModules = mutableSetOf<Project>()
val externalModules = mutableSetOf<GradleNodeModule>()
}
@@ -34,7 +34,7 @@ import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile
* For external gradle modules, fake npm packages will be created and added to `package.json`
* as path to directory.
*/
internal class NpmResolver private constructor(val rootProject: Project) {
internal class NpmResolver private constructor(val rootProject: Project) : AutoCloseable {
companion object {
fun resolve(project: Project): ResolutionCallResult {
val rootProject = project.rootProject
@@ -47,7 +47,9 @@ internal class NpmResolver private constructor(val rootProject: Project) {
return if (resolved != null) AlreadyResolved(ProjectData[project]!!.resolved!!)
else {
NpmResolver(rootProject).resolve(rootProject, null)!!
val resolver = NpmResolver(rootProject)
resolver.resolve(rootProject)!!
resolver.close()
ResolvedNow(ProjectData[project]!!.resolved!!)
}
}
@@ -77,8 +79,8 @@ internal class NpmResolver private constructor(val rootProject: Project) {
private val nodeJs = NodeJsPlugin.apply(rootProject).root
private val npmProject = rootProject.npmProject
private val gradleNodeModules = GradleNodeModulesCache(rootProject)
private val packageManager = nodeJs.packageManager
private val hoistGradleNodeModules = npmProject.hoistGradleNodeModules
private val npmPackages = mutableListOf<NpmPackage>()
private val requiredByTasks = mutableMapOf<RequiresNpmDependencies, Collection<RequiredKotlinJsDependency>>()
private val gson = GsonBuilder()
@@ -120,27 +122,20 @@ internal class NpmResolver private constructor(val rootProject: Project) {
packageManagerInstalled = true
}
private fun getOrResolve(project: Project, parentGradleModules: GradleNodeModulesBuilder?): ResolvedProject {
return (ProjectData[project] ?: resolve(project, parentGradleModules)!!).resolved!!
private fun getOrResolve(project: Project): ResolvedProject {
return (ProjectData[project] ?: resolve(project)!!).resolved!!
}
private fun resolve(
project: Project,
parentGradleModules: GradleNodeModulesBuilder?
): ProjectData? {
private fun resolve(project: Project): ProjectData? {
val result = ProjectData().also {
ProjectData[project] = it
}
val gradleModules =
if (hoistGradleNodeModules && parentGradleModules != null) parentGradleModules
else GradleNodeModulesBuilder(project)
project.subprojects.forEach {
getOrResolve(it, gradleModules)
getOrResolve(it)
}
val npmPackage = extractNpmPackage(project, gradleModules, parentGradleModules)
val npmPackage = extractNpmPackage(project)
if (npmPackage != null) {
npmPackage.savePackageJson(gson)
@@ -159,35 +154,27 @@ internal class NpmResolver private constructor(val rootProject: Project) {
}
}
if (gradleModules != parentGradleModules) {
gradleModules.close()
}
return result
}
private fun extractNpmPackage(
project: Project,
gradleComponents: GradleNodeModulesBuilder,
parentGradleModules: GradleNodeModulesBuilder?
): NpmPackage? {
private fun extractNpmPackage(project: Project): NpmPackage? {
val packageJson = PackageJson(project.name, project.version.toString())
val npmDependencies = mutableSetOf<NpmDependency>()
val gradleDeps = NpmProjectGradleDeps()
visitTasksRequiredDependencies(project, npmDependencies, gradleComponents)
visitTasksRequiredDependencies(project, npmDependencies, gradleDeps)
visitNpmDependencies(project, npmDependencies, gradleComponents, packageJson)
collectDependencies(project, npmDependencies, gradleDeps, packageJson)
if (!hoistGradleNodeModules || project == project.rootProject) {
gradleComponents.modules.forEach {
val relativePath = it.path.relativeTo(NpmProject[project].nodeWorkDir)
packageJson.dependencies[it.name] = "file:$relativePath"
}
gradleComponents.projects.forEach {
val npmPackage = getOrResolve(it, parentGradleModules).npmPackage
if (npmPackage != null) {
packageJson.dependencies[npmPackage.packageJson.name] = npmPackage.packageJson.version
}
gradleDeps.externalModules.forEach {
val relativePath = it.path.relativeTo(NpmProject[project].nodeWorkDir)
packageJson.dependencies[it.name] = "file:$relativePath"
}
gradleDeps.internalModules.forEach {
val npmPackage = getOrResolve(it).npmPackage
if (npmPackage != null) {
packageJson.dependencies[npmPackage.packageJson.name] = npmPackage.packageJson.version
}
}
@@ -206,7 +193,7 @@ internal class NpmResolver private constructor(val rootProject: Project) {
private fun visitTasksRequiredDependencies(
project: Project,
npmDependencies: MutableSet<NpmDependency>,
gradleComponents: GradleNodeModulesBuilder
gradleDeps: NpmProjectGradleDeps
) {
val requiredDependencies = mutableListOf<Dependency>()
@@ -227,23 +214,23 @@ internal class NpmResolver private constructor(val rootProject: Project) {
configuration.dependencies.add(it)
}
configuration.resolve()
visitConfiguration(configuration, npmDependencies, gradleComponents)
visitConfiguration(configuration, npmDependencies, gradleDeps)
}
}
private fun visitNpmDependencies(
private fun collectDependencies(
project: Project,
npmDependencies: MutableSet<NpmDependency>,
gradleComponents: GradleNodeModulesBuilder,
gradleDeps: NpmProjectGradleDeps,
packageJson: PackageJson
) {
val kotlin = project.kotlinExtensionOrNull
if (kotlin != null) {
when (kotlin) {
is KotlinSingleTargetExtension -> visitTarget(kotlin.target, project, npmDependencies, gradleComponents, packageJson)
is KotlinSingleTargetExtension -> visitTarget(kotlin.target, project, npmDependencies, gradleDeps, packageJson)
is KotlinMultiplatformExtension -> kotlin.targets.forEach {
visitTarget(it, project, npmDependencies, gradleComponents, packageJson)
visitTarget(it, project, npmDependencies, gradleDeps, packageJson)
}
}
@@ -260,14 +247,14 @@ internal class NpmResolver private constructor(val rootProject: Project) {
target: KotlinTarget,
project: Project,
npmDependencies: MutableSet<NpmDependency>,
gradleComponents: GradleNodeModulesBuilder,
gradleDeps: NpmProjectGradleDeps,
packageJson: PackageJson
) {
if (target.platformType == KotlinPlatformType.js) {
target.compilations.toList().forEach { compilation ->
compilation.relatedConfigurationNames.forEach {
val configuration = project.configurations.getByName(it)
visitConfiguration(configuration, npmDependencies, gradleComponents)
visitConfiguration(configuration, npmDependencies, gradleDeps)
}
if (compilation is KotlinJsCompilation) {
@@ -284,9 +271,9 @@ internal class NpmResolver private constructor(val rootProject: Project) {
private fun visitConfiguration(
configuration: Configuration,
npmDependencies: MutableSet<NpmDependency>,
gradleComponents: GradleNodeModulesBuilder
gradleDeps: NpmProjectGradleDeps
) {
gradleComponents.visitConfiguration(configuration)
gradleNodeModules.collectDependenciesFromConfiguration(configuration, gradleDeps)
configuration.allDependencies.forEach { dependency ->
when (dependency) {
@@ -336,4 +323,8 @@ internal class NpmResolver private constructor(val rootProject: Project) {
}
}
}
override fun close() {
gradleNodeModules.close()
}
}