[Editor] Bump JVM version to 17

This commit is contained in:
2021-11-23 12:17:09 +01:00
parent 688fb8eea6
commit cfd3dc7789
26 changed files with 195 additions and 256 deletions

View File

@@ -1,6 +1,6 @@
plugins { plugins {
id 'org.jetbrains.kotlin.jvm' version '1.4.10' id 'org.jetbrains.kotlin.jvm' version "$kotlinJvmVersion"
id 'org.openjfx.javafxplugin' version '0.0.8' id 'org.openjfx.javafxplugin' version "$javaFxPluginVersion"
id 'org.springframework.boot' version "$springBootVersion" id 'org.springframework.boot' version "$springBootVersion"
id 'io.spring.dependency-management' version "$springDependencyManagementVersion" id 'io.spring.dependency-management' version "$springDependencyManagementVersion"
id 'idea' id 'idea'
@@ -24,11 +24,11 @@ javafx {
} }
compileKotlin { compileKotlin {
kotlinOptions.jvmTarget = "14" kotlinOptions.jvmTarget = "17"
} }
compileTestKotlin { compileTestKotlin {
kotlinOptions.jvmTarget = "14" kotlinOptions.jvmTarget = "17"
} }
dependencies { dependencies {

View File

@@ -2,7 +2,14 @@ package com.bartlomiejpluta.base.editor.code.build.compiler
import com.bartlomiejpluta.base.editor.file.model.FileSystemNode import com.bartlomiejpluta.base.editor.file.model.FileSystemNode
import java.io.File import java.io.File
import java.io.PrintStream
interface Compiler { interface Compiler {
fun compile(sourceDirectories: Array<FileSystemNode>, targetDirectory: File, classPath: Array<File> = emptyArray()) fun compile(
sourceDirectories: Array<FileSystemNode>,
targetDirectory: File,
classPath: Array<File> = emptyArray(),
stdout: PrintStream,
stderr: PrintStream
)
} }

View File

@@ -1,15 +1,15 @@
package com.bartlomiejpluta.base.editor.code.build.compiler package com.bartlomiejpluta.base.editor.code.build.compiler
import com.bartlomiejpluta.base.editor.code.build.exception.BuildException import com.bartlomiejpluta.base.editor.code.build.exception.BuildException
import com.bartlomiejpluta.base.editor.common.logs.enumeration.Severity
import com.bartlomiejpluta.base.editor.common.logs.model.Location
import com.bartlomiejpluta.base.editor.event.AppendBuildLogsEvent
import com.bartlomiejpluta.base.editor.file.model.FileSystemNode import com.bartlomiejpluta.base.editor.file.model.FileSystemNode
import com.bartlomiejpluta.base.editor.file.model.FileType import com.bartlomiejpluta.base.editor.file.model.FileType
import com.bartlomiejpluta.base.editor.project.context.ProjectContext
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.annotation.Primary import org.springframework.context.annotation.Primary
import org.springframework.stereotype.Component import org.springframework.stereotype.Component
import tornadofx.FX
import java.io.File import java.io.File
import java.io.PrintStream
import java.io.PrintWriter
import javax.tools.Diagnostic import javax.tools.Diagnostic
import javax.tools.DiagnosticCollector import javax.tools.DiagnosticCollector
import javax.tools.JavaFileObject import javax.tools.JavaFileObject
@@ -20,8 +20,17 @@ import javax.tools.ToolProvider
class JDKCompiler : Compiler { class JDKCompiler : Compiler {
private val compiler = ToolProvider.getSystemJavaCompiler() private val compiler = ToolProvider.getSystemJavaCompiler()
override fun compile(sourceDirectories: Array<FileSystemNode>, targetDirectory: File, classPath: Array<File>) { @Autowired
val classpath = classPath.joinToString(";") { it.absolutePath } private lateinit var projectContext: ProjectContext
override fun compile(
sourceDirectories: Array<FileSystemNode>,
targetDirectory: File,
classPath: Array<File>,
stdout: PrintStream,
stderr: PrintStream
) {
val classpath = classPath.joinToString(":") { it.absolutePath }
val options = listOf("-g", "-d", targetDirectory.absolutePath, "-classpath", classpath) val options = listOf("-g", "-d", targetDirectory.absolutePath, "-classpath", classpath)
val collector = DiagnosticCollector<JavaFileObject>() val collector = DiagnosticCollector<JavaFileObject>()
@@ -33,32 +42,33 @@ class JDKCompiler : Compiler {
.map { it.file } .map { it.file }
.let { manager.getJavaFileObjects(*it.toTypedArray()) } .let { manager.getJavaFileObjects(*it.toTypedArray()) }
val task = compiler.getTask(null, manager, collector, options, null, sources) val task = compiler.getTask(PrintWriter(stdout), manager, collector, options, null, sources)
val success = task.call() val success = task.call()
collector.diagnostics.forEach(this::fireDiagnosticEvent) collector.diagnostics.forEach(compilationError(stdout, stderr))
if (!success) { if (!success) {
throw BuildException() throw BuildException()
} }
} }
private fun fireDiagnosticEvent(diagnostic: Diagnostic<out JavaFileObject>) { private fun compilationError(stdout: PrintStream, stderr: PrintStream): (Diagnostic<out JavaFileObject>) -> Unit {
val severity = when (diagnostic.kind!!) {
Diagnostic.Kind.ERROR -> Severity.ERROR return { d ->
Diagnostic.Kind.WARNING -> Severity.WARNING val stream = when (d.kind!!) {
Diagnostic.Kind.MANDATORY_WARNING -> Severity.WARNING Diagnostic.Kind.ERROR -> stderr
Diagnostic.Kind.NOTE -> Severity.NOTE Diagnostic.Kind.WARNING -> stderr
Diagnostic.Kind.OTHER -> Severity.INFO Diagnostic.Kind.MANDATORY_WARNING -> stderr
Diagnostic.Kind.NOTE -> stdout
Diagnostic.Kind.OTHER -> stdout
}
val source =
projectContext.project?.let { File(d.source.name).toRelativeString(it.codeFSNode.file) } ?: d.source.name
stream.println("[$TAG] $source:${d.lineNumber},${d.columnNumber}: ${d.getMessage(null)}")
} }
val location = diagnostic.source?.let {
Location(diagnostic.source.name, diagnostic.lineNumber, diagnostic.columnNumber)
}
FX.eventbus.fire(AppendBuildLogsEvent(severity, diagnostic.getMessage(null), location, TAG))
} }
companion object { companion object {

View File

@@ -2,23 +2,26 @@ package com.bartlomiejpluta.base.editor.code.build.compiler
import com.bartlomiejpluta.base.editor.code.build.exception.BuildException import com.bartlomiejpluta.base.editor.code.build.exception.BuildException
import com.bartlomiejpluta.base.editor.code.build.model.FileNodeResourceAdapter import com.bartlomiejpluta.base.editor.code.build.model.FileNodeResourceAdapter
import com.bartlomiejpluta.base.editor.common.logs.enumeration.Severity
import com.bartlomiejpluta.base.editor.common.logs.model.Location
import com.bartlomiejpluta.base.editor.event.AppendBuildLogsEvent
import com.bartlomiejpluta.base.editor.file.model.FileSystemNode import com.bartlomiejpluta.base.editor.file.model.FileSystemNode
import com.bartlomiejpluta.base.editor.file.model.FileType import com.bartlomiejpluta.base.editor.file.model.FileType
import org.codehaus.commons.compiler.CompileException import org.codehaus.commons.compiler.CompileException
import org.codehaus.janino.CompilerFactory import org.codehaus.janino.CompilerFactory
import org.springframework.stereotype.Component import org.springframework.stereotype.Component
import tornadofx.FX.Companion.eventbus
import java.io.File import java.io.File
import java.io.PrintStream
@Component @Component
class JaninoCompiler : Compiler { class JaninoCompiler : Compiler {
private val compilerFactory = CompilerFactory() private val compilerFactory = CompilerFactory()
override fun compile(sourceDirectories: Array<FileSystemNode>, targetDirectory: File, classPath: Array<File>) = try { override fun compile(
tryToCompile(sourceDirectories, targetDirectory, classPath) sourceDirectories: Array<FileSystemNode>,
targetDirectory: File,
classPath: Array<File>,
stdout: PrintStream,
stderr: PrintStream
) = try {
tryToCompile(sourceDirectories, targetDirectory, classPath, stdout)
/* Because Janino parser does not provide error handler for parsers: /* Because Janino parser does not provide error handler for parsers:
* *
@@ -31,14 +34,16 @@ class JaninoCompiler : Compiler {
* as BuildException * as BuildException
*/ */
} catch (e: CompileException) { } catch (e: CompileException) {
val locationIndex = e.location?.toString()?.length?.plus(2) ?: 0 stderr.println("[$TAG] ${e.message}")
val message = e.message?.substring(locationIndex) throw BuildException()
val location = Location(e.location.fileName, e.location.lineNumber.toLong(), e.location.columnNumber.toLong())
throw BuildException(Severity.ERROR, TAG, location, message, e)
} }
private fun tryToCompile(sourceDirectories: Array<FileSystemNode>, targetDirectory: File, classPath: Array<File>) { private fun tryToCompile(
sourceDirectories: Array<FileSystemNode>,
targetDirectory: File,
classPath: Array<File>,
stdout: PrintStream
) {
val compilationUnits = sourceDirectories.flatMap(FileSystemNode::allChildren) val compilationUnits = sourceDirectories.flatMap(FileSystemNode::allChildren)
.filter { it.type == FileType.FILE } .filter { it.type == FileType.FILE }
.map(::FileNodeResourceAdapter) .map(::FileNodeResourceAdapter)
@@ -50,8 +55,7 @@ class JaninoCompiler : Compiler {
setClassPath(classPath) setClassPath(classPath)
setWarningHandler { handle, message, loc -> setWarningHandler { handle, message, loc ->
val location = Location(loc.fileName, loc.lineNumber.toLong(), loc.columnNumber.toLong()) stdout.println("[$TAG] $message:$loc ($handle)")
eventbus.fire(AppendBuildLogsEvent(Severity.WARNING, "$message ($handle)", location, TAG))
} }
compile(compilationUnits) compile(compilationUnits)

View File

@@ -2,7 +2,8 @@ package com.bartlomiejpluta.base.editor.code.build.database
import com.bartlomiejpluta.base.editor.project.model.Project import com.bartlomiejpluta.base.editor.project.model.Project
import java.io.File import java.io.File
import java.io.PrintStream
interface DatabaseAssembler { interface DatabaseAssembler {
fun assembly(project: Project, targetJar: File) fun assembly(project: Project, targetJar: File, stdout: PrintStream, stderr: PrintStream)
} }

View File

@@ -2,12 +2,12 @@ package com.bartlomiejpluta.base.editor.code.build.database
import com.bartlomiejpluta.base.editor.code.build.exception.BuildException import com.bartlomiejpluta.base.editor.code.build.exception.BuildException
import com.bartlomiejpluta.base.editor.code.build.packager.JarPackager import com.bartlomiejpluta.base.editor.code.build.packager.JarPackager
import com.bartlomiejpluta.base.editor.common.logs.enumeration.Severity
import com.bartlomiejpluta.base.editor.database.service.DatabaseService import com.bartlomiejpluta.base.editor.database.service.DatabaseService
import com.bartlomiejpluta.base.editor.project.model.Project import com.bartlomiejpluta.base.editor.project.model.Project
import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component import org.springframework.stereotype.Component
import java.io.File import java.io.File
import java.io.PrintStream
@Component @Component
class H2DatabaseAssembler : DatabaseAssembler { class H2DatabaseAssembler : DatabaseAssembler {
@@ -18,11 +18,12 @@ class H2DatabaseAssembler : DatabaseAssembler {
@Autowired @Autowired
private lateinit var packager: JarPackager private lateinit var packager: JarPackager
override fun assembly(project: Project, targetJar: File) { override fun assembly(project: Project, targetJar: File, stdout: PrintStream, stderr: PrintStream) {
try { try {
tryToAssembly(project, targetJar) tryToAssembly(project, targetJar)
} catch (e: Exception) { } catch (e: Exception) {
throw BuildException(Severity.ERROR, TAG, e.message, e) stderr.println("[$TAG] ${e.message}")
throw BuildException()
} }
} }

View File

@@ -1,19 +1,3 @@
package com.bartlomiejpluta.base.editor.code.build.exception package com.bartlomiejpluta.base.editor.code.build.exception
import com.bartlomiejpluta.base.editor.common.logs.enumeration.Severity class BuildException : Exception()
import com.bartlomiejpluta.base.editor.common.logs.model.Location
class BuildException(
val severity: Severity?,
val tag: String?,
val location: Location?,
message: String?,
override val cause: Throwable?
) : Exception() {
constructor(severity: Severity?, tag: String?, message: String?, cause: Throwable?)
: this(severity, tag, null, message, cause)
constructor() : this(null, null, null, null, null)
override val message = message ?: ""
}

View File

@@ -1,9 +1,9 @@
package com.bartlomiejpluta.base.editor.code.build.game package com.bartlomiejpluta.base.editor.code.build.game
import com.bartlomiejpluta.base.editor.code.build.exception.BuildException import com.bartlomiejpluta.base.editor.code.build.exception.BuildException
import com.bartlomiejpluta.base.editor.common.logs.enumeration.Severity
import org.springframework.stereotype.Component import org.springframework.stereotype.Component
import java.io.File import java.io.File
import java.io.PrintStream
/* TODO /* TODO
* There is an idea to have a different GameEngine providers for different OS (Windows, Mac OS X, Linux etc.) * There is an idea to have a different GameEngine providers for different OS (Windows, Mac OS X, Linux etc.)
@@ -17,18 +17,19 @@ import java.io.File
@Component @Component
class DefaultGameEngineProvider : GameEngineProvider { class DefaultGameEngineProvider : GameEngineProvider {
override fun provideBaseGameEngine(targetJar: File) { override fun provideBaseGameEngine(targetJar: File, stdout: PrintStream, stderr: PrintStream) {
try { try {
tryToProvide(targetJar) tryToProvide(targetJar)
} catch (e: Exception) { } catch (e: Exception) {
throw BuildException(Severity.ERROR, TAG, e.message, e) stderr.println("[$TAG] ${e.message}")
throw BuildException()
} }
} }
private fun tryToProvide(targetJar: File) { private fun tryToProvide(targetJar: File) {
javaClass.getResourceAsStream(GAME_ENGINE_JAR).use { ris -> javaClass.getResourceAsStream(GAME_ENGINE_JAR).use { ris ->
targetJar.outputStream().use { fos -> targetJar.outputStream().use { fos ->
ris.copyTo(fos) ris?.copyTo(fos)
} }
} }
} }

View File

@@ -1,7 +1,8 @@
package com.bartlomiejpluta.base.editor.code.build.game package com.bartlomiejpluta.base.editor.code.build.game
import java.io.File import java.io.File
import java.io.PrintStream
interface GameEngineProvider { interface GameEngineProvider {
fun provideBaseGameEngine(targetJar: File) fun provideBaseGameEngine(targetJar: File, stdout: PrintStream, stderr: PrintStream)
} }

View File

@@ -2,8 +2,10 @@ package com.bartlomiejpluta.base.editor.code.build.pipeline
import javafx.beans.property.BooleanProperty import javafx.beans.property.BooleanProperty
import javafx.concurrent.Task import javafx.concurrent.Task
import java.io.OutputStream
interface BuildPipelineService { interface BuildPipelineService {
fun initStreams(stdout: OutputStream, stderr: OutputStream)
val isRunningProperty: BooleanProperty val isRunningProperty: BooleanProperty
fun build(): Task<Boolean> fun build(): Task<Boolean>
fun clean() fun clean()

View File

@@ -8,8 +8,6 @@ import com.bartlomiejpluta.base.editor.code.build.generator.CodeGenerator
import com.bartlomiejpluta.base.editor.code.build.packager.JarPackager import com.bartlomiejpluta.base.editor.code.build.packager.JarPackager
import com.bartlomiejpluta.base.editor.code.build.project.ProjectAssembler import com.bartlomiejpluta.base.editor.code.build.project.ProjectAssembler
import com.bartlomiejpluta.base.editor.code.dependency.DependenciesProvider import com.bartlomiejpluta.base.editor.code.dependency.DependenciesProvider
import com.bartlomiejpluta.base.editor.common.logs.enumeration.Severity
import com.bartlomiejpluta.base.editor.event.AppendBuildLogsEvent
import com.bartlomiejpluta.base.editor.event.ClearBuildLogsEvent import com.bartlomiejpluta.base.editor.event.ClearBuildLogsEvent
import com.bartlomiejpluta.base.editor.file.model.FileSystemNode import com.bartlomiejpluta.base.editor.file.model.FileSystemNode
import com.bartlomiejpluta.base.editor.project.context.ProjectContext import com.bartlomiejpluta.base.editor.project.context.ProjectContext
@@ -19,6 +17,8 @@ import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component import org.springframework.stereotype.Component
import tornadofx.* import tornadofx.*
import tornadofx.FX.Companion.eventbus import tornadofx.FX.Companion.eventbus
import java.io.OutputStream
import java.io.PrintStream
@Component @Component
class DefaultBuildPipelineService : BuildPipelineService { class DefaultBuildPipelineService : BuildPipelineService {
@@ -50,6 +50,18 @@ class DefaultBuildPipelineService : BuildPipelineService {
private val latchProperty = SimpleObjectProperty<Latch?>() private val latchProperty = SimpleObjectProperty<Latch?>()
private var latch by latchProperty private var latch by latchProperty
private lateinit var stdout: OutputStream
private lateinit var stderr: OutputStream
private lateinit var out: PrintStream
private lateinit var err: PrintStream
override fun initStreams(stdout: OutputStream, stderr: OutputStream) {
this.stdout = stdout
this.stderr = stderr
this.out = PrintStream(stdout)
this.err = PrintStream(stderr)
}
override val isRunningProperty = false.toProperty() override val isRunningProperty = false.toProperty()
private var isRunning by isRunningProperty private var isRunning by isRunningProperty
@@ -70,18 +82,18 @@ class DefaultBuildPipelineService : BuildPipelineService {
latch = Latch() latch = Latch()
val startTime = System.currentTimeMillis()
try { try {
projectContext.project?.let(this@DefaultBuildPipelineService::runPipeline) projectContext.project?.let(this@DefaultBuildPipelineService::runPipeline)
out.println("Build completed")
return@runAsync true return@runAsync true
} catch (e: BuildException) { } catch (e: BuildException) {
e.severity?.let { err.println("Build failed")
val event = AppendBuildLogsEvent(it, e.message, e.location, e.tag)
eventbus.fire(event)
}
eventbus.fire(AppendBuildLogsEvent(Severity.ERROR, "Build failed", tag = TAG))
} finally { } finally {
latch?.release() latch?.release()
val buildingTime = (System.currentTimeMillis() - startTime) / 1000.0
out.println("Finished in [${buildingTime}s]")
} }
false false
@@ -92,35 +104,33 @@ class DefaultBuildPipelineService : BuildPipelineService {
prepareBuildDirectory(project) prepareBuildDirectory(project)
val outputFile = project.buildOutputJarFile val outputFile = project.buildOutputJarFile
val startTime = System.currentTimeMillis()
eventbus.fire(AppendBuildLogsEvent(Severity.INFO, "Providing compile-time dependencies...", tag = TAG)) out.println("Providing compile-time dependencies...")
val dependencies = dependenciesProvider.provideDependenciesTo(project.buildDependenciesDirectory) val dependencies = dependenciesProvider.provideDependenciesTo(project.buildDependenciesDirectory)
eventbus.fire(AppendBuildLogsEvent(Severity.INFO, "Generating sources...", tag = TAG)) out.println("Generating sources...")
generators.forEach(CodeGenerator::generate) generators.forEach(CodeGenerator::generate)
eventbus.fire(AppendBuildLogsEvent(Severity.INFO, "Compiling sources...", tag = TAG)) out.println("Compiling sources...")
compiler.compile( compiler.compile(
arrayOf(project.codeFSNode, FileSystemNode(project.buildGeneratedCodeDirectory)), arrayOf(project.codeFSNode, FileSystemNode(project.buildGeneratedCodeDirectory)),
project.buildClassesDirectory, project.buildClassesDirectory,
dependencies.toTypedArray() dependencies.toTypedArray(),
out,
err
) )
eventbus.fire(AppendBuildLogsEvent(Severity.INFO, "Assembling game engine...", tag = TAG)) out.println("Assembling game engine...")
engineProvider.provideBaseGameEngine(outputFile) engineProvider.provideBaseGameEngine(outputFile, out, err)
eventbus.fire(AppendBuildLogsEvent(Severity.INFO, "Assembling compiled classes...", tag = TAG)) out.println("Linking compilation units...")
packager.pack(project.buildClassesDirectory, outputFile, "BOOT-INF/classes") packager.pack(project.buildClassesDirectory, outputFile, "BOOT-INF/classes")
eventbus.fire(AppendBuildLogsEvent(Severity.INFO, "Assembling project assets...", tag = TAG)) out.println("Assembling project assets...")
projectAssembler.assembly(project, outputFile) projectAssembler.assembly(project, outputFile, out, err)
eventbus.fire(AppendBuildLogsEvent(Severity.INFO, "Assembling database...", tag = TAG)) out.println("Assembling database...")
databaseAssembler.assembly(project, outputFile) databaseAssembler.assembly(project, outputFile, out, err)
val buildingTime = (System.currentTimeMillis() - startTime) / 1000.0
eventbus.fire(AppendBuildLogsEvent(Severity.INFO, "Build done [${buildingTime}s]", tag = TAG))
} }
private fun prepareBuildDirectory(project: Project) { private fun prepareBuildDirectory(project: Project) {
@@ -129,14 +139,11 @@ class DefaultBuildPipelineService : BuildPipelineService {
project.buildClassesDirectory.mkdirs() project.buildClassesDirectory.mkdirs()
project.buildOutDirectory.mkdirs() project.buildOutDirectory.mkdirs()
project.buildDependenciesDirectory.mkdirs() project.buildDependenciesDirectory.mkdirs()
project.buildGeneratedCodeDirectory.mkdirs()
} }
override fun clean() { override fun clean() {
projectContext.project?.apply { buildDirectory.deleteRecursively() } projectContext.project?.apply { buildDirectory.deleteRecursively() }
eventbus.fire(AppendBuildLogsEvent(Severity.INFO, "Cleaning done", tag = TAG)) out.println("Cleaning done")
}
companion object {
private const val TAG = "Build"
} }
} }

View File

@@ -2,11 +2,11 @@ package com.bartlomiejpluta.base.editor.code.build.project
import com.bartlomiejpluta.base.editor.code.build.exception.BuildException import com.bartlomiejpluta.base.editor.code.build.exception.BuildException
import com.bartlomiejpluta.base.editor.code.build.packager.JarPackager import com.bartlomiejpluta.base.editor.code.build.packager.JarPackager
import com.bartlomiejpluta.base.editor.common.logs.enumeration.Severity
import com.bartlomiejpluta.base.editor.project.model.Project import com.bartlomiejpluta.base.editor.project.model.Project
import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component import org.springframework.stereotype.Component
import java.io.File import java.io.File
import java.io.PrintStream
@Component @Component
class DefaultProjectAssembler : ProjectAssembler { class DefaultProjectAssembler : ProjectAssembler {
@@ -14,11 +14,12 @@ class DefaultProjectAssembler : ProjectAssembler {
@Autowired @Autowired
private lateinit var packager: JarPackager private lateinit var packager: JarPackager
override fun assembly(project: Project, targetJar: File) { override fun assembly(project: Project, targetJar: File, stdout: PrintStream, stderr: PrintStream) {
try { try {
tryToAssembly(project, targetJar) tryToAssembly(project, targetJar)
} catch (e: Exception) { } catch (e: Exception) {
throw BuildException(Severity.ERROR, TAG, e.message, e) stderr.println("[$TAG] ${e.message}")
throw BuildException()
} }
} }

View File

@@ -2,7 +2,8 @@ package com.bartlomiejpluta.base.editor.code.build.project
import com.bartlomiejpluta.base.editor.project.model.Project import com.bartlomiejpluta.base.editor.project.model.Project
import java.io.File import java.io.File
import java.io.PrintStream
interface ProjectAssembler { interface ProjectAssembler {
fun assembly(project: Project, targetJar: File) fun assembly(project: Project, targetJar: File, stdout: PrintStream, stderr: PrintStream)
} }

View File

@@ -1,52 +1,31 @@
package com.bartlomiejpluta.base.editor.code.view.build package com.bartlomiejpluta.base.editor.code.view.build
import com.bartlomiejpluta.base.editor.code.build.pipeline.BuildPipelineService
import com.bartlomiejpluta.base.editor.common.logs.component.LogsPane import com.bartlomiejpluta.base.editor.common.logs.component.LogsPane
import com.bartlomiejpluta.base.editor.common.logs.model.Location
import com.bartlomiejpluta.base.editor.event.AppendBuildLogsEvent
import com.bartlomiejpluta.base.editor.event.ClearBuildLogsEvent import com.bartlomiejpluta.base.editor.event.ClearBuildLogsEvent
import com.bartlomiejpluta.base.editor.main.controller.MainController
import com.bartlomiejpluta.base.editor.project.context.ProjectContext
import org.kordamp.ikonli.javafx.FontIcon import org.kordamp.ikonli.javafx.FontIcon
import tornadofx.* import tornadofx.*
import java.io.File
import kotlin.math.max
class BuildLogsView : View() { class BuildLogsView : View() {
private val projectContext: ProjectContext by di() private val pipelineService: BuildPipelineService by di()
private val mainController: MainController by di()
private val followCaret = true.toProperty() private val logsPane = LogsPane()
private val buildLogs = LogsPane(this::locationClick)
init { init {
subscribe<AppendBuildLogsEvent> { event ->
buildLogs.appendEntry(event.message, event.severity, followCaret.value, event.location, event.tag)
}
subscribe<ClearBuildLogsEvent> { subscribe<ClearBuildLogsEvent> {
buildLogs.clear() logsPane.clear()
} }
}
private fun locationClick(location: Location) { pipelineService.initStreams(logsPane.stdout, logsPane.stderr)
projectContext.project?.codeFSNode?.findByFile(File(location.sourceName))?.let {
mainController.openScript(it, max(1, location.lineNumber.toInt()), 1)
}
} }
override val root = borderpane { override val root = borderpane {
left = vbox { left = vbox {
button(graphic = FontIcon("fa-trash")) { button(graphic = FontIcon("fa-trash")) {
action { buildLogs.clear() } action { logsPane.clear() }
}
togglebutton {
followCaret.bind(selectedProperty())
graphic = FontIcon("fa-angle-double-down")
} }
} }
center = buildLogs center = logsPane
} }
} }

View File

@@ -1,18 +1,18 @@
package com.bartlomiejpluta.base.editor.common.logs.component package com.bartlomiejpluta.base.editor.common.logs.component
import com.bartlomiejpluta.base.editor.common.logs.enumeration.Severity
import com.bartlomiejpluta.base.editor.common.logs.model.Location
import com.bartlomiejpluta.base.editor.common.logs.style.LogsPaneStyle import com.bartlomiejpluta.base.editor.common.logs.style.LogsPaneStyle
import com.bartlomiejpluta.base.editor.common.logs.stylesheet.LogsPaneStylesheet import com.bartlomiejpluta.base.editor.common.logs.stylesheet.LogsPaneStylesheet
import javafx.scene.layout.StackPane import javafx.scene.layout.StackPane
import org.fxmisc.flowless.VirtualizedScrollPane import org.fxmisc.flowless.VirtualizedScrollPane
import org.fxmisc.richtext.StyledTextArea import org.fxmisc.richtext.StyledTextArea
import tornadofx.addClass import tornadofx.addClass
import tornadofx.runLater
import java.io.OutputStream
class LogsPane(private val locationClick: (location: Location) -> Unit = {}) : StackPane() { class LogsPane : StackPane() {
private val editor = StyledTextArea("logs-pane", private val editor = StyledTextArea("logs-pane",
{ text, style -> text.addClass(style) }, { text, style -> text.addClass(style) },
LogsPaneStyle.NO_STYLE, LogsPaneStyle.DEFAULT,
{ text, style -> style.apply(text) } { text, style -> style.apply(text) }
).apply { isEditable = false } ).apply { isEditable = false }
@@ -20,27 +20,25 @@ class LogsPane(private val locationClick: (location: Location) -> Unit = {}) : S
children += VirtualizedScrollPane(editor) children += VirtualizedScrollPane(editor)
} }
fun appendEntry(
message: String,
severity: Severity,
follow: Boolean,
location: Location? = null,
tag: String? = null
) {
val locationRef = LogsPaneStyle(location = location, onClick = locationClick)
val severityStyle = LogsPaneStyle(severity = severity)
tag?.let { editor.insert(editor.length, "[$it] ", severityStyle) }
editor.insert(editor.length, location?.toString() ?: "", locationRef)
editor.insert(editor.length, (location?.let { ": " } ?: "") + message, LogsPaneStyle(severity = severity))
editor.insert(editor.length, "\n", LogsPaneStyle.NO_STYLE)
if (follow) {
editor.requestFollowCaret()
}
}
fun clear() = editor.clear() fun clear() = editor.clear()
override fun getUserAgentStylesheet(): String = LogsPaneStylesheet().base64URL.toExternalForm() override fun getUserAgentStylesheet(): String = LogsPaneStylesheet().base64URL.toExternalForm()
val stdout = object : OutputStream() {
override fun write(b: Int) {
runLater {
editor.insert(editor.length, (b.toChar()).toString(), LogsPaneStyle.DEFAULT)
editor.requestFollowCaret()
}
}
}
val stderr = object : OutputStream() {
override fun write(b: Int) {
runLater {
editor.insert(editor.length, (b.toChar()).toString(), LogsPaneStyle.ERROR)
editor.requestFollowCaret()
}
}
}
} }

View File

@@ -1,8 +0,0 @@
package com.bartlomiejpluta.base.editor.common.logs.enumeration
enum class Severity {
INFO,
NOTE,
WARNING,
ERROR
}

View File

@@ -1,43 +1,13 @@
package com.bartlomiejpluta.base.editor.common.logs.style package com.bartlomiejpluta.base.editor.common.logs.style
import com.bartlomiejpluta.base.editor.common.logs.enumeration.Severity
import com.bartlomiejpluta.base.editor.common.logs.model.Location
import javafx.scene.Cursor
import javafx.scene.paint.Color import javafx.scene.paint.Color
import javafx.scene.text.Text import javafx.scene.text.Text
class LogsPaneStyle( enum class LogsPaneStyle(private val color: Color?) {
private val location: Location? = null, DEFAULT(null),
private val severity: Severity? = null, ERROR(Color.RED);
private val onClick: (Location) -> Unit = {}
) {
fun apply(text: Text) = when { fun apply(text: Text) {
severity != null -> message(text, severity) text.fill = color ?: text.fill
location != null -> location(text, location)
else -> {
}
}
private fun message(text: Text, severity: Severity) {
text.fill = when (severity) {
Severity.WARNING -> Color.ORANGE
Severity.ERROR -> Color.RED
Severity.NOTE -> Color.DARKGRAY
Severity.INFO -> text.fill
}
}
private fun location(text: Text, location: Location) {
text.cursor = Cursor.HAND
text.fill = Color.BLUE
text.isUnderline = true
text.setOnMouseClicked {
onClick(location)
}
}
companion object {
val NO_STYLE = LogsPaneStyle()
} }
} }

View File

@@ -1,13 +0,0 @@
package com.bartlomiejpluta.base.editor.event
import com.bartlomiejpluta.base.editor.common.logs.enumeration.Severity
import com.bartlomiejpluta.base.editor.common.logs.model.Location
import tornadofx.EventBus
import tornadofx.FXEvent
data class AppendBuildLogsEvent(
val severity: Severity,
val message: String,
val location: Location? = null,
val tag: String? = null
) : FXEvent(EventBus.RunOn.ApplicationThread)

View File

@@ -1,8 +0,0 @@
package com.bartlomiejpluta.base.editor.event
import com.bartlomiejpluta.base.editor.common.logs.enumeration.Severity
import tornadofx.EventBus
import tornadofx.FXEvent
data class AppendProcessLogsEvent(val severity: Severity, val message: String) :
FXEvent(EventBus.RunOn.ApplicationThread)

View File

@@ -8,8 +8,6 @@ import com.bartlomiejpluta.base.editor.code.viewmodel.CodeVM
import com.bartlomiejpluta.base.editor.database.view.list.TablesListView import com.bartlomiejpluta.base.editor.database.view.list.TablesListView
import com.bartlomiejpluta.base.editor.database.view.query.QueryResultFragment import com.bartlomiejpluta.base.editor.database.view.query.QueryResultFragment
import com.bartlomiejpluta.base.editor.database.viewmodel.QueryVM import com.bartlomiejpluta.base.editor.database.viewmodel.QueryVM
import com.bartlomiejpluta.base.editor.event.AppendBuildLogsEvent
import com.bartlomiejpluta.base.editor.event.AppendProcessLogsEvent
import com.bartlomiejpluta.base.editor.event.SelectMainViewTabEvent import com.bartlomiejpluta.base.editor.event.SelectMainViewTabEvent
import com.bartlomiejpluta.base.editor.main.component.EditorTab import com.bartlomiejpluta.base.editor.main.component.EditorTab
import com.bartlomiejpluta.base.editor.main.controller.MainController import com.bartlomiejpluta.base.editor.main.controller.MainController
@@ -94,14 +92,6 @@ class MainView : View("BASE Game Editor") {
}.let { titleProperty.bind(it) } }.let { titleProperty.bind(it) }
} }
subscribe<AppendBuildLogsEvent> {
buildLogItem.expanded = true
}
subscribe<AppendProcessLogsEvent> {
processLogItem.expanded = true
}
subscribe<SelectMainViewTabEvent> { event -> subscribe<SelectMainViewTabEvent> { event ->
openTabs[event.targetScope]?.let { openTabs[event.targetScope]?.let {
tabPane.selectionModel.select(it) tabPane.selectionModel.select(it)

View File

@@ -2,8 +2,10 @@ package com.bartlomiejpluta.base.editor.process.runner.app
import javafx.beans.binding.BooleanExpression import javafx.beans.binding.BooleanExpression
import javafx.beans.property.ObjectProperty import javafx.beans.property.ObjectProperty
import java.io.OutputStream
interface ApplicationRunner { interface ApplicationRunner {
fun initStreams(stdout: OutputStream, stderr: OutputStream)
val isRunningProperty: BooleanExpression val isRunningProperty: BooleanExpression
val processProperty: ObjectProperty<Process> val processProperty: ObjectProperty<Process>
fun run() fun run()

View File

@@ -1,8 +1,6 @@
package com.bartlomiejpluta.base.editor.process.runner.app package com.bartlomiejpluta.base.editor.process.runner.app
import com.bartlomiejpluta.base.editor.code.build.pipeline.BuildPipelineService import com.bartlomiejpluta.base.editor.code.build.pipeline.BuildPipelineService
import com.bartlomiejpluta.base.editor.common.logs.enumeration.Severity
import com.bartlomiejpluta.base.editor.event.AppendProcessLogsEvent
import com.bartlomiejpluta.base.editor.event.ClearProcessLogsEvent import com.bartlomiejpluta.base.editor.event.ClearProcessLogsEvent
import com.bartlomiejpluta.base.editor.process.runner.jar.JarRunner import com.bartlomiejpluta.base.editor.process.runner.jar.JarRunner
import com.bartlomiejpluta.base.editor.project.context.ProjectContext import com.bartlomiejpluta.base.editor.project.context.ProjectContext
@@ -10,8 +8,14 @@ import com.bartlomiejpluta.base.editor.project.model.Project
import javafx.beans.property.SimpleObjectProperty import javafx.beans.property.SimpleObjectProperty
import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component import org.springframework.stereotype.Component
import tornadofx.*
import tornadofx.FX.Companion.eventbus import tornadofx.FX.Companion.eventbus
import tornadofx.getValue
import tornadofx.runAsync
import tornadofx.setValue
import tornadofx.toProperty
import java.io.IOException
import java.io.OutputStream
import java.io.PrintStream
@Component @Component
class DefaultApplicationRunner : ApplicationRunner { class DefaultApplicationRunner : ApplicationRunner {
@@ -25,12 +29,25 @@ class DefaultApplicationRunner : ApplicationRunner {
@Autowired @Autowired
private lateinit var jarRunner: JarRunner private lateinit var jarRunner: JarRunner
override val isRunningProperty = false.toProperty() private lateinit var stdout: OutputStream
private var isRunning by isRunningProperty private lateinit var stderr: OutputStream
private lateinit var out: PrintStream
private lateinit var err: PrintStream
override val isRunningProperty = false.toProperty()
private var isRunning by isRunningProperty
override val processProperty = SimpleObjectProperty<Process>() override val processProperty = SimpleObjectProperty<Process>()
private var process by processProperty private var process by processProperty
override fun initStreams(stdout: OutputStream, stderr: OutputStream) {
this.stdout = stdout
this.stderr = stderr
this.out = PrintStream(stdout)
this.err = PrintStream(stderr)
}
override fun run() { override fun run() {
projectContext.project?.let { project -> projectContext.project?.let { project ->
if (process != null) { if (process != null) {
@@ -65,19 +82,16 @@ class DefaultApplicationRunner : ApplicationRunner {
process = builder.start() process = builder.start()
runAsync { runAsync {
process.inputStream.bufferedReader().forEachLine { try {
eventbus.fire(AppendProcessLogsEvent(Severity.INFO, it)) process.inputStream.transferTo(stdout)
} process.errorStream.transferTo(stderr)
} } catch (e: IOException) {
// Ignore stream termination exception
runAsync {
process.errorStream.bufferedReader().forEachLine {
eventbus.fire(AppendProcessLogsEvent(Severity.ERROR, it))
} }
} }
process.onExit().thenApply { process.onExit().thenApply {
eventbus.fire(AppendProcessLogsEvent(Severity.INFO, "\nProcess exited with code ${it.exitValue()}")) out.println("\nProcess exited with code ${it.exitValue()}")
process = null process = null
isRunning = false isRunning = false
} }

View File

@@ -1,38 +1,32 @@
package com.bartlomiejpluta.base.editor.process.view package com.bartlomiejpluta.base.editor.process.view
import com.bartlomiejpluta.base.editor.common.logs.component.LogsPane import com.bartlomiejpluta.base.editor.common.logs.component.LogsPane
import com.bartlomiejpluta.base.editor.event.AppendProcessLogsEvent
import com.bartlomiejpluta.base.editor.event.ClearProcessLogsEvent import com.bartlomiejpluta.base.editor.event.ClearProcessLogsEvent
import com.bartlomiejpluta.base.editor.process.runner.app.ApplicationRunner
import org.kordamp.ikonli.javafx.FontIcon import org.kordamp.ikonli.javafx.FontIcon
import tornadofx.* import tornadofx.*
class ProcessLogsView : View() { class ProcessLogsView : View() {
private val buildLogs = LogsPane() private val logsPane = LogsPane()
private val followCaret = true.toProperty()
private val applicationRunner: ApplicationRunner by di()
init { init {
subscribe<AppendProcessLogsEvent> { event -> subscribe<ClearProcessLogsEvent> {
buildLogs.appendEntry(event.message, event.severity, followCaret.value) logsPane.clear()
} }
subscribe<ClearProcessLogsEvent> { applicationRunner.initStreams(logsPane.stdout, logsPane.stderr)
buildLogs.clear()
}
} }
override val root = borderpane { override val root = borderpane {
left = vbox { left = vbox {
button(graphic = FontIcon("fa-trash")) { button(graphic = FontIcon("fa-trash")) {
action { buildLogs.clear() } action { logsPane.clear() }
}
togglebutton {
followCaret.bind(selectedProperty())
graphic = FontIcon("fa-angle-double-down")
} }
} }
center = buildLogs center = logsPane
} }
} }

View File

@@ -176,7 +176,7 @@ class Project {
const val FONTS_DIR = "fonts" const val FONTS_DIR = "fonts"
const val WIDGETS_DIR = "widgets" const val WIDGETS_DIR = "widgets"
const val AUDIO_DIR = "audio" const val AUDIO_DIR = "audio"
const val CODE_DIR = "code" const val CODE_DIR = "src/main/java"
const val BUILD_DIR = "build" const val BUILD_DIR = "build"
const val BUILD_CLASSES_DIR = "$BUILD_DIR/classes" const val BUILD_CLASSES_DIR = "$BUILD_DIR/classes"
const val BUILD_OUT_DIR = "$BUILD_DIR/out" const val BUILD_OUT_DIR = "$BUILD_DIR/out"

View File

@@ -42,7 +42,6 @@ configurations {
repositories { repositories {
mavenCentral() mavenCentral()
jcenter()
} }
bootJar { bootJar {

View File

@@ -5,7 +5,9 @@ slf4jVersion=1.7.30
lombokVersion=1.18.22 lombokVersion=1.18.22
jomlVersion=1.10.0 jomlVersion=1.10.0
guavaVersion=29.0-jre guavaVersion=29.0-jre
kotlinJvmVersion=1.6.0-M1
javaFxVersion=15.0.1 javaFxVersion=15.0.1
javaFxPluginVersion=0.0.10
tornadoFxVersion=2.0.0-SNAPSHOT tornadoFxVersion=2.0.0-SNAPSHOT
ikonliVersion=12.2.0 ikonliVersion=12.2.0
protobufPluginVersion=0.8.14 protobufPluginVersion=0.8.14