All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.kotlin.modules.KotlinModuleXmlBuilder.kt Maven / Gradle / Ivy

There is a newer version: 2.1.0-RC
Show newest version
/*
 * Copyright 2010-2015 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jetbrains.kotlin.modules

import org.jetbrains.kotlin.build.JvmSourceRoot
import org.jetbrains.kotlin.cli.common.modules.ModuleXmlParser.*
import org.jetbrains.kotlin.config.IncrementalCompilation
import org.jetbrains.kotlin.utils.Printer
import java.io.File

class KotlinModuleXmlBuilder {
    private val xml = StringBuilder()
    private val p = Printer(xml)
    private var done = false

    init {
        openTag(p, MODULES)
    }

    @Deprecated(message = "State of IC should be set explicitly")
    fun addModule(
        moduleName: String,
        outputDir: String,
        sourceFiles: Iterable,
        javaSourceRoots: Iterable,
        classpathRoots: Iterable,
        commonSourceFiles: Iterable,
        modularJdkRoot: File?,
        targetTypeId: String,
        isTests: Boolean,
        directoriesToFilterOut: Set,
        friendDirs: Iterable
    ) = addModule(
        moduleName,
        outputDir,
        sourceFiles,
        javaSourceRoots,
        classpathRoots,
        commonSourceFiles,
        modularJdkRoot,
        targetTypeId,
        isTests,
        directoriesToFilterOut,
        friendDirs,
        IncrementalCompilation.isEnabledForJvm()
    )

    fun addModule(
        moduleName: String,
        outputDir: String,
        sourceFiles: Iterable,
        javaSourceRoots: Iterable,
        classpathRoots: Iterable,
        commonSourceFiles: Iterable,
        modularJdkRoot: File?,
        targetTypeId: String,
        isTests: Boolean,
        directoriesToFilterOut: Set,
        friendDirs: Iterable,
        isIncrementalCompilation: Boolean
    ): KotlinModuleXmlBuilder {
        assert(!done) { "Already done" }

        p.println("")

        p.println("<", MODULE, " ",
                  NAME, "=\"", escapeXml(moduleName), "\" ",
                  TYPE, "=\"", escapeXml(targetTypeId), "\" ",
                  OUTPUT_DIR, "=\"", getEscapedPath(File(outputDir)), "\">")
        p.pushIndent()

        for (friendDir in friendDirs) {
            p.println("<", FRIEND_DIR, " ", PATH, "=\"", getEscapedPath(friendDir), "\"/>")
        }

        for (sourceFile in sourceFiles) {
            p.println("<", SOURCES, " ", PATH, "=\"", getEscapedPath(sourceFile), "\"/>")
        }

        for (commonSourceFile in commonSourceFiles) {
            p.println("<", COMMON_SOURCES, " ", PATH, "=\"", getEscapedPath(commonSourceFile), "\"/>")
        }

        processJavaSourceRoots(javaSourceRoots)
        processClasspath(classpathRoots, directoriesToFilterOut, isIncrementalCompilation)

        if (modularJdkRoot != null) {
            p.println("<", MODULAR_JDK_ROOT, " ", PATH, "=\"", getEscapedPath(modularJdkRoot), "\"/>")
        }

        closeTag(p, MODULE)
        return this
    }

    private fun processClasspath(
            files: Iterable,
            directoriesToFilterOut: Set,
            isIncrementalCompilation: Boolean) {
        p.println("")
        for (file in files) {
            val isOutput = directoriesToFilterOut.contains(file) && !isIncrementalCompilation
            if (isOutput) {
                // For IDEA's make (incremental compilation) purposes, output directories of the current module and its dependencies
                // appear on the class path, so we are at risk of seeing the results of the previous build, i.e. if some class was
                // removed in the sources, it may still be there in binaries. Thus, we delete these entries from the classpath.
                p.println("")
                p.println("")
            }
        }
    }

    private fun processJavaSourceRoots(roots: Iterable) {
        p.println("")
        for (root in roots) {
            p.print("<")
            p.printWithNoIndent(JAVA_SOURCE_ROOTS, " ", PATH, "=\"", getEscapedPath(root.file), "\"")

            if (root.packagePrefix != null) {
                p.printWithNoIndent(" ", JAVA_SOURCE_PACKAGE_PREFIX, "=\"", root.packagePrefix, "\"")
            }

            p.printWithNoIndent("/>")
            p.println()
        }
    }

    fun asText(): CharSequence {
        if (!done) {
            closeTag(p, MODULES)
            done = true
        }
        return xml
    }

    private fun openTag(p: Printer, tag: String) {
        p.println("<$tag>")
        p.pushIndent()
    }

    private fun closeTag(p: Printer, tag: String) {
        p.popIndent()
        p.println("")
    }

    private fun getEscapedPath(sourceFile: File): String {
        return escapeXml(sourceFile.invariantSeparatorsPath)
    }

    private companion object {
        private val xmlEscapeReplacement = mapOf("<" to "<", ">" to ">", "&" to "&", "'" to "'", "\"" to """)
        private val xmlEscapeRegex = Regex(xmlEscapeReplacement.keys.joinToString("|", "(?:", ")") { Regex.escape(it) })

        private fun escapeXml(string: String) = string.replace(xmlEscapeRegex) { xmlEscapeReplacement.getValue(it.value) }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy