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