Skip to content

Commit

Permalink
Merge pull request #65 from apposed/cfg-vars
Browse files Browse the repository at this point in the history
Improve support for JVM max heap configuration
  • Loading branch information
ctrueden authored Dec 17, 2024
2 parents ef6984d + fced73c commit b77b20a
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 10 deletions.
2 changes: 1 addition & 1 deletion configs/jvm.toml
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ jvm.distros-blocked = []

jvm.root-paths = [
'--java-home|${java-home}', # user override (CLI flag)
'!--system|${jvm.dir}', # read from <app>.cfg
'!--system|${cfg.jvm-dir}', # read from <app>.cfg
'!--system|${app-dir}/lib/runtime', # jpackage
'!--system|OS:LINUX|ARCH:ARM64|${app-dir}/java/linux-arm64/*', # bundled (Linux aarch64)
'!--system|OS:LINUX|ARCH:X64|${app-dir}/java/linux-x64/*', # bundled (Linux x86-64)
Expand Down
14 changes: 14 additions & 0 deletions src/commonMain/kotlin/config.kt
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@ data class JaunchConfig (

/** Arguments to pass to the main class on the Java side. */
val jvmMainArgs: Array<String> = emptyArray(),

/** The list of options overridable by .cfg files understood by Jaunch. */
val cfgVars: Map<String, Any> = emptyMap(),
) {
/** Return true iff the given argument is on the specified list of recognized args. */
fun recognizes(arg: String, recognizedArgs: Array<String>): Boolean {
Expand Down Expand Up @@ -154,6 +157,7 @@ data class JaunchConfig (
programName = config.programName ?: programName,
includes = merge(config.includes, includes),
supportedOptions = merge(config.supportedOptions, supportedOptions),
cfgVars = cfgVars + config.cfgVars,
osAliases = merge(config.osAliases, osAliases),
archAliases = merge(config.archAliases, archAliases),
modes = merge(config.modes, modes),
Expand Down Expand Up @@ -246,6 +250,8 @@ fun readConfig(
var jvmMainClass: List<String>? = null
var jvmMainArgs: List<String>? = null

val cfgVars = mutableMapOf<String, Any>()

// Parse TOML file lines into tokens.
val tokens = mutableListOf<Any>()
tomlFile.lines().forEach { appendTokens(it, tokens) }
Expand Down Expand Up @@ -300,6 +306,13 @@ fun readConfig(
"jvm.runtime-args" -> jvmRuntimeArgs = asList(value)
"jvm.main-class" -> jvmMainClass = asList(value)
"jvm.main-args" -> jvmMainArgs = asList(value)
else -> {
// Parse cfg.* variable assignments into a cfgVars map
if (name.startsWith("cfg.") && value != null) {
cfgVars[name] = value
}
else warn("[TOML] Unsupported key: '$name'")
}
}
}
else -> warn("[TOML] Ignoring extraneous token: '$token' [${token::class.simpleName}]")
Expand All @@ -317,6 +330,7 @@ fun readConfig(
programName = programName,
includes = asArray(includes),
supportedOptions = asArray(supportedOptions),
cfgVars = cfgVars,
osAliases = asArray(osAliases),
archAliases = asArray(archAliases),
modes = asArray(modes),
Expand Down
25 changes: 19 additions & 6 deletions src/commonMain/kotlin/jvm.kt
Original file line number Diff line number Diff line change
Expand Up @@ -118,14 +118,11 @@ class JvmRuntimeConfig(recognizedArgs: Array<String>) :
}
}

// If not already declared, calculate and declare the max heap size.
// If not manually declared, add a max heap flag from the config.
val mxIndex = runtimeArgs.indexOfFirst { it.startsWith("-Xmx") }
if (mxIndex < 0) {
val maxHeap = calculateMaxHeap(config.jvmMaxHeap)
if (maxHeap != null) {
runtimeArgs += "-Xmx$maxHeap"
debug("Added maxHeap arg: ${runtimeArgs.last()}")
}
runtimeArgs += "-Xmx${config.jvmMaxHeap}"
debug("Added maxHeap arg: ${runtimeArgs.last()}")
}

// Calculate main class.
Expand Down Expand Up @@ -165,6 +162,22 @@ class JvmRuntimeConfig(recognizedArgs: Array<String>) :
}
}

override fun processArgs(args: MutableList<String>) {
val prefix = "-Xmx"
val memIndices = args.withIndex()
.filter{ (_, value) -> value.startsWith("-Xmx" ) }
.map{it.index}

for (memIdx in memIndices) {
if (args[memIdx].contains('%')) {
val memPercent = args[memIdx].substring(prefix.length)
val maxHeap = calculateMaxHeap(memPercent)
args[memIdx] = "$prefix$maxHeap";
debug("Expanded % in jvm runtime arg: ${args[memIdx]}")
}
}
}

// -- Directive handlers --

fun classpath(divider: String = "\n- "): String? {
Expand Down
11 changes: 10 additions & 1 deletion src/commonMain/kotlin/main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ fun main(args: Array<String>) {

// Declare a set to store option parameter values.
// It will be populated at argument parsing time.
val vars = Vars(appDir, configDir, exeFile)
val vars = Vars(appDir, configDir, exeFile, config.cfgVars)

// Sort out the arguments, keeping the user-specified runtime and main arguments in a struct. At this point,
// it may yet be ambiguous whether certain user args belong with the runtime, the main program, or neither.
Expand Down Expand Up @@ -110,6 +110,15 @@ fun main(args: Array<String>) {
vars.interpolateInto(programArgs.main)
}

// Now that our program arguments have been fully interpolated, we offer the
// runtimes an additional opportunity to perform any runtime-specific
// custom logic (for example, resolving %'s in -Xmx notation).
for (programArgs in argsInContext.values) {
for (runtime in runtimes) {
runtime.processArgs(programArgs.runtime)
}
}

// Finally, execute all the directives! \^_^/
executeDirectives(nonGlobalDirectives, launchDirectives, runtimes, argsInContext)

Expand Down
4 changes: 4 additions & 0 deletions src/commonMain/kotlin/python.kt
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,10 @@ class PythonRuntimeConfig(recognizedArgs: Array<String>) :
}
}

override fun processArgs(args: MutableList<String>) {
// No-op
}

// -- Directive handlers --

fun dryRun(args: ProgramArgs): String {
Expand Down
5 changes: 5 additions & 0 deletions src/commonMain/kotlin/runtime.kt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ abstract class RuntimeConfig(
/** Get the launch directive block for this runtime configuration. */
abstract fun launch(args: ProgramArgs): List<String>

/**
* Perform any runtime-specific argument processing here.
*/
abstract fun processArgs(args: MutableList<String>)

/**
* Check whether the given argument matches one of the [recognizedArgs].
*
Expand Down
14 changes: 12 additions & 2 deletions src/commonMain/kotlin/vars.kt
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
// Vars class and related functions for working with variables.

class Vars(appDir: File, configDir: File, exeFile: File?) {
class Vars(
appDir: File,
configDir: File,
exeFile: File?,
cfgVars: Map<String, Any>
) {
private val vars = mutableMapOf<String, Any>()

init {
vars["app-dir"] = appDir.path
vars["config-dir"] = configDir.path
if (exeFile?.exists == true) vars["executable"] = exeFile.path

// Parse any Vars that were previously defined in toml.
if (cfgVars is Map) {
vars.putAll(cfgVars)
}

// Build the list of config files
val cfgFiles = mutableListOf<File>()
var cfgName = exeFile?.base?.name
Expand All @@ -24,7 +34,7 @@ class Vars(appDir: File, configDir: File, exeFile: File?) {
.filter { it.indexOf("=") >= 0 }
.associate {
val eq = it.indexOf("=")
it.substring(0, eq).trim() to it.substring(eq + 1).trim()
("cfg." + it.substring(0, eq).trim()) to it.substring(eq + 1).trim()
}
}
}
Expand Down

0 comments on commit b77b20a

Please sign in to comment.