diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/ProcessedFilesCache.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/ProcessedFilesCache.kt index 5192e820203..22be0b7c1fc 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/ProcessedFilesCache.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/ProcessedFilesCache.kt @@ -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 } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/GradleNodeModuleBuilder.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/GradleNodeModuleBuilder.kt index 3b08c14ebc4..06f794bc48d 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/GradleNodeModuleBuilder.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/GradleNodeModuleBuilder.kt @@ -16,7 +16,7 @@ internal class GradleNodeModuleBuilder( val project: Project, val dependency: ResolvedDependency, val artifacts: Set, - val cache: GradleNodeModulesBuilder + val cache: GradleNodeModulesCache ) { var srcPackageJsonFile: File? = null val files = mutableListOf() diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/GradleNodeModulesBuilder.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/GradleNodeModulesCache.kt similarity index 70% rename from libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/GradleNodeModulesBuilder.kt rename to libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/GradleNodeModulesCache.kt index 1cefa9e8216..c2443dbd087 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/GradleNodeModulesBuilder.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/GradleNodeModulesCache.kt @@ -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() - val modules - get() = cache.targets.map { - GradleNodeModule(it, dir.resolve(it)) - } - - val projects = mutableSetOf() - - 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 + artifacts: MutableSet, + 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))) + } } } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmApi.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmApi.kt index 9d7b98acfa1..360427a46bb 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmApi.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmApi.kt @@ -30,7 +30,12 @@ interface NpmApi { allWorkspaces: Collection ): 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 = diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProject.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProject.kt index 1617fa9f12a..422fbbe1e25 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProject.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProject.kt @@ -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 diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProjectGradleDeps.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProjectGradleDeps.kt new file mode 100644 index 00000000000..52379a45f39 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProjectGradleDeps.kt @@ -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() + val externalModules = mutableSetOf() +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmResolver.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmResolver.kt index 5b5eb1816a3..8e61991fbd2 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmResolver.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmResolver.kt @@ -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() private val requiredByTasks = mutableMapOf>() 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() + 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, - gradleComponents: GradleNodeModulesBuilder + gradleDeps: NpmProjectGradleDeps ) { val requiredDependencies = mutableListOf() @@ -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, - 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, - 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, - 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() + } } \ No newline at end of file