ce9553c0e6a45eec321d9e0b22c3067f869a5669
[ccsdk/cds.git] /
1 /*
2  * Copyright © 2017-2018 AT&T Intellectual Property.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package org.onap.ccsdk.apps.controllerblueprints.scripts
18
19 import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
20 import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoots
21 import org.jetbrains.kotlin.cli.common.environment.setIdeaIoUseFallback
22 import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
23 import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
24 import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
25 import org.jetbrains.kotlin.cli.common.messages.MessageCollector
26 import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
27 import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
28 import org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler
29 import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot
30 import org.jetbrains.kotlin.com.intellij.openapi.util.Disposer
31 import org.jetbrains.kotlin.config.*
32 import org.slf4j.LoggerFactory
33 import java.io.File
34 import kotlin.script.experimental.api.*
35 import kotlin.script.experimental.host.ScriptingHostConfiguration
36 import kotlin.script.experimental.jvm.util.classpathFromClasspathProperty
37 import kotlin.script.experimental.jvmhost.KJvmCompilerProxy
38
39 open class BluePrintsCompilerProxy(private val hostConfiguration: ScriptingHostConfiguration) : KJvmCompilerProxy {
40
41     private val log = LoggerFactory.getLogger(BluePrintsCompilerProxy::class.java)!!
42
43     override fun compile(script: SourceCode, scriptCompilationConfiguration: ScriptCompilationConfiguration)
44             : ResultWithDiagnostics<CompiledScript<*>> {
45
46         val messageCollector = ScriptDiagnosticsMessageCollector()
47
48         fun failure(vararg diagnostics: ScriptDiagnostic): ResultWithDiagnostics.Failure =
49                 ResultWithDiagnostics.Failure(*messageCollector.diagnostics.toTypedArray(), *diagnostics)
50
51         // Compile the Code
52         try {
53
54             log.trace("Scripting Host Configuration : $hostConfiguration")
55
56             setIdeaIoUseFallback()
57
58             val blueprintSourceCode = script as BluePrintSourceCode
59
60             val compiledJarFile = blueprintSourceCode.targetJarFile
61
62             if (!compiledJarFile.exists() || blueprintSourceCode.regenerate) {
63
64                 var environment: KotlinCoreEnvironment? = null
65
66                 val rootDisposable = Disposer.newDisposable()
67
68                 val compilerConfiguration = CompilerConfiguration().apply {
69
70                     put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector)
71                     put(CommonConfigurationKeys.MODULE_NAME, blueprintSourceCode.moduleName)
72                     put(JVMConfigurationKeys.OUTPUT_JAR, compiledJarFile)
73                     put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, false)
74
75                     // Load Current Class loader to Compilation Class loader
76                     val currentClassLoader = classpathFromClasspathProperty()
77                     currentClassLoader?.forEach {
78                         add(CLIConfigurationKeys.CONTENT_ROOTS, JvmClasspathRoot(it))
79                     }
80
81                     // Add all Kotlin Sources
82                     addKotlinSourceRoots(blueprintSourceCode.blueprintKotlinSources)
83
84                     languageVersionSettings = LanguageVersionSettingsImpl(
85                             LanguageVersion.LATEST_STABLE, ApiVersion.LATEST_STABLE, mapOf(AnalysisFlags.skipMetadataVersionCheck to true)
86                     )
87                 }
88
89                 //log.info("Executing with compiler configuration : $compilerConfiguration")
90
91                 environment = KotlinCoreEnvironment.createForProduction(rootDisposable, compilerConfiguration,
92                         EnvironmentConfigFiles.JVM_CONFIG_FILES)
93
94                 // Compile Kotlin Sources
95                 val compiled = KotlinToJVMBytecodeCompiler.compileBunchOfSources(environment)
96
97                 val analyzerWithCompilerReport = AnalyzerWithCompilerReport(messageCollector,
98                         environment.configuration.languageVersionSettings)
99
100                 if (analyzerWithCompilerReport.hasErrors()) {
101                     return ResultWithDiagnostics.Failure(messageCollector.diagnostics)
102                 }
103             }
104
105             val res = BluePrintCompiledScript<File>(scriptCompilationConfiguration, compiledJarFile)
106
107             return ResultWithDiagnostics.Success(res, messageCollector.diagnostics)
108
109         } catch (ex: Throwable) {
110             return failure(ex.asDiagnostics())
111         }
112     }
113 }
114
115 class ScriptDiagnosticsMessageCollector : MessageCollector {
116
117     private val _diagnostics = arrayListOf<ScriptDiagnostic>()
118
119     val diagnostics: List<ScriptDiagnostic> get() = _diagnostics
120
121     override fun clear() {
122         _diagnostics.clear()
123     }
124
125     override fun hasErrors(): Boolean =
126             _diagnostics.any { it.severity == ScriptDiagnostic.Severity.ERROR }
127
128
129     override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageLocation?) {
130         val mappedSeverity = when (severity) {
131             CompilerMessageSeverity.EXCEPTION,
132             CompilerMessageSeverity.ERROR -> ScriptDiagnostic.Severity.ERROR
133             CompilerMessageSeverity.STRONG_WARNING,
134             CompilerMessageSeverity.WARNING -> ScriptDiagnostic.Severity.WARNING
135             CompilerMessageSeverity.INFO -> ScriptDiagnostic.Severity.INFO
136             CompilerMessageSeverity.LOGGING -> ScriptDiagnostic.Severity.DEBUG
137             else -> null
138         }
139         if (mappedSeverity != null) {
140             val mappedLocation = location?.let {
141                 if (it.line < 0 && it.column < 0) null // special location created by CompilerMessageLocation.create
142                 else SourceCode.Location(SourceCode.Position(it.line, it.column))
143             }
144             _diagnostics.add(ScriptDiagnostic(message, mappedSeverity, location?.path, mappedLocation))
145         }
146     }
147 }
148