Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
will be used to provide auto compile on kotlin code
- Loading branch information
Showing
6 changed files
with
305 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<parent> | ||
<groupId>io.restx</groupId> | ||
<artifactId>restx-parent</artifactId> | ||
<version>0.36-SNAPSHOT</version> | ||
</parent> | ||
|
||
<artifactId>restx-kotlin-compiler</artifactId> | ||
<name>restx-kotlin-compiler</name> | ||
|
||
<properties> | ||
<maven.compiler.source>1.8</maven.compiler.source> | ||
<maven.compiler.target>1.8</maven.compiler.target> | ||
<kotlin.version>1.2.21</kotlin.version> | ||
<kotlin.compiler.incremental>false</kotlin.compiler.incremental> | ||
</properties> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>io.restx</groupId> | ||
<artifactId>restx-common</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>javax.inject</groupId> | ||
<artifactId>javax.inject</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.google.guava</groupId> | ||
<artifactId>guava</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.jetbrains.kotlin</groupId> | ||
<artifactId>kotlin-stdlib</artifactId> | ||
<version>${kotlin.version}</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.jetbrains.kotlin</groupId> | ||
<artifactId>kotlin-compiler-embeddable</artifactId> | ||
<version>${kotlin.version}</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.slf4j</groupId> | ||
<artifactId>slf4j-api</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>junit</groupId> | ||
<artifactId>junit</artifactId> | ||
<scope>test</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.assertj</groupId> | ||
<artifactId>assertj-core</artifactId> | ||
<scope>test</scope> | ||
</dependency> | ||
</dependencies> | ||
<build> | ||
<plugins> | ||
<plugin> | ||
<artifactId>kotlin-maven-plugin</artifactId> | ||
<groupId>org.jetbrains.kotlin</groupId> | ||
<version>${kotlin.version}</version> | ||
<executions> | ||
<execution> | ||
<id>compile</id> | ||
<goals> <goal>compile</goal> </goals> | ||
<configuration> | ||
<sourceDirs> | ||
<sourceDir>${project.basedir}/src/main/kotlin</sourceDir> | ||
<sourceDir>${project.basedir}/src/main/java</sourceDir> | ||
</sourceDirs> | ||
</configuration> | ||
</execution> | ||
<execution> | ||
<id>test-compile</id> | ||
<goals> <goal>test-compile</goal> </goals> | ||
<configuration> | ||
<sourceDirs> | ||
<sourceDir>${project.basedir}/src/test/kotlin</sourceDir> | ||
<sourceDir>${project.basedir}/src/test/java</sourceDir> | ||
</sourceDirs> | ||
</configuration> | ||
</execution> | ||
</executions> | ||
</plugin> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-compiler-plugin</artifactId> | ||
<version>3.5.1</version> | ||
<executions> | ||
<!-- Replacing default-compile as it is treated specially by maven --> | ||
<execution> | ||
<id>default-compile</id> | ||
<phase>none</phase> | ||
</execution> | ||
<!-- Replacing default-testCompile as it is treated specially by maven --> | ||
<execution> | ||
<id>default-testCompile</id> | ||
<phase>none</phase> | ||
</execution> | ||
<execution> | ||
<id>java-compile</id> | ||
<phase>compile</phase> | ||
<goals> <goal>compile</goal> </goals> | ||
</execution> | ||
<execution> | ||
<id>java-test-compile</id> | ||
<phase>test-compile</phase> | ||
<goals> <goal>testCompile</goal> </goals> | ||
</execution> | ||
</executions> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
|
||
</project> |
35 changes: 35 additions & 0 deletions
35
restx-kotlin-compiler/src/main/java/restx/kt/compiler/KotlinCompiler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package restx.kt.compiler; | ||
|
||
import javax.tools.Diagnostic; | ||
import java.net.MalformedURLException; | ||
import java.nio.file.Path; | ||
import java.util.Collection; | ||
import java.util.Collections; | ||
|
||
/** | ||
* Created by xhanin on 09/02/2018. | ||
*/ | ||
public class KotlinCompiler { | ||
private final Path destination; | ||
|
||
public KotlinCompiler(Path destination) { | ||
this.destination = destination; | ||
} | ||
|
||
public Collection<Diagnostic<?>> compile(Collection<Path> sources) { | ||
for (Path source : sources) { | ||
try { | ||
KotlinCompilerHelper.INSTANCE.compileKotlinScript( | ||
Thread.currentThread().getContextClassLoader(), | ||
source.toUri().toURL(), | ||
destination, | ||
(state, d) -> true | ||
); | ||
} catch (MalformedURLException e) { | ||
throw new IllegalArgumentException("can't convert path to URL: " + e); | ||
} | ||
} | ||
|
||
return Collections.emptyList(); | ||
} | ||
} |
112 changes: 112 additions & 0 deletions
112
restx-kotlin-compiler/src/main/kotlin/restx/kt/compiler/KotlinCompilerHelper.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
package restx.kt.compiler | ||
|
||
import org.jetbrains.kotlin.com.intellij.openapi.* | ||
import org.jetbrains.kotlin.cli.common.* | ||
import org.jetbrains.kotlin.cli.common.messages.* | ||
import org.jetbrains.kotlin.cli.jvm.compiler.* | ||
import org.jetbrains.kotlin.cli.jvm.config.* | ||
import org.jetbrains.kotlin.codegen.* | ||
import org.jetbrains.kotlin.codegen.state.* | ||
import org.jetbrains.kotlin.config.* | ||
import org.jetbrains.kotlin.descriptors.* | ||
import org.jetbrains.kotlin.load.java.* | ||
import org.jetbrains.kotlin.name.* | ||
import org.jetbrains.kotlin.resolve.* | ||
import java.io.* | ||
import java.net.* | ||
import java.nio.file.* | ||
import java.util.* | ||
import java.util.jar.* | ||
|
||
/** | ||
* Author: Sergey Mashkov | ||
* Mostly borrowed from vertx koltin compiler | ||
*/ | ||
object KotlinCompilerHelper { | ||
fun compileKotlinScript(classLoader: ClassLoader, | ||
url: URL, | ||
destination: Path, | ||
predicate: (GenerationState, ClassDescriptor) -> Boolean | ||
): Map<Class<*>, ClassDescriptor> { | ||
|
||
val configuration = CompilerConfiguration() | ||
val printingMessageCollector = PrintingMessageCollector(System.err, MessageRenderer.WITHOUT_PATHS, false) | ||
configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, printingMessageCollector) | ||
configuration.put(CLIConfigurationKeys.ALLOW_KOTLIN_PACKAGE, false) | ||
configuration.put(CLIConfigurationKeys.REPORT_PERF, false) | ||
|
||
configuration.put(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS, LanguageVersionSettingsImpl.DEFAULT) | ||
|
||
configuration.put(JVMConfigurationKeys.JVM_TARGET, JvmTarget.JVM_1_8) | ||
configuration.put(JVMConfigurationKeys.OUTPUT_DIRECTORY, destination.toFile()) | ||
configuration.put(JVMConfigurationKeys.SKIP_RUNTIME_VERSION_CHECK, true) | ||
configuration.put(CommonConfigurationKeys.MODULE_NAME, JvmAbi.DEFAULT_MODULE_NAME) | ||
|
||
val classPath = ( | ||
classLoader.classPath() | ||
+ ClassLoader.getSystemClassLoader().classPath() | ||
+ (Thread.currentThread().contextClassLoader?.classPath() ?: emptyList()) | ||
+ propertyClassPath("java.class.path") | ||
+ propertyClassPath("sun.boot.class.path") | ||
).distinct().filter { Files.exists(it) } | ||
|
||
for (item in classPath) { | ||
configuration.add(JVMConfigurationKeys.CONTENT_ROOTS, JvmClasspathRoot(item.toFile())) | ||
} | ||
configuration.add(JVMConfigurationKeys.CONTENT_ROOTS, KotlinSourceRoot(Paths.get(url.toURI()).toString())) | ||
|
||
val collected = HashMap<String, ClassDescriptor>() | ||
|
||
val environment = KotlinCoreEnvironment.createForProduction(Disposable { }, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES) | ||
val finalState = KotlinToJVMBytecodeCompiler.analyzeAndGenerate(environment) | ||
|
||
if (printingMessageCollector.hasErrors()) { | ||
throw CompilationException("Compilation failed", null, null) | ||
} | ||
if (finalState == null) { | ||
return emptyMap() | ||
} | ||
|
||
val compilerClassLoader = GeneratedClassLoader(finalState.factory, classLoader) | ||
|
||
return finalState.factory.getClassFiles().toList() | ||
.map { it.relativePath.removeSuffix(".class").replace("/", ".") } | ||
.filter { it !in collected } | ||
.mapNotNull { finalState.bindingContext.get(BindingContext.FQNAME_TO_CLASS_DESCRIPTOR, FqNameUnsafe(it.replace("$", "."))) } | ||
.filter { predicate(finalState, it) } | ||
.associateBy { finalState.typeMapper.mapClass(it).className } | ||
.mapKeys { compilerClassLoader.loadClass(it.key) } | ||
} | ||
|
||
private fun ClassLoader.classPath() = (classPathImpl() + manifestClassPath()).distinct() | ||
|
||
private fun ClassLoader.classPathImpl(): List<Path> { | ||
val parentUrls = parent?.classPathImpl() ?: emptyList() | ||
|
||
return when { | ||
this is URLClassLoader -> urLs.filterNotNull().map(URL::toURI).mapNotNull { ifFailed(null) { Paths.get(it) } } + parentUrls | ||
else -> parentUrls | ||
} | ||
} | ||
|
||
private fun ClassLoader.manifestClassPath() = | ||
getResources("META-INF/MANIFEST.MF") | ||
.asSequence() | ||
.mapNotNull { ifFailed(null) { it.openStream().use { Manifest().apply { read(it) } } } } | ||
.flatMap { it.mainAttributes?.getValue("Class-Path")?.splitToSequence(" ")?.filter(String::isNotBlank) ?: emptySequence() } | ||
.mapNotNull { ifFailed(null) { Paths.get(URI.create(it)) } } | ||
.toList() | ||
|
||
private fun propertyClassPath(key: String) = System.getProperty(key) | ||
?.split(File.pathSeparator) | ||
?.filter(String::isNotEmpty) | ||
?.map { Paths.get(it) } | ||
?: emptyList() | ||
|
||
private inline fun <R> ifFailed(default: R, block: () -> R) = try { | ||
block() | ||
} catch (t: Throwable) { | ||
default | ||
} | ||
|
||
} |
38 changes: 38 additions & 0 deletions
38
restx-kotlin-compiler/src/test/java/restx/kt/compiler/KotlinCompilerTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package restx.kt.compiler; | ||
|
||
import org.junit.Rule; | ||
import org.junit.Test; | ||
import org.junit.rules.TemporaryFolder; | ||
|
||
import javax.tools.Diagnostic; | ||
import java.io.File; | ||
import java.nio.file.Path; | ||
import java.nio.file.Paths; | ||
import java.util.Collection; | ||
|
||
import static java.util.Arrays.asList; | ||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
/** | ||
* Created by xhanin on 09/02/2018. | ||
*/ | ||
public class KotlinCompilerTest { | ||
@Rule | ||
public TemporaryFolder folder = new TemporaryFolder(); | ||
|
||
@Test | ||
public void should_compile_simple_class() throws Exception { | ||
File target = folder.newFolder("target"); | ||
|
||
KotlinCompiler compiler = new KotlinCompiler(target.toPath()); | ||
|
||
Collection<Path> sources = asList(Paths.get("src/test/resources/MyClass.kt")); | ||
Collection<Diagnostic<?>> diagnostics = compiler.compile(sources); | ||
|
||
assertThat(diagnostics) | ||
.isNotNull() | ||
.isEmpty(); | ||
|
||
assertThat(new File(target, "MyClass.class")).exists(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
class MyClass |