Gradle, js, npm: store imported packages as yarn workspaces

#KT-30530
This commit is contained in:
Sergey Rostov
2019-05-17 11:02:05 +03:00
parent 64f997daa4
commit fab879bf33
9 changed files with 40 additions and 28 deletions
@@ -28,15 +28,15 @@ open class NodeJsRootExtension(project: Project) : NodeJsExtension(project) {
val npmResolveTask: NpmResolveTask val npmResolveTask: NpmResolveTask
get() = project.tasks.getByName(NpmResolveTask.NAME) as NpmResolveTask get() = project.tasks.getByName(NpmResolveTask.NAME) as NpmResolveTask
val nodeModulesGradleCacheDir: File
get() = project.buildDir.resolve("node_modules_gradle")
val rootPackageDir: File val rootPackageDir: File
get() = project.buildDir.resolve("js") get() = project.buildDir.resolve("js")
val projectPackagesDir: File val projectPackagesDir: File
get() = rootPackageDir.resolve("packages") get() = rootPackageDir.resolve("packages")
val nodeModulesGradleCacheDir: File
get() = rootPackageDir.resolve("packages_imported")
internal val environment: NodeJsEnv internal val environment: NodeJsEnv
get() { get() {
val platform = NodeJsPlatform.name val platform = NodeJsPlatform.name
@@ -10,4 +10,4 @@ import java.io.File
/** /**
* Fake NodeJS module directory created from Gradle external module * Fake NodeJS module directory created from Gradle external module
*/ */
class GradleNodeModule(val name: String, val path: File) class GradleNodeModule(val name: String, val version: String, val path: File)
@@ -39,7 +39,7 @@ internal class GradleNodeModuleBuilder(
} }
} }
fun rebuild(): File? { fun rebuild(): PackageJson? {
if (files.isEmpty()) return null if (files.isEmpty()) return null
val packageJson = srcPackageJsonFile?.reader()?.use { val packageJson = srcPackageJsonFile?.reader()?.use {
@@ -100,7 +100,7 @@ fun makeNodeModule(
container: File, container: File,
packageJson: PackageJson, packageJson: PackageJson,
files: (File) -> Unit files: (File) -> Unit
): File { ): PackageJson {
val dir = container.resolve(packageJson.name) val dir = container.resolve(packageJson.name)
if (dir.exists()) dir.deleteRecursively() if (dir.exists()) dir.deleteRecursively()
@@ -119,5 +119,5 @@ fun makeNodeModule(
gson.toJson(packageJson, it) gson.toJson(packageJson, it)
} }
return dir return packageJson
} }
@@ -22,10 +22,10 @@ internal class GradleNodeModulesCache(val project: Project) : AutoCloseable {
} }
internal val dir = project.nodeJs.root.nodeModulesGradleCacheDir internal val dir = project.nodeJs.root.nodeModulesGradleCacheDir
private val cache = ProcessedFilesCache(project, dir, STATE_FILE_NAME, "5") private val cache = ProcessedFilesCache(project, dir, STATE_FILE_NAME, "6")
private val visited = mutableSetOf<ResolvedDependency>() private val visited = mutableSetOf<ResolvedDependency>()
fun collectDependenciesFromConfiguration(configuration: Configuration, result: NpmProjectGradleDeps) { fun collectDependenciesFromConfiguration(configuration: Configuration, result: NpmGradleDependencies) {
if (configuration.isCanBeResolved) { if (configuration.isCanBeResolved) {
configuration.resolvedConfiguration.firstLevelModuleDependencies.forEach { configuration.resolvedConfiguration.firstLevelModuleDependencies.forEach {
visitDependency(it, result) visitDependency(it, result)
@@ -33,7 +33,7 @@ internal class GradleNodeModulesCache(val project: Project) : AutoCloseable {
} }
} }
private fun visitDependency(dependency: ResolvedDependency, result: NpmProjectGradleDeps) { private fun visitDependency(dependency: ResolvedDependency, result: NpmGradleDependencies) {
if (!visited.add(dependency)) return if (!visited.add(dependency)) return
visitArtifacts(dependency, dependency.moduleArtifacts, result) visitArtifacts(dependency, dependency.moduleArtifacts, result)
@@ -46,14 +46,8 @@ internal class GradleNodeModulesCache(val project: Project) : AutoCloseable {
private fun visitArtifacts( private fun visitArtifacts(
dependency: ResolvedDependency, dependency: ResolvedDependency,
artifacts: MutableSet<ResolvedArtifact>, artifacts: MutableSet<ResolvedArtifact>,
result: NpmProjectGradleDeps result: NpmGradleDependencies
) { ) {
val lazyDirName: String? by lazy {
val module = GradleNodeModuleBuilder(project, dependency, artifacts, this)
module.visitArtifacts()
module.rebuild()?.canonicalFile?.relativeTo(dir)?.path
}
artifacts.forEach { artifact -> artifacts.forEach { artifact ->
val componentIdentifier = artifact.id.componentIdentifier val componentIdentifier = artifact.id.componentIdentifier
if (componentIdentifier is ProjectComponentIdentifier) { if (componentIdentifier is ProjectComponentIdentifier) {
@@ -63,11 +57,16 @@ internal class GradleNodeModulesCache(val project: Project) : AutoCloseable {
result.internalModules.add(dependentProject) result.internalModules.add(dependentProject)
} else { } else {
val key = cache.getOrCompute(artifact.file) { val key = cache.getOrCompute(artifact.file) {
lazyDirName val module = GradleNodeModuleBuilder(project, dependency, artifacts, this)
module.visitArtifacts()
module.rebuild()?.let {
it.name + ":" + it.version
}
} }
if (key != null) { if (key != null) {
result.externalModules.add(GradleNodeModule(key, dir.resolve(key))) val (name, version) = key.split(":")
result.externalModules.add(GradleNodeModule(name, version, dir.resolve(name)))
} }
} }
} }
@@ -10,7 +10,12 @@ import org.gradle.api.Project
/** /**
* Gradle dependencies for [NpmProject]. * Gradle dependencies for [NpmProject].
*/ */
class NpmProjectGradleDeps { class NpmGradleDependencies {
val internalModules = mutableSetOf<Project>() val internalModules = mutableSetOf<Project>()
val externalModules = mutableSetOf<GradleNodeModule>() val externalModules = mutableSetOf<GradleNodeModule>()
fun addAll(other: NpmGradleDependencies) {
internalModules.addAll(other.internalModules)
externalModules.addAll(other.externalModules)
}
} }
@@ -14,5 +14,6 @@ class NpmProjectPackage(
val project: Project, val project: Project,
val npmProject: NpmProject, val npmProject: NpmProject,
val npmDependencies: Collection<NpmDependency>, val npmDependencies: Collection<NpmDependency>,
val gradleDependencies: NpmGradleDependencies,
val packageJson: PackageJson val packageJson: PackageJson
) )
@@ -99,7 +99,7 @@ internal class NpmProjectVisitor(val resolver: NpmResolver, val project: Project
project.version.toString() project.version.toString()
) )
val npmDependencies = mutableSetOf<NpmDependency>() val npmDependencies = mutableSetOf<NpmDependency>()
val gradleDeps = NpmProjectGradleDeps() val gradleDeps = NpmGradleDependencies()
compilation.allKotlinSourceSets.forEach { sourceSet -> compilation.allKotlinSourceSets.forEach { sourceSet ->
sourceSet.relatedConfigurationNames.forEach { configurationName -> sourceSet.relatedConfigurationNames.forEach { configurationName ->
@@ -125,8 +125,7 @@ internal class NpmProjectVisitor(val resolver: NpmResolver, val project: Project
} }
gradleDeps.externalModules.forEach { gradleDeps.externalModules.forEach {
val relativePath = it.path.relativeTo(npmProject.dir) packageJson.dependencies[it.name] = it.version
packageJson.dependencies[it.name] = "file:$relativePath"
} }
gradleDeps.internalModules.forEach { target -> gradleDeps.internalModules.forEach { target ->
@@ -140,7 +139,7 @@ internal class NpmProjectVisitor(val resolver: NpmResolver, val project: Project
it(packageJson) it(packageJson)
} }
val npmPackage = NpmProjectPackage(project, npmProject, npmDependencies, packageJson) val npmPackage = NpmProjectPackage(project, npmProject, npmDependencies, gradleDeps, packageJson)
npmPackage.packageJson.saveTo(npmProject.packageJsonFile) npmPackage.packageJson.saveTo(npmProject.packageJsonFile)
resolver.packageManager.resolveProject(npmPackage) resolver.packageManager.resolveProject(npmPackage)
@@ -151,9 +150,9 @@ internal class NpmProjectVisitor(val resolver: NpmResolver, val project: Project
private fun visitConfiguration( private fun visitConfiguration(
configuration: Configuration, configuration: Configuration,
npmDependencies: MutableSet<NpmDependency>, npmDependencies: MutableSet<NpmDependency>,
gradleDeps: NpmProjectGradleDeps gradleDependencies: NpmGradleDependencies
) { ) {
resolver.gradleNodeModules.collectDependenciesFromConfiguration(configuration, gradleDeps) resolver.gradleNodeModules.collectDependenciesFromConfiguration(configuration, gradleDependencies)
configuration.allDependencies.forEach { dependency -> configuration.allDependencies.forEach { dependency ->
when (dependency) { when (dependency) {
@@ -124,6 +124,7 @@ internal class NpmResolver private constructor(val rootProject: Project) : AutoC
val visited = NpmProjectVisitor(this, project).visitProject() val visited = NpmProjectVisitor(this, project).visitProject()
data.visit = visited data.visit = visited
allNpmPackages.addAll(visited.npmProjects) allNpmPackages.addAll(visited.npmProjects)
return visited return visited
@@ -125,8 +125,15 @@ object Yarn : NpmApi {
) { ) {
val rootPackageJson = PackageJson(rootProject.name, rootProject.version.toString()) val rootPackageJson = PackageJson(rootProject.name, rootProject.version.toString())
rootPackageJson.private = true rootPackageJson.private = true
rootPackageJson.workspaces = npmProjects
.map { it.npmProject.dir.relativeTo(nodeJsWorldDir).path } val npmProjectWorkspaces = npmProjects.map { it.npmProject.dir.relativeTo(nodeJsWorldDir).path }
val importedProjectWorkspaces = npmProjects.flatMapTo(mutableSetOf()) {
it.gradleDependencies.externalModules.map { importedProject ->
importedProject.path.relativeTo(nodeJsWorldDir).path
}
}
rootPackageJson.workspaces = npmProjectWorkspaces + importedProjectWorkspaces
rootProject.nodeJs.packageJsonHandlers.forEach { rootProject.nodeJs.packageJsonHandlers.forEach {
it(rootPackageJson) it(rootPackageJson)