aboutsummaryrefslogtreecommitdiffstats
path: root/ms/controllerblueprints/modules/blueprint-scripts/src/main/kotlin/org/onap/ccsdk/apps/controllerblueprints/scripts/BluePrintCompilerProxy.kt
blob: 572724d072ab10ec86bc5856966898dc8e18f9c0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/*
 * Copyright © 2017-2018 AT&T Intellectual Property.
 * Modifications Copyright © 2018 IBM.
 *
 * 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.onap.ccsdk.apps.controllerblueprints.scripts

import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoots
import org.jetbrains.kotlin.cli.common.environment.setIdeaIoUseFallback
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler
import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot
import org.jetbrains.kotlin.com.intellij.openapi.util.Disposer
import org.jetbrains.kotlin.config.*
import org.slf4j.LoggerFactory
import java.io.File
import kotlin.script.experimental.api.*
import kotlin.script.experimental.host.ScriptingHostConfiguration
import kotlin.script.experimental.jvm.util.classpathFromClasspathProperty
import kotlin.script.experimental.jvmhost.KJvmCompilerProxy

open class BluePrintsCompilerProxy(private val hostConfiguration: ScriptingHostConfiguration) : KJvmCompilerProxy {

    private val log = LoggerFactory.getLogger(BluePrintsCompilerProxy::class.java)!!

    override fun compile(script: SourceCode, scriptCompilationConfiguration: ScriptCompilationConfiguration)
            : ResultWithDiagnostics<CompiledScript<*>> {

        val messageCollector = ScriptDiagnosticsMessageCollector()

        fun failure(vararg diagnostics: ScriptDiagnostic): ResultWithDiagnostics.Failure =
                ResultWithDiagnostics.Failure(*messageCollector.diagnostics.toTypedArray(), *diagnostics)

        // Compile the Code
        try {

            log.trace("Scripting Host Configuration : $hostConfiguration")

            setIdeaIoUseFallback()

            val blueprintSourceCode = script as BluePrintSourceCode

            val compiledJarFile = blueprintSourceCode.targetJarFile

            if (!compiledJarFile.exists() || blueprintSourceCode.regenerate) {

                var environment: KotlinCoreEnvironment? = null

                val rootDisposable = Disposer.newDisposable()

                try {

                    val compilerConfiguration = CompilerConfiguration().apply {

                        put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector)
                        put(CommonConfigurationKeys.MODULE_NAME, blueprintSourceCode.moduleName)
                        put(JVMConfigurationKeys.OUTPUT_JAR, compiledJarFile)
                        put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, false)

                        // Load Current Class loader to Compilation Class loader
                        val currentClassLoader = classpathFromClasspathProperty()
                        currentClassLoader?.forEach {
                            add(CLIConfigurationKeys.CONTENT_ROOTS, JvmClasspathRoot(it))
                        }

                        // Add all Kotlin Sources
                        addKotlinSourceRoots(blueprintSourceCode.blueprintKotlinSources)

                        languageVersionSettings = LanguageVersionSettingsImpl(
                                LanguageVersion.LATEST_STABLE, ApiVersion.LATEST_STABLE, mapOf(AnalysisFlags.skipMetadataVersionCheck to true)
                        )
                    }

                    //log.info("Executing with compiler configuration : $compilerConfiguration")

                    environment = KotlinCoreEnvironment.createForProduction(rootDisposable, compilerConfiguration,
                            EnvironmentConfigFiles.JVM_CONFIG_FILES)

                    // Compile Kotlin Sources
                    val compiled = KotlinToJVMBytecodeCompiler.compileBunchOfSources(environment)

                    val analyzerWithCompilerReport = AnalyzerWithCompilerReport(messageCollector,
                            environment.configuration.languageVersionSettings)

                    if (analyzerWithCompilerReport.hasErrors()) {
                        return ResultWithDiagnostics.Failure(messageCollector.diagnostics)
                    }
                } finally {
                    rootDisposable.dispose()
                }
            }

            val res = BluePrintCompiledScript<File>(scriptCompilationConfiguration, compiledJarFile)

            return ResultWithDiagnostics.Success(res, messageCollector.diagnostics)

        } catch (ex: Throwable) {
            return failure(ex.asDiagnostics())
        }
    }
}

class ScriptDiagnosticsMessageCollector : MessageCollector {

    private val _diagnostics = arrayListOf<ScriptDiagnostic>()

    val diagnostics: List<ScriptDiagnostic> get() = _diagnostics

    override fun clear() {
        _diagnostics.clear()
    }

    override fun hasErrors(): Boolean =
            _diagnostics.any { it.severity == ScriptDiagnostic.Severity.ERROR }


    override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageLocation?) {
        val mappedSeverity = when (severity) {
            CompilerMessageSeverity.EXCEPTION,
            CompilerMessageSeverity.ERROR -> ScriptDiagnostic.Severity.ERROR
            CompilerMessageSeverity.STRONG_WARNING,
            CompilerMessageSeverity.WARNING -> ScriptDiagnostic.Severity.WARNING
            CompilerMessageSeverity.INFO -> ScriptDiagnostic.Severity.INFO
            CompilerMessageSeverity.LOGGING -> ScriptDiagnostic.Severity.DEBUG
            else -> null
        }
        if (mappedSeverity != null) {
            val mappedLocation = location?.let {
                if (it.line < 0 && it.column < 0) null // special location created by CompilerMessageLocation.create
                else SourceCode.Location(SourceCode.Position(it.line, it.column))
            }
            _diagnostics.add(ScriptDiagnostic(message, mappedSeverity, location?.path, mappedLocation))
        }
    }
}