| /* |
| * Copyright 2010-2020 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.pill |
| |
| import org.jetbrains.kotlin.pill.model.* |
| import org.jetbrains.kotlin.pill.util.* |
| import java.io.File |
| |
| class PFile(val path: File, private val text: String) { |
| constructor(path: File, xml: XmlNode) : this(path, xml.toString()) |
| |
| fun write() { |
| path.parentFile.mkdirs() |
| path.writeText(text) |
| } |
| } |
| |
| fun render(project: PProject): List<PFile> { |
| val files = mutableListOf<PFile>() |
| |
| files += renderModulesFile(project) |
| project.modules.forEach { files += renderModule(project, it) } |
| project.libraries.forEach { files += renderLibrary(project, it) } |
| |
| return files |
| } |
| |
| private fun renderModulesFile(project: PProject) = PFile( |
| File(project.rootDirectory, ".idea/modules.xml"), |
| xml("project", "version" to 4) { |
| xml("component", "name" to "ProjectModuleManager") { |
| xml("modules") { |
| val pathContext = ProjectContext(project) |
| |
| for (module in project.modules) { |
| val moduleFilePath = pathContext(module.moduleFile) |
| xml("module", "fileurl" to "file://$moduleFilePath", "filepath" to moduleFilePath) |
| } |
| } |
| } |
| } |
| ) |
| |
| private fun renderModule(project: PProject, module: PModule) = PFile( |
| module.moduleFile, |
| xml( |
| "module", |
| "type" to "JAVA_MODULE", |
| "version" to 4 |
| ) { |
| val moduleForProductionSources = module.moduleForProductionSources |
| if (moduleForProductionSources != null) { |
| xml("component", "name" to "TestModuleProperties", "production-module" to moduleForProductionSources.name) |
| } |
| |
| val kotlinCompileOptions = module.kotlinOptions |
| val pathContext = ModuleContext(project, module) |
| |
| val platformVersion = (kotlinCompileOptions?.jvmTarget ?: "1.8") |
| val classesDirectory = File(project.rootDirectory, "out/production/${module.name}") |
| |
| if (kotlinCompileOptions != null) { |
| xml("component", "name" to "FacetManager") { |
| xml("facet", "type" to "kotlin-language", "name" to "Kotlin") { |
| xml("configuration", "version" to 3, "platform" to "JVM $platformVersion", "useProjectSettings" to "false") { |
| xml("compilerSettings") { |
| xml( |
| "option", |
| "name" to "additionalArguments", |
| "value" to kotlinCompileOptions.extraArguments.joinToString(" ") |
| ) |
| } |
| xml("compilerArguments") { |
| xml("option", "name" to "destination", "value" to pathContext(classesDirectory)) |
| |
| fun Any?.option(name: String) { |
| if (this != null) xml("option", "name" to name, "value" to this.toString()) |
| } |
| |
| kotlinCompileOptions.noStdlib.option("noStdlib") |
| kotlinCompileOptions.noReflect.option("noReflect") |
| module.name.option("moduleName") |
| xml("option", "name" to "jvmTarget", "value" to platformVersion) |
| kotlinCompileOptions.languageVersion.option("languageVersion") |
| kotlinCompileOptions.apiVersion.option("apiVersion") |
| |
| xml("option", "name" to "pluginOptions") { xml("array") } |
| xml("option", "name" to "pluginClasspaths") { |
| xml("array") { |
| for (path in kotlinCompileOptions.pluginClasspath) { |
| xml("option", "value" to path) |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| xml( |
| "component", |
| "name" to "NewModuleRootManager", |
| "LANGUAGE_LEVEL" to "JDK_${platformVersion.replace('.', '_')}", |
| "inherit-compiler-output" to "true" |
| ) { |
| xml("exclude-output") |
| |
| for (contentRoot in module.contentRoots.filter { it.path.exists() }) { |
| xml("content", pathContext.url(contentRoot.path)) { |
| for (sourceRoot in contentRoot.sourceRoots) { |
| var args = arrayOf(pathContext.url(sourceRoot.directory)) |
| |
| args += when (sourceRoot.kind) { |
| PSourceRoot.Kind.PRODUCTION -> ("isTestSource" to "false") |
| PSourceRoot.Kind.TEST -> ("isTestSource" to "true") |
| PSourceRoot.Kind.RESOURCES -> ("type" to "java-resource") |
| PSourceRoot.Kind.TEST_RESOURCES -> ("type" to "java-test-resource") |
| } |
| |
| xml("sourceFolder", *args) |
| } |
| |
| for (excludedDir in contentRoot.excludedDirectories) { |
| xml("excludeFolder", pathContext.url(excludedDir)) |
| } |
| } |
| } |
| |
| when (val javaLanguageVersion = module.javaLanguageVersion) { |
| null -> xml("orderEntry", "type" to "inheritedJdk") |
| else -> xml("orderEntry", "type" to "jdk", "jdkName" to javaLanguageVersion.toString(), "jdkType" to "JavaSDK") |
| } |
| |
| xml("orderEntry", "type" to "sourceFolder", "forTests" to "false") |
| |
| for (orderRoot in module.orderRoots) { |
| val dependency = orderRoot.dependency |
| |
| val args = when (dependency) { |
| is PDependency.ModuleLibrary -> mutableListOf( |
| "type" to "module-library" |
| ) |
| is PDependency.Module -> mutableListOf( |
| "type" to "module", |
| "module-name" to dependency.module.name |
| ) |
| is PDependency.Library -> mutableListOf( |
| "type" to "library", |
| "name" to dependency.name, |
| "level" to "project" |
| ) |
| } |
| |
| if (orderRoot.scope != POrderRoot.Scope.COMPILE) { |
| args.add(1, "scope" to orderRoot.scope.toString()) |
| } |
| |
| if (!module.forTests && dependency is PDependency.Module && dependency.module.forTests) { |
| args += ("production-on-test" to "") |
| } |
| |
| if (orderRoot.isExported) { |
| args += ("exported" to "") |
| } |
| |
| xml("orderEntry", *args.toTypedArray()) { |
| if (dependency is PDependency.ModuleLibrary) { |
| add(renderLibraryToXml(dependency.library, pathContext, named = false)) |
| } |
| } |
| } |
| } |
| } |
| ) |
| |
| private fun renderLibrary(project: PProject, library: PLibrary): PFile { |
| val pathContext = ProjectContext(project) |
| |
| // TODO find how IDEA escapes library names |
| val escapedName = library.renderName().replace(" ", "_").replace(".", "_").replace("-", "_") |
| |
| return PFile( |
| File(project.rootDirectory, ".idea/libraries/$escapedName.xml"), |
| |
| xml("component", "name" to "libraryTable") { |
| add(renderLibraryToXml(library, pathContext)) |
| }) |
| } |
| |
| private fun renderLibraryToXml(library: PLibrary, pathContext: PathContext, named: Boolean = true): XmlNode { |
| val args = if (named) arrayOf("name" to library.renderName()) else emptyArray() |
| |
| return xml("library", *args) { |
| xml("CLASSES") { |
| library.classes.forEach { xml("root", pathContext.url(it)) } |
| } |
| |
| xml("JAVADOC") { |
| library.javadoc.forEach { xml("root", pathContext.url(it)) } |
| } |
| |
| xml("SOURCES") { |
| library.sources.forEach { xml("root", pathContext.url(it)) } |
| } |
| } |
| } |
| |
| fun PLibrary.renderName() = name.takeIf { it != "unspecified" } ?: classes.first().nameWithoutExtension |