Gradle, js, npm: resolver between projects
#KT-30530
This commit is contained in:
+9
-3
@@ -10,9 +10,7 @@ import org.gradle.api.artifacts.Configuration
|
||||
import org.gradle.api.artifacts.ResolvedArtifact
|
||||
import org.gradle.api.artifacts.ResolvedDependency
|
||||
import org.gradle.api.artifacts.component.ProjectComponentIdentifier
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
|
||||
import org.jetbrains.kotlin.gradle.internal.ProcessedFilesCache
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
|
||||
|
||||
internal class GradleNodeModulesBuilder(val project: Project) : AutoCloseable {
|
||||
companion object {
|
||||
@@ -28,6 +26,8 @@ internal class GradleNodeModulesBuilder(val project: Project) : AutoCloseable {
|
||||
GradleNodeModule(it, dir.resolve(it))
|
||||
}
|
||||
|
||||
val projects = mutableSetOf<Project>()
|
||||
|
||||
fun visitConfiguration(configuration: Configuration) {
|
||||
if (configuration.isCanBeResolved) {
|
||||
configuration.resolvedConfiguration.firstLevelModuleDependencies.forEach {
|
||||
@@ -57,7 +57,13 @@ internal class GradleNodeModulesBuilder(val project: Project) : AutoCloseable {
|
||||
}
|
||||
|
||||
artifacts.forEach { artifact ->
|
||||
if (artifact.id.componentIdentifier !is ProjectComponentIdentifier) {
|
||||
val componentIdentifier = artifact.id.componentIdentifier
|
||||
if (componentIdentifier is ProjectComponentIdentifier) {
|
||||
val dependentProject = project.findProject(componentIdentifier.projectPath)
|
||||
?: error("Cannot find project ${componentIdentifier.projectPath}")
|
||||
|
||||
projects.add(dependentProject)
|
||||
} else {
|
||||
cache.getOrCompute(artifact.file) {
|
||||
lazyDirName
|
||||
}
|
||||
|
||||
+2
-2
@@ -56,14 +56,14 @@ data class NpmDependency(
|
||||
return when (result) {
|
||||
is AlreadyInProgress -> null
|
||||
is AlreadyResolved -> {
|
||||
check(this in result.resolution.dependencies) {
|
||||
check(this in result.resolution.npmPackage!!.npmDependencies) {
|
||||
"Project hierarchy is already resolved in NPM without $this"
|
||||
}
|
||||
|
||||
result.resolution
|
||||
}
|
||||
is ResolvedNow -> {
|
||||
check(this in result.resolution.dependencies) {
|
||||
check(this in result.resolution.npmPackage!!.npmDependencies) {
|
||||
"$this was not visited during resolution"
|
||||
}
|
||||
|
||||
|
||||
+27
-30
@@ -28,7 +28,7 @@ import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile
|
||||
|
||||
/**
|
||||
* Generates `package.json` file for projects with npm or js dependencies and
|
||||
* runs selected [NodeJsRootExtension.packageManager] to download and install it.
|
||||
* runs selected [NodeJsRootExtension.packageManager] to download and install all of it's dependencies.
|
||||
*
|
||||
* All [NpmDependency] for configurations related to kotlin/js will be added to `package.json`.
|
||||
* For external gradle modules, fake npm packages will be created and added to `package.json`
|
||||
@@ -45,14 +45,10 @@ internal class NpmResolver private constructor(val rootProject: Project) {
|
||||
|
||||
val resolved = process?.resolved
|
||||
|
||||
return if (resolved != null) AlreadyResolved(resolved)
|
||||
return if (resolved != null) AlreadyResolved(ProjectData[project]!!.resolved!!)
|
||||
else {
|
||||
val resolver = NpmResolver(rootProject)
|
||||
check(resolver.resolve(rootProject, null))
|
||||
val resolution = ResolvedProject(resolver.npmPackages, resolver.requiredByTasks)
|
||||
ProjectData[rootProject]!!.resolved = resolution
|
||||
|
||||
ResolvedNow(resolution)
|
||||
NpmResolver(rootProject).resolve(rootProject, null)!!
|
||||
ResolvedNow(ProjectData[project]!!.resolved!!)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +57,7 @@ internal class NpmResolver private constructor(val rootProject: Project) {
|
||||
?: error("NPM dependencies should be resolved$reason")
|
||||
|
||||
fun checkRequiredDependencies(project: Project, target: RequiresNpmDependencies) {
|
||||
val required = requireResolved(project, "before $target execution").requiredByTasks
|
||||
val required = requireResolved(project, "before $target execution").taskDependencies
|
||||
val targetRequired = required[target]?.toSet() ?: setOf()
|
||||
|
||||
target.requiredNpmDependencies.forEach {
|
||||
@@ -98,13 +94,9 @@ internal class NpmResolver private constructor(val rootProject: Project) {
|
||||
}
|
||||
|
||||
class ResolvedProject(
|
||||
val npmPackages: Collection<NpmPackage>,
|
||||
val requiredByTasks: Map<RequiresNpmDependencies, Collection<RequiredKotlinJsDependency>>
|
||||
) {
|
||||
val dependencies by lazy {
|
||||
npmPackages.flatMapTo(mutableSetOf()) { it.npmDependencies }
|
||||
}
|
||||
}
|
||||
val npmPackage: NpmPackage?,
|
||||
val taskDependencies: Map<RequiresNpmDependencies, Collection<RequiredKotlinJsDependency>>
|
||||
)
|
||||
|
||||
class NpmPackage(
|
||||
val project: Project,
|
||||
@@ -128,19 +120,15 @@ 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 resolve(
|
||||
project: Project,
|
||||
parentGradleModules: GradleNodeModulesBuilder?
|
||||
): Boolean {
|
||||
val existedProcess = ProjectData[project]
|
||||
if (existedProcess != null) {
|
||||
if (existedProcess.resolved != null) error("yarn dependencies for $project already resolved")
|
||||
else {
|
||||
// called inside resolution of classpath (from visitTarget)
|
||||
// we should return as we are already in progress
|
||||
return false
|
||||
}
|
||||
} else ProjectData().also {
|
||||
): ProjectData? {
|
||||
val result = ProjectData().also {
|
||||
ProjectData[project] = it
|
||||
}
|
||||
|
||||
@@ -149,10 +137,10 @@ internal class NpmResolver private constructor(val rootProject: Project) {
|
||||
else GradleNodeModulesBuilder(project)
|
||||
|
||||
project.subprojects.forEach {
|
||||
resolve(it, gradleModules)
|
||||
getOrResolve(it, gradleModules)
|
||||
}
|
||||
|
||||
val npmPackage = extractNpmPackage(project, gradleModules)
|
||||
val npmPackage = extractNpmPackage(project, gradleModules, parentGradleModules)
|
||||
if (npmPackage != null) {
|
||||
npmPackage.savePackageJson(gson)
|
||||
|
||||
@@ -162,6 +150,8 @@ internal class NpmResolver private constructor(val rootProject: Project) {
|
||||
npmPackages.add(npmPackage)
|
||||
}
|
||||
|
||||
result.resolved = ResolvedProject(npmPackage, requiredByTasks)
|
||||
|
||||
if (project == rootProject) {
|
||||
if (npmPackages.isNotEmpty()) {
|
||||
requirePackageManagerSetup()
|
||||
@@ -173,12 +163,13 @@ internal class NpmResolver private constructor(val rootProject: Project) {
|
||||
gradleModules.close()
|
||||
}
|
||||
|
||||
return true
|
||||
return result
|
||||
}
|
||||
|
||||
private fun extractNpmPackage(
|
||||
project: Project,
|
||||
gradleComponents: GradleNodeModulesBuilder
|
||||
gradleComponents: GradleNodeModulesBuilder,
|
||||
parentGradleModules: GradleNodeModulesBuilder?
|
||||
): NpmPackage? {
|
||||
val packageJson = PackageJson(project.name, project.version.toString())
|
||||
val npmDependencies = mutableSetOf<NpmDependency>()
|
||||
@@ -192,6 +183,12 @@ internal class NpmResolver private constructor(val rootProject: Project) {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
project.nodeJs.packageJsonHandlers.forEach {
|
||||
|
||||
+2
-2
@@ -111,8 +111,8 @@ object Yarn : NpmApi {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldHoistGradleNodeModules(project: Project): Boolean =
|
||||
project.rootProject.yarn.useWorkspaces
|
||||
// override fun shouldHoistGradleNodeModules(project: Project): Boolean =
|
||||
// project.rootProject.yarn.useWorkspaces
|
||||
|
||||
@Suppress("EXPOSED_PARAMETER_TYPE")
|
||||
override fun resolveRootProject(
|
||||
|
||||
Reference in New Issue
Block a user