[CLI] Arguments: Implement raw vs resolved delimiters

KTIJ-24976
This commit is contained in:
Sebastian Sellmair
2023-03-31 10:23:52 +02:00
committed by Space Team
parent d07b1b6502
commit 7f91e94e7a
4 changed files with 44 additions and 21 deletions
@@ -10,6 +10,7 @@ package org.jetbrains.kotlin.compilerRunner
import org.jetbrains.kotlin.cli.common.arguments.Argument
import org.jetbrains.kotlin.cli.common.arguments.CommonToolArguments
import org.jetbrains.kotlin.cli.common.arguments.isAdvanced
import org.jetbrains.kotlin.cli.common.arguments.resolvedDelimiter
import kotlin.reflect.KClass
import kotlin.reflect.full.findAnnotation
import kotlin.reflect.full.memberProperties
@@ -31,8 +32,8 @@ internal fun <T : CommonToolArguments> toArgumentStrings(thisArguments: T, type:
val rawPropertyValue = property.get(thisArguments)
val rawDefaultValue = property.get(defaultArguments)
/* Default value can be omitted when not marked as 'isExplicit' */
if (rawPropertyValue == rawDefaultValue && !argumentAnnotation.isExplicit) {
/* Default value can be omitted */
if (rawPropertyValue == rawDefaultValue) {
return@forEach
}
@@ -78,8 +79,8 @@ internal fun <T : CommonToolArguments> toArgumentStrings(thisArguments: T, type:
private fun getArgumentStringValue(argumentAnnotation: Argument, values: Array<*>?): List<String> {
if (values.isNullOrEmpty()) return emptyList()
val delimiter = argumentAnnotation.delimiter
return if (delimiter.isEmpty()) values.map { it.toString() }
val delimiter = argumentAnnotation.resolvedDelimiter
return if (delimiter.isNullOrEmpty()) values.map { it.toString() }
else listOf(values.joinToString(delimiter))
}
@@ -188,7 +188,7 @@ abstract class CommonCompilerArguments : CommonToolArguments() {
value = "-Xcompiler-plugin",
valueDescription = "<path1>,<path2>:<optionName>=<value>,<optionName>=<value>",
description = "Register compiler plugin",
delimiter = ""
delimiter = Argument.Delimiters.none
)
var pluginConfigurations: Array<String>? = null
set(value) {
@@ -44,7 +44,7 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
@Argument(value="-include-binary", deprecatedName = "-includeBinary", shortName = "-ib", valueDescription = "<path>", description = "Pack external binary within the klib")
var includeBinaries: Array<String>? = null
@Argument(value = "-library", shortName = "-l", valueDescription = "<path>", description = "Link with the library", delimiter = "")
@Argument(value = "-library", shortName = "-l", valueDescription = "<path>", description = "Link with the library", delimiter = Argument.Delimiters.none)
var libraries: Array<String>? = null
@Argument(value = "-library-version", shortName = "-lv", valueDescription = "<version>", description = "Set library version")
@@ -76,7 +76,7 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
deprecatedName = "-nativelibrary",
shortName = "-nl",
valueDescription = "<path>",
description = "Include the native bitcode library", delimiter = ""
description = "Include the native bitcode library", delimiter = Argument.Delimiters.none
)
var nativeLibraries: Array<String>? = null
@@ -95,7 +95,7 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
@Argument(value="-linker-options", deprecatedName = "-linkerOpts", valueDescription = "<arg>", description = "Pass arguments to linker", delimiter = " ")
var linkerArguments: Array<String>? = null
@Argument(value="-linker-option", valueDescription = "<arg>", description = "Pass argument to linker", delimiter = "")
@Argument(value="-linker-option", valueDescription = "<arg>", description = "Pass argument to linker", delimiter = Argument.Delimiters.none)
var singleLinkerArguments: Array<String>? = null
@Argument(value = "-nostdlib", description = "Don't link with stdlib")
@@ -138,7 +138,7 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
value = "-Xcache-directory",
valueDescription = "<path>",
description = "Path to the directory containing caches",
delimiter = ""
delimiter = Argument.Delimiters.none
)
var cacheDirectories: Array<String>? = null
@@ -146,7 +146,7 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
value = CACHED_LIBRARY,
valueDescription = "<library path>,<cache path>",
description = "Comma-separated paths of a library and its cache",
delimiter = ""
delimiter = Argument.Delimiters.none
)
var cachedLibraries: Array<String>? = null
@@ -155,7 +155,7 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
valueDescription = "<path>",
description = "Path to the root directory from which dependencies are to be cached automatically.\n" +
"By default caches will be placed into the kotlin-native system cache directory.",
delimiter = ""
delimiter = Argument.Delimiters.none
)
var autoCacheableFrom: Array<String>? = null
@@ -163,7 +163,7 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
value = "-Xauto-cache-dir",
valueDescription = "<path>",
description = "Path to the directory where to put caches for auto-cacheable dependencies",
delimiter = ""
delimiter = Argument.Delimiters.none
)
var autoCacheDir: String? = null
@@ -184,7 +184,7 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
valueDescription = "<path>",
description = "A library to be included into produced framework API.\n" +
"Must be one of libraries passed with '-library'",
delimiter = ""
delimiter = Argument.Delimiters.none
)
var exportedLibraries: Array<String>? = null
@@ -232,7 +232,7 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
value = ADD_CACHE,
valueDescription = "<path>",
description = "Path to the library to be added to cache",
delimiter = ""
delimiter = Argument.Delimiters.none
)
var libraryToAddToCache: String? = null
@@ -240,7 +240,7 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
value = "-Xfile-to-cache",
valueDescription = "<path>",
description = "Path to file to cache",
delimiter = ""
delimiter = Argument.Delimiters.none
)
var filesToCache: Array<String>? = null
@@ -341,7 +341,7 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
valueDescription = "<path>",
description = "Provide code coverage for the given library.\n" +
"Must be one of libraries passed with '-library'",
delimiter = ""
delimiter = Argument.Delimiters.none
)
var coveredLibraries: Array<String>? = null
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.cli.common.arguments
import org.jetbrains.kotlin.cli.common.CompilerSystemProperties
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.utils.SmartList
import kotlin.reflect.KClass
import kotlin.reflect.KMutableProperty1
@@ -28,14 +29,35 @@ annotation class Argument(
val value: String,
val shortName: String = "",
val deprecatedName: String = "",
val delimiter: String = ",",
@property:RawDelimiter
val delimiter: String = Delimiters.default,
val valueDescription: String = "",
val description: String
)
) {
@RequiresOptIn(
message = "The raw delimiter value needs to be resolved. See 'resolvedDelimiter'. Using the raw value requires opt-in",
level = RequiresOptIn.Level.ERROR
)
annotation class RawDelimiter
object Delimiters {
const val default = ","
const val none = ""
const val pathSeparator = "<path_separator>"
}
}
val Argument.isAdvanced: Boolean
get() = value.startsWith(ADVANCED_ARGUMENT_PREFIX) && value.length > ADVANCED_ARGUMENT_PREFIX.length
@OptIn(Argument.RawDelimiter::class)
val Argument.resolvedDelimiter: String?
get() = when (delimiter) {
Argument.Delimiters.none -> null
Argument.Delimiters.pathSeparator -> File.pathSeparator
else -> delimiter
}
private const val ADVANCED_ARGUMENT_PREFIX = "-X"
private const val FREE_ARGS_DELIMITER = "--"
@@ -211,7 +233,7 @@ private fun <A : CommonToolArguments> parsePreprocessedCommandLineArguments(
errors.value.duplicateArguments[argument.value] = value
}
updateField(property, result, value, argument.delimiter, overrideArguments)
updateField(property, result, value, argument.resolvedDelimiter, overrideArguments)
}
result.freeArgs += freeArgs
@@ -238,13 +260,13 @@ private fun <A : CommonToolArguments> updateField(
property: KMutableProperty1<A, Any?>,
result: A,
value: Any,
delimiter: String,
delimiter: String?,
overrideArguments: Boolean
) {
when (property.returnType.classifier) {
Boolean::class, String::class -> property.set(result, value)
Array<String>::class -> {
val newElements = if (delimiter.isEmpty()) {
val newElements = if (delimiter.isNullOrEmpty()) {
arrayOf(value as String)
} else {
(value as String).split(delimiter).toTypedArray()