Gradle, js, npm: remove hoisted gradle node modules. Split results collection from shared cache.
#KT-30530
This commit is contained in:
+3
-1
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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>()
|
||||
|
||||
+14
-16
@@ -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)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-1
@@ -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 =
|
||||
|
||||
+1
-6
@@ -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
|
||||
|
||||
+13
@@ -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>()
|
||||
}
|
||||
+37
-46
@@ -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()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user