10 Commits
1.0.1 ... 1.0.2

18 changed files with 348 additions and 125 deletions

View File

@@ -7,4 +7,13 @@
## 1.0.1 | 2023.09.04
- 新增启用 `isEnableTypeAutoConversion` 后可以使用 '' 或 "" 强制设置一个键值内容为字符串类型
- 修改生成的代码中属性键值的内容使用优化后的类型呈现
- 修改生成的代码中属性键值的内容使用优化后的类型呈现
## 1.0.2 | 2023.09.07
- 使用 `net.lingala.zip4j` 取代 JDK 默认创建压缩文档功能修复在 Windows 平台中 Gradle 8.0.2+ 版本创建的 JAR 损坏导致找不到生成的 Class 问题
- 重构自动生成代码部分的装载功能,增加可能找不到 Class 的错误提示
- 作废了 ~~`propertiesFileName`~~ 方法
- 新增 `propertiesFileNames` 方法,现在你可以同时设置一组属性配置文件名称了
- 新增 `includeKeys` 方法,现在你可以设置仅包含的属性键值名称数组了
- 新增 `keyValuesRules` 方法,现在你可以在属性键值装载过程中修改键值内容的实际解析结果

View File

@@ -7,4 +7,14 @@
## 1.0.1 | 2023.09.04
- After enabling `isEnableTypeAutoConversion`, you can use '' or "" to force the content of a value to be a string type
- Modify the content of the properties key-values in the generated code to use the optimized type to render
- Modify the content of the properties key-values in the generated code to use the optimized type to render
## 1.0.2 | 2023.09.07
- Use `net.lingala.zip4j` to replace JDK's default function of creating compressed files and fix the problem that the JAR created by Gradle 8.0.2+
version on Windows platform is broken and the generated classes cannot be found
- Refactor the loading function of the automatically generated code part, and add an error message that classes may not be found
- Deprecated ~~`propertiesFileName`~~ method
- Added `propertiesFileNames` method, now you can set a group of properties file names at the same time
- Added `includeKeys` method, now you can set an array of properties key names to include only
- Added `keyValuesRules` method, now you can modify the actual parsing result of the value content during the properties key-values loading process

View File

@@ -70,11 +70,6 @@ sweetProperty {
// 启用功能
// 你可以分别对 "sourcesCode"、"buildScript" 进行设置
isEnable = true
// 设置属性配置文件名称
// 一般情况下不需要修改此设置,错误的文件名将导致获取到空键值内容
// 如果你有一个自定义名称的属性键值文件,你可以修改这里的设置
// 注意:建议为每个项目单独配置,而不是在全局中修改,以防发生问题
propertiesFileName = "gradle.properties"
// 是否启用排除非字符串类型键值内容
// 默认启用,启用后将从属性键值中排除不是字符串类型的键值及内容
// 这可以排除例如一些系统环境变量的配置或内存中的数据
@@ -90,6 +85,18 @@ sweetProperty {
// 默认启用,启用后将自动识别属性键值内容中的 ${...} 内容并进行替换
// 注意:插值的内容仅会从当前 (当前配置文件) 属性键值列表进行查找
isEnableValueInterpolation = true
// 设置属性配置文件名称数组
// 属性配置文件将根据你设置的文件名称自动从当前根项目、子项目以及用户目录的根目录进行获取
// 你可以添加多组属性配置文件名称,将按照顺序依次进行读取
// 一般情况下不需要修改此设置,错误的文件名将导致获取到空键值内容
// 你可以配置 "isAddDefault" 参数来决定是否添加默认的 "gradle.properties" 文件名称
// 如果你有一个或多个自定义名称的属性键值文件,你可以修改这里的设置
// 注意:建议为每个项目单独配置,而不是在全局中修改,以防发生问题
propertiesFileNames(
"some_other_1.properties",
"some_other_2.properties",
isAddDefault = true
)
// 设置固定存在的属性键值数组
// 在这里可以设置一些一定存在的键值,这些键值无论能否从属性键值中得到都会进行生成
// 这些键值在属性键值存在时使用属性键值的内容,不存在时使用这里设置的内容
@@ -111,6 +118,21 @@ sweetProperty {
"exclude.some.key1",
"exclude.some.key2"
)
// 设置需要包含的属性键值名称数组
// 在这里可以设置一些你希望从已知的属性键值中包含的键值名称
// 这些键值在属性键值存在它们时被包含,未被包含的键值不会出现在生成的代码中
// 你可以传入 Regex 或使用 String.toRegex 以使用正则功能
includeKeys(
"include.some.key1",
"include.some.key2"
)
// 设置属性键值规则数组
// 你可以设置一组键值规则,使用 "createValueRule" 创建新的规则,用于解析得到的键值内容
// 这些键值规则在属性键值存在它们时被应用
keyValuesRules(
"some.key1" to createValueRule { if (it.contains("_")) it.replace("_", "-") else it },
"some.key2" to createValueRule { "$it-value" }
)
// 设置从何处生成属性键值
// 默认为 "CURRENT_PROJECT" 和 "ROOT_PROJECT"
// 你可以使用以下类型来进行设置

View File

@@ -73,11 +73,6 @@ sweetProperty {
// Enable functionality
// You can set "sourcesCode" and "buildScript" respectively
isEnable = true
// Set properties name
// In general, you don't need to modify this setting, the wrong file name will lead to getting empty key-values content
// If you have a properties file with a custom name, you can modify the settings here
// Note: It is recommended to configure each project individually, rather than modifying globally, in case of problems
propertiesFileName = "gradle.properties"
// Whether to enable the exclusion of non-string type key-values content
// Enabled by default, when enabled, key-values and content that are not string types will be excluded from the properties key-values
// This can exclude e.g. configuration of some system environment variables or data in memory
@@ -96,7 +91,20 @@ sweetProperty {
// will be automatically recognized and replaced
// Note: The interpolated content will only be searching from the current (current configuration file) properties key-values list
isEnableValueInterpolation = true
// Set a fixed attribute key-value array
// Set properties names array
// The properties file will be automatically obtained from the root directory of
// the current root project, subproject and user directory according to the file name you set
// You can add multiple sets of properties file names, which will be read in order
// In general, you don't need to modify this setting, the wrong file name will lead to getting empty key-values content
// You can configure the "isAddDefault" parameter to decide whether to add the default "gradle.properties" file name
// If you have one or more properties files with custom names, you can modify the settings here
// Note: It is recommended to configure each project individually, rather than modifying globally, in case of problems
propertiesFileNames(
"some_other_1.properties",
"some_other_2.properties",
isAddDefault = true
)
// Set fixed properties key-values array
// Here you can set some key values that must exist,
// and these key values will be generated regardless of whether they can be obtained from the properties key-values
// These key-values use the content of the properties key-values when the properties key-values exists,
@@ -110,7 +118,7 @@ sweetProperty {
"permanent.some.key1" to "some_value_1",
"permanent.some.key2" to "some_value_2"
)
// Set an array of properties key-values names that need to be excluded
// Set properties key-values array names that need to be excluded
// Here you can set some key names that you want to exclude from the known properties keys
// These keys are excluded when they exist in the properties keys and will not appear in the generated code
// Note: If you exclude the key-values set in "permanentKeyValues",
@@ -120,6 +128,22 @@ sweetProperty {
"exclude.some.key1",
"exclude.some.key2"
)
// Set properties key-values array names that need to be included
// Here you can set some key-values names that you want to include from known properties keys
// These keys are included when the properties key-values exists
// Key-values that are not included will not appear in the generated code
// You can pass in a Regex or use String.toRegex to use the regex function
includeKeys(
"include.some.key1",
"include.some.key2"
)
// Set properties key-values rules array
// You can set a set of key-values rules and use "createValueRule" to create new rules for parsing the obtained value content
// These key-values rules are applied when the properties key-values exists
keyValuesRules(
"some.key1" to createValueRule { if (it.contains("_")) it.replace("_", "-") else it },
"some.key2" to createValueRule { "$it-value" }
)
// Set where to generate properties key-values
// Defaults to "CURRENT_PROJECT" and "ROOT_PROJECT"
// You can use the following types to set

View File

@@ -4,7 +4,7 @@ project.description=An easy get project properties anywhere Gradle plugin
project.url=https://github.com/HighCapable/SweetProperty
project.groupName=com.highcapable.sweetproperty
project.moduleName=sweet-property
project.version=1.0.1
project.version=1.0.2
project.licence.name=Apache License 2.0
project.licence.url=https://github.com/HighCapable/SweetProperty/blob/master/LICENSE
project.developer.id=0

View File

@@ -22,4 +22,7 @@ libraries:
kotlinpoet:
version: 1.14.2
javapoet:
version: 1.13.0
version: 1.13.0
net.lingala.zip4j:
zip4j:
version: 2.11.5

View File

@@ -8,8 +8,8 @@ pluginManagement {
}
}
plugins {
id("com.highcapable.sweetdependency") version "1.0.0"
id("com.highcapable.sweetproperty") version "1.0.1"
id("com.highcapable.sweetdependency") version "1.0.1"
id("com.highcapable.sweetproperty") version "1.0.2"
}
sweetDependency {
isEnableVerboseMode = false

View File

@@ -23,6 +23,7 @@ kotlin {
dependencies {
implementation(com.squareup.kotlinpoet)
implementation(com.squareup.javapoet)
implementation(net.lingala.zip4j.zip4j)
}
gradlePlugin {

View File

@@ -67,4 +67,4 @@ internal fun Project.addDependencyToBuildScript(repositoryPath: String, pomData:
* @param name [Class] 完整名称
* @return [Class]
*/
internal fun Project.loadBuildScriptClass(name: String) = buildscript.classLoader.loadClass(name)
internal fun Project.loadBuildScriptClass(name: String) = runCatching { buildscript.classLoader.loadClass(name) }.getOrNull()

View File

@@ -23,7 +23,7 @@ package com.highcapable.sweetproperty.plugin.config.default
import com.highcapable.sweetproperty.plugin.config.proxy.ISweetPropertyConfigs
import com.highcapable.sweetproperty.plugin.extension.dsl.configure.SweetPropertyConfigureExtension
import com.highcapable.sweetproperty.utils.noBlank
import com.highcapable.sweetproperty.plugin.generator.factory.PropertyValueRule
/**
* 默认配置类实现类
@@ -63,10 +63,10 @@ internal object DefaultConfigs {
get() = selfBase?.isEnable
?: globalBase?.isEnable
?: baseGenerateConfigs(name).isEnable
override val propertiesFileName
get() = selfBase?.propertiesFileName?.noBlank()
?: globalBase?.propertiesFileName?.noBlank()
?: baseGenerateConfigs(name).propertiesFileName
override val propertiesFileNames
get() = selfBase?.propertiesFileNames
?: globalBase?.propertiesFileNames
?: baseGenerateConfigs(name).propertiesFileNames
override val permanentKeyValues
get() = selfBase?.permanentKeyValues
?: globalBase?.permanentKeyValues
@@ -75,6 +75,14 @@ internal object DefaultConfigs {
get() = selfBase?.excludeKeys
?: globalBase?.excludeKeys
?: baseGenerateConfigs(name).excludeKeys
override val includeKeys
get() = selfBase?.includeKeys
?: globalBase?.includeKeys
?: baseGenerateConfigs(name).includeKeys
override val keyValuesRules
get() = selfBase?.keyValuesRules
?: globalBase?.keyValuesRules
?: baseGenerateConfigs(name).keyValuesRules
override val isEnableExcludeNonStringValue
get() = selfBase?.isEnableExcludeNonStringValue
?: globalBase?.isEnableExcludeNonStringValue
@@ -111,10 +119,10 @@ internal object DefaultConfigs {
get() = selfBase?.isEnable
?: globalBase?.isEnable
?: baseGenerateConfigs(name).isEnable
override val propertiesFileName
get() = selfBase?.propertiesFileName?.noBlank()
?: globalBase?.propertiesFileName?.noBlank()
?: baseGenerateConfigs(name).propertiesFileName
override val propertiesFileNames
get() = selfBase?.propertiesFileNames
?: globalBase?.propertiesFileNames
?: baseGenerateConfigs(name).propertiesFileNames
override val permanentKeyValues
get() = selfBase?.permanentKeyValues
?: globalBase?.permanentKeyValues
@@ -123,6 +131,14 @@ internal object DefaultConfigs {
get() = selfBase?.excludeKeys
?: globalBase?.excludeKeys
?: baseGenerateConfigs(name).excludeKeys
override val includeKeys
get() = selfBase?.includeKeys
?: globalBase?.includeKeys
?: baseGenerateConfigs(name).includeKeys
override val keyValuesRules
get() = selfBase?.keyValuesRules
?: globalBase?.keyValuesRules
?: baseGenerateConfigs(name).keyValuesRules
override val isEnableExcludeNonStringValue
get() = selfBase?.isEnableExcludeNonStringValue
?: globalBase?.isEnableExcludeNonStringValue
@@ -149,9 +165,11 @@ internal object DefaultConfigs {
private fun baseGenerateConfigs(name: String) = object : ISweetPropertyConfigs.IBaseGenerateConfigs {
override val name get() = name
override val isEnable get() = true
override val propertiesFileName get() = ISweetPropertyConfigs.DEFAULT_PROPERTIES_FILE_NAME
override val propertiesFileNames get() = mutableListOf(ISweetPropertyConfigs.DEFAULT_PROPERTIES_FILE_NAME)
override val permanentKeyValues get() = mutableMapOf<String, Any>()
override val excludeKeys get() = mutableListOf<Any>()
override val includeKeys get() = mutableListOf<Any>()
override val keyValuesRules get() = mutableMapOf<String, PropertyValueRule>()
override val isEnableExcludeNonStringValue get() = true
override val isEnableTypeAutoConversion get() = true
override val isEnableValueInterpolation get() = true

View File

@@ -92,10 +92,10 @@ private fun SweetPropertyConfigureExtension.SourcesCodeGenerateConfigureExtensio
?: global?.isEnable
?: globalBase?.isEnable
?: DefaultConfigs.sourcesCodeGenerateConfigs(name, selfBase, globalBase).isEnable
override val propertiesFileName
get() = this@create.propertiesFileName.noBlank()
?: global?.propertiesFileName?.noBlank()
?: DefaultConfigs.sourcesCodeGenerateConfigs(name, selfBase, globalBase).propertiesFileName
override val propertiesFileNames
get() = this@create.propertiesFileNames
?: global?.propertiesFileNames
?: DefaultConfigs.sourcesCodeGenerateConfigs(name, selfBase, globalBase).propertiesFileNames
override val permanentKeyValues
get() = this@create.permanentKeyValues
?: global?.permanentKeyValues
@@ -104,6 +104,14 @@ private fun SweetPropertyConfigureExtension.SourcesCodeGenerateConfigureExtensio
get() = this@create.excludeKeys
?: global?.excludeKeys
?: DefaultConfigs.sourcesCodeGenerateConfigs(name, selfBase, globalBase).excludeKeys
override val includeKeys
get() = this@create.includeKeys
?: global?.includeKeys
?: DefaultConfigs.sourcesCodeGenerateConfigs(name, selfBase, globalBase).includeKeys
override val keyValuesRules
get() = this@create.keyValuesRules
?: global?.keyValuesRules
?: DefaultConfigs.sourcesCodeGenerateConfigs(name, selfBase, globalBase).keyValuesRules
override val isEnableExcludeNonStringValue
get() = this@create.isEnableExcludeNonStringValue
?: selfBase?.isEnableExcludeNonStringValue
@@ -155,10 +163,10 @@ private fun SweetPropertyConfigureExtension.BuildScriptGenerateConfigureExtensio
?: global?.isEnable
?: globalBase?.isEnable
?: DefaultConfigs.buildScriptGenerateConfigs(name, selfBase, globalBase).isEnable
override val propertiesFileName
get() = this@create.propertiesFileName.noBlank()
?: global?.propertiesFileName?.noBlank()
?: DefaultConfigs.buildScriptGenerateConfigs(name, selfBase, globalBase).propertiesFileName
override val propertiesFileNames
get() = this@create.propertiesFileNames
?: global?.propertiesFileNames
?: DefaultConfigs.buildScriptGenerateConfigs(name, selfBase, globalBase).propertiesFileNames
override val permanentKeyValues
get() = this@create.permanentKeyValues
?: global?.permanentKeyValues
@@ -167,6 +175,14 @@ private fun SweetPropertyConfigureExtension.BuildScriptGenerateConfigureExtensio
get() = this@create.excludeKeys
?: global?.excludeKeys
?: DefaultConfigs.buildScriptGenerateConfigs(name, selfBase, globalBase).excludeKeys
override val includeKeys
get() = this@create.includeKeys
?: global?.includeKeys
?: DefaultConfigs.buildScriptGenerateConfigs(name, selfBase, globalBase).includeKeys
override val keyValuesRules
get() = this@create.keyValuesRules
?: global?.keyValuesRules
?: DefaultConfigs.buildScriptGenerateConfigs(name, selfBase, globalBase).keyValuesRules
override val isEnableExcludeNonStringValue
get() = this@create.isEnableExcludeNonStringValue
?: selfBase?.isEnableExcludeNonStringValue

View File

@@ -24,6 +24,7 @@ package com.highcapable.sweetproperty.plugin.config.proxy
import com.highcapable.sweetproperty.SweetProperty
import com.highcapable.sweetproperty.generated.SweetPropertyProperties
import com.highcapable.sweetproperty.plugin.config.type.GenerateLocationType
import com.highcapable.sweetproperty.plugin.generator.factory.PropertyValueRule
/**
* [SweetProperty] 配置类接口类
@@ -120,8 +121,8 @@ internal interface ISweetPropertyConfigs {
/** 是否为当前功能生成代码 */
val isEnable: Boolean
/** 属性配置文件名称 */
val propertiesFileName: String
/** 属性配置文件名称数组 */
val propertiesFileNames: MutableList<String>
/** 固定存在的属性键值数组 */
val permanentKeyValues: MutableMap<String, Any>
@@ -129,6 +130,12 @@ internal interface ISweetPropertyConfigs {
/** 被排除的属性键值名称数组 */
val excludeKeys: MutableList<Any>
/** 被包含的属性键值名称数组 */
val includeKeys: MutableList<Any>
/** 属性键值规则数组 */
val keyValuesRules: MutableMap<String, PropertyValueRule>
/** 是否启用排除非字符串类型键值内容 */
val isEnableExcludeNonStringValue: Boolean

View File

@@ -28,6 +28,7 @@ import com.highcapable.sweetproperty.gradle.factory.isUnSafeExtName
import com.highcapable.sweetproperty.plugin.config.factory.create
import com.highcapable.sweetproperty.plugin.config.proxy.ISweetPropertyConfigs
import com.highcapable.sweetproperty.plugin.config.type.GenerateLocationType
import com.highcapable.sweetproperty.plugin.generator.factory.PropertyValueRule
import com.highcapable.sweetproperty.utils.debug.SError
import com.highcapable.sweetproperty.utils.noEmpty
import org.gradle.api.Action
@@ -200,12 +201,21 @@ open class SweetPropertyConfigureExtension internal constructor() {
*/
open inner class BaseGenerateConfigureExtension internal constructor() {
/** 当前属性配置文件路径数组 */
internal var propertiesFileNames: MutableList<String>? = null
/** 当前固定存在的属性键值数组 */
internal var permanentKeyValues: MutableMap<String, Any>? = null
/** 当前被排除的属性键值名称数组 */
internal var excludeKeys: MutableList<Any>? = null
/** 当前被包含的属性键值名称数组 */
internal var includeKeys: MutableList<Any>? = null
/** 当前属性键值规则数组 */
internal var keyValuesRules: MutableMap<String, PropertyValueRule>? = null
/** 当前生成位置类型数组 */
internal var generateLocationTypes: Array<GenerateLocationType>? = null
@@ -226,10 +236,11 @@ open class SweetPropertyConfigureExtension internal constructor() {
/**
* 设置属性配置文件名称
*
* 默认为 [ISweetPropertyConfigs.DEFAULT_PROPERTIES_FILE_NAME]
* - 此方法已弃用 - 在之后的版本中将直接被删除
*
* - 注意:一般情况下不需要修改此设置 - 错误的文件名将导致获取到空键值内容
* - 请现在迁移到 [propertiesFileNames]
*/
@Deprecated(message = "Migrate to propertiesFileNames(...)")
var propertiesFileName = ""
@JvmName("propertiesFileName") set
@@ -263,6 +274,27 @@ open class SweetPropertyConfigureExtension internal constructor() {
var isEnableValueInterpolation: Boolean? = null
@JvmName("enableValueInterpolation") set
/**
* 设置属性配置文件名称数组
*
* 属性配置文件将根据你设置的文件名称自动从当前根项目、子项目以及用户目录的根目录进行获取
*
* 默认为 [ISweetPropertyConfigs.DEFAULT_PROPERTIES_FILE_NAME]
*
* 你可以添加多组属性配置文件名称 - 将按照顺序依次进行读取
*
* - 注意:一般情况下不需要修改此设置 - 错误的文件名称将导致获取到空键值内容
* @param names 要添加的属性配置文件名称数组
* @param isAddDefault 是否添加默认的属性配置文件名称 - 默认是
*/
@JvmOverloads
fun propertiesFileNames(vararg names: String, isAddDefault: Boolean = true) {
if (names.isEmpty()) SError.make("Properties file names must not be empty")
if (names.any { it.isBlank() }) SError.make("Properties file names must not have blank contents")
propertiesFileNames = names.distinct().toMutableList()
if (isAddDefault) propertiesFileNames?.add(0, ISweetPropertyConfigs.DEFAULT_PROPERTIES_FILE_NAME)
}
/**
* 设置固定存在的属性键值数组
*
@@ -313,6 +345,65 @@ open class SweetPropertyConfigureExtension internal constructor() {
excludeKeys = keys.distinct().toMutableList()
}
/**
* 设置需要包含的属性键值名称数组
*
* 在这里可以设置一些你希望从已知的属性键值中包含的键值名称
*
* 这些键值在属性键值存在它们时被包含 - 未被包含的键值不会出现在生成的代码中
* @param keys 键值名称数组 - 你可以传入 [Regex] 或使用 [String.toRegex] 以使用正则功能
*/
fun includeKeys(vararg keys: Any) {
if (keys.isEmpty()) SError.make("Include keys must not be empty")
if (keys.any { it.toString().isBlank() }) SError.make("Include keys must not have blank contents")
includeKeys = keys.distinct().toMutableList()
}
/**
* 设置属性键值规则数组
*
* 你可以设置一组键值规则 - 使用 [createValueRule] 创建新的规则 - 用于解析得到的键值内容
*
* 示例如下 ↓
*
* ```kotlin
* keyValuesRules(
* "some.key1" to createValueRule { if (it.contains("_")) it.replace("_", "-") else it },
* "some.key2" to createValueRule { "$it-value" }
* )
* ```
*
* 这些键值规则在属性键值存在它们时被应用
* @param pairs 属性键值规则数组
*/
@JvmName("-kotlin-dsl-only-keyValuesRules-")
fun keyValuesRules(vararg pairs: Pair<String, PropertyValueRule>) {
if (pairs.isEmpty()) SError.make("Key-values rules must not be empty")
if (pairs.any { it.first.isBlank() }) SError.make("Key-values rules must not have blank contents")
keyValuesRules = mutableMapOf(*pairs)
}
/**
* 设置属性键值规则数组 (Groovy 兼容方法)
*
* 你可以设置一组键值规则 - 使用 [createValueRule] 创建新的规则 - 用于解析得到的键值内容
*
* 这些键值规则在属性键值存在它们时被应用
* @param rules 属性键值规则数组
*/
fun keyValuesRules(rules: Map<String, PropertyValueRule>) {
if (rules.isEmpty()) SError.make("Key-values rules must not be empty")
if (rules.any { it.key.isBlank() }) SError.make("Key-values rules must not have blank contents")
keyValuesRules = rules.toMutableMap()
}
/**
* 创建新的属性键值规则
* @param rule 回调当前规则
* @return [PropertyValueRule]
*/
fun createValueRule(rule: PropertyValueRule) = rule
/**
* 设置从何处生成属性键值
*

View File

@@ -26,6 +26,9 @@ import kotlin.reflect.KClass
/** 属性键值数组类型定义 */
internal typealias PropertyMap = MutableMap<String, Any>
/** 属性键值规则类型定义 */
internal typealias PropertyValueRule = (value: String) -> String
/**
* 解析到键值内容类型
* @param isAutoConversion 是否自动转换类型

View File

@@ -45,8 +45,8 @@ import com.highcapable.sweetproperty.utils.hasInterpolation
import com.highcapable.sweetproperty.utils.isEmpty
import com.highcapable.sweetproperty.utils.noBlank
import com.highcapable.sweetproperty.utils.noEmpty
import com.highcapable.sweetproperty.utils.parseFileSeparator
import com.highcapable.sweetproperty.utils.replaceInterpolation
import com.highcapable.sweetproperty.utils.toStringMap
import com.highcapable.sweetproperty.utils.uppercamelcase
import org.gradle.api.DomainObjectCollection
import org.gradle.api.Project
@@ -156,7 +156,10 @@ internal object PropertiesDeployHelper {
allProperties.add(generatedProperties(subConfigs.buildScript, ProjectDescriptor.create(settings, name)))
allConfigs.add(subConfigs.buildScript)
}
if (isConfigsModified.not() && allProperties == cachedSettingsProperties && accessorsDir.isEmpty().not()) return
if (isConfigsModified.not() &&
allProperties == cachedSettingsProperties &&
accessorsDir.resolve(accessorsPomData.relativePomPath).isEmpty().not()
) return
cachedSettingsProperties = allProperties
accessorsGenerator.build(allConfigs, allProperties).compile(accessorsPomData, accessorsDir.absolutePath, accessorsGenerator.compileStubFiles)
}
@@ -166,7 +169,8 @@ internal object PropertiesDeployHelper {
* @param rootProject 当前根项目
*/
private fun resolveAccessors(rootProject: Project) {
if (accessorsDir.isEmpty().not()) rootProject.addDependencyToBuildScript(accessorsDir.absolutePath, accessorsPomData)
if (accessorsDir.resolve(accessorsPomData.relativePomPath).isEmpty().not())
rootProject.addDependencyToBuildScript(accessorsDir.absolutePath, accessorsPomData)
}
/**
@@ -178,7 +182,15 @@ internal object PropertiesDeployHelper {
fun Project.deploy() {
val configs = configs.with(this).buildScript
if (configs.isEnable.not()) return
getOrCreate(configs.extensionName.camelcase(), loadBuildScriptClass(accessorsGenerator.propertiesClass(configs.name)))
val className = accessorsGenerator.propertiesClass(configs.name)
val accessorsClass = loadBuildScriptClass(className) ?: SError.make(
"""
Generated class "$className" not found, stop loading $this
Please check whether the initialization process is interrupted and re-run Gradle Sync
If this doesn't work, please manually delete the entire "${accessorsDir.absolutePath}" directory
""".trimIndent()
)
getOrCreate(configs.extensionName.camelcase(), accessorsClass)
}
rootProject.deploy()
rootProject.subprojects.forEach { it.deploy() }
@@ -244,43 +256,52 @@ internal object PropertiesDeployHelper {
val propteries = mutableMapOf<String, Any>()
configs.permanentKeyValues.forEach { (key, value) -> propteries[key] = value }
configs.generateLocationTypes.forEach {
val nativeKeyValues = when (it) {
GenerateLocationType.CURRENT_PROJECT -> createProperties(configs, descriptor.currentDir)
GenerateLocationType.ROOT_PROJECT -> createProperties(configs, descriptor.rootDir)
GenerateLocationType.GLOBAL -> createProperties(configs, descriptor.homeDir)
GenerateLocationType.SYSTEM -> System.getProperties()
GenerateLocationType.SYSTEM_ENV -> System.getenv()
} ?: emptyMap()
val resolveKeyValues = mutableMapOf<String, Any>()
nativeKeyValues.forEach native@{ (key, value) ->
val hasExcludeKeys = configs.excludeKeys.noEmpty()?.any { content ->
when (content) {
is Regex -> content.toString().isNotBlank() && content.matches(key.toString())
else -> content.toString() == key
}
} ?: false
if (hasExcludeKeys) return@native
val isAvailableKeyValue = if (configs.isEnableExcludeNonStringValue)
mutableMapOf<Any?, Any?>().apply {
when (it) {
GenerateLocationType.CURRENT_PROJECT -> createProperties(configs, descriptor.currentDir).forEach { putAll(it) }
GenerateLocationType.ROOT_PROJECT -> createProperties(configs, descriptor.rootDir).forEach { putAll(it) }
GenerateLocationType.GLOBAL -> createProperties(configs, descriptor.homeDir).forEach { putAll(it) }
GenerateLocationType.SYSTEM -> putAll(System.getProperties())
GenerateLocationType.SYSTEM_ENV -> putAll(System.getenv())
}
}.filter { (key, value) ->
if (configs.isEnableExcludeNonStringValue)
key is CharSequence && key.isNotBlank() && value is CharSequence
else key.toString().isNotBlank() && value != null
if (isAvailableKeyValue) resolveKeyValues[key.toString()] = value
}
resolveKeyValues.forEach { (key, value) ->
val resolveKeys = mutableListOf<String>()
}.toStringMap().filter { (key, _) ->
configs.includeKeys.noEmpty()?.any { content ->
when (content) {
is Regex -> content.matches(key)
else -> content.toString() == key
}
} ?: true
}.filter { (key, _) ->
configs.excludeKeys.noEmpty()?.none { content ->
when (content) {
is Regex -> content.matches(key)
else -> content.toString() == key
}
} ?: true
}.toMutableMap().also { resolveKeyValues ->
resolveKeyValues.onEach { (key, value) ->
val resolveKeys = mutableListOf<String>()
/**
* 处理键值内容
* @return [String]
*/
fun String.resolveValue(): String = replaceInterpolation { matchKey ->
if (resolveKeys.size > 5) SError.make("Key \"$key\" has been called recursively multiple times of those $resolveKeys")
resolveKeys.add(matchKey)
val resolveValue = if (configs.isEnableValueInterpolation) resolveKeyValues[matchKey]?.toString() ?: "" else matchKey
if (resolveValue.hasInterpolation()) resolveValue.resolveValue()
else resolveValue
}
if (value.toString().hasInterpolation()) resolveKeyValues[key] = value.toString().resolveValue()
}; propteries.putAll(resolveKeyValues)
/**
* 处理键值内容
* @return [String]
*/
fun String.resolveValue(): String = replaceInterpolation { matchKey ->
if (resolveKeys.size > 5) SError.make("Key \"$key\" has been called recursively multiple times of those $resolveKeys")
resolveKeys.add(matchKey)
val resolveValue = if (configs.isEnableValueInterpolation) resolveKeyValues[matchKey] ?: "" else matchKey
if (resolveValue.hasInterpolation()) resolveValue.resolveValue()
else resolveValue
}
if (value.hasInterpolation()) resolveKeyValues[key] = value.resolveValue()
}.takeIf { configs.keyValuesRules.isNotEmpty() }?.forEach { (key, value) ->
configs.keyValuesRules[key]?.also { resolveKeyValues[key] = it(value) }
}; propteries.putAll(resolveKeyValues)
}
}; return propteries
}
@@ -320,12 +341,17 @@ internal object PropertiesDeployHelper {
}
/**
* 创建新的 [Properties]
* 创建新的 [Properties] 数组
* @param configs 当前配置
* @param dir 当前目录
* @return [Properties] or null
* @return [MutableList]<[Properties]>
*/
private fun createProperties(configs: ISweetPropertyConfigs.IBaseGenerateConfigs, dir: File?) = runCatching {
Properties().apply { load(FileReader(dir?.resolve(configs.propertiesFileName)?.absolutePath?.parseFileSeparator() ?: "")) }
}.getOrNull()
mutableListOf<Properties>().apply {
configs.propertiesFileNames.forEach {
val propertiesFile = dir?.resolve(it)
if (propertiesFile?.exists() == true) add(Properties().apply { load(FileReader(propertiesFile.absolutePath)) })
}
}
}.getOrNull() ?: mutableListOf()
}

View File

@@ -21,6 +21,12 @@
*/
package com.highcapable.sweetproperty.utils
/**
* 转换当前 [Map] 键值到字符串类型
* @return [Map]<[String], [String]>
*/
internal inline fun <reified K, V> Map<K, V>.toStringMap() = mapKeys { e -> e.key.toString() }.mapValues { e -> e.value.toString() }
/**
* 当数组不为空时返回非空
* @return [T] or null

View File

@@ -24,11 +24,10 @@ package com.highcapable.sweetproperty.utils.code
import com.highcapable.sweetproperty.utils.code.entity.MavenPomData
import com.highcapable.sweetproperty.utils.debug.SError
import com.highcapable.sweetproperty.utils.deleteEmptyRecursively
import com.highcapable.sweetproperty.utils.parseFileSeparator
import com.highcapable.sweetproperty.utils.toFile
import net.lingala.zip4j.ZipFile
import net.lingala.zip4j.model.ZipParameters
import java.io.File
import java.util.jar.JarEntry
import java.util.jar.JarOutputStream
import javax.tools.DiagnosticCollector
import javax.tools.JavaFileObject
import javax.tools.StandardLocation
@@ -84,8 +83,8 @@ internal object CodeCompiler {
sourceFile.writeText(it.getCharContent(true).toString())
}
}; outputClassesDir.deleteEmptyRecursively()
writeMetaInf(outputClassesDir.absolutePath)
writeMetaInf(outputSourcesDir.absolutePath)
writeMetaInf(outputClassesDir)
writeMetaInf(outputSourcesDir)
createJarAndPom(pomData, outputDir, outputBuildDir, outputClassesDir, outputSourcesDir)
} else SError.make("Failed to compile java files into path: $outputDirPath\n$diagnosticsMessage")
}
@@ -99,30 +98,29 @@ internal object CodeCompiler {
* @param sourcesDir 编译源码目录
*/
private fun createJarAndPom(pomData: MavenPomData, outputDir: File, buildDir: File, classesDir: File, sourcesDir: File) {
val pomPath = "${pomData.groupId.toPomPathName()}/${pomData.artifactId}/${pomData.version}"
val pomDir = "${outputDir.absolutePath}/$pomPath".toFile().also { if (it.exists().not()) it.mkdirs() }
val pomDir = outputDir.resolve(pomData.relativePomPath).also { if (it.exists().not()) it.mkdirs() }
packageToJar(classesDir, pomDir, pomData, isSourcesJar = false)
packageToJar(sourcesDir, pomDir, pomData, isSourcesJar = true)
writePom(pomDir.absolutePath, pomData)
writePom(pomDir, pomData)
buildDir.deleteRecursively()
}
/**
* 写入 META-INF/MANIFEST.MF
* @param dirPath 当前目录路径
* @param dir 当前目录
*/
private fun writeMetaInf(dirPath: String) {
val metaInfFile = "$dirPath/META-INF".toFile().apply { mkdirs() }
"${metaInfFile.absolutePath}/MANIFEST.MF".toFile().writeText("Manifest-Version: 1.0")
private fun writeMetaInf(dir: File) {
val metaInfDir = dir.resolve("META-INF").apply { mkdirs() }
metaInfDir.resolve("MANIFEST.MF").writeText("Manifest-Version: 1.0")
}
/**
* 写入 POM
* @param dirPath 当前目录路径
* @param dir 当前目录
* @param pomData Maven POM 实体
*/
private fun writePom(dirPath: String, pomData: MavenPomData) =
"$dirPath/${pomData.artifactId}-${pomData.version}.pom".toFile().writeText(
private fun writePom(dir: File, pomData: MavenPomData) =
dir.resolve("${pomData.artifactId}-${pomData.version}.pom").writeText(
"""
<?xml version="1.0" encoding="UTF-8"?>
<project
@@ -137,12 +135,6 @@ internal object CodeCompiler {
""".trimIndent()
)
/**
* 转换到 [MavenPomData] 目录名称
* @return [String]
*/
private fun String.toPomPathName() = trim().replace(".", "/").replace("_", "/").replace(":", "/").replace("-", "/")
/**
* 转换到文件
* @param outputDir 输出目录
@@ -167,26 +159,8 @@ internal object CodeCompiler {
*/
private fun packageToJar(buildDir: File, outputDir: File, pomData: MavenPomData, isSourcesJar: Boolean) {
if (buildDir.exists().not()) SError.make("Jar file output path not found: ${buildDir.absolutePath}")
/**
* 添加文件到 JAR
* @param jos 当前输出流
* @param parentPath 父级路径
*/
fun File.addToJar(jos: JarOutputStream, parentPath: String = "") {
val currentPath = "$parentPath$name".replace("${buildDir.name}|", "").replace("|", "/").parseFileSeparator()
if (isFile) {
if (name.startsWith(".")) return
jos.putNextEntry(JarEntry(currentPath))
inputStream().use { fis ->
val buffer = ByteArray(4096)
var bytesRead: Int
while (fis.read(buffer).also { bytesRead = it } != -1) jos.write(buffer, 0, bytesRead)
}
jos.closeEntry()
} else listFiles()?.forEach { it.addToJar(jos, parentPath = "$currentPath|") }
}
val jarFile = "${outputDir.absolutePath}/${pomData.artifactId}-${pomData.version}${if (isSourcesJar) "-sources" else ""}.jar".toFile()
val jarFile = outputDir.resolve("${pomData.artifactId}-${pomData.version}${if (isSourcesJar) "-sources" else ""}.jar")
if (jarFile.exists()) jarFile.delete()
jarFile.outputStream().use { fos -> JarOutputStream(fos).use { jos -> buildDir.addToJar(jos) } }
ZipFile(jarFile).addFolder(buildDir, ZipParameters().apply { isIncludeRootFolder = false })
}
}

View File

@@ -27,4 +27,17 @@ package com.highcapable.sweetproperty.utils.code.entity
* @param artifactId Artifact Id
* @param version 版本
*/
internal data class MavenPomData(internal val groupId: String, internal val artifactId: String, internal val version: String)
internal data class MavenPomData(internal val groupId: String, internal val artifactId: String, internal val version: String) {
/**
* 获取 [MavenPomData] 相对路径
* @return [String]
*/
internal val relativePomPath get() = "${groupId.toPomPathName()}/$artifactId/$version"
/**
* 转换到 [MavenPomData] 目录名称
* @return [String]
*/
private fun String.toPomPathName() = trim().replace(".", "/").replace("_", "/").replace(":", "/").replace("-", "/")
}