11 Commits
1.0.3 ... 1.0.4

20 changed files with 130 additions and 42 deletions

2
.idea/kotlinc.xml generated
View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinJpsPluginSettings">
<option name="version" value="1.9.10" />
<option name="version" value="1.9.20" />
</component>
</project>

View File

@@ -10,6 +10,11 @@
[English](https://github.com/HighCapable/SweetProperty/blob/master/README.md) | 简体中文
| <img src="https://github.com/HighCapable/.github/blob/main/img-src/logo.jpg?raw=true" width = "30" height = "30" alt="LOGO"/> | [HighCapable](https://github.com/HighCapable) |
|-------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------|
这个项目属于上述组织,**点击上方链接关注这个组织**,发现更多好项目。
## 这是什么
这是一个用来轻松获取 Gradle 项目属性配置文件 `gradle.properties` 中键值的 Gradle 插件。

View File

@@ -10,6 +10,11 @@ An easy get project properties anywhere Gradle plugin.
English | [简体中文](https://github.com/HighCapable/SweetProperty/blob/master/README-zh-CN.md)
| <img src="https://github.com/HighCapable/.github/blob/main/img-src/logo.jpg?raw=true" width = "30" height = "30" alt="LOGO"/> | [HighCapable](https://github.com/HighCapable) |
|-------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------|
This project belongs to the above-mentioned organization, **click the link above to follow this organization** and discover more good projects.
## What's this
This is a Gradle plugin to easily get the key-values in the Gradle project properties configuration file `gradle.properties`.

View File

@@ -26,4 +26,12 @@
- 修复在全局配置中使用过其它配置方法后,子项目的 `all` 方法失效问题
- 改进并采用 Gradle 项目命名规范
- 新增插件自身检查更新功能
- 一些其它功能性的改进
## 1.0.4 | 2023.11.04
- 修复类似 `a=some``a_b=some` 的属性键值名称会造成重复方法名称的问题
- 修复使用 `${...}` 生成的插值内容依然会携带字符串类型引号问题
- 生成的代码使用 `@Nonnull` 标记以使其能够在 Kotlin DSL 脚本中识别为非空返回值类型
- 新增 `project(...)` 配置方法支持同时配置多个项目
- 一些其它功能性的改进

View File

@@ -27,4 +27,12 @@
- Fix `all` function of the sub-project fails after using other configuration functions in the global configuration
- Improve and adopt Gradle project naming convention
- Added plugin own update function
- Some other functional improvements
## 1.0.4 | 2023.11.04
- Fix the issue where attribute key value names like `a=some` and `a_b=some` would cause duplicate method names
- Fix the problem that the interpolation content generated using `${...}` still carries string type quotes
- Generated code is marked with `@Nonnull` to make it recognized as a non-null return type in Kotlin DSL scripts
- Added `project(...)` configuration method to support configuring multiple projects at the same time
- Some other functional improvements

View File

@@ -213,6 +213,19 @@ sweetProperty {
// 配置 "buildScript"
}
}
// 同时进行多个项目与子项目配置
// 在方法参数中填入需要配置的项目完整名称数组来配置每个对应的项目
project(":modules:library1", ":modules:library2") {
all {
// 配置 "all"
}
sourcesCode {
// 配置 "sourcesCode"
}
buildScript {
// 配置 "buildScript"
}
}
}
```

View File

@@ -227,7 +227,20 @@ sweetProperty {
// Configure "buildScript"
}
}
}
// Configure multiple projects and sub-projects at the same time
// Fill in the method parameters with the array of complete names of the projects that need to be configured
// to configure each corresponding project
project(":modules:library1", ":modules:library2") {
all {
// Configure "all"
}
sourcesCode {
// Configure "sourcesCode"
}
buildScript {
// Configure "buildScript"
}
}
```
If you want to use it in Groovy DSL, please change the `=` of all variables to spaces, delete the `is` in front of `Enable` and lowercase `E`.

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.3
project.version=1.0.4
project.licence.name=Apache License 2.0
project.licence.url=https://github.com/HighCapable/SweetProperty/blob/master/LICENSE
project.developer.id="0"

View File

@@ -12,7 +12,7 @@ repositories:
plugins:
org.jetbrains.kotlin.jvm:
alias: kotlin-jvm
version: 1.9.10
version: 1.9.20
com.vanniktech.maven.publish:
alias: maven-publish
version: 0.25.3
@@ -20,7 +20,7 @@ plugins:
libraries:
com.squareup.okhttp3:
okhttp:
version: 4.11.0
version: 4.12.0
com.squareup:
kotlinpoet:
version: 1.14.2

View File

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

View File

@@ -48,7 +48,7 @@ internal class ProjectDescriptor private constructor() {
it.type = Type.SETTINGS
it.name = name.noBlank() ?: settings.rootProject.name
it.currentDir = (if (isRootProject) settings.rootProject else settings.findProject(name))?.projectDir
?: SError.make("Project \"$name\" not found${if (name.startsWith(":").not()) ", $subProjectNotice" else ""}")
?: SError.make("Project \"$name\" not found${if (!name.startsWith(":")) ", $subProjectNotice" else ""}")
it.rootDir = settings.rootDir
it.homeDir = settings.gradle.gradleUserHomeDir
}

View File

@@ -37,7 +37,7 @@ import org.gradle.api.plugins.ExtensionAware
*/
internal fun ExtensionAware.getOrCreate(name: String, clazz: Class<*>, vararg args: Any?) = name.toSafeExtName().let { sName ->
runCatching { extensions.create(sName, clazz, *args).asExtension() }.getOrElse {
if ((it is IllegalArgumentException && it.message?.startsWith("Cannot add extension with name") == true).not()) throw it
if (!(it is IllegalArgumentException && it.message?.startsWith("Cannot add extension with name") == true)) throw it
runCatching { extensions.getByName(sName).asExtension() }.getOrNull() ?: SError.make("Create or get extension failed with name \"$sName\"")
}
}
@@ -50,7 +50,7 @@ internal fun ExtensionAware.getOrCreate(name: String, clazz: Class<*>, vararg ar
*/
internal inline fun <reified T> ExtensionAware.getOrCreate(name: String, vararg args: Any?) = name.toSafeExtName().let { sName ->
runCatching { extensions.create(sName, T::class.java, *args) as T }.getOrElse {
if ((it is IllegalArgumentException && it.message?.startsWith("Cannot add extension with name") == true).not()) throw it
if (!(it is IllegalArgumentException && it.message?.startsWith("Cannot add extension with name") == true)) throw it
runCatching { extensions.getByName(sName) as? T? }.getOrNull() ?: SError.make("Create or get extension failed with name \"$sName\"")
}
}

View File

@@ -44,7 +44,7 @@ internal fun Project.fullName(isUseColon: Boolean = true): String {
project.parent?.also { if (it != it.rootProject) fetchChild(it) }
baseNames.add(project.name)
}; fetchChild(project = this)
return buildString { baseNames.onEach { append(":$it") }.clear() }.let { if (isUseColon && isRoot.not()) it else it.drop(1) }
return buildString { baseNames.onEach { append(":$it") }.clear() }.let { if (isUseColon && !isRoot) it else it.drop(1) }
}
/**

View File

@@ -95,11 +95,11 @@ open class SweetPropertyConfigureExtension internal constructor() {
fun rootProject(action: Action<SubConfigureExtension>) = configureProject(ROOT_PROJECT_TAG, action)
/**
* 配置指定项目
* @param name 项目完整名称
* 配置指定项目 (数组)
* @param names 项目完整名称 (数组)
* @param action 配置方法体
*/
fun project(name: String, action: Action<SubConfigureExtension>) = configureProject(name, action)
fun project(vararg names: String, action: Action<SubConfigureExtension>) = names.forEach { configureProject(it, action) }
/**
* 配置项目
@@ -474,13 +474,13 @@ open class SweetPropertyConfigureExtension internal constructor() {
/** 检查合法包名 */
fun String.checkingValidPackageName() {
if (isNotBlank() && matches("^[a-zA-Z_][a-zA-Z0-9_]*(\\.[a-zA-Z_][a-zA-Z0-9_]*)*$".toRegex()).not())
if (isNotBlank() && !matches("^[a-zA-Z_][a-zA-Z0-9_]*(\\.[a-zA-Z_][a-zA-Z0-9_]*)*$".toRegex()))
SError.make("Invalid package name \"$this\"")
}
/** 检查合法类名 */
fun String.checkingValidClassName() {
if (isNotBlank() && matches("^[a-zA-Z][a-zA-Z0-9_]*$".toRegex()).not())
if (isNotBlank() && !matches("^[a-zA-Z][a-zA-Z0-9_]*$".toRegex()))
SError.make("Invalid class name \"$this\"")
}

View File

@@ -40,6 +40,7 @@ import com.squareup.javapoet.MethodSpec
import com.squareup.javapoet.TypeSpec
import java.text.SimpleDateFormat
import java.util.*
import javax.annotation.Nonnull
import javax.lang.model.element.Modifier
import kotlin.properties.Delegates
@@ -84,6 +85,9 @@ internal class PropertiesAccessorsGenerator {
/** 生成的属性键值连续名称重复次数数组 */
private val grandSuccessiveDuplicateIndexs = mutableMapOf<String, Int>()
/** 生成的属性键值不重复调用方法数组 */
private val usedSuccessiveMethods = mutableMapOf<String, MutableList<String>>()
/** 生成的属性键值不重复 TAG 数组 */
private val usedSuccessiveTags = mutableSetOf<String>()
@@ -94,7 +98,7 @@ internal class PropertiesAccessorsGenerator {
*/
private inline fun noRepeated(vararg tags: String, block: () -> Unit) {
val allTag = tags.joinToString("-")
if (usedSuccessiveTags.contains(allTag).not()) block()
if (!usedSuccessiveTags.contains(allTag)) block()
usedSuccessiveTags.add(allTag)
}
@@ -177,9 +181,10 @@ internal class PropertiesAccessorsGenerator {
*/
private fun TypeSpec.Builder.addSuccessiveMethod(accessorsName: String, methodName: String, className: String) =
addMethod(
MethodSpec.methodBuilder("get${methodName.capitalize()}")
MethodSpec.methodBuilder("get${getOrCreateUsedSuccessiveMethodName(methodName, className).capitalize()}")
.addJavadoc("Resolve the \"$accessorsName\" accessors")
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.addAnnotation(Nonnull::class.java)
.returns(className.capitalized().asClassType())
.addStatement("return ${className.uncapitalized()}")
.build()
@@ -189,15 +194,17 @@ internal class PropertiesAccessorsGenerator {
* 向通用构建器描述类添加最终键值方法
* @param accessorsName 接续名
* @param methodName 方法名
* @param className 类名
* @param value 键值内容
* @return [TypeSpec.Builder]
*/
private fun TypeSpec.Builder.addFinalValueMethod(accessorsName: String, methodName: String, value: Any) =
private fun TypeSpec.Builder.addFinalValueMethod(accessorsName: String, methodName: String, className: String, value: Any) =
addMethod(
MethodSpec.methodBuilder("get${methodName.capitalize()}").apply {
MethodSpec.methodBuilder("get${getOrCreateUsedSuccessiveMethodName(methodName, className).capitalize()}").apply {
val typedValue = value.parseTypedValue(configs.isEnableTypeAutoConversion)
addJavadoc("Resolve the \"$accessorsName\" value ${typedValue.second}")
addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.addAnnotation(Nonnull::class.java)
.returns(typedValue.first.java)
.addStatement("return ${typedValue.second}")
}.build()
@@ -211,6 +218,20 @@ internal class PropertiesAccessorsGenerator {
private fun MethodSpec.Builder.addSuccessiveStatement(className: String) =
addStatement("${className.uncapitalized()} = new ${className.capitalized()}()")
/**
* 获取不重复调用方法名称
* @param methodName 方法名
* @param className 类名
* @return [String]
*/
private fun getOrCreateUsedSuccessiveMethodName(methodName: String, className: String): String {
if (usedSuccessiveMethods[className] == null) usedSuccessiveMethods[className] = mutableListOf()
val methods = usedSuccessiveMethods[className]!!
val finalName = if (methods.contains(methodName)) "$methodName${methods.filter { it == methodName }.size + 1}" else methodName
methods.add(methodName)
return finalName
}
/**
* 获取、创建通用构建器描述类
* @param name 名称
@@ -279,9 +300,10 @@ internal class PropertiesAccessorsGenerator {
val nextAccessorsName = nextItem?.first ?: ""
val nextClassName = nextItem?.second ?: ""
val nextMethodName = nextItem?.third ?: ""
val lastClassName = lastItem?.second ?: ""
val lastMethodName = lastItem?.third ?: ""
val isPreLastIndex = index == successiveNames.lastIndex - 1
if (successiveNames.size == 1) getOrCreateClassSpec(TOP_SUCCESSIVE_NAME).addFinalValueMethod(successiveName, methodName, value)
if (successiveNames.size == 1) getOrCreateClassSpec(TOP_SUCCESSIVE_NAME).addFinalValueMethod(successiveName, methodName, className, value)
if (index == successiveNames.lastIndex) return@forEachIndexed
if (index == 0) noRepeated(TOP_SUCCESSIVE_NAME, methodName, className) {
getOrCreateClassSpec(TOP_SUCCESSIVE_NAME, accessorsName)
@@ -291,12 +313,12 @@ internal class PropertiesAccessorsGenerator {
}
noRepeated(className, nextMethodName, nextClassName) {
getOrCreateClassSpec(className, accessorsName).apply {
if (isPreLastIndex.not()) {
if (!isPreLastIndex) {
addSuccessiveField(nextAccessorsName, nextClassName)
addSuccessiveMethod(nextAccessorsName, nextMethodName, nextClassName)
} else addFinalValueMethod(successiveName, lastMethodName, value)
} else addFinalValueMethod(successiveName, lastMethodName, lastClassName, value)
}
if (isPreLastIndex.not()) preAddConstructorSpecNames.add(className to nextClassName)
if (!isPreLastIndex) preAddConstructorSpecNames.add(className to nextClassName)
}
}
}
@@ -342,6 +364,7 @@ internal class PropertiesAccessorsGenerator {
preAddConstructorSpecNames.clear()
grandSuccessiveNames.clear()
grandSuccessiveDuplicateIndexs.clear()
usedSuccessiveMethods.clear()
usedSuccessiveTags.clear()
if (isClearAll) memoryExtensionClasses.clear()
}
@@ -380,10 +403,15 @@ internal class PropertiesAccessorsGenerator {
*/
internal val compileStubFiles get(): List<JavaFile> {
val stubFiles = mutableListOf<JavaFile>()
val nonnullFile =
TypeSpec.annotationBuilder(Nonnull::class.java.simpleName)
.addModifiers(Modifier.PUBLIC)
.build().createJavaFile(Nonnull::class.java.packageName)
val iExtensionAccessorsFile =
TypeSpec.interfaceBuilder(IExtensionAccessors::class.java.simpleName)
.addModifiers(Modifier.PUBLIC)
.build().createJavaFile(IExtensionAccessors::class.java.packageName)
stubFiles.add(nonnullFile)
stubFiles.add(iExtensionAccessorsFile)
return stubFiles
}

View File

@@ -29,6 +29,12 @@ internal typealias PropertyMap = MutableMap<String, Any>
/** 属性键值规则类型定义 */
internal typealias PropertyValueRule = (value: String) -> String
/**
* 移除键值内容自动转换类型的引号
* @return [String]
*/
internal fun String.removeAutoConversion() = removeSurrounding("\"").removeSurrounding("'")
/**
* 解析到键值内容类型
* @param isAutoConversion 是否自动转换类型
@@ -46,7 +52,7 @@ internal fun Any.parseTypedValue(isAutoConversion: Boolean): Pair<KClass<*>, Str
it.drop(1).dropLast(1)
} else it.replace("\"", "\\\"")
}
if (isAutoConversion.not()) return Pair(String::class, "\"$valueString\"")
if (!isAutoConversion) return Pair(String::class, "\"$valueString\"")
val typeSpec = when {
isStringType -> String::class
valueString.trim().toIntOrNull() != null -> Int::class
@@ -56,6 +62,6 @@ internal fun Any.parseTypedValue(isAutoConversion: Boolean): Pair<KClass<*>, Str
valueString.trim() == "true" || valueString.trim() == "false" -> Boolean::class
else -> String::class
}; return Pair(typeSpec, if (typeSpec == String::class) "\"$valueString\"" else valueString.let {
if (typeSpec == Long::class && it.endsWith("L").not()) "${it}L" else it
if (typeSpec == Long::class && !it.endsWith("L")) "${it}L" else it
})
}

View File

@@ -73,7 +73,7 @@ internal object PluginUpdateHelper {
* @return [String]
*/
private fun String.findLatest() = runCatching {
if ((contains("<metadata ") || contains("<metadata>")).not() || endsWith("</metadata>").not()) return@runCatching ""
if (!(contains("<metadata ") || contains("<metadata>")) || !endsWith("</metadata>")) return@runCatching ""
DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(InputSource(StringReader(this))).let { document ->
document.getElementsByTagName("latest")?.let { if (it.length > 0) it.item(0)?.textContent ?: "" else "" }
}

View File

@@ -36,6 +36,7 @@ import com.highcapable.sweetproperty.plugin.config.type.GenerateLocationType
import com.highcapable.sweetproperty.plugin.generator.PropertiesAccessorsGenerator
import com.highcapable.sweetproperty.plugin.generator.PropertiesSourcesGenerator
import com.highcapable.sweetproperty.plugin.generator.factory.PropertyMap
import com.highcapable.sweetproperty.plugin.generator.factory.removeAutoConversion
import com.highcapable.sweetproperty.utils.camelcase
import com.highcapable.sweetproperty.utils.code.entity.MavenPomData
import com.highcapable.sweetproperty.utils.code.factory.compile
@@ -102,7 +103,7 @@ internal object PropertiesDeployHelper {
internal fun initialize(settings: Settings, configs: ISweetPropertyConfigs) {
this.configs = configs
checkingConfigsModified(settings)
if (configs.isEnable.not()) return
if (!configs.isEnable) return
generatedAccessors(settings)
}
@@ -111,7 +112,7 @@ internal object PropertiesDeployHelper {
* @param rootProject 当前根项目
*/
internal fun resolve(rootProject: Project) {
if (configs.isEnable.not()) return
if (!configs.isEnable) return
resolveAccessors(rootProject)
}
@@ -120,7 +121,7 @@ internal object PropertiesDeployHelper {
* @param rootProject 当前根项目
*/
internal fun deploy(rootProject: Project) {
if (configs.isEnable.not()) return
if (!configs.isEnable) return
deployAccessors(rootProject)
deploySourcesCode(rootProject)
}
@@ -152,13 +153,13 @@ internal object PropertiesDeployHelper {
allConfigs.add(configs.global.buildScript)
}
configs.projects.forEach { (name, subConfigs) ->
if (subConfigs.buildScript.isEnable.not()) return@forEach
if (!subConfigs.buildScript.isEnable) return@forEach
allProperties.add(generatedProperties(subConfigs.buildScript, ProjectDescriptor.create(settings, name)))
allConfigs.add(subConfigs.buildScript)
}
if (isConfigsModified.not() &&
if (!isConfigsModified &&
allProperties == cachedSettingsProperties &&
accessorsDir.resolve(accessorsPomData.relativePomPath).isEmpty().not()
!accessorsDir.resolve(accessorsPomData.relativePomPath).isEmpty()
) return
cachedSettingsProperties = allProperties
accessorsGenerator.build(allConfigs, allProperties).compile(accessorsPomData, accessorsDir.absolutePath, accessorsGenerator.compileStubFiles)
@@ -169,7 +170,7 @@ internal object PropertiesDeployHelper {
* @param rootProject 当前根项目
*/
private fun resolveAccessors(rootProject: Project) {
if (accessorsDir.resolve(accessorsPomData.relativePomPath).isEmpty().not())
if (!accessorsDir.resolve(accessorsPomData.relativePomPath).isEmpty())
rootProject.addDependencyToBuildScript(accessorsDir.absolutePath, accessorsPomData)
}
@@ -181,7 +182,7 @@ internal object PropertiesDeployHelper {
/** 部署扩展方法 */
fun Project.deploy() {
val configs = configs.with(this).buildScript
if (configs.isEnable.not()) return
if (!configs.isEnable) return
val className = accessorsGenerator.propertiesClass(configs.name)
val accessorsClass = loadBuildScriptClass(className) ?: SError.make(
"""
@@ -205,9 +206,9 @@ internal object PropertiesDeployHelper {
fun Project.generate() {
val configs = configs.with(this).sourcesCode
val outputDir = file(configs.generateDirPath)
if (configs.isEnable.not()) return
if (!configs.isEnable) return
val properties = generatedProperties(configs, ProjectDescriptor.create(project = this))
if (isConfigsModified.not() && properties == cachedProjectProperties[fullName()] && outputDir.isEmpty().not()) {
if (!isConfigsModified && properties == cachedProjectProperties[fullName()] && !outputDir.isEmpty()) {
if (configs.isEnable) configureSourceSets(project = this)
return
}; outputDir.apply { if (exists()) deleteRecursively() }
@@ -293,7 +294,8 @@ internal object PropertiesDeployHelper {
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
var resolveValue = if (configs.isEnableValueInterpolation) resolveKeyValues[matchKey] ?: "" else matchKey
resolveValue = resolveValue.removeAutoConversion()
if (resolveValue.hasInterpolation()) resolveValue.resolveValue()
else resolveValue
}

View File

@@ -52,7 +52,7 @@ internal fun String.parseUnixFileSeparator() = replace("\\", "/")
* - 如果文件不存在 - 返回 true
* @return [Boolean]
*/
internal fun File.isEmpty() = exists().not() || isDirectory.not() || listFiles().isNullOrEmpty()
internal fun File.isEmpty() = !exists() || !isDirectory || listFiles().isNullOrEmpty()
/** 删除目录下的空子目录 */
internal fun File.deleteEmptyRecursively() {

View File

@@ -59,7 +59,7 @@ internal object CodeCompiler {
if (files.isEmpty()) {
if (outputDir.exists()) outputDir.deleteRecursively()
return
} else outputDir.also { if (it.exists().not()) it.mkdirs() }
} else outputDir.also { if (!it.exists()) it.mkdirs() }
val outputBuildDir = "$outputDirPath/build".toFile().also { if (it.exists()) it.deleteRecursively(); it.mkdirs() }
val outputClassesDir = "${outputBuildDir.absolutePath}/classes".toFile().apply { mkdirs() }
val outputSourcesDir = "${outputBuildDir.absolutePath}/sources".toFile().apply { mkdirs() }
@@ -99,7 +99,7 @@ internal object CodeCompiler {
* @param sourcesDir 编译源码目录
*/
private fun createJarAndPom(pomData: MavenPomData, outputDir: File, buildDir: File, classesDir: File, sourcesDir: File) {
val pomDir = outputDir.resolve(pomData.relativePomPath).also { if (it.exists().not()) it.mkdirs() }
val pomDir = outputDir.resolve(pomData.relativePomPath).also { if (!it.exists()) it.mkdirs() }
packageToJar(classesDir, pomDir, pomData, isSourcesJar = false)
packageToJar(sourcesDir, pomDir, pomData, isSourcesJar = true)
writePom(pomDir, pomData)
@@ -159,7 +159,7 @@ internal object CodeCompiler {
* @throws IllegalStateException 如果编译输出目录不存在
*/
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}")
if (!buildDir.exists()) SError.make("Jar file output path not found: ${buildDir.absolutePath}")
val jarFile = outputDir.resolve("${pomData.artifactId}-${pomData.version}${if (isSourcesJar) "-sources" else ""}.jar")
if (jarFile.exists()) jarFile.delete()
ZipFile(jarFile).addFolder(buildDir, ZipParameters().apply { isIncludeRootFolder = false })