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