13 Commits
1.0.0 ... 1.0.1

22 changed files with 153 additions and 77 deletions

View File

@@ -1,8 +1,8 @@
# Sweet Dependency
[![Blank](https://img.shields.io/badge/license-Apache2.0-blue)](https://github.com/HighCapable/SweetDependency/blob/master/LICENSE)
![Blank](https://img.shields.io/badge/version-v1.0.0-green)
[![Telegram](https://img.shields.io/badge/Discussion-Telegram-blue.svg?logo=telegram)](https://t.me/HighCapable_Dev)
[![GitHub license](https://img.shields.io/github/license/HighCapable/SweetDependency?color=blue)](https://github.com/HighCapable/SweetDependency/blob/master/LICENSE)
[![GitHub release](https://img.shields.io/github/v/release/HighCapable/SweetDependency?display_name=release&logo=github&color=green)](https://github.com/HighCapable/SweetDependency/releases)
[![Telegram](https://img.shields.io/badge/discussion-Telegram-blue.svg?logo=telegram)](https://t.me/HighCapable_Dev)
<img src="https://github.com/HighCapable/SweetDependency/blob/master/img-src/icon.png?raw=true" width = "100" height = "100" alt="LOGO"/>

View File

@@ -1,8 +1,8 @@
# Sweet Dependency
[![Blank](https://img.shields.io/badge/license-Apache2.0-blue)](https://github.com/HighCapable/SweetDependency/blob/master/LICENSE)
![Blank](https://img.shields.io/badge/version-v1.0.0-green)
[![Telegram](https://img.shields.io/badge/Discussion-Telegram-blue.svg?logo=telegram)](https://t.me/HighCapable_Dev)
[![GitHub license](https://img.shields.io/github/license/HighCapable/SweetDependency?color=blue)](https://github.com/HighCapable/SweetDependency/blob/master/LICENSE)
[![GitHub release](https://img.shields.io/github/v/release/HighCapable/SweetDependency?display_name=release&logo=github&color=green)](https://github.com/HighCapable/SweetDependency/releases)
[![Telegram](https://img.shields.io/badge/discussion-Telegram-blue.svg?logo=telegram)](https://t.me/HighCapable_Dev)
<img src="https://github.com/HighCapable/SweetDependency/blob/master/img-src/icon.png?raw=true" width = "100" height = "100" alt="LOGO"/>

View File

@@ -2,4 +2,11 @@
## 1.0.0 | 2023.09.03
- 首个版本提交至 Maven
- 首个版本提交至 Maven
## 1.0.1 | 2023.09.07
- 使用 `net.lingala.zip4j` 取代 JDK 默认创建压缩文档功能修复在 Windows 平台中 Gradle 8.0.2+ 版本创建的 JAR 损坏导致找不到生成的 Class 问题
- 重构自动生成代码部分的装载功能,增加可能找不到 Class 的错误提示
- 新增在设置了未定义版本的插件依赖条件下直接运行自动装配相关 Gradle Task 将抛出异常
- 修复可能的旧版本 Gradle 在使用 `repositories``content` 功能会抛出异常

View File

@@ -2,4 +2,13 @@
## 1.0.0 | 2023.09.03
- The first version is submitted to Maven
- The first version is submitted to Maven
## 1.0.1 | 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
- Added an exception will be thrown when running the autowire related Gradle task directly
under the condition of setting an undefined version of plugins
- Fix possible old version of Gradle throwing exception when using `content` function of `repositories`

View File

@@ -80,6 +80,12 @@ plugins {
上述配置完成后,运行一次 Gradle Sync。
**可能遇到的问题**
如果在运行 Gradle Sync 后失败并报错 `Cannot have abstract method KotlinTarget. withSourcesJar()`,这可能是你当前项目的 Kotlin 插件版本的问题。
此问题为 Kotlin 插件从 `1.8.0+``1.9.0+` 升级导致的错误,解决方案为将 Kotlin 插件的版本修改为 `1.9.0+`
**特别注意**
`SweetDependency` 会替换 `pluginManagement``dependencyResolutionManagement` 中设置的存储库,如果你手动在这些方法块中配置了存储库,它们都将会无效。

View File

@@ -81,6 +81,15 @@ Please replace `<version>` in the above code with the latest version in
After the above configuration is complete, run Gradle Sync once.
**Possible Problems**
If running Gradle Sync fails with the error `Cannot have abstract method KotlinTarget. withSourcesJar()`,
this may be a problem with the Kotlin plugin version of your current project.
This problem is an error caused by upgrading the Kotlin plugin from `1.8.0+``1.9.0+`.
The solution is to modify the version of the Kotlin plugin to `1.9.0+`.
**Pay Attention**
`SweetDependency` will replace the repositories set in `pluginManagement` and `dependencyResolutionManagement`,

View File

@@ -5,12 +5,12 @@ plugins {
android {
namespace = "com.highcapable.sweetdependency.demo_app"
compileSdk = 33
compileSdk = 34
defaultConfig {
applicationId = "com.highcapable.sweetdependency.demo_app"
minSdk = 24
targetSdk = 33
targetSdk = 34
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"

View File

@@ -5,11 +5,10 @@ plugins {
android {
namespace = "com.highcapable.sweetdependency.demo_library"
compileSdk = 33
compileSdk = 34
defaultConfig {
minSdk = 24
targetSdk = 33
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro")
}

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME

View File

@@ -8,7 +8,7 @@ pluginManagement {
plugins {
// Import the SweetDependency plugin here
// 在这里引入 SweetDependency 插件
id("com.highcapable.sweetdependency") version "1.0.0"
id("com.highcapable.sweetdependency") version "1.0.1"
}
sweetDependency {
configFileName = "sweet-dependency-config.yaml"

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@@ -8,7 +8,7 @@ pluginManagement {
plugins {
// Import the SweetDependency plugin here
// 在这里引入 SweetDependency 插件
id("com.highcapable.sweetdependency") version "1.0.0"
id("com.highcapable.sweetdependency") version "1.0.1"
}
sweetDependency {
configFileName = "sweet-dependency-config.yaml"

View File

@@ -1,12 +1,12 @@
# Project Configuration
project.name=SweetDependency
project.description=An easy autowire and manage dependencies Gradle plugin
project.url=https://github.com/fankes/HighCapable/SweetDependency
project.url=https://github.com/HighCapable/SweetDependency
project.groupName=com.highcapable.sweetdependency
project.moduleName=sweet-dependency
project.version=1.0.0
project.version=1.0.1
project.licence.name=Apache License 2.0
project.licence.url=https://github.com/fankes/HighCapable/SweetDependency/blob/master/LICENSE
project.licence.url=https://github.com/HighCapable/SweetDependency/blob/master/LICENSE
project.developer.id=0
project.developer.name=fankes
project.developer.email=qzmmcn@163.com

View File

@@ -35,4 +35,7 @@ libraries:
version: 4.11.0
com.squareup:
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.0"
id("com.highcapable.sweetdependency") version "1.0.1"
id("com.highcapable.sweetproperty") version "1.0.2"
}
sweetDependency {
isEnableVerboseMode = false

View File

@@ -27,6 +27,7 @@ dependencies {
implementation(com.charleskorn.kaml.kaml)
implementation(com.squareup.okhttp3.okhttp)
implementation(com.squareup.javapoet)
implementation(net.lingala.zip4j.zip4j)
}
gradlePlugin {

View File

@@ -78,6 +78,24 @@ internal class DependencyVersion(internal var actual: String, optionalType: Opti
else -> current
}
/**
* 获取固定存在的版本
*
* 满足以下情况
*
* - [isBlank]
* - [isNoSpecific]
*
* 这些情况都会返回 [AUTOWIRE_VERSION_NAME]
*
* 其余情况会返回 [current]
* @return [String]
*/
internal val fixed get() = when {
isBlank || isNoSpecific -> AUTOWIRE_VERSION_NAME
else -> current
}
/**
* 获取部署版本
*

View File

@@ -85,9 +85,9 @@ internal fun Project.addDependencyToBuildScript(repositoryPath: String, pomData:
/**
* 装载构建脚本的 [Class]
* @param name [Class] 完整名称
* @return [Class]
* @return [Class] or null
*/
internal fun Project.loadBuildScriptClass(name: String) = buildscript.classLoader.loadClass(name)
internal fun Project.loadBuildScriptClass(name: String) = runCatching { buildscript.classLoader.loadClass(name) }.getOrNull()
/**
* 获取指定项目部署的插件依赖数组 (实时)

View File

@@ -24,6 +24,7 @@ package com.highcapable.sweetdependency.manager
import com.highcapable.sweetdependency.document.PreferencesDocument
import com.highcapable.sweetdependency.document.RepositoryDocument
import com.highcapable.sweetdependency.exception.SweetDependencyUnresolvedException
import com.highcapable.sweetdependency.gradle.helper.GradleHelper
import com.highcapable.sweetdependency.manager.const.AdditionalRepositories
import com.highcapable.sweetdependency.manager.content.Repositories
import com.highcapable.sweetdependency.plugin.config.content.SweetDependencyConfigs
@@ -100,9 +101,17 @@ internal object RepositoryManager {
fun List<String>.forEachParams(size: Int, result: (List<String>) -> Unit) = forEach {
result(it.split(":").also { e -> if (e.size != size) SError.make("Missing argument in content configuration") })
}
/**
* 对旧版本不兼容的方法打印警告信息
* @param name 方法名称
*/
fun warnIfNotSupport(name: String) = SLog.warn("Current Gradle ${GradleHelper.version} not support \"$name\"")
document.content.exclude.also {
it.group().noEmpty()?.forEach { e -> excludeGroup(e) }
it.groupAndSubgroups().noEmpty()?.forEach { e -> excludeGroupAndSubgroups(e) }
runCatching {
it.groupAndSubgroups().noEmpty()?.forEach { e -> excludeGroupAndSubgroups(e) }
}.onFailure { warnIfNotSupport(name = "excludeGroupAndSubgroups") }
it.groupByRegex().noEmpty()?.forEach { e -> excludeGroupByRegex(e) }
it.module().noEmpty()?.forEachParams(size = 2) { e -> excludeModule(e[0], e[1]) }
it.moduleByRegex().noEmpty()?.forEachParams(size = 2) { e -> excludeModuleByRegex(e[0], e[1]) }
@@ -111,7 +120,9 @@ internal object RepositoryManager {
}
document.content.include.also {
it.group().noEmpty()?.forEach { e -> includeGroup(e) }
it.groupAndSubgroups().noEmpty()?.forEach { e -> includeGroupAndSubgroups(e) }
runCatching {
it.groupAndSubgroups().noEmpty()?.forEach { e -> includeGroupAndSubgroups(e) }
}.onFailure { warnIfNotSupport(name = "includeGroupAndSubgroups") }
it.groupByRegex().noEmpty()?.forEach { e -> includeGroupByRegex(e) }
it.module().noEmpty()?.forEachParams(size = 2) { e -> includeModule(e[0], e[1]) }
it.moduleByRegex().noEmpty()?.forEachParams(size = 2) { e -> includeModuleByRegex(e[0], e[1]) }

View File

@@ -26,6 +26,7 @@ import com.highcapable.sweetdependency.environment.Environment
import com.highcapable.sweetdependency.generated.SweetDependencyProperties
import com.highcapable.sweetdependency.gradle.delegate.ProjectTransaction
import com.highcapable.sweetdependency.gradle.delegate.entity.ExternalDependencyDelegate
import com.highcapable.sweetdependency.gradle.entity.DependencyVersion
import com.highcapable.sweetdependency.gradle.factory.addDependencyToBuildScript
import com.highcapable.sweetdependency.gradle.factory.applyPlugin
import com.highcapable.sweetdependency.gradle.factory.getOrCreate
@@ -79,6 +80,25 @@ internal object DependencyDeployHelper {
runCatching {
settings.dependencyResolutionManagement.versionCatalogs.create(pluginsNamespace) {
Dependencies.plugins().forEach { (dependencyName, artifact) ->
if (GradleTaskManager.isInternalRunningTask && artifact.version().isAutowire) SError.make(
"""
It looks like now you directly execute ${SweetDependency.TAG}'s autowiring related Gradle task
Since this plugin "$dependencyName" that set "${DependencyVersion.AUTOWIRE_VERSION_NAME}" as the version,
you now need to ensure that the version exists during the initialization phase
The version catalogs rules require that a plugin version must be declared
You can try the following solutions to resolve this problem:
1. Manually re-run Gradle Sync
Make sure "autowire-on-sync-mode" is one of:
- UPDATE_OPTIONAL_DEPENDENCIES
- UPDATE_OPTIONAL_PLUGINS
- UPDATE_ALL_DEPENDENCIES
- UPDATE_ALL_PLUGINS
- ONLY_AUTOWIRE_DEPENDENCIES
- ONLY_AUTOWIRE_PLUGINS
2. Fill an existing version for plugin "$dependencyName" and re-run Gradle Sync
If you get this error again after doing the above, maybe the currently set repositories cannot find this plugin
""".trimIndent()
)
if (artifact.version().isNoSpecific) return@forEach SLog.warn(
"""
You must specific a version for plugin "$dependencyName" or use Gradle's internal plugin function instead it
@@ -98,13 +118,13 @@ internal object DependencyDeployHelper {
""".trimIndent()
)
val deployedName = dependencyName.ambiguousName(symbol = "-", isReplaceFirstChar = true, isLowerCase = false)
plugin(deployedName, dependencyName.current).version(artifact.version().deployed)
plugin(deployedName, dependencyName.current).version(artifact.version().fixed)
artifact.versions().forEach { (name, version) ->
plugin("$deployedName-${name.camelcase()}", dependencyName.current).version(version.deployed)
plugin("$deployedName-${name.camelcase()}", dependencyName.current).version(version.fixed)
if (artifact.alias.isNotBlank())
plugin("${artifact.alias}-${name.camelcase()}", dependencyName.current).version(version.deployed)
plugin("${artifact.alias}-${name.camelcase()}", dependencyName.current).version(version.fixed)
}
if (artifact.alias.isNotBlank()) plugin(artifact.alias, dependencyName.current).version(artifact.version().deployed)
if (artifact.alias.isNotBlank()) plugin(artifact.alias, dependencyName.current).version(artifact.version().fixed)
}
}
}.onFailure {
@@ -120,7 +140,7 @@ internal object DependencyDeployHelper {
* @param rootProject 当前根项目
*/
internal fun resolveAccessors(rootProject: Project) {
if (Dependencies.isOutdate || accessorsDir.isEmpty())
if (Dependencies.isOutdate || accessorsDir.resolve(accessorsPomData.relativePomPath).isEmpty())
accessorsGenerator.build().compile(accessorsPomData, accessorsDir.absolutePath, accessorsGenerator.compileStubFiles)
rootProject.addDependencyToBuildScript(accessorsDir.absolutePath, accessorsPomData)
}
@@ -132,7 +152,14 @@ internal object DependencyDeployHelper {
*/
internal fun deployAccessors(project: Project, extension: ExtensionAware) =
accessorsGenerator.librariesClasses.forEach { (name, className) ->
extension.getOrCreate(name, project.loadBuildScriptClass(className))
val accessorsClass = project.loadBuildScriptClass(className) ?: SError.make(
"""
Generated class "$className" not found, stop loading $project
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()
)
extension.getOrCreate(name, accessorsClass)
}
/**

View File

@@ -21,15 +21,13 @@
*/
package com.highcapable.sweetdependency.utils.code
import com.highcapable.sweetdependency.plugin.SweetDependencyExtension
import com.highcapable.sweetdependency.utils.code.entity.MavenPomData
import com.highcapable.sweetdependency.utils.debug.SError
import com.highcapable.sweetdependency.utils.deleteEmptyRecursively
import com.highcapable.sweetdependency.utils.parseFileSeparator
import com.highcapable.sweetdependency.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
@@ -49,7 +47,7 @@ internal object CodeCompiler {
* @param outputDirPath 编译输出目录路径
* @param files [JavaFileObject] 数组
* @param compileOnlyFiles [JavaFileObject] 仅编译数组 - 默认空
* @throws SweetDependencyExtension 如果编译失败
* @throws IllegalStateException 如果编译失败
*/
internal fun compile(
pomData: MavenPomData,
@@ -85,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")
}
@@ -100,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
@@ -138,12 +135,6 @@ internal object CodeCompiler {
""".trimIndent()
)
/**
* 转换到 [MavenPomData] 目录名称
* @return [String]
*/
private fun String.toPomPathName() = trim().replace(".", "/").replace("_", "/").replace(":", "/").replace("-", "/")
/**
* 转换到文件
* @param outputDir 输出目录
@@ -164,30 +155,12 @@ internal object CodeCompiler {
* @param outputDir 输出目录
* @param pomData Maven POM 实体
* @param isSourcesJar 是否为源码 JAR
* @throws SweetDependencyExtension 如果编译输出目录不存在
* @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}")
/**
* 添加文件到 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.sweetdependency.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("-", "/")
}