mirror of
https://github.com/HighCapable/SweetDependency.git
synced 2025-09-07 11:10:17 +08:00
Initial commit
This commit is contained in:
@@ -0,0 +1,335 @@
|
||||
/*
|
||||
* SweetDependency - An easy autowire and manage dependencies Gradle plugin
|
||||
* Copyright (C) 2019-2023 HighCapable
|
||||
* https://github.com/HighCapable/SweetDependency
|
||||
*
|
||||
* Apache License Version 2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* This file is Created by fankes on 2023/5/16.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.manager
|
||||
|
||||
import com.highcapable.sweetdependency.SweetDependency
|
||||
import com.highcapable.sweetdependency.document.PreferencesDocument
|
||||
import com.highcapable.sweetdependency.document.VersionFilterDocument
|
||||
import com.highcapable.sweetdependency.document.factory.DependenciesCondition
|
||||
import com.highcapable.sweetdependency.document.factory.DependencyMap
|
||||
import com.highcapable.sweetdependency.document.factory.RepositoryList
|
||||
import com.highcapable.sweetdependency.gradle.entity.DependencyName
|
||||
import com.highcapable.sweetdependency.gradle.entity.DependencyUpdateMode
|
||||
import com.highcapable.sweetdependency.gradle.entity.DependencyVersion
|
||||
import com.highcapable.sweetdependency.gradle.factory.get
|
||||
import com.highcapable.sweetdependency.gradle.factory.getOrCreate
|
||||
import com.highcapable.sweetdependency.gradle.factory.waitForPluginAdded
|
||||
import com.highcapable.sweetdependency.gradle.helper.GradleHelper
|
||||
import com.highcapable.sweetdependency.manager.content.Dependencies
|
||||
import com.highcapable.sweetdependency.manager.content.Repositories
|
||||
import com.highcapable.sweetdependency.manager.helper.DependencyAutowireLogHelper
|
||||
import com.highcapable.sweetdependency.manager.helper.DependencyDeployHelper
|
||||
import com.highcapable.sweetdependency.manager.maven.MavenParser
|
||||
import com.highcapable.sweetdependency.manager.maven.entity.MavenMetadata
|
||||
import com.highcapable.sweetdependency.plugin.config.content.SweetDependencyConfigs
|
||||
import com.highcapable.sweetdependency.plugin.extension.dsl.manager.SweetDependencyAutowireExtension
|
||||
import com.highcapable.sweetdependency.utils.debug.SLog
|
||||
import com.highcapable.sweetdependency.utils.noEmpty
|
||||
import com.highcapable.sweetdependency.utils.single
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.initialization.Settings
|
||||
import org.gradle.api.plugins.ExtensionAware
|
||||
|
||||
/**
|
||||
* 依赖部署、自动装配、更新管理类
|
||||
*/
|
||||
internal object DependencyManager {
|
||||
|
||||
/** 生成并应用依赖数组 */
|
||||
internal fun generateAndApply() {
|
||||
Dependencies.generate(SweetDependencyConfigs.document.plugins(), SweetDependencyConfigs.document.libraries())
|
||||
val pluginsSize = Dependencies.plugins().size
|
||||
val librariesSize = Dependencies.libraries().size
|
||||
if (Dependencies.isNotEmpty()) SLog.verbose(
|
||||
"${SweetDependency.TAG} help you autowired ${pluginsSize + librariesSize} dependencies" +
|
||||
" (plugins: $pluginsSize, libraries: $librariesSize)", SLog.STRNG
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成并应用依赖数组
|
||||
* @param settings 当前设置
|
||||
*/
|
||||
internal fun generateAndApply(settings: Settings) {
|
||||
val isDisableOnSync = SweetDependencyConfigs.document.preferences().autowireOnSyncMode == PreferencesDocument.AutowireOnSyncMode.OFF
|
||||
var requiresAutowiringLibrariesSize = 0
|
||||
Dependencies.all().forEach { (_, artifact) -> if (artifact.version().isAutowire) requiresAutowiringLibrariesSize++ }
|
||||
if (requiresAutowiringLibrariesSize > 0 && GradleHelper.isSyncMode && isDisableOnSync) SLog.warn(
|
||||
"Found $requiresAutowiringLibrariesSize dependencies need to be autowired, " +
|
||||
"please manually run \"${GradleTaskManager.AUTOWIRE_DEPENDENCIES_TASK_NAME}\" task and re-run Gradle Sync"
|
||||
)
|
||||
DependencyDeployHelper.generateVersionCatalogs(settings)
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化库依赖可访问类
|
||||
* @param rootProject 当前根项目
|
||||
*/
|
||||
internal fun resolve(rootProject: Project) = DependencyDeployHelper.resolveAccessors(rootProject)
|
||||
|
||||
/**
|
||||
* 部署依赖
|
||||
* @param rootProject 当前根项目
|
||||
*/
|
||||
internal fun deploy(rootProject: Project) {
|
||||
/**
|
||||
* 为 Groovy 创建扩展方法
|
||||
* @param extension 当前扩展实例
|
||||
*/
|
||||
fun Project.deployForGroovy(extension: ExtensionAware) {
|
||||
if (buildFile.name.endsWith(".gradle"))
|
||||
extension.getOrCreate<SweetDependencyAutowireExtension>(SweetDependencyAutowireExtension.NAME, this)
|
||||
}
|
||||
|
||||
/**
|
||||
* 部署到当前项目
|
||||
* @param extension 当前扩展实例
|
||||
*/
|
||||
fun Project.deployEach(extension: ExtensionAware) = DependencyDeployHelper.deployAccessors(project = this, extension)
|
||||
|
||||
/** 适配 Kotlin Multiplatform */
|
||||
fun Project.deployForKotlinMultiplatform() =
|
||||
waitForPluginAdded("org.jetbrains.kotlin.multiplatform") {
|
||||
get("kotlin").also { extension ->
|
||||
deployForGroovy(extension)
|
||||
deployEach(extension)
|
||||
}
|
||||
}
|
||||
|
||||
/** 部署到当前项目 */
|
||||
fun Project.deploy() {
|
||||
deployForGroovy(dependencies)
|
||||
deployEach(dependencies)
|
||||
deployForKotlinMultiplatform()
|
||||
}
|
||||
rootProject.deploy()
|
||||
rootProject.subprojects.forEach { it.deploy() }
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动装配、更新依赖
|
||||
* @param updateMode 更新模式
|
||||
* @param isRunningOnSync 是否在 Gradle Sync 时运行 - 默认是
|
||||
*/
|
||||
internal fun autowireAndUpdate(updateMode: DependencyUpdateMode, isRunningOnSync: Boolean = true) {
|
||||
/**
|
||||
* 在适当时候打印 Log
|
||||
* @param msg 消息内容
|
||||
* @param symbol 前缀符号
|
||||
*/
|
||||
fun logIfNeeded(msg: String, symbol: String) = if (isRunningOnSync) SLog.verbose(msg, symbol) else SLog.info(msg, symbol)
|
||||
|
||||
/**
|
||||
* 通过指定类型和条件查找依赖数组
|
||||
* @param condition 条件方法体
|
||||
* @return [DependencyMap]
|
||||
*/
|
||||
fun findByType(condition: DependenciesCondition) = when (updateMode.dependencyType) {
|
||||
DependencyUpdateMode.DependencyType.ALL -> Dependencies.findAll(condition)
|
||||
DependencyUpdateMode.DependencyType.PLUGINS -> Dependencies.findPlugins(condition)
|
||||
DependencyUpdateMode.DependencyType.LIBRARIES -> Dependencies.findLibraries(condition)
|
||||
}
|
||||
if (Repositories.isEmpty()) return SLog.warn(
|
||||
"""
|
||||
Repositories is empty, ${SweetDependency.TAG} will stop auto update dependencies
|
||||
This will cause Gradle fail to load dependencies, you must add some repositories and enable them
|
||||
""".trimIndent()
|
||||
)
|
||||
if (GradleHelper.isOfflineMode) SLog.warn("Gradle is in offline mode, some dependencies on online repositories will be ignored")
|
||||
val isOnlyAutowireMode = updateMode.updateType == DependencyUpdateMode.UpdateType.ONLY_AUTOWIRE
|
||||
var currentIndex = 0
|
||||
var updPluginsCount = 0
|
||||
var updLbrariesCount = 0
|
||||
val needUpdateDependencies = mutableMapOf<String, Pair<DependencyName, DependencyVersion>>()
|
||||
findByType { _, artifact ->
|
||||
artifact.version().isNoSpecific.not() && (artifact.versionRef.isBlank() &&
|
||||
((updateMode.updateType == DependencyUpdateMode.UpdateType.UPDATE_ALL ||
|
||||
(updateMode.updateType == DependencyUpdateMode.UpdateType.UPDATE_OPTIONAL &&
|
||||
(artifact.version().isOptional || artifact.version().isAutowire)) ||
|
||||
(updateMode.updateType == DependencyUpdateMode.UpdateType.ONLY_AUTOWIRE && artifact.version().isAutowire))))
|
||||
}.apply {
|
||||
if (isNotEmpty()) SLog.info("Starting ${when (updateMode.updateType) {
|
||||
DependencyUpdateMode.UpdateType.UPDATE_OPTIONAL -> "autowire and update $size optional dependencies"
|
||||
DependencyUpdateMode.UpdateType.UPDATE_ALL -> "autowire and update all $size dependencies"
|
||||
DependencyUpdateMode.UpdateType.ONLY_AUTOWIRE -> "autowire $size dependencies"
|
||||
}}", SLog.ANLZE)
|
||||
forEach { (dependencyName, artifact) ->
|
||||
val versionFilterExclusionList = artifact.versionFilter?.exclusionList()
|
||||
?: SweetDependencyConfigs.document.preferences().versionFilter.exclusionList()
|
||||
fetchUpdate(
|
||||
positionTagName = "${++currentIndex}/$size",
|
||||
dependencyName = dependencyName,
|
||||
currentVersion = artifact.version(),
|
||||
alternateVersions = artifact.versions().values.toMutableList(),
|
||||
isAutoUpdate = artifact.isAutoUpdate,
|
||||
versionFilterExclusionList = versionFilterExclusionList,
|
||||
repositories = artifact.repositories()
|
||||
) { newVersion ->
|
||||
DependencyAutowireLogHelper.record(dependencyName, artifact.version(), newVersion)
|
||||
artifact.updateVersion(newVersion)
|
||||
needUpdateDependencies[dependencyName.current] = dependencyName to newVersion
|
||||
when (dependencyName.type) {
|
||||
DependencyName.Type.PLUGIN -> updPluginsCount++
|
||||
DependencyName.Type.LIBRARY -> updLbrariesCount++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/** 找出所有版本引用依赖 - 为其设置版本 */
|
||||
needUpdateDependencies.forEach { (notation, dependencyData) ->
|
||||
val alias = findByType { key, _ -> dependencyData.first == key }.single()?.value?.alias ?: ""
|
||||
findByType { _, artifact ->
|
||||
artifact.versionRef.isNotBlank() && (artifact.versionRef == notation || artifact.versionRef == alias)
|
||||
}.forEach { (dependencyName, artifact) ->
|
||||
artifact.updateVersion(dependencyData.second)
|
||||
SLog.info("Link ${dependencyName.description} to ${dependencyData.first.description} version ${dependencyData.second}", SLog.LINK)
|
||||
}
|
||||
}
|
||||
if (needUpdateDependencies.isNotEmpty()) {
|
||||
SLog.info(
|
||||
(if (isOnlyAutowireMode) "Autowired" else "Autowired and updated") +
|
||||
" ${needUpdateDependencies.size} dependencies (plugins: $updPluginsCount, libraries: $updLbrariesCount)", SLog.DONE
|
||||
)
|
||||
if (SweetDependencyConfigs.configs.isEnableDependenciesAutowireLog)
|
||||
logIfNeeded(msg = "Autowiring logs have been automatically written to: ${DependencyAutowireLogHelper.logFile}", SLog.LINK)
|
||||
SweetDependencyConfigs.documentMapping.updateDependencies(needUpdateDependencies)
|
||||
if (isRunningOnSync.not()) SLog.warn(
|
||||
"""
|
||||
**************************** NOTICE ****************************
|
||||
${needUpdateDependencies.size} dependencies (plugins: $updPluginsCount, libraries: $updLbrariesCount) has been changed
|
||||
You must to manually re-run Gradle Sync to apply those changes
|
||||
**************************** NOTICE ****************************
|
||||
""".trimIndent(), noTag = true
|
||||
)
|
||||
Dependencies.refreshState(isOutdate = true)
|
||||
} else logIfNeeded(msg = "No dependencies need to ${if (isOnlyAutowireMode) "autowire" else "autowire and update"}", SLog.DONE)
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动装配或更新当前依赖
|
||||
* @param positionTagName 当前位置标签名称
|
||||
* @param dependencyName 依赖名称
|
||||
* @param currentVersion 当前依赖版本
|
||||
* @param alternateVersions 备选依赖版本数组
|
||||
* @param isAutoUpdate 是否自动更新
|
||||
* @param versionFilterExclusionList 版本管理器排除列表
|
||||
* @param repositories 使用的存储库数组
|
||||
* @param result 回调新版本
|
||||
*/
|
||||
private inline fun fetchUpdate(
|
||||
positionTagName: String,
|
||||
dependencyName: DependencyName,
|
||||
currentVersion: DependencyVersion,
|
||||
alternateVersions: MutableList<DependencyVersion>,
|
||||
isAutoUpdate: Boolean,
|
||||
versionFilterExclusionList: VersionFilterDocument.ExclusionList,
|
||||
repositories: RepositoryList,
|
||||
result: (newVersion: DependencyVersion) -> Unit
|
||||
) {
|
||||
val poms = mutableListOf<MavenMetadata>()
|
||||
val headerInfo = if (GradleHelper.isOfflineMode) "$positionTagName > OFFLINE" else "$positionTagName > NOT-FOUND"
|
||||
val displayInfo = "${dependencyName.description} ${currentVersion.let{ if (it.isAutowire) "" else "version $it" }}"
|
||||
(repositories.noEmpty() ?: Repositories.all()).apply {
|
||||
forEachIndexed { index, entry ->
|
||||
val currentVersionFilterExclusionList = versionFilterExclusionList.depends(currentVersion)
|
||||
val availableVersions = mutableListOf<DependencyVersion>()
|
||||
poms.add(MavenParser.acquire(dependencyName, entry, currentVersion))
|
||||
if (index == lastIndex) poms.noEmpty()
|
||||
?.sortedByDescending { it.lastUpdated }
|
||||
?.let { if (it.all { e -> e.lastUpdated <= 0L }) it.sortedByDescending { e -> e.versions.size } else it }
|
||||
?.filter { it.versions.isNotEmpty() }
|
||||
?.let { linkedSetOf<DependencyVersion>().apply { it.forEach { entity -> addAll(entity.versions) } }.toMutableList() }
|
||||
?.let { availableVersions.addAll(it); currentVersionFilterExclusionList.filter(it) }
|
||||
?.also {
|
||||
if (currentVersionFilterExclusionList.isNotEmpty() && availableVersions.isNotEmpty() && it.isEmpty()) SLog.warn(
|
||||
"""
|
||||
${dependencyName.description} available versions exclusion to nothing by version filter
|
||||
All available versions have been filtered, if this is wrong, please reconfigure your version filter
|
||||
You can disable internal version filter like following:
|
||||
""".trimIndent() + "\n" + when (dependencyName.type) {
|
||||
DependencyName.Type.PLUGIN -> """
|
||||
${dependencyName.groupId}:
|
||||
version-filter:
|
||||
use-internal: false
|
||||
...
|
||||
""".trimIndent()
|
||||
DependencyName.Type.LIBRARY -> """
|
||||
${dependencyName.groupId}:
|
||||
${dependencyName.artifactId}:
|
||||
version-filter:
|
||||
use-internal: false
|
||||
...
|
||||
""".trimIndent()
|
||||
} + "\n" + """
|
||||
Available versions: $availableVersions
|
||||
Version filter: $currentVersionFilterExclusionList
|
||||
""".trimIndent()
|
||||
)
|
||||
}?.noEmpty()?.also { versions ->
|
||||
resolveEachUpdate(
|
||||
positionTagName, dependencyName, versions, currentVersion,
|
||||
versions.first(), alternateVersions, isAutoUpdate, result
|
||||
)
|
||||
} ?: if (GradleHelper.isOfflineMode) SLog.warn("$headerInfo $displayInfo") else SLog.error("$headerInfo $displayInfo")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动装配或更新每项依赖
|
||||
* @param positionTagName 当前位置标签名称
|
||||
* @param dependencyName 依赖名称
|
||||
* @param versions 全部可用依赖版本数组
|
||||
* @param currentVersion 当前依赖版本
|
||||
* @param latestVersion 最新依赖版本
|
||||
* @param alternateVersions 备选依赖版本数组
|
||||
* @param isAutoUpdate 是否自动更新
|
||||
* @param result 回调新版本
|
||||
*/
|
||||
private inline fun resolveEachUpdate(
|
||||
positionTagName: String,
|
||||
dependencyName: DependencyName,
|
||||
versions: MutableList<DependencyVersion>,
|
||||
currentVersion: DependencyVersion,
|
||||
latestVersion: DependencyVersion,
|
||||
alternateVersions: MutableList<DependencyVersion>,
|
||||
isAutoUpdate: Boolean,
|
||||
result: (newVersion: DependencyVersion) -> Unit
|
||||
) = when {
|
||||
currentVersion.isAutowire.not() && versions.contains(currentVersion).not() ->
|
||||
SLog.warn("$positionTagName > MISSING ${dependencyName.description} version $currentVersion, available are $versions")
|
||||
currentVersion.isAutowire.not() && alternateVersions.isNotEmpty() && alternateVersions.all { versions.contains(it) }.not() ->
|
||||
SLog.warn("$positionTagName > MISSING ${dependencyName.description} version alias $alternateVersions, available are $versions")
|
||||
latestVersion != currentVersion -> when {
|
||||
currentVersion.isAutowire -> {
|
||||
SLog.info("$positionTagName > AUTOWIRE ${dependencyName.description} version $latestVersion", SLog.WIRE)
|
||||
result(latestVersion)
|
||||
}
|
||||
isAutoUpdate -> {
|
||||
SLog.info("$positionTagName > AUTO-UPDATE ${dependencyName.description} version $currentVersion -> $latestVersion", SLog.UP)
|
||||
result(latestVersion)
|
||||
}
|
||||
else -> SLog.note("$positionTagName > UPDATE-AVAILABLE ${dependencyName.description} version $currentVersion -> $latestVersion", SLog.ROTATE)
|
||||
}
|
||||
else -> SLog.info("$positionTagName > UP-TO-DATE ${dependencyName.description} version $currentVersion", SLog.DONE)
|
||||
}
|
||||
}
|
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* SweetDependency - An easy autowire and manage dependencies Gradle plugin
|
||||
* Copyright (C) 2019-2023 HighCapable
|
||||
* https://github.com/HighCapable/SweetDependency
|
||||
*
|
||||
* Apache License Version 2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* This file is Created by fankes on 2023/6/29.
|
||||
*/
|
||||
@file:Suppress("MemberVisibilityCanBePrivate")
|
||||
|
||||
package com.highcapable.sweetdependency.manager
|
||||
|
||||
import com.highcapable.sweetdependency.SweetDependency
|
||||
import com.highcapable.sweetdependency.generated.SweetDependencyProperties
|
||||
import com.highcapable.sweetdependency.gradle.factory.createTask
|
||||
import com.highcapable.sweetdependency.gradle.helper.GradleHelper
|
||||
import com.highcapable.sweetdependency.plugin.task.AutowireDependenciesTask
|
||||
import com.highcapable.sweetdependency.plugin.task.AutowireLibrariesTask
|
||||
import com.highcapable.sweetdependency.plugin.task.AutowirePluginsTask
|
||||
import com.highcapable.sweetdependency.plugin.task.CreateDependenciesMigrationTemplateTask
|
||||
import com.highcapable.sweetdependency.plugin.task.SweetDependencyDebugTask
|
||||
import com.highcapable.sweetdependency.plugin.task.UpdateAllDependenciesTask
|
||||
import com.highcapable.sweetdependency.plugin.task.UpdateAllLibrariesTask
|
||||
import com.highcapable.sweetdependency.plugin.task.UpdateAllPluginsTask
|
||||
import com.highcapable.sweetdependency.plugin.task.UpdateOptionalDependenciesTask
|
||||
import com.highcapable.sweetdependency.plugin.task.UpdateOptionalLibrariesTask
|
||||
import com.highcapable.sweetdependency.plugin.task.UpdateOptionalPluginsTask
|
||||
import org.gradle.api.Project
|
||||
|
||||
/**
|
||||
* Gradle Task 管理类
|
||||
*/
|
||||
internal object GradleTaskManager {
|
||||
|
||||
/** Gradle Task 分组名称 */
|
||||
internal const val TASK_GROUP_NAME = SweetDependencyProperties.PROJECT_MODULE_NAME
|
||||
|
||||
/** 创建依赖迁移模板 Gradle Task 名称 */
|
||||
internal const val CREATE_DEPENDENCIES_MIGRATION_TEMPLATE_TASK_NAME = "createDependenciesMigrationTemplate"
|
||||
|
||||
/** 依赖自动装配、更新 (可选) (插件依赖 + 库依赖) Gradle Task 名称 */
|
||||
internal const val UPDATE_OPTIONAL_DEPENDENCIES_TASK_NAME = "updateOptionalDependencies"
|
||||
|
||||
/** 依赖自动装配、更新 (全部) (插件依赖 + 库依赖) Gradle Task 名称 */
|
||||
internal const val UPDATE_ALL_DEPENDENCIES_TASK_NAME = "updateAllDependencies"
|
||||
|
||||
/** 依赖自动装配 (插件依赖 + 库依赖) Gradle Task 名称 */
|
||||
internal const val AUTOWIRE_DEPENDENCIES_TASK_NAME = "autowireDependencies"
|
||||
|
||||
/** 依赖自动装配、更新 (可选) (插件依赖) Gradle Task 名称 */
|
||||
internal const val UPDATE_OPTIONAL_PLUGINS_TASK_NAME = "updateOptionalPlugins"
|
||||
|
||||
/** 依赖自动装配、更新 (全部) (插件依赖) Gradle Task 名称 */
|
||||
internal const val UPDATE_ALL_PLUGINS_TASK_NAME = "updateAllPlugins"
|
||||
|
||||
/** 插件依赖自动装配 (插件依赖) Gradle Task 名称 */
|
||||
internal const val AUTOWIRE_PLUGINS_TASK_NAME = "autowirePlugins"
|
||||
|
||||
/** 依赖自动装配、更新 (可选) (库依赖) Gradle Task 名称 */
|
||||
internal const val UPDATE_OPTIONAL_LIBRARIES_TASK_NAME = "updateOptionalLibraries"
|
||||
|
||||
/** 依赖自动装配、更新 (全部) (库依赖) Gradle Task 名称 */
|
||||
internal const val UPDATE_ALL_LIBRARIES_TASK_NAME = "updateAllLibraries"
|
||||
|
||||
/** 依赖自动装配 (库依赖) Gradle Task 名称 */
|
||||
internal const val AUTOWIRE_LIBRARIES_TASK_NAME = "autowireLibraries"
|
||||
|
||||
/** 调试 Gradle Task 名称 */
|
||||
internal const val SWEET_DEPENDENCY_DEBUG_TASK_NAME = "sweetDependencyDebug"
|
||||
|
||||
/**
|
||||
* 当前正在运行的是否为 [SweetDependency] 内部 Gradle Task
|
||||
* @return [Boolean]
|
||||
*/
|
||||
internal val isInternalRunningTask
|
||||
get() = GradleHelper.runningTaskNames.orEmpty().any {
|
||||
it == CREATE_DEPENDENCIES_MIGRATION_TEMPLATE_TASK_NAME ||
|
||||
it == UPDATE_OPTIONAL_DEPENDENCIES_TASK_NAME ||
|
||||
it == UPDATE_ALL_DEPENDENCIES_TASK_NAME ||
|
||||
it == AUTOWIRE_DEPENDENCIES_TASK_NAME ||
|
||||
it == UPDATE_OPTIONAL_PLUGINS_TASK_NAME ||
|
||||
it == UPDATE_ALL_PLUGINS_TASK_NAME ||
|
||||
it == AUTOWIRE_PLUGINS_TASK_NAME ||
|
||||
it == UPDATE_OPTIONAL_LIBRARIES_TASK_NAME ||
|
||||
it == UPDATE_ALL_LIBRARIES_TASK_NAME ||
|
||||
it == AUTOWIRE_LIBRARIES_TASK_NAME ||
|
||||
it == SWEET_DEPENDENCY_DEBUG_TASK_NAME
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册 [SweetDependency] 全部 Gradle Task
|
||||
* @param rootProject 根项目
|
||||
*/
|
||||
internal fun register(rootProject: Project) {
|
||||
rootProject.createTask<CreateDependenciesMigrationTemplateTask>(TASK_GROUP_NAME, CREATE_DEPENDENCIES_MIGRATION_TEMPLATE_TASK_NAME)
|
||||
rootProject.createTask<UpdateOptionalDependenciesTask>(TASK_GROUP_NAME, UPDATE_OPTIONAL_DEPENDENCIES_TASK_NAME)
|
||||
rootProject.createTask<UpdateAllDependenciesTask>(TASK_GROUP_NAME, UPDATE_ALL_DEPENDENCIES_TASK_NAME)
|
||||
rootProject.createTask<AutowireDependenciesTask>(TASK_GROUP_NAME, AUTOWIRE_DEPENDENCIES_TASK_NAME)
|
||||
rootProject.createTask<UpdateOptionalPluginsTask>(TASK_GROUP_NAME, UPDATE_OPTIONAL_PLUGINS_TASK_NAME)
|
||||
rootProject.createTask<UpdateAllPluginsTask>(TASK_GROUP_NAME, UPDATE_ALL_PLUGINS_TASK_NAME)
|
||||
rootProject.createTask<AutowirePluginsTask>(TASK_GROUP_NAME, AUTOWIRE_PLUGINS_TASK_NAME)
|
||||
rootProject.createTask<UpdateOptionalLibrariesTask>(TASK_GROUP_NAME, UPDATE_OPTIONAL_LIBRARIES_TASK_NAME)
|
||||
rootProject.createTask<UpdateAllLibrariesTask>(TASK_GROUP_NAME, UPDATE_ALL_LIBRARIES_TASK_NAME)
|
||||
rootProject.createTask<AutowireLibrariesTask>(TASK_GROUP_NAME, AUTOWIRE_LIBRARIES_TASK_NAME)
|
||||
rootProject.createTask<SweetDependencyDebugTask>(TASK_GROUP_NAME, SWEET_DEPENDENCY_DEBUG_TASK_NAME)
|
||||
}
|
||||
}
|
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* SweetDependency - An easy autowire and manage dependencies Gradle plugin
|
||||
* Copyright (C) 2019-2023 HighCapable
|
||||
* https://github.com/HighCapable/SweetDependency
|
||||
*
|
||||
* Apache License Version 2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* This file is Created by fankes on 2023/6/6.
|
||||
*/
|
||||
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.manager.const.AdditionalRepositories
|
||||
import com.highcapable.sweetdependency.manager.content.Repositories
|
||||
import com.highcapable.sweetdependency.plugin.config.content.SweetDependencyConfigs
|
||||
import com.highcapable.sweetdependency.utils.debug.SError
|
||||
import com.highcapable.sweetdependency.utils.debug.SLog
|
||||
import com.highcapable.sweetdependency.utils.noBlank
|
||||
import com.highcapable.sweetdependency.utils.noEmpty
|
||||
import com.highcapable.sweetdependency.utils.toFile
|
||||
import org.gradle.api.artifacts.dsl.RepositoryHandler
|
||||
import org.gradle.api.artifacts.repositories.ArtifactRepository
|
||||
import org.gradle.api.artifacts.repositories.AuthenticationSupported
|
||||
import org.gradle.api.artifacts.repositories.UrlArtifactRepository
|
||||
import org.gradle.api.initialization.Settings
|
||||
import java.net.URI
|
||||
import org.gradle.api.initialization.resolve.RepositoriesMode as GradleRepositoriesMode
|
||||
|
||||
/**
|
||||
* 存储库装配管理类
|
||||
*/
|
||||
internal object RepositoryManager {
|
||||
|
||||
/**
|
||||
* 生成并应用存储库数组
|
||||
* @param settings 当前设置
|
||||
*/
|
||||
internal fun generateAndApply(settings: Settings) {
|
||||
val repositories = SweetDependencyConfigs.document.repositories()
|
||||
Repositories.generate(repositories)
|
||||
/**
|
||||
* 应用存储库数组到 Gradle
|
||||
* @param isPlugins 当前应用类型是否为插件依赖
|
||||
*/
|
||||
fun RepositoryHandler.apply(isPlugins: Boolean) = repositories.forEach {
|
||||
if (it.isIncludeScope(isPlugins)) when (it.nodeType) {
|
||||
RepositoryDocument.RepositoryType.GOOGLE -> google { applyToArtifact(it) }
|
||||
RepositoryDocument.RepositoryType.MAVEN_CENTRAL -> mavenCentral { applyToArtifact(it) }
|
||||
RepositoryDocument.RepositoryType.MAVEN_LOCAL -> mavenLocal { applyToArtifact(it) }
|
||||
RepositoryDocument.RepositoryType.MAVEN -> maven { applyToArtifact(it) }
|
||||
RepositoryDocument.RepositoryType.GRADLE_PLUGIN_PORTAL -> gradlePluginPortal { applyToArtifact(it) }
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
settings.pluginManagement {
|
||||
this.repositories.clear()
|
||||
this.repositories.apply(isPlugins = true)
|
||||
}
|
||||
settings.dependencyResolutionManagement {
|
||||
this.repositoriesMode.set(when (SweetDependencyConfigs.document.preferences().repositoriesMode) {
|
||||
PreferencesDocument.RepositoriesMode.PREFER_PROJECT -> GradleRepositoriesMode.PREFER_PROJECT
|
||||
PreferencesDocument.RepositoriesMode.PREFER_SETTINGS -> GradleRepositoriesMode.PREFER_SETTINGS
|
||||
PreferencesDocument.RepositoriesMode.FAIL_ON_PROJECT_REPOS -> GradleRepositoriesMode.FAIL_ON_PROJECT_REPOS
|
||||
})
|
||||
this.repositories.clear()
|
||||
this.repositories.apply(isPlugins = false)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用存储库到 [ArtifactRepository]
|
||||
* @param document 存储库配置项文档实体
|
||||
*/
|
||||
private fun ArtifactRepository.applyToArtifact(document: RepositoryDocument) {
|
||||
document.nodeName.noBlank()?.also { docName -> this.name = docName }
|
||||
if (this is AuthenticationSupported && document.credentials.let { it.username.isNotBlank() || it.password.isNotBlank() })
|
||||
credentials { this.username = document.credentials.username; this.password = document.credentials.password }
|
||||
if (document.content.isEmpty().not()) content {
|
||||
/**
|
||||
* 使用 ":" 分割字符串
|
||||
* @param size 期望的个数
|
||||
* @param result 回调每项
|
||||
* @return [List]<[String]>
|
||||
* @throws SweetDependencyUnresolvedException 如果 [size] 不是期望的个数
|
||||
*/
|
||||
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") })
|
||||
}
|
||||
document.content.exclude.also {
|
||||
it.group().noEmpty()?.forEach { e -> excludeGroup(e) }
|
||||
it.groupAndSubgroups().noEmpty()?.forEach { e -> excludeGroupAndSubgroups(e) }
|
||||
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]) }
|
||||
it.version().noEmpty()?.forEachParams(size = 3) { e -> excludeVersion(e[0], e[1], e[2]) }
|
||||
it.versionByRegex().noEmpty()?.forEachParams(size = 3) { e -> excludeVersionByRegex(e[0], e[1], e[2]) }
|
||||
}
|
||||
document.content.include.also {
|
||||
it.group().noEmpty()?.forEach { e -> includeGroup(e) }
|
||||
it.groupAndSubgroups().noEmpty()?.forEach { e -> includeGroupAndSubgroups(e) }
|
||||
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]) }
|
||||
it.version().noEmpty()?.forEachParams(size = 3) { e -> includeVersion(e[0], e[1], e[2]) }
|
||||
it.versionByRegex().noEmpty()?.forEachParams(size = 3) { e -> includeVersionByRegex(e[0], e[1], e[2]) }
|
||||
}
|
||||
}
|
||||
if (document.nodeType != RepositoryDocument.RepositoryType.MAVEN_LOCAL)
|
||||
(document.url.noBlank()?.let {
|
||||
/** JCenter 已经终止服务 - 不确定其镜像源是否也会同时关闭 */
|
||||
if (it == AdditionalRepositories.ALIYUN_JCENTER_MIRROR)
|
||||
SLog.warn("JCenter has shut down, and its mirror server may stop soon, please transfer to other repositories")
|
||||
URI.create(it)
|
||||
} ?: document.path.noBlank()?.toFile()?.toURI())
|
||||
?.also { uri -> if (this is UrlArtifactRepository) this.url = uri }
|
||||
}
|
||||
}
|
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* SweetDependency - An easy autowire and manage dependencies Gradle plugin
|
||||
* Copyright (C) 2019-2023 HighCapable
|
||||
* https://github.com/HighCapable/SweetDependency
|
||||
*
|
||||
* Apache License Version 2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* This file is Created by fankes on 2023/5/16.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.manager.const
|
||||
|
||||
/**
|
||||
* 附加常用第三方存储库
|
||||
*/
|
||||
internal object AdditionalRepositories {
|
||||
|
||||
/** 中央存储库 (分流) */
|
||||
const val MAVEN_CENTRAL_BRANCH = "https://repo1.maven.org/maven2"
|
||||
|
||||
/** JitPack */
|
||||
const val JITPACK = "https://www.jitpack.io"
|
||||
|
||||
/** OSS Release */
|
||||
const val SONATYPE_OSS_RELEASES = "https://s01.oss.sonatype.org/content/repositories/releases"
|
||||
|
||||
/** OSS Snapshots */
|
||||
const val SONATYPE_OSS_SNAPSHOTS = "https://s01.oss.sonatype.org/content/repositories/snapshots"
|
||||
|
||||
/** 阿里云 Google 存储库镜像 */
|
||||
const val ALIYUN_GOOGLE_MIRROR = "https://maven.aliyun.com/repository/google"
|
||||
|
||||
/** 阿里云中央存储库镜像 */
|
||||
const val ALIYUN_MAVEN_CENTRAL_MIRROR = "https://maven.aliyun.com/repository/central"
|
||||
|
||||
/** 阿里云公共存储库镜像 */
|
||||
const val ALIYUN_MAVEN_PUBLIC_MIRROR = "https://maven.aliyun.com/repository/public"
|
||||
|
||||
/** 阿里云 JCenter 镜像 */
|
||||
const val ALIYUN_JCENTER_MIRROR = "https://maven.aliyun.com/nexus/content/repositories/jcenter"
|
||||
|
||||
/**
|
||||
* 存储库简洁名称定义类
|
||||
*/
|
||||
internal object Name {
|
||||
|
||||
/** 中央存储库 (分流) */
|
||||
const val MAVEN_CENTRAL_BRANCH = "maven-central-branch"
|
||||
|
||||
/** JitPack */
|
||||
const val JITPACK = "jit-pack"
|
||||
|
||||
/** OSS Release */
|
||||
const val SONATYPE_OSS_RELEASES = "sonatype-oss-releases"
|
||||
|
||||
/** OSS Snapshots */
|
||||
const val SONATYPE_OSS_SNAPSHOTS = "sonatype-oss-snapshots"
|
||||
|
||||
/** 阿里云 Google 存储库镜像 */
|
||||
const val ALIYUN_GOOGLE_MIRROR = "aliyun-google-mirror"
|
||||
|
||||
/** 阿里云中央存储库镜像 */
|
||||
const val ALIYUN_MAVEN_CENTRAL_MIRROR = "aliyun-maven-central-mirror"
|
||||
|
||||
/** 阿里云公共存储库镜像 */
|
||||
const val ALIYUN_MAVEN_PUBLIC_MIRROR = "aliyun-maven-public-mirror"
|
||||
|
||||
/** 阿里云 JCenter 镜像 */
|
||||
const val ALIYUN_JCENTER_MIRROR = "aliyun-jcenter-mirror"
|
||||
}
|
||||
}
|
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* SweetDependency - An easy autowire and manage dependencies Gradle plugin
|
||||
* Copyright (C) 2019-2023 HighCapable
|
||||
* https://github.com/HighCapable/SweetDependency
|
||||
*
|
||||
* Apache License Version 2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* This file is Created by fankes on 2023/5/18.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.manager.const
|
||||
|
||||
/**
|
||||
* 内置存储库
|
||||
*/
|
||||
internal object InternalRepositories {
|
||||
|
||||
/** 本地 Maven 存储库相对路径 */
|
||||
const val MAVEN_LOCAL_RELATIVE_PATH = ".m2/repository"
|
||||
|
||||
/** Google Maven */
|
||||
const val GOOGLE = "https://dl.google.com/dl/android/maven2"
|
||||
|
||||
/** 中央存储库 */
|
||||
const val MAVEN_CENTRAL = "https://repo.maven.apache.org/maven2"
|
||||
|
||||
/** Gradle Plugin 存储库 */
|
||||
const val GRADLE_PLUGIN_PORTAL = "https://plugins.gradle.org/m2"
|
||||
|
||||
/**
|
||||
* 存储库简洁名称定义类
|
||||
*/
|
||||
internal object Name {
|
||||
|
||||
/** Google Maven */
|
||||
const val GOOGLE = "google"
|
||||
|
||||
/** 中央存储库 */
|
||||
const val MAVEN_CENTRAL = "maven-central"
|
||||
|
||||
/** 本地 Maven 存储库 */
|
||||
const val MAVEN_LOCAL = "maven-local"
|
||||
|
||||
/** Maven 存储库 */
|
||||
const val MAVEN = "maven"
|
||||
|
||||
/** Ivy 存储库 */
|
||||
const val IVY = "ivy"
|
||||
|
||||
/** Gradle Plugin 存储库 */
|
||||
const val GRADLE_PLUGIN_PORTAL = "gradle-plugin-portal"
|
||||
}
|
||||
}
|
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* SweetDependency - An easy autowire and manage dependencies Gradle plugin
|
||||
* Copyright (C) 2019-2023 HighCapable
|
||||
* https://github.com/HighCapable/SweetDependency
|
||||
*
|
||||
* Apache License Version 2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* This file is Created by fankes on 2023/6/25.
|
||||
*/
|
||||
@file:Suppress("unused", "MemberVisibilityCanBePrivate")
|
||||
|
||||
package com.highcapable.sweetdependency.manager.content
|
||||
|
||||
import com.highcapable.sweetdependency.document.DependencyDocument
|
||||
import com.highcapable.sweetdependency.document.factory.DependenciesCondition
|
||||
import com.highcapable.sweetdependency.document.factory.DependencyMap
|
||||
import com.highcapable.sweetdependency.gradle.entity.DependencyName
|
||||
import com.highcapable.sweetdependency.utils.filter
|
||||
|
||||
/**
|
||||
* 已添加的依赖管理类
|
||||
*/
|
||||
internal object Dependencies {
|
||||
|
||||
/** 当前已添加的全部插件依赖数组 */
|
||||
private val pluginEntries = mutableMapOf<DependencyName, DependencyDocument>()
|
||||
|
||||
/** 当前已添加的全部库依赖数组 */
|
||||
private val libraryEntries = mutableMapOf<DependencyName, DependencyDocument>()
|
||||
|
||||
/** 标识当前是否为已过期状态 */
|
||||
private var isMarkedOutdate = true
|
||||
|
||||
/**
|
||||
* 获取当前过期状态
|
||||
* @return [Boolean]
|
||||
*/
|
||||
internal val isOutdate get() = isMarkedOutdate
|
||||
|
||||
/**
|
||||
* 刷新当前缓存数据状态
|
||||
* @param isOutdate 是否标识为已过期
|
||||
*/
|
||||
internal fun refreshState(isOutdate: Boolean) {
|
||||
isMarkedOutdate = isOutdate
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前全部数组
|
||||
* @return [DependencyMap]
|
||||
*/
|
||||
internal fun all() = (pluginEntries + libraryEntries).toMutableMap()
|
||||
|
||||
/**
|
||||
* 获取当前插件依赖数组
|
||||
* @return [DependencyMap]
|
||||
*/
|
||||
internal fun plugins() = pluginEntries
|
||||
|
||||
/**
|
||||
* 获取当前库依赖数组
|
||||
* @return [DependencyMap]
|
||||
*/
|
||||
internal fun libraries() = libraryEntries
|
||||
|
||||
/**
|
||||
* 当前是否存在依赖
|
||||
* @return [Boolean]
|
||||
*/
|
||||
internal fun isEmpty() = all().isEmpty()
|
||||
|
||||
/**
|
||||
* 当前是否不存在依赖
|
||||
* @return [Boolean]
|
||||
*/
|
||||
internal fun isNotEmpty() = isEmpty().not()
|
||||
|
||||
/**
|
||||
* 查找是否存在指定的依赖
|
||||
* @param condition 条件方法体
|
||||
* @return [Boolean]
|
||||
*/
|
||||
internal inline fun hasAll(condition: DependenciesCondition) = findAll { key, value -> condition(key, value) }.isNotEmpty()
|
||||
|
||||
/**
|
||||
* 查找是否存在指定的插件依赖
|
||||
* @param condition 条件方法体
|
||||
* @return [Boolean]
|
||||
*/
|
||||
internal inline fun hasPlugin(condition: DependenciesCondition) = findPlugins { key, value -> condition(key, value) }.isNotEmpty()
|
||||
|
||||
/**
|
||||
* 查找是否存在指定的库依赖
|
||||
* @param condition 条件方法体
|
||||
* @return [Boolean]
|
||||
*/
|
||||
internal inline fun hasLibrary(condition: DependenciesCondition) = findLibraries { key, value -> condition(key, value) }.isNotEmpty()
|
||||
|
||||
/**
|
||||
* 查找指定条件的依赖数组
|
||||
* @param condition 条件方法体
|
||||
* @return [DependencyMap]
|
||||
*/
|
||||
internal inline fun findAll(condition: DependenciesCondition) = all().filter { condition(it.key, it.value) }
|
||||
|
||||
/**
|
||||
* 查找指定条件的插件依赖数组
|
||||
* @param condition 条件方法体
|
||||
* @return [DependencyMap]
|
||||
*/
|
||||
internal inline fun findPlugins(condition: DependenciesCondition) = plugins().filter { condition(it.key, it.value) }
|
||||
|
||||
/**
|
||||
* 查找指定条件的库依赖数组
|
||||
* @param condition 条件方法体
|
||||
* @return [DependencyMap]
|
||||
*/
|
||||
internal inline fun findLibraries(condition: DependenciesCondition) = libraries().filter { condition(it.key, it.value) }
|
||||
|
||||
/**
|
||||
* 生成依赖数组
|
||||
* @param plugins 插件依赖数组
|
||||
* @param libraries 依赖数组
|
||||
*/
|
||||
internal fun generate(plugins: DependencyMap, libraries: DependencyMap) {
|
||||
if (plugins == plugins() && libraries == libraries()) return refreshState(isOutdate = false)
|
||||
resetData()
|
||||
plugins().putAll(plugins)
|
||||
libraries().putAll(libraries)
|
||||
}
|
||||
|
||||
/** 重置 (清空) 当前依赖数组 */
|
||||
private fun resetData() {
|
||||
pluginEntries.clear()
|
||||
libraryEntries.clear()
|
||||
refreshState(isOutdate = true)
|
||||
}
|
||||
}
|
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* SweetDependency - An easy autowire and manage dependencies Gradle plugin
|
||||
* Copyright (C) 2019-2023 HighCapable
|
||||
* https://github.com/HighCapable/SweetDependency
|
||||
*
|
||||
* Apache License Version 2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* This file is Created by fankes on 2023/5/16.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.manager.content
|
||||
|
||||
import com.highcapable.sweetdependency.document.RepositoryDocument
|
||||
import com.highcapable.sweetdependency.document.factory.RepositoryList
|
||||
import com.highcapable.sweetdependency.manager.const.AdditionalRepositories
|
||||
import com.highcapable.sweetdependency.manager.const.InternalRepositories
|
||||
import com.highcapable.sweetdependency.utils.parseFileSeparator
|
||||
|
||||
/**
|
||||
* 已添加的存储库管理类
|
||||
*/
|
||||
internal object Repositories {
|
||||
|
||||
/** 默认本地 Maven 存储库路径 */
|
||||
internal val defaultMavenLocalPath by lazy {
|
||||
"${System.getProperty("user.home")}/${InternalRepositories.MAVEN_LOCAL_RELATIVE_PATH}".parseFileSeparator()
|
||||
}
|
||||
|
||||
/** 默认版本过滤器排除列表数组 */
|
||||
internal val defaultVersionFilterExclusionList = arrayOf("-beta", "-alpha", "-dev", "-canary", "-pre", "-rc", "-ga", "-snapshot")
|
||||
|
||||
/** 当前已添加的全部存储库数组 */
|
||||
private val entries = mutableListOf<RepositoryDocument>()
|
||||
|
||||
/**
|
||||
* 获取当前存储库数组
|
||||
* @return [MutableList]<[RepositoryDocument]>
|
||||
*/
|
||||
internal fun all() = entries
|
||||
|
||||
/**
|
||||
* 当前是否存在存储库
|
||||
* @return [Boolean]
|
||||
*/
|
||||
internal fun isEmpty() = all().isEmpty()
|
||||
|
||||
/**
|
||||
* 当前是否不存在存储库
|
||||
* @return [Boolean]
|
||||
*/
|
||||
internal fun isNotEmpty() = isEmpty().not()
|
||||
|
||||
/**
|
||||
* 生成存储库数组
|
||||
* @param repositories 存储库数组
|
||||
*/
|
||||
internal fun generate(repositories: RepositoryList) {
|
||||
if (repositories == all()) return
|
||||
resetData()
|
||||
all().addAll(repositories)
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找可用的存储库名 URL 地址
|
||||
* @param name 存储库名
|
||||
* @return [String]
|
||||
*/
|
||||
internal fun findAdditional(name: String) = when (name) {
|
||||
AdditionalRepositories.Name.MAVEN_CENTRAL_BRANCH -> AdditionalRepositories.MAVEN_CENTRAL_BRANCH
|
||||
AdditionalRepositories.Name.JITPACK -> AdditionalRepositories.JITPACK
|
||||
AdditionalRepositories.Name.SONATYPE_OSS_RELEASES -> AdditionalRepositories.SONATYPE_OSS_RELEASES
|
||||
AdditionalRepositories.Name.SONATYPE_OSS_SNAPSHOTS -> AdditionalRepositories.SONATYPE_OSS_SNAPSHOTS
|
||||
AdditionalRepositories.Name.ALIYUN_GOOGLE_MIRROR -> AdditionalRepositories.ALIYUN_GOOGLE_MIRROR
|
||||
AdditionalRepositories.Name.ALIYUN_MAVEN_CENTRAL_MIRROR -> AdditionalRepositories.ALIYUN_MAVEN_CENTRAL_MIRROR
|
||||
AdditionalRepositories.Name.ALIYUN_MAVEN_PUBLIC_MIRROR -> AdditionalRepositories.ALIYUN_MAVEN_PUBLIC_MIRROR
|
||||
AdditionalRepositories.Name.ALIYUN_JCENTER_MIRROR -> AdditionalRepositories.ALIYUN_JCENTER_MIRROR
|
||||
else -> ""
|
||||
}
|
||||
|
||||
/** 重置 (清空) 当前存储库数组 */
|
||||
private fun resetData() = entries.clear()
|
||||
}
|
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* SweetDependency - An easy autowire and manage dependencies Gradle plugin
|
||||
* Copyright (C) 2019-2023 HighCapable
|
||||
* https://github.com/HighCapable/SweetDependency
|
||||
*
|
||||
* Apache License Version 2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* This file is Created by fankes on 2023/5/21.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.manager.helper
|
||||
|
||||
import com.highcapable.sweetdependency.environment.Environment
|
||||
import com.highcapable.sweetdependency.gradle.entity.DependencyName
|
||||
import com.highcapable.sweetdependency.gradle.entity.DependencyVersion
|
||||
import com.highcapable.sweetdependency.plugin.config.content.SweetDependencyConfigs
|
||||
import com.highcapable.sweetdependency.utils.debug.SLog
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* 依赖自动装配日志工具类
|
||||
*/
|
||||
internal object DependencyAutowireLogHelper {
|
||||
|
||||
/** 当前日志文件名 */
|
||||
private const val LOG_FILE_NAME = "dependencies-autowire.log"
|
||||
|
||||
/**
|
||||
* 当前日志文件
|
||||
* @return [String]
|
||||
*/
|
||||
internal val logFile get() = Environment.memoryDir(LOG_FILE_NAME)
|
||||
|
||||
/**
|
||||
* 记录当前依赖改变
|
||||
* @param dependencyName 依赖名称
|
||||
* @param fromVersion 起始版本
|
||||
* @param toVersion 最终版本
|
||||
*/
|
||||
internal fun record(dependencyName: DependencyName, fromVersion: DependencyVersion, toVersion: DependencyVersion) {
|
||||
if (SweetDependencyConfigs.configs.isEnableDependenciesAutowireLog.not()) return
|
||||
val versionInfo = if (fromVersion.isAutowire)
|
||||
"autowire version \"$toVersion\""
|
||||
else "update version \"$fromVersion\" -> \"$toVersion\""
|
||||
logFile.runCatching {
|
||||
appendText("[${SimpleDateFormat.getDateTimeInstance().format(Date())}] ${dependencyName.description} $versionInfo\n")
|
||||
}.onFailure { SLog.error("Failed to written log file \"$logFile\"\n$it") }
|
||||
}
|
||||
}
|
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* SweetDependency - An easy autowire and manage dependencies Gradle plugin
|
||||
* Copyright (C) 2019-2023 HighCapable
|
||||
* https://github.com/HighCapable/SweetDependency
|
||||
*
|
||||
* Apache License Version 2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* This file is Created by fankes on 2023/6/13.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.manager.helper
|
||||
|
||||
import com.highcapable.sweetdependency.SweetDependency
|
||||
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.factory.addDependencyToBuildScript
|
||||
import com.highcapable.sweetdependency.gradle.factory.applyPlugin
|
||||
import com.highcapable.sweetdependency.gradle.factory.getOrCreate
|
||||
import com.highcapable.sweetdependency.gradle.factory.loadBuildScriptClass
|
||||
import com.highcapable.sweetdependency.manager.GradleTaskManager
|
||||
import com.highcapable.sweetdependency.manager.content.Dependencies
|
||||
import com.highcapable.sweetdependency.plugin.config.content.SweetDependencyConfigs
|
||||
import com.highcapable.sweetdependency.plugin.generator.LibrariesAccessorsGenerator
|
||||
import com.highcapable.sweetdependency.utils.camelcase
|
||||
import com.highcapable.sweetdependency.utils.code.entity.MavenPomData
|
||||
import com.highcapable.sweetdependency.utils.code.factory.compile
|
||||
import com.highcapable.sweetdependency.utils.debug.SError
|
||||
import com.highcapable.sweetdependency.utils.debug.SLog
|
||||
import com.highcapable.sweetdependency.utils.isEmpty
|
||||
import com.highcapable.sweetdependency.utils.isValidZip
|
||||
import com.highcapable.sweetdependency.utils.single
|
||||
import com.highcapable.sweetdependency.utils.toAbsoluteFilePaths
|
||||
import com.highcapable.sweetdependency.utils.toFile
|
||||
import org.gradle.api.InvalidUserDataException
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.initialization.Settings
|
||||
import org.gradle.api.plugins.ExtensionAware
|
||||
import org.gradle.plugin.use.PluginDependenciesSpec
|
||||
import org.gradle.plugin.use.PluginDependencySpec
|
||||
|
||||
/**
|
||||
* 依赖部署工具类
|
||||
*/
|
||||
internal object DependencyDeployHelper {
|
||||
|
||||
/** 库依赖可访问 [Class] 标识名称 */
|
||||
private const val ACCESSORS_NAME = "dependencies-accessors"
|
||||
|
||||
/** 库依赖可访问 [Class] 生成目录 */
|
||||
private val accessorsDir = Environment.memoryDir(ACCESSORS_NAME)
|
||||
|
||||
/** 库依赖可访问 [Class] 虚拟依赖数据 */
|
||||
private val accessorsPomData = MavenPomData(SweetDependencyProperties.PROJECT_GROUP_NAME, ACCESSORS_NAME, SweetDependency.VERSION)
|
||||
|
||||
/** 库依赖可访问 [Class] 生成实例 */
|
||||
private val accessorsGenerator = LibrariesAccessorsGenerator()
|
||||
|
||||
/**
|
||||
* 生成 Version Catalogs
|
||||
*
|
||||
* 由于 Gradle API 限制 - 无法针对插件依赖进行自定义 - 所以间接使用 Version Catalogs 生成
|
||||
* @param settings 当前设置
|
||||
*/
|
||||
internal fun generateVersionCatalogs(settings: Settings) {
|
||||
val pluginsNamespace = SweetDependencyConfigs.document.preferences().dependenciesNamespace.plugins()
|
||||
runCatching {
|
||||
settings.dependencyResolutionManagement.versionCatalogs.create(pluginsNamespace) {
|
||||
Dependencies.plugins().forEach { (dependencyName, artifact) ->
|
||||
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
|
||||
This problem came from the version catalogs rules, so will not generate "$dependencyName"
|
||||
You can also use "autowire("$dependencyName")" to solve this problem
|
||||
You will see this warning every time, because we don't recommend declaring plugins without version
|
||||
""".trimIndent()
|
||||
)
|
||||
if (artifact.version().isAutowire) SError.make(
|
||||
"""
|
||||
This plugin "$dependencyName" is not autowired and cannot be generate
|
||||
You can try the following solutions to resolve this problem:
|
||||
1. Manually re-run Gradle Sync (make sure "autowire-on-sync-mode" not be "OFF")
|
||||
2. Manually run "${GradleTaskManager.AUTOWIRE_PLUGINS_TASK_NAME}" task and re-run Gradle Sync
|
||||
3. 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()
|
||||
)
|
||||
val deployedName = dependencyName.ambiguousName(symbol = "-", isReplaceFirstChar = true, isLowerCase = false)
|
||||
plugin(deployedName, dependencyName.current).version(artifact.version().deployed)
|
||||
artifact.versions().forEach { (name, version) ->
|
||||
plugin("$deployedName-${name.camelcase()}", dependencyName.current).version(version.deployed)
|
||||
if (artifact.alias.isNotBlank())
|
||||
plugin("${artifact.alias}-${name.camelcase()}", dependencyName.current).version(version.deployed)
|
||||
}
|
||||
if (artifact.alias.isNotBlank()) plugin(artifact.alias, dependencyName.current).version(artifact.version().deployed)
|
||||
}
|
||||
}
|
||||
}.onFailure {
|
||||
when (it) {
|
||||
is InvalidUserDataException -> SError.make("Illegal name called in Gradle version catalogs", it)
|
||||
else -> throw it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理库依赖可访问 [Class] 装载
|
||||
* @param rootProject 当前根项目
|
||||
*/
|
||||
internal fun resolveAccessors(rootProject: Project) {
|
||||
if (Dependencies.isOutdate || accessorsDir.isEmpty())
|
||||
accessorsGenerator.build().compile(accessorsPomData, accessorsDir.absolutePath, accessorsGenerator.compileStubFiles)
|
||||
rootProject.addDependencyToBuildScript(accessorsDir.absolutePath, accessorsPomData)
|
||||
}
|
||||
|
||||
/**
|
||||
* 部署库依赖可访问 [Class]
|
||||
* @param project 当前项目
|
||||
* @param extension 当前扩展实例
|
||||
*/
|
||||
internal fun deployAccessors(project: Project, extension: ExtensionAware) =
|
||||
accessorsGenerator.librariesClasses.forEach { (name, className) ->
|
||||
extension.getOrCreate(name, project.loadBuildScriptClass(className))
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理自动装配的插件依赖
|
||||
* @param spec 当前插件依赖声明对象
|
||||
* @param params 当前参数数组
|
||||
* @return [PluginDependencySpec]
|
||||
*/
|
||||
internal fun resolveAutowire(spec: PluginDependenciesSpec, params: Array<out Any>): PluginDependencySpec {
|
||||
if (params.isEmpty()) SError.make("The autowire function need a param to resolve plugin")
|
||||
if (params.size > 2) SError.make("The autowire function currently does not support more than 2 params of plugin")
|
||||
return when (params[0]) {
|
||||
is String -> {
|
||||
val entry = Dependencies.findPlugins { key, value -> params[0] == key.current || params[0] == value.alias }.single()
|
||||
?: SError.make("Failed to resolve plugin \"${params[0]}\", also tried alias")
|
||||
val version = if (params.size == 2)
|
||||
entry.value.versions()[params[1]] ?: SError.make("Failed to resolve plugin \"${params[0]}\" with version alias \"${params[1]}\"")
|
||||
else entry.value.version()
|
||||
spec.applyPlugin(entry.key.current, version.deployed)
|
||||
}
|
||||
else -> spec.applyPlugin(params[0])
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理自动装配的依赖
|
||||
* @param project 当前项目 - 默认为 [ProjectTransaction.current]
|
||||
* @param params 当前参数数组
|
||||
* @return [Any]
|
||||
*/
|
||||
internal fun resolveAutowire(project: Project = ProjectTransaction.current, params: Array<out String>): Any {
|
||||
if (params.isEmpty()) SError.make("The autowire function need a param to resolve library")
|
||||
return if (params[0].let { it.contains("/").not() && it.contains("\\").not() && it.startsWith("(").not() && it.endsWith(")").not() }) {
|
||||
if (params.size > 2) SError.make("The autowire function currently does not support more than 2 params of external dependency")
|
||||
val entry = Dependencies.findLibraries { key, value -> params[0] == key.current || params[0] == value.alias }.single()
|
||||
?: SError.make("Failed to resolve library \"${params[0]}\", also tried alias")
|
||||
val version = if (params.size == 2)
|
||||
entry.value.versions()[params[1]] ?: SError.make("Failed to resolve library \"${params[0]}\" with version alias \"${params[1]}\"")
|
||||
else entry.value.version()
|
||||
ExternalDependencyDelegate(entry.key.groupId, entry.key.artifactId, version.deployed)
|
||||
} else mutableListOf<String>().let {
|
||||
params.forEach { param ->
|
||||
val relativePath = if (param.startsWith("(") && param.endsWith(")")) param.replace("(", "").replace(")", "") else param
|
||||
it.addAll(relativePath.toAbsoluteFilePaths(project.projectDir.absolutePath).onEach { path ->
|
||||
if (path.toFile().isValidZip().not()) SError.make(
|
||||
"""
|
||||
Invalid library at file path $path
|
||||
The file collection dependency needs to be a valid zip package
|
||||
""".trimIndent()
|
||||
)
|
||||
})
|
||||
}; project.files(it.toTypedArray())
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* SweetDependency - An easy autowire and manage dependencies Gradle plugin
|
||||
* Copyright (C) 2019-2023 HighCapable
|
||||
* https://github.com/HighCapable/SweetDependency
|
||||
*
|
||||
* Apache License Version 2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* This file is Created by fankes on 2023/6/6.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.manager.maven
|
||||
|
||||
import com.highcapable.sweetdependency.document.RepositoryDocument
|
||||
import com.highcapable.sweetdependency.gradle.entity.DependencyName
|
||||
import com.highcapable.sweetdependency.gradle.entity.DependencyVersion
|
||||
import com.highcapable.sweetdependency.gradle.helper.GradleHelper
|
||||
import com.highcapable.sweetdependency.manager.maven.entity.MavenMetadata
|
||||
import com.highcapable.sweetdependency.utils.debug.SError
|
||||
import com.highcapable.sweetdependency.utils.executeFileBody
|
||||
import com.highcapable.sweetdependency.utils.executeUrlBody
|
||||
import com.highcapable.sweetdependency.utils.noEmpty
|
||||
import org.xml.sax.InputSource
|
||||
import java.io.StringReader
|
||||
import javax.xml.parsers.DocumentBuilderFactory
|
||||
|
||||
/**
|
||||
* Maven 解析器工具类
|
||||
*/
|
||||
internal object MavenParser {
|
||||
|
||||
/** 依赖配置文件名 */
|
||||
private const val METADATA_FILE_NAME = "maven-metadata.xml"
|
||||
|
||||
/** 依赖配置文件名 (本地) */
|
||||
private const val METADATA_LOCAL_FILE_NAME = "maven-metadata-local.xml"
|
||||
|
||||
/**
|
||||
* 通过依赖全称使用指定存储库得到 [MavenMetadata] 实体
|
||||
* @param dependencyName 依赖名称
|
||||
* @param repo 当前存储库实体
|
||||
* @param currentVersion 当前依赖版本
|
||||
* @return [MavenMetadata]
|
||||
*/
|
||||
internal fun acquire(dependencyName: DependencyName, repo: RepositoryDocument, currentVersion: DependencyVersion): MavenMetadata {
|
||||
val headerUrlOrPath = "${repo.url.ifBlank { repo.path }}/${dependencyName.urlName}/"
|
||||
val isIncludeScope = repo.isIncludeScope(dependencyName.type == DependencyName.Type.PLUGIN)
|
||||
/** 离线模式下不会自动装配、更新在线依赖 */
|
||||
if (isIncludeScope && GradleHelper.isOfflineMode) return MavenMetadata()
|
||||
return when {
|
||||
repo.url.isNotBlank() -> "$headerUrlOrPath$METADATA_FILE_NAME".executeUrlBody(repo.credentials.username, repo.credentials.password)
|
||||
repo.path.isNotBlank() -> "$headerUrlOrPath$METADATA_LOCAL_FILE_NAME".executeFileBody()
|
||||
else -> SError.make("Could not resolve this repository \"${repo.nodeName}\"")
|
||||
}.trim().toMetadata(currentVersion)
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 [METADATA_FILE_NAME]、[METADATA_LOCAL_FILE_NAME] 内容到 [MavenMetadata] 实体
|
||||
* @param currentVersion 当前依赖版本
|
||||
* @return [MavenMetadata]
|
||||
*/
|
||||
private fun String.toMetadata(currentVersion: DependencyVersion) = runCatching {
|
||||
if ((contains("<metadata ") || contains("<metadata>")).not() || endsWith("</metadata>").not()) return@runCatching MavenMetadata()
|
||||
DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(InputSource(StringReader(this))).let { document ->
|
||||
val lastUpdated = document.getElementsByTagName("lastUpdated").item(0)?.textContent?.toLongOrNull() ?: 0L
|
||||
val versionNodeList = document.getElementsByTagName("version")
|
||||
val versions = mutableListOf<DependencyVersion>()
|
||||
for (i in 0..versionNodeList.length) versionNodeList.item(i)?.textContent?.also { versions.add(currentVersion.clone(it)) }
|
||||
MavenMetadata(versions.noEmpty()?.reversed()?.toMutableList() ?: mutableListOf(), lastUpdated)
|
||||
}
|
||||
}.getOrNull() ?: MavenMetadata()
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* SweetDependency - An easy autowire and manage dependencies Gradle plugin
|
||||
* Copyright (C) 2019-2023 HighCapable
|
||||
* https://github.com/HighCapable/SweetDependency
|
||||
*
|
||||
* Apache License Version 2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* This file is Created by fankes on 2023/6/6.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.manager.maven.entity
|
||||
|
||||
import com.highcapable.sweetdependency.gradle.entity.DependencyVersion
|
||||
|
||||
/**
|
||||
* Maven Metadata 实体
|
||||
* @param versions 版本数组
|
||||
* @param lastUpdated 最后更新时间戳
|
||||
*/
|
||||
internal data class MavenMetadata(
|
||||
internal var versions: MutableList<DependencyVersion> = mutableListOf(),
|
||||
internal var lastUpdated: Long = 0L
|
||||
)
|
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* SweetDependency - An easy autowire and manage dependencies Gradle plugin
|
||||
* Copyright (C) 2019-2023 HighCapable
|
||||
* https://github.com/HighCapable/SweetDependency
|
||||
*
|
||||
* Apache License Version 2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* This file is Created by fankes on 2023/6/1.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.manager.transaction
|
||||
|
||||
import com.highcapable.sweetdependency.SweetDependency
|
||||
import com.highcapable.sweetdependency.document.DependencyDocument
|
||||
import com.highcapable.sweetdependency.document.RootConfigDocument
|
||||
import com.highcapable.sweetdependency.gradle.entity.DependencyVersion
|
||||
import com.highcapable.sweetdependency.gradle.factory.fullName
|
||||
import com.highcapable.sweetdependency.gradle.factory.libraries
|
||||
import com.highcapable.sweetdependency.gradle.factory.plugins
|
||||
import com.highcapable.sweetdependency.gradle.helper.GradleHelper
|
||||
import com.highcapable.sweetdependency.gradle.wrapper.type.LibraryDependencyType
|
||||
import com.highcapable.sweetdependency.manager.GradleTaskManager
|
||||
import com.highcapable.sweetdependency.manager.content.Dependencies
|
||||
import com.highcapable.sweetdependency.plugin.config.content.SweetDependencyConfigs
|
||||
import com.highcapable.sweetdependency.utils.debug.SLog
|
||||
import com.highcapable.sweetdependency.utils.parseFileSeparator
|
||||
import com.highcapable.sweetdependency.utils.toFile
|
||||
import com.highcapable.sweetdependency.utils.yaml.Yaml
|
||||
|
||||
/**
|
||||
* 依赖迁移模版管理类
|
||||
*/
|
||||
internal object DependencyMigrationTemplateTransaction {
|
||||
|
||||
/** 模板文件头部内容 */
|
||||
private const val TEMPLATE_FILE_HEADER_CONTENT = """
|
||||
# SweetDependency project configuration template file
|
||||
# Template files are automatically generated using Gradle task "${GradleTaskManager.CREATE_DEPENDENCIES_MIGRATION_TEMPLATE_TASK_NAME}"
|
||||
# The automatically generated configuration is determined according to your project
|
||||
# Please adjust these contents at any time in actual use, the generated content is for reference only, and its availability is unknown
|
||||
# You can copy the content of the corresponding node in the template file to the project configuration file, and then delete this file
|
||||
# You can visit ${SweetDependency.PROJECT_URL} for more help
|
||||
#
|
||||
# SweetDependency 项目配置模板文件
|
||||
# 模版文件是使用 Gradle Task "${GradleTaskManager.CREATE_DEPENDENCIES_MIGRATION_TEMPLATE_TASK_NAME}" 自动生成的
|
||||
# 自动生成的配置根据你的项目决定,请在实际使用中随时调整这些内容,生成的内容仅供参考,其可用性未知
|
||||
# 你可以复制模板文件中对应节点的内容到项目配置文件,然后删除此文件
|
||||
# 你可以前往 ${SweetDependency.PROJECT_URL} 以获得更多帮助
|
||||
"""
|
||||
|
||||
/** 模板文件扩展名 */
|
||||
private const val TEMPLATE_FILE_EXT_NAME = "template.yaml"
|
||||
|
||||
/** 模板文件头部内容 */
|
||||
private val templateFileHeaderContent = TEMPLATE_FILE_HEADER_CONTENT.trimIndent()
|
||||
|
||||
/** 排除的部分内置插件名称前缀数组 */
|
||||
private val exclusionPluginPrefixs = arrayOf("org.gradle", "com.android.internal")
|
||||
|
||||
/** 生成模板使用的文档实例 */
|
||||
private val document = RootConfigDocument()
|
||||
|
||||
/** 创建模版 */
|
||||
internal fun createTemplate() {
|
||||
SLog.info("Starting analyze projects dependencies structure", SLog.ANLZE)
|
||||
GradleHelper.allProjects.forEach { subProject ->
|
||||
subProject.plugins().onEach {
|
||||
if (exclusionPluginPrefixs.any { prefix -> it.id.startsWith(prefix) }) return@onEach
|
||||
if (Dependencies.hasPlugin { key, _ -> key.current == it.id }) return@onEach
|
||||
if (document.plugins == null) document.plugins = mutableMapOf()
|
||||
val declareDocument = DependencyDocument(version = DependencyVersion.AUTOWIRE_VERSION_NAME)
|
||||
document.plugins?.set(it.id, declareDocument)
|
||||
}.apply { if (isNotEmpty()) SLog.info("Found $size plugins in project \"${subProject.fullName}\"", SLog.LINK) }
|
||||
subProject.libraries().onEach {
|
||||
if (Dependencies.hasLibrary { key, _ -> key.current == it.toString() }) return@onEach
|
||||
if (document.libraries == null) document.libraries = mutableMapOf()
|
||||
if (it.type == LibraryDependencyType.EXTERNAL) document.libraries?.also { entities ->
|
||||
if (entities[it.groupId] == null) entities[it.groupId] = mutableMapOf()
|
||||
val declareDocument = DependencyDocument(version = it.version.existed)
|
||||
entities[it.groupId]?.set(it.artifactId, declareDocument)
|
||||
}
|
||||
}.apply { if (isNotEmpty()) SLog.info("Found $size libraries in project \"${subProject.fullName}\"", SLog.LINK) }
|
||||
}; saveTemplateFile()
|
||||
}
|
||||
|
||||
/** 保存模版到文件 */
|
||||
private fun saveTemplateFile() {
|
||||
if (document.plugins?.isEmpty() == true) document.plugins = null
|
||||
if (document.libraries?.isEmpty() == true) document.libraries = null
|
||||
if (document.plugins?.isNotEmpty() == true || document.libraries?.isNotEmpty() == true) {
|
||||
val templateFilePath = SweetDependencyConfigs.configs.configFilePath
|
||||
.let { it.toFile().let { e -> "${e.parent}/${e.name.split(".")[0]}.$TEMPLATE_FILE_EXT_NAME" } }.parseFileSeparator()
|
||||
Yaml.parseToFile(document, templateFilePath) { "$templateFileHeaderContent\n\n${replace("\"", "")}" }
|
||||
SLog.info("Template file is created at $templateFilePath", SLog.DONE)
|
||||
document.plugins?.clear()
|
||||
document.libraries?.clear()
|
||||
} else SLog.info("No suitable dependencies can be found in all projects to create template file, nothing to do", SLog.IGNORE)
|
||||
}
|
||||
}
|
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
* SweetDependency - An easy autowire and manage dependencies Gradle plugin
|
||||
* Copyright (C) 2019-2023 HighCapable
|
||||
* https://github.com/HighCapable/SweetDependency
|
||||
*
|
||||
* Apache License Version 2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* This file is Created by fankes on 2023/6/8.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.manager.transaction
|
||||
|
||||
import com.highcapable.sweetdependency.SweetDependency
|
||||
import com.highcapable.sweetdependency.document.factory.DependencyMap
|
||||
import com.highcapable.sweetdependency.environment.Environment
|
||||
import com.highcapable.sweetdependency.gradle.factory.fullName
|
||||
import com.highcapable.sweetdependency.gradle.factory.libraries
|
||||
import com.highcapable.sweetdependency.gradle.factory.plugins
|
||||
import com.highcapable.sweetdependency.gradle.helper.GradleHelper
|
||||
import com.highcapable.sweetdependency.gradle.wrapper.type.LibraryDependencyType
|
||||
import com.highcapable.sweetdependency.plugin.config.content.SweetDependencyConfigs
|
||||
import com.highcapable.sweetdependency.utils.debug.SLog
|
||||
import com.highcapable.sweetdependency.utils.noBlank
|
||||
import com.highcapable.sweetdependency.utils.noEmpty
|
||||
|
||||
/**
|
||||
* 运行时调试管理类
|
||||
*/
|
||||
internal object RuntimeDebugTransaction {
|
||||
|
||||
private val configs get() = SweetDependencyConfigs.configs
|
||||
private val preferences get() = SweetDependencyConfigs.document.preferences()
|
||||
private val repositories get() = SweetDependencyConfigs.document.repositories()
|
||||
private val plugins get() = SweetDependencyConfigs.document.plugins(duplicate = true)
|
||||
private val libraries get() = SweetDependencyConfigs.document.libraries(duplicate = true)
|
||||
private val vfExclusionList get() = preferences.versionFilter.exclusionList().all()
|
||||
|
||||
/** 存储库内存数组 */
|
||||
private val repositoriesMap = mutableMapOf<String, Any>()
|
||||
|
||||
/** 插件依赖内存数组 */
|
||||
private val pluginsMap = mutableMapOf<String, Any>()
|
||||
|
||||
/** 依赖内存数组 */
|
||||
private val librariesMap = mutableMapOf<String, Any>()
|
||||
|
||||
/** 版本过滤器内存数组 */
|
||||
private val versionFilterMap = mutableMapOf<String, Any>()
|
||||
|
||||
/** 项目插件依赖内存数组 */
|
||||
private val projectPluginsMap = mutableMapOf<String, Any>()
|
||||
|
||||
/** 项目库依赖内存数组 */
|
||||
private val projectLibrariesMap = mutableMapOf<String, Any>()
|
||||
|
||||
/** 写出调试信息 */
|
||||
internal fun dump() {
|
||||
configureMemoryData()
|
||||
log(
|
||||
"""
|
||||
|
||||
+--------------------------------------+
|
||||
| SWEET DEPENDENCY MEMORY DATA DUMP |
|
||||
+--------------------------------------+
|
||||
|
||||
"""
|
||||
)
|
||||
log(
|
||||
"System Environment" value Environment.systemInfo,
|
||||
"Character Encoding" value Environment.characterEncoding,
|
||||
"Java Version" value Environment.javaVersion,
|
||||
"Gradle Version" value GradleHelper.version,
|
||||
"Plugin Version" value SweetDependency.VERSION,
|
||||
"Plugin Configuration" to mapOf(
|
||||
"configFileName" with "(path) ${configs.configFilePath}" to mapOf(
|
||||
"preferences" to mapOf(
|
||||
"autowire-on-sync-mode" value preferences.autowireOnSyncMode,
|
||||
"repositories-mode" value preferences.repositoriesMode,
|
||||
"dependencies-namespace" to mapOf(
|
||||
"plugins" value preferences.dependenciesNamespace.plugins().ifBlank { NONE },
|
||||
"libraries" value preferences.dependenciesNamespace.libraries().ifBlank { NONE }
|
||||
),
|
||||
"version-filter" with (if (vfExclusionList.isEmpty()) "(disabled)" else "") to versionFilterMap
|
||||
),
|
||||
"repositories" to repositoriesMap,
|
||||
"plugins" to pluginsMap,
|
||||
"libraries" to librariesMap
|
||||
),
|
||||
"isEnableDependenciesAutowireLog" value configs.isEnableDependenciesAutowireLog,
|
||||
"isEnableVerboseMode" value configs.isEnableVerboseMode
|
||||
),
|
||||
"Project Dependencies" to mapOf(
|
||||
"Plugins" with (if (projectPluginsMap.isEmpty()) "(load failed)" else "") to projectPluginsMap,
|
||||
"Libraries" with (if (projectLibrariesMap.isEmpty()) "(load failed)" else "") to projectLibrariesMap
|
||||
)
|
||||
)
|
||||
log(
|
||||
"""
|
||||
|
||||
All debug information has been dumped, if your project is not working properly, please give us feedback on this report
|
||||
For details, please visit: ${SweetDependency.PROJECT_URL}
|
||||
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
/** 配置内存数据 */
|
||||
private fun configureMemoryData() {
|
||||
if (repositoriesMap.isNotEmpty() &&
|
||||
pluginsMap.isNotEmpty() &&
|
||||
librariesMap.isNotEmpty() &&
|
||||
versionFilterMap.isNotEmpty() &&
|
||||
projectLibrariesMap.isNotEmpty()
|
||||
) return
|
||||
repositoriesMap.clear()
|
||||
pluginsMap.clear()
|
||||
librariesMap.clear()
|
||||
versionFilterMap.clear()
|
||||
projectLibrariesMap.clear()
|
||||
repositories.forEach { repo ->
|
||||
val hasCredentials = repo.credentials.let { it.username.isNotBlank() || it.password.isNotBlank() }
|
||||
val repoMap = mutableMapOf<String, Any>(
|
||||
"enable" value repo.isEnable,
|
||||
"url" value repo.url.ifBlank { NONE },
|
||||
"path" value repo.path.ifBlank { NONE }
|
||||
)
|
||||
if (hasCredentials) repoMap["credentials"] = mapOf(
|
||||
"username" value repo.credentials.username,
|
||||
"password" value repo.credentials.password
|
||||
)
|
||||
repositoriesMap[repo.nodeName] = repoMap
|
||||
}
|
||||
plugins.resolveDependencies(pluginsMap)
|
||||
libraries.resolveDependencies(librariesMap)
|
||||
if (vfExclusionList.isNotEmpty()) versionFilterMap["exclusionList"] = mutableMapOf<String, Any>()
|
||||
vfExclusionList.forEach { versionFilterMap["exclusionList"]?.addAsMap(it) }
|
||||
GradleHelper.allProjects.forEach { subProject ->
|
||||
projectPluginsMap[subProject.fullName] = mutableMapOf<String, Any>()
|
||||
projectLibrariesMap[subProject.fullName] = mutableMapOf<String, Any>()
|
||||
subProject.plugins().forEach { projectPluginsMap[subProject.fullName]?.addAsMap(it.id) }
|
||||
subProject.libraries().forEach {
|
||||
val prefix = "(${it.configurationName})"
|
||||
when (it.type) {
|
||||
LibraryDependencyType.EXTERNAL, LibraryDependencyType.EXTERNAL_DELEGATE -> {
|
||||
val suffix = it.version.deployed.noBlank()?.let { e -> ":$e" } ?: ""
|
||||
projectLibrariesMap[subProject.fullName]?.addAsMap("$prefix ${it.groupId}:${it.artifactId}$suffix")
|
||||
}
|
||||
LibraryDependencyType.PROJECT -> projectLibrariesMap[subProject.fullName]?.addAsMap("$prefix (project) ${it.project?.fullName}")
|
||||
LibraryDependencyType.FILES -> {
|
||||
val filesMap = mutableMapOf<String, String>()
|
||||
it.files?.noEmpty()?.forEach { e -> filesMap.addAsMap(e.absolutePath) }?.also {
|
||||
projectLibrariesMap[subProject.fullName] = mapOf("$prefix (files)" to filesMap)
|
||||
} ?: projectLibrariesMap[subProject.fullName]?.addAsMap("$prefix (files) not found or empty folder")
|
||||
}
|
||||
LibraryDependencyType.OTHERS -> projectLibrariesMap[subProject.fullName]?.addAsMap("$prefix unknown type dependency")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理依赖数组
|
||||
* @param dependenciesMap 依赖内存数组
|
||||
*/
|
||||
private fun DependencyMap.resolveDependencies(dependenciesMap: MutableMap<String, Any>) =
|
||||
forEach { (dependencyName, artifact) ->
|
||||
val repoMap = mutableMapOf<String, Any>()
|
||||
val childVersionFilterMap = mutableMapOf<String, Any>()
|
||||
val childVfExclusionList = artifact.versionFilter?.exclusionList()?.all()
|
||||
if (childVfExclusionList?.isNotEmpty() == true) childVersionFilterMap["exclusionList"] = mutableMapOf<String, Any>()
|
||||
childVfExclusionList?.forEach { childVersionFilterMap["exclusionList"]?.addAsMap(it) }
|
||||
artifact.repositories().forEach { repoMap.addAsMap(it.nodeName) }
|
||||
dependenciesMap[dependencyName.current] = mapOf(
|
||||
"alias" value artifact.alias.ifBlank { NONE },
|
||||
"version" value artifact.version().let { if (it.isNoSpecific) "(no specific)" else it.current },
|
||||
"auto-update" value artifact.isAutoUpdate,
|
||||
"version-filter" with (if (childVfExclusionList?.isEmpty() == true) "(disabled)" else "") to childVersionFilterMap,
|
||||
"repositories" to repoMap,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成单边 [Pair]
|
||||
* @param value 键值内容
|
||||
* @return [Pair]<[String], [String]>
|
||||
*/
|
||||
private infix fun String.value(value: Any) = Pair(with(value), "")
|
||||
|
||||
/**
|
||||
* 生成冒号键值对字符串
|
||||
* @param value 键值内容
|
||||
* @return [String]
|
||||
*/
|
||||
private infix fun String.with(value: Any) = if (value != NONE) "$this${if (value.toString().isBlank()) "" else ": $value"}" else ""
|
||||
|
||||
/**
|
||||
* 任意类型转换为 [MutableMap] 并设置空键值内容
|
||||
* @param key 键值名称
|
||||
*/
|
||||
private fun Any.addAsMap(key: String) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
(this as MutableMap<String, Any>)[key] = ""
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 [MutableMap]
|
||||
* @param pairs 键值对数组
|
||||
* @return [MutableMap]<[String], [Any]>
|
||||
*/
|
||||
private fun mapOf(vararg pairs: Pair<String, Any>) = mutableMapOf(*pairs)
|
||||
|
||||
/**
|
||||
* 根据 [Map] 生成键值对树图形字符串
|
||||
* @return [String]
|
||||
*/
|
||||
private fun Map<*, *>.genMapTree(): String {
|
||||
/**
|
||||
* 生成子项目
|
||||
* @param prefix 前缀
|
||||
* @return [String]
|
||||
*/
|
||||
fun Map<*, *>.genChild(prefix: String = ""): String {
|
||||
val currentMap = filterKeys { it.toString().isNotBlank() }.filterValues { it !is Map<*, *> || it.isNotEmpty() }
|
||||
val builder = StringBuilder()
|
||||
currentMap.keys.forEachIndexed { index, key ->
|
||||
val value = currentMap[key]
|
||||
val isLast = index == currentMap.keys.size - 1
|
||||
val branch = if (isLast) "└─ " else "├─ "
|
||||
val newPrefix = if (isLast) "$prefix " else "$prefix│ "
|
||||
builder.append("$prefix$branch$key\n")
|
||||
if (value is Map<*, *>) builder.append(value.genChild(newPrefix))
|
||||
}; return builder.toString()
|
||||
}; return "${SweetDependency.TAG}\n${genChild()}"
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印日志
|
||||
* @param pairs 键值对数组
|
||||
*/
|
||||
private fun log(vararg pairs: Pair<String, Any>) = log(mapOf(*pairs).genMapTree())
|
||||
|
||||
/**
|
||||
* 打印日志
|
||||
* @param any 任意内容
|
||||
*/
|
||||
private fun log(any: Any) = SLog.info(any.toString().trimIndent(), noTag = true)
|
||||
|
||||
/** 标识当前值为空 */
|
||||
private const val NONE = "/*-none-*/"
|
||||
}
|
Reference in New Issue
Block a user