Rewrite package names in compiled script files

This commit is contained in:
Gary Tierney
2017-09-17 18:42:19 +01:00
parent 112b8aab57
commit 89516dab63
7 changed files with 89 additions and 19 deletions
+1
View File
@@ -20,6 +20,7 @@ repositories {
dependencies {
compile gradleApi()
compile group: 'org.ow2.asm', name: 'asm-all', version: '5.0.3'
compile group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jre8', version: "$kotlinVersion"
compile group: 'org.jetbrains.kotlin', name: 'kotlin-compiler-embeddable', version: "$kotlinVersion"
}
@@ -109,7 +109,6 @@ class ApolloPluginExtension {
compileClasspath = mainSources.compileClasspath + mainSources.runtimeClasspath + mainSources.output
scriptDefinitionClass = "org.apollo.game.plugin.kotlin.KotlinPluginScript"
mustRunAfter buildTask
}
@@ -41,11 +41,10 @@ class KotlinCompilerConfigurationFactory {
classpath.addAll(bootClasspath.split(File.pathSeparatorChar.toString()).collect { new File(it) })
}
def classLoader = new URLClassLoader(classpath.collect { it.toURL() }.toArray(new URL[classpath.size()]))
def classpathFiles = classpath.findAll { it.exists() }
def classLoader = new URLClassLoader(classpathFiles.collect { it.toURL() }.toArray(new URL[classpath.size()]))
def configuration = new CompilerConfiguration()
def scriptDefinitionClass = classLoader.loadClass(scriptDefinitionClassName)
def classpathFiles = classpath.collect { it }
def scriptDefinition = new KotlinScriptDefinitionFromAnnotatedTemplate(JvmClassMappingKt.getKotlinClass(scriptDefinitionClass),
null, null, null, classpathFiles)
@@ -2,12 +2,22 @@ package org.apollo.build.plugin.compiler
import java.nio.file.Path
class KotlinScriptBinary {
final String fullyQualifiedName
final Path output
class KotlinScriptBinaryArtifact {
final String relativePath
final byte[] data
KotlinScriptBinary(String fullyQualifiedName, Path output) {
this.output = output
this.fullyQualifiedName = fullyQualifiedName
KotlinScriptBinaryArtifact(String relativePath, byte[] data) {
this.relativePath = relativePath
this.data = data
}
}
class KotlinScriptBinary {
final String mainClassName
final List<KotlinScriptBinaryArtifact> artifacts
KotlinScriptBinary(String mainClassName, List<KotlinScriptBinaryArtifact> artifacts) {
this.mainClassName = mainClassName
this.artifacts = artifacts
}
}
@@ -0,0 +1,39 @@
package org.apollo.build.plugin.compiler
import org.objectweb.asm.ClassReader
import org.objectweb.asm.ClassWriter
import org.objectweb.asm.commons.Remapper
import org.objectweb.asm.commons.RemappingClassAdapter
class KotlinScriptBinaryArtifactRemapper {
String mainClassName
KotlinScriptBinaryArtifactRemapper(String mainClassName) {
this.mainClassName = mainClassName
}
KotlinScriptBinaryArtifact remapToPackage(KotlinScriptBinaryArtifact artifact, String packageName) {
def reader = new ClassReader(new ByteArrayInputStream(artifact.data))
def writer = new ClassWriter(0)
def normalizedPackageName = packageName.replace('.', '/')
def oldClassName = reader.getClassName()
def newClassName = artifact.relativePath.replace(oldClassName, "$normalizedPackageName/$oldClassName")
def remapper = new Remapper() {
@Override
String map(String typeName) {
if (typeName.equals(mainClassName) || typeName.startsWith("$mainClassName\$")) {
return "$normalizedPackageName/$typeName"
}
return super.map(typeName);
}
}
def remappingAdapter = new RemappingClassAdapter(writer, remapper)
reader.accept(remappingAdapter, ClassReader.EXPAND_FRAMES)
writer.visitEnd()
return new KotlinScriptBinaryArtifact(newClassName, writer.toByteArray())
}
}
@@ -5,13 +5,12 @@ 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.com.intellij.openapi.util.Disposer
import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.java.PsiPackageStatementImpl
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.config.KotlinSourceRoot
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.StandardOpenOption
class KotlinScriptCompiler {
private String scriptDefinitionClass
@@ -24,7 +23,7 @@ class KotlinScriptCompiler {
this.messageCollector = messageCollector
}
KotlinScriptBinary compile(Path input, Path output) {
KotlinScriptBinary compile(Path input) {
def compilerConfiguration = KotlinCompilerConfigurationFactory.create(
scriptDefinitionClass,
classpath,
@@ -34,7 +33,6 @@ class KotlinScriptCompiler {
def rootDisposable = Disposer.newDisposable()
def configuration = compilerConfiguration.copy()
output.toFile().mkdirs()
configuration.put(CommonConfigurationKeys.MODULE_NAME, input.toString())
configuration.add(JVMConfigurationKeys.CONTENT_ROOTS, new KotlinSourceRoot(input.toAbsolutePath().toString()))
@@ -50,6 +48,7 @@ class KotlinScriptCompiler {
def sourceFiles = environment.getSourceFiles()
def script = sourceFiles[0].script
if (script == null) {
throw new KotlinScriptCompilerException("Main source file is not a script")
}
@@ -61,11 +60,10 @@ class KotlinScriptCompiler {
throw new KotlinScriptCompilerException("Unable to find compiled plugin class file $scriptFilePath")
}
generationState.factory.asList().forEach {
Files.write(output.resolve(it.relativePath), it.asByteArray(), StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING)
}
def outputs = generationState.factory.asList()
def artifacts = outputs.collect { new KotlinScriptBinaryArtifact(it.relativePath, it.asByteArray()) }
return new KotlinScriptBinary(script.fqName.asString(), output.resolve(scriptFileClass.relativePath))
return new KotlinScriptBinary(script.fqName.asString(), artifacts)
} catch (ex) {
throw new KotlinScriptCompilerException("Compilation failed", ex)
} finally {
@@ -1,5 +1,7 @@
package org.apollo.build.plugin.tasks
import org.apollo.build.plugin.ApolloPluginExtension
import org.apollo.build.plugin.compiler.KotlinScriptBinaryArtifactRemapper
import org.apollo.build.plugin.compiler.KotlinScriptCompiler
import org.gradle.api.DefaultTask
import org.gradle.api.file.FileCollection
@@ -10,6 +12,9 @@ import org.gradle.api.tasks.incremental.IncrementalTaskInputs
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector
import java.nio.file.Files
import java.nio.file.StandardOpenOption
class ApolloScriptCompileTask extends DefaultTask {
@OutputDirectory
File outputsDir
@@ -22,6 +27,9 @@ class ApolloScriptCompileTask extends DefaultTask {
@TaskAction
def execute(IncrementalTaskInputs inputs) {
def extension = getProject().getExtensions().getByType(ApolloPluginExtension.class);
def packageName = extension.packageName
if (scriptDefinitionClass == null) {
throw new Exception("No script definition class given")
}
@@ -34,9 +42,25 @@ class ApolloScriptCompileTask extends DefaultTask {
def messageCollector = new PrintingMessageCollector(System.err, MessageRenderer.PLAIN_RELATIVE_PATHS, true);
def compiler = new KotlinScriptCompiler(scriptDefinitionClass, classpath, messageCollector)
outputsDir.mkdirs()
inputs.outOfDate {
removeBinariesFor(it.file)
compiler.compile(it.file.toPath(), outputsDir.toPath())
def binary = compiler.compile(it.file.toPath())
def binaryArtifactRemapper = new KotlinScriptBinaryArtifactRemapper(binary.mainClassName)
def artifacts = binary.artifacts.collect { binaryArtifactRemapper.remapToPackage(it, packageName) }
artifacts.each {
def artifactOutput = outputsDir.toPath().resolve(it.relativePath)
Files.createDirectories(artifactOutput.getParent())
Files.write(artifactOutput, it.data,
StandardOpenOption.CREATE,
StandardOpenOption.WRITE,
StandardOpenOption.TRUNCATE_EXISTING
)
}
}
inputs.removed {