mirror of
https://github.com/HighCapable/SweetDependency.git
synced 2025-09-04 09:45:56 +08:00
Initial commit
This commit is contained in:
2
sweetdependency-gradle-plugin/.gitignore
vendored
Normal file
2
sweetdependency-gradle-plugin/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
.gradle
|
||||
build/
|
69
sweetdependency-gradle-plugin/build.gradle.kts
Normal file
69
sweetdependency-gradle-plugin/build.gradle.kts
Normal file
@@ -0,0 +1,69 @@
|
||||
plugins {
|
||||
`kotlin-dsl`
|
||||
autowire(libs.plugins.kotlin.jvm)
|
||||
autowire(libs.plugins.kotlin.serialization)
|
||||
autowire(libs.plugins.maven.publish)
|
||||
}
|
||||
|
||||
allprojects {
|
||||
group = property.project.groupName
|
||||
version = property.project.version
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
withSourcesJar()
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvmToolchain(17)
|
||||
sourceSets.all { languageSettings { languageVersion = "2.0" } }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(org.jetbrains.kotlin.kotlin.gradle.plugin.api)
|
||||
implementation(org.snakeyaml.snakeyaml.engine)
|
||||
implementation(com.charleskorn.kaml.kaml)
|
||||
implementation(com.squareup.okhttp3.okhttp)
|
||||
implementation(com.squareup.javapoet)
|
||||
}
|
||||
|
||||
gradlePlugin {
|
||||
plugins {
|
||||
create(property.project.moduleName) {
|
||||
id = property.project.groupName
|
||||
implementationClass = property.gradle.plugin.implementationClass
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mavenPublishing {
|
||||
coordinates(property.project.groupName, property.project.moduleName, property.project.version)
|
||||
pom {
|
||||
name = property.project.name
|
||||
description = property.project.description
|
||||
url = property.project.url
|
||||
licenses {
|
||||
license {
|
||||
name = property.project.licence.name
|
||||
url = property.project.licence.url
|
||||
distribution = property.project.licence.url
|
||||
}
|
||||
}
|
||||
developers {
|
||||
developer {
|
||||
id = property.project.developer.id
|
||||
name = property.project.developer.name
|
||||
email = property.project.developer.email
|
||||
}
|
||||
}
|
||||
scm {
|
||||
url = property.maven.publish.scm.url
|
||||
connection = property.maven.publish.scm.connection
|
||||
developerConnection = property.maven.publish.scm.developerConnection
|
||||
}
|
||||
}
|
||||
publishToMavenCentral(com.vanniktech.maven.publish.SonatypeHost.S01)
|
||||
signAllPublications()
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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/17.
|
||||
*/
|
||||
package com.highcapable.sweetdependency
|
||||
|
||||
import com.highcapable.sweetdependency.generated.SweetDependencyProperties
|
||||
|
||||
/**
|
||||
* [SweetDependency] 的装载调用类
|
||||
*/
|
||||
object SweetDependency {
|
||||
|
||||
/** Banner 内容 */
|
||||
private const val BANNER_CONTENT = """
|
||||
_____ _ _____ _
|
||||
/ ____| | | | __ \ | |
|
||||
| (_____ _____ ___| |_ | | | | ___ _ __ ___ _ __ __| | ___ _ __ ___ _ _
|
||||
\___ \ \ /\ / / _ \/ _ \ __| | | | |/ _ \ '_ \ / _ \ '_ \ / _` |/ _ \ '_ \ / __| | | |
|
||||
____) \ V V / __/ __/ |_ | |__| | __/ |_) | __/ | | | (_| | __/ | | | (__| |_| |
|
||||
|_____/ \_/\_/ \___|\___|\__| |_____/ \___| .__/ \___|_| |_|\__,_|\___|_| |_|\___|\__, |
|
||||
| | __/ |
|
||||
|_| |___/
|
||||
"""
|
||||
|
||||
/** Banner 内容 */
|
||||
val bannerContent = BANNER_CONTENT.trimIndent()
|
||||
|
||||
/** 标签名称 */
|
||||
const val TAG = SweetDependencyProperties.PROJECT_NAME
|
||||
|
||||
/** 版本 */
|
||||
const val VERSION = SweetDependencyProperties.PROJECT_VERSION
|
||||
|
||||
/** 项目地址 */
|
||||
const val PROJECT_URL = SweetDependencyProperties.PROJECT_URL
|
||||
}
|
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
@file:Suppress("unused")
|
||||
|
||||
package com.highcapable.sweetdependency.document
|
||||
|
||||
import com.highcapable.sweetdependency.gradle.entity.DependencyVersion
|
||||
import com.highcapable.sweetdependency.manager.content.Repositories
|
||||
import com.highcapable.sweetdependency.utils.debug.SError
|
||||
import com.highcapable.sweetdependency.utils.toSpaceList
|
||||
import com.highcapable.sweetdependency.utils.yaml.proxy.IYamlDocument
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
/**
|
||||
* 依赖每项文档实体
|
||||
* @param alias 别名
|
||||
* @param version 版本
|
||||
* @param versionRef 版本引用
|
||||
* @param versions 版本别名数组
|
||||
* @param isAutoUpdate 是否自动更新
|
||||
* @param versionFilter 版本过滤器文档实体
|
||||
* @param repositories 指定使用的存储库名称
|
||||
*/
|
||||
@Serializable
|
||||
internal data class DependencyDocument(
|
||||
@SerialName("alias")
|
||||
internal var alias: String = "",
|
||||
@SerialName("version")
|
||||
internal var version: String = "",
|
||||
@SerialName("version-ref")
|
||||
internal var versionRef: String = "",
|
||||
@SerialName("versions")
|
||||
internal var versions: MutableMap<String, String> = mutableMapOf(),
|
||||
@SerialName("auto-update")
|
||||
internal var isAutoUpdate: Boolean = true,
|
||||
@SerialName("version-filter")
|
||||
internal var versionFilter: VersionFilterDocument? = null,
|
||||
@SerialName("repositories")
|
||||
internal var repositories: String = ""
|
||||
) : IYamlDocument {
|
||||
|
||||
/**
|
||||
* 获取版本
|
||||
* @return [DependencyVersion]
|
||||
*/
|
||||
internal fun version() = DependencyVersion(version)
|
||||
|
||||
/**
|
||||
* 获取版本别名数组
|
||||
* @return <[MutableMap]><[String], [DependencyVersion]>
|
||||
*/
|
||||
internal fun versions() = mutableMapOf<String, DependencyVersion>().also {
|
||||
versions.forEach { (key, value) -> it[key] = DependencyVersion(value.replace(DependencyVersion.LATEST_VERSION_NAME, version)) }
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新版本
|
||||
* @param newVersion 新版本
|
||||
*/
|
||||
internal fun updateVersion(newVersion: DependencyVersion) {
|
||||
version = newVersion.current
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新版本
|
||||
* @param document 当前文档实例
|
||||
*/
|
||||
internal fun updateVersion(document: DependencyDocument) {
|
||||
version = document.version
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定使用的存储库数组
|
||||
* @return [MutableList]<[RepositoryDocument]>
|
||||
*/
|
||||
internal fun repositories() = mutableListOf<RepositoryDocument>().apply {
|
||||
repositories.toSpaceList().forEach {
|
||||
add(Repositories.all().firstOrNull { e -> e.nodeName == it } ?: SError.make("Could not found repository with name \"$it\""))
|
||||
}
|
||||
}.distinctBy { it.url.ifBlank { it.path } }.toMutableList()
|
||||
}
|
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* 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/17.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.document
|
||||
|
||||
import com.highcapable.sweetdependency.document.factory.checkingName
|
||||
import com.highcapable.sweetdependency.utils.camelcase
|
||||
import com.highcapable.sweetdependency.utils.debug.SError
|
||||
import com.highcapable.sweetdependency.utils.yaml.proxy.IYamlDocument
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import org.gradle.api.initialization.resolve.RepositoriesMode as GradleRepositoriesMode
|
||||
|
||||
/**
|
||||
* 偏好配置项文档实体
|
||||
* @param autowireOnSyncMode Gradle Sync 自动装配、更新依赖模式
|
||||
* @param repositoriesMode 存储库装载模式
|
||||
* @param dependenciesNamespace 依赖命名空间
|
||||
* @param versionFilter 版本过滤器文档实体
|
||||
*/
|
||||
@Serializable
|
||||
internal data class PreferencesDocument(
|
||||
@SerialName("autowire-on-sync-mode")
|
||||
internal var autowireOnSyncMode: AutowireOnSyncMode = AutowireOnSyncMode.UPDATE_OPTIONAL_DEPENDENCIES,
|
||||
@SerialName("repositories-mode")
|
||||
internal var repositoriesMode: RepositoriesMode = RepositoriesMode.FAIL_ON_PROJECT_REPOS,
|
||||
@SerialName("dependencies-namespace")
|
||||
internal var dependenciesNamespace: DependenciesNamespaceDocument = DependenciesNamespaceDocument(),
|
||||
@SerialName("version-filter")
|
||||
internal var versionFilter: VersionFilterDocument = VersionFilterDocument()
|
||||
) : IYamlDocument {
|
||||
|
||||
@Serializable
|
||||
internal data class DependenciesNamespaceDocument(
|
||||
@SerialName("plugins")
|
||||
var plugins: String = "libs",
|
||||
@SerialName("libraries")
|
||||
var libraries: String = ""
|
||||
) : IYamlDocument {
|
||||
|
||||
init {
|
||||
if (plugins.isNotBlank() && libraries.isNotBlank() && plugins == libraries)
|
||||
SError.make("Duplicated dependencies namespace \"$plugins\"")
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取插件依赖命名空间
|
||||
* @return [String]
|
||||
*/
|
||||
internal fun plugins() = plugins.apply { checkingName("plugins namespace", isCheckExtName = true) }.camelcase()
|
||||
|
||||
/**
|
||||
* 获取库依赖命名空间
|
||||
* @return [String]
|
||||
*/
|
||||
internal fun libraries() = libraries.apply { checkingName("libraries namespace", isCheckExtName = true) }.camelcase()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gradle Sync 自动装配、更新依赖模式定义类
|
||||
*/
|
||||
internal enum class AutowireOnSyncMode {
|
||||
/** 自动装配和更新可选依赖 (插件依赖 + 库依赖) */
|
||||
UPDATE_OPTIONAL_DEPENDENCIES,
|
||||
|
||||
/** 自动装配和更新所有依赖 (插件依赖 + 库依赖) */
|
||||
UPDATE_ALL_DEPENDENCIES,
|
||||
|
||||
/** 仅自动装配使用“+”填充版本的依赖 (插件依赖 + 库依赖) */
|
||||
ONLY_AUTOWIRE_DEPENDENCIES,
|
||||
|
||||
/** 自动装配和更新可选依赖 (插件依赖) */
|
||||
UPDATE_OPTIONAL_PLUGINS,
|
||||
|
||||
/** 自动装配和更新所有依赖 (插件依赖) */
|
||||
UPDATE_ALL_PLUGINS,
|
||||
|
||||
/** 仅自动装配使用“+”填充版本的依赖 (插件依赖) */
|
||||
ONLY_AUTOWIRE_PLUGINS,
|
||||
|
||||
/** 自动装配和更新可选依赖 (库依赖) */
|
||||
UPDATE_OPTIONAL_LIBRARIES,
|
||||
|
||||
/** 自动装配和更新所有依赖 (库依赖) */
|
||||
UPDATE_ALL_LIBRARIES,
|
||||
|
||||
/** 仅自动装配使用“+”填充版本的依赖 (库依赖) */
|
||||
ONLY_AUTOWIRE_LIBRARIES,
|
||||
|
||||
/** 什么也不做 - 关闭所有功能 */
|
||||
OFF
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储库装载模式定义类 (跟随 Gradle 进行配置调整)
|
||||
*/
|
||||
internal enum class RepositoriesMode {
|
||||
/** 参考 [GradleRepositoriesMode.PREFER_PROJECT] */
|
||||
PREFER_PROJECT,
|
||||
|
||||
/** 参考 [GradleRepositoriesMode.PREFER_SETTINGS] */
|
||||
PREFER_SETTINGS,
|
||||
|
||||
/** 参考 [GradleRepositoriesMode.FAIL_ON_PROJECT_REPOS] */
|
||||
FAIL_ON_PROJECT_REPOS
|
||||
}
|
||||
}
|
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
* 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/17.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.document
|
||||
|
||||
import com.highcapable.sweetdependency.SweetDependency
|
||||
import com.highcapable.sweetdependency.manager.const.InternalRepositories
|
||||
import com.highcapable.sweetdependency.manager.content.Repositories
|
||||
import com.highcapable.sweetdependency.utils.debug.SError
|
||||
import com.highcapable.sweetdependency.utils.parseUnixFileSeparator
|
||||
import com.highcapable.sweetdependency.utils.toSpaceList
|
||||
import com.highcapable.sweetdependency.utils.yaml.proxy.IYamlDocument
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.Transient
|
||||
import org.gradle.api.artifacts.repositories.PasswordCredentials
|
||||
import org.gradle.api.artifacts.repositories.RepositoryContentDescriptor
|
||||
|
||||
/**
|
||||
* 存储库配置项文档实体
|
||||
* @param isEnable 是否启用
|
||||
* @param scope 作用域
|
||||
* @param content 内容过滤器
|
||||
* @param credentials 身份验证配置项文档实体
|
||||
* @param url URL 地址
|
||||
* @param path 文件路径
|
||||
*/
|
||||
@Serializable
|
||||
internal data class RepositoryDocument(
|
||||
@SerialName("enable")
|
||||
internal var isEnable: Boolean = true,
|
||||
@SerialName("scope")
|
||||
internal var scope: RepositoryScope = RepositoryScope.ALL,
|
||||
@SerialName("content")
|
||||
internal var content: ContentDocument = ContentDocument(),
|
||||
@SerialName("credentials")
|
||||
internal var credentials: CredentialsDocument = CredentialsDocument(),
|
||||
@SerialName("url")
|
||||
internal var url: String = "",
|
||||
@SerialName("path")
|
||||
internal var path: String = "",
|
||||
) : IYamlDocument {
|
||||
|
||||
/**
|
||||
* 身份验证配置项文档实体
|
||||
*
|
||||
* 这些内容来自 [PasswordCredentials]
|
||||
* @param username 用户名
|
||||
* @param password 密码
|
||||
*/
|
||||
@Serializable
|
||||
internal data class CredentialsDocument(
|
||||
@SerialName("username")
|
||||
internal var username: String = "",
|
||||
@SerialName("password")
|
||||
internal var password: String = ""
|
||||
) : IYamlDocument
|
||||
|
||||
/**
|
||||
* 内容配置文档实体
|
||||
*
|
||||
* 这些内容来自 [RepositoryContentDescriptor]
|
||||
* @param exclude 排除配置文档实体
|
||||
* @param include 包含配置文档实体
|
||||
*/
|
||||
@Serializable
|
||||
internal data class ContentDocument(
|
||||
@SerialName("exclude")
|
||||
internal var exclude: FilterDocument = FilterDocument(),
|
||||
@SerialName("include")
|
||||
internal var include: FilterDocument = FilterDocument()
|
||||
) : IYamlDocument {
|
||||
|
||||
/**
|
||||
* 内容过滤器配置文档实体
|
||||
*
|
||||
* 这些内容来自 [RepositoryContentDescriptor]
|
||||
* @param group 过滤器条件内容
|
||||
* @param groupAndSubgroups 过滤器条件内容
|
||||
* @param groupByRegex 过滤器条件内容
|
||||
* @param module 过滤器条件内容
|
||||
* @param moduleByRegex 过滤器条件内容
|
||||
* @param version 过滤器条件内容
|
||||
* @param versionByRegex 过滤器条件内容
|
||||
*/
|
||||
@Serializable
|
||||
internal data class FilterDocument(
|
||||
@SerialName("group")
|
||||
internal var group: String = "",
|
||||
@SerialName("group-and-subgroups")
|
||||
internal var groupAndSubgroups: String = "",
|
||||
@SerialName("group-by-regex")
|
||||
internal var groupByRegex: String = "",
|
||||
@SerialName("module")
|
||||
internal var module: String = "",
|
||||
@SerialName("module-by-regex")
|
||||
internal var moduleByRegex: String = "",
|
||||
@SerialName("version")
|
||||
internal var version: String = "",
|
||||
@SerialName("version-by-regex")
|
||||
internal var versionByRegex: String = ""
|
||||
) : IYamlDocument {
|
||||
|
||||
/**
|
||||
* 获取过滤器条件内容
|
||||
* @return [List]<[String]>
|
||||
*/
|
||||
internal fun group() = group.toSpaceList()
|
||||
|
||||
/**
|
||||
* 获取过滤器条件内容
|
||||
* @return [List]<[String]>
|
||||
*/
|
||||
internal fun groupAndSubgroups() = groupAndSubgroups.toSpaceList()
|
||||
|
||||
/**
|
||||
* 获取过滤器条件内容
|
||||
* @return [List]<[String]>
|
||||
*/
|
||||
internal fun groupByRegex() = groupByRegex.toSpaceList()
|
||||
|
||||
/**
|
||||
* 获取过滤器条件内容
|
||||
* @return [List]<[String]>
|
||||
*/
|
||||
internal fun module() = module.toSpaceList()
|
||||
|
||||
/**
|
||||
* 获取过滤器条件内容
|
||||
* @return [List]<[String]>
|
||||
*/
|
||||
internal fun moduleByRegex() = moduleByRegex.toSpaceList()
|
||||
|
||||
/**
|
||||
* 获取过滤器条件内容
|
||||
* @return [List]<[String]>
|
||||
*/
|
||||
internal fun version() = version.toSpaceList()
|
||||
|
||||
/**
|
||||
* 获取过滤器条件内容
|
||||
* @return [List]<[String]>
|
||||
*/
|
||||
internal fun versionByRegex() = versionByRegex.toSpaceList()
|
||||
|
||||
/**
|
||||
* 当前规则是否为空
|
||||
* @return [Boolean]
|
||||
*/
|
||||
internal fun isEmpty() =
|
||||
group.isBlank() && groupAndSubgroups.isBlank() && groupByRegex.isBlank() &&
|
||||
module.isBlank() && moduleByRegex.isBlank() &&
|
||||
version.isBlank() && versionByRegex.isBlank()
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前规则是否为空
|
||||
* @return [Boolean]
|
||||
*/
|
||||
internal fun isEmpty() = exclude.isEmpty() && include.isEmpty()
|
||||
}
|
||||
|
||||
/** 节点名称 */
|
||||
@Transient
|
||||
internal var nodeName = ""
|
||||
|
||||
/** 节点类型 */
|
||||
@Transient
|
||||
internal var nodeType = RepositoryType.UNSPECIFIED
|
||||
|
||||
/**
|
||||
* 存储库作用域定义类
|
||||
*/
|
||||
internal enum class RepositoryScope {
|
||||
/** 作用于所有类型依赖 */
|
||||
ALL,
|
||||
|
||||
/** 作用于插件依赖 */
|
||||
PLUGINS,
|
||||
|
||||
/** 作用于库依赖 */
|
||||
LIBRARIES
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储库已知类型定义类
|
||||
*/
|
||||
internal enum class RepositoryType {
|
||||
/** 未指定 */
|
||||
UNSPECIFIED,
|
||||
|
||||
/** Google Maven */
|
||||
GOOGLE,
|
||||
|
||||
/** 中央存储库 */
|
||||
MAVEN_CENTRAL,
|
||||
|
||||
/** 本地存储库 */
|
||||
MAVEN_LOCAL,
|
||||
|
||||
/** 自定义存储库 */
|
||||
MAVEN,
|
||||
|
||||
/** Gradle Plugin 存储库 */
|
||||
GRADLE_PLUGIN_PORTAL
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取是否包含在作用域内
|
||||
* @param isPlugins 当前类型是否为插件依赖
|
||||
* @return [Boolean]
|
||||
*/
|
||||
internal fun isIncludeScope(isPlugins: Boolean) =
|
||||
if (isPlugins) scope == RepositoryScope.ALL || scope == RepositoryScope.PLUGINS
|
||||
else scope == RepositoryScope.ALL || scope == RepositoryScope.LIBRARIES
|
||||
|
||||
/**
|
||||
* 创建当前实体
|
||||
* @param name 键值名称
|
||||
* @return [RepositoryDocument]
|
||||
*/
|
||||
internal fun build(name: String) = apply {
|
||||
when (name) {
|
||||
InternalRepositories.Name.GOOGLE -> {
|
||||
url = url.ifBlank { InternalRepositories.GOOGLE }
|
||||
nodeType = RepositoryType.GOOGLE
|
||||
}
|
||||
InternalRepositories.Name.MAVEN_CENTRAL -> {
|
||||
url = url.ifBlank { InternalRepositories.MAVEN_CENTRAL }
|
||||
nodeType = RepositoryType.MAVEN_CENTRAL
|
||||
}
|
||||
InternalRepositories.Name.GRADLE_PLUGIN_PORTAL -> {
|
||||
url = url.ifBlank { InternalRepositories.GRADLE_PLUGIN_PORTAL }
|
||||
nodeType = RepositoryType.GRADLE_PLUGIN_PORTAL
|
||||
}
|
||||
InternalRepositories.Name.MAVEN_LOCAL -> {
|
||||
path = path.ifBlank { Repositories.defaultMavenLocalPath }
|
||||
nodeType = RepositoryType.MAVEN_LOCAL
|
||||
}
|
||||
InternalRepositories.Name.MAVEN -> SError.make("Use \"maven\" as a repository name is an error, please choose another name")
|
||||
InternalRepositories.Name.IVY -> SError.make("Ivy is not support on ${SweetDependency.TAG} ${SweetDependency.VERSION}")
|
||||
else -> {
|
||||
url = url.ifBlank {
|
||||
Repositories.findAdditional(name).ifBlank {
|
||||
SError.make("Could not found internal or additional repository URL by repository name \"$name\", you must specify a URL")
|
||||
}
|
||||
}; nodeType = RepositoryType.MAVEN
|
||||
}
|
||||
}; nodeName = name
|
||||
if (url.isNotBlank() && path.isNotBlank()) SError.make("There can only be one \"url\" and \"path\" parameter of \"$name\"")
|
||||
if (path.isNotBlank() && (path.startsWith("https://") || path.startsWith("http://"))) SError.make("Invalid repository path: $path")
|
||||
if (url.isNotBlank() && url.startsWith("https://").not() && url.startsWith("http://").not()) SError.make("Invalid repository URL: $url")
|
||||
if (path.isNotBlank()) path = path.parseUnixFileSeparator()
|
||||
}
|
||||
}
|
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
* 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/17.
|
||||
*/
|
||||
@file:Suppress("MemberVisibilityCanBePrivate")
|
||||
|
||||
package com.highcapable.sweetdependency.document
|
||||
|
||||
import com.highcapable.sweetdependency.SweetDependency
|
||||
import com.highcapable.sweetdependency.document.factory.DependencyMap
|
||||
import com.highcapable.sweetdependency.document.factory.RepositoryList
|
||||
import com.highcapable.sweetdependency.document.factory.checkingName
|
||||
import com.highcapable.sweetdependency.document.factory.convertToDependencyAmbiguousName
|
||||
import com.highcapable.sweetdependency.gradle.entity.DependencyName
|
||||
import com.highcapable.sweetdependency.gradle.entity.DependencyVersion
|
||||
import com.highcapable.sweetdependency.utils.capitalize
|
||||
import com.highcapable.sweetdependency.utils.debug.SError
|
||||
import com.highcapable.sweetdependency.utils.findDuplicates
|
||||
import com.highcapable.sweetdependency.utils.hasDuplicate
|
||||
import com.highcapable.sweetdependency.utils.yaml.proxy.IYamlDocument
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
/**
|
||||
* 项目 (根节点) 配置文档实体
|
||||
* @param preferences 偏好配置项文档实体
|
||||
* @param repositories 每项存储库配置项文档实体
|
||||
* @param plugins 每项插件依赖文档实体
|
||||
* @param libraries 每项库依赖文档实体
|
||||
* @param versions 每项版本定义数组
|
||||
*/
|
||||
@Serializable
|
||||
internal data class RootConfigDocument(
|
||||
@SerialName("preferences")
|
||||
internal var preferences: PreferencesDocument? = PreferencesDocument(),
|
||||
@SerialName("repositories")
|
||||
internal var repositories: MutableMap<String, RepositoryDocument?>? = null,
|
||||
@SerialName("plugins")
|
||||
internal var plugins: MutableMap<String, DependencyDocument>? = null,
|
||||
@SerialName("libraries")
|
||||
internal var libraries: MutableMap<String, MutableMap<String, DependencyDocument>>? = null,
|
||||
@SerialName("versions")
|
||||
internal var versions: MutableMap<String, String>? = null
|
||||
) : IYamlDocument {
|
||||
|
||||
internal companion object {
|
||||
|
||||
/** 默认文档内容 */
|
||||
private const val DEFAULT_CONTENT = """
|
||||
# SweetDependency project configuration file
|
||||
# You can adjust your custom configuration to your liking here
|
||||
# You can visit ${SweetDependency.PROJECT_URL} for more help
|
||||
#
|
||||
# SweetDependency 项目配置文件
|
||||
# 你可以在这里调整你喜欢的自定义配置
|
||||
# 你可以前往 ${SweetDependency.PROJECT_URL} 以获得更多帮助
|
||||
|
||||
# Configure preferences
|
||||
# 配置偏好设置
|
||||
preferences:
|
||||
autowire-on-sync-mode: UPDATE_OPTIONAL_DEPENDENCIES
|
||||
repositories-mode: FAIL_ON_PROJECT_REPOS
|
||||
|
||||
# Configure repositories used by dependencies
|
||||
# 配置依赖使用的存储库
|
||||
repositories:
|
||||
gradle-plugin-portal:
|
||||
scope: PLUGINS
|
||||
google:
|
||||
maven-central:
|
||||
|
||||
# Configure plugins that need to be used
|
||||
# For example:
|
||||
# plugins:
|
||||
# org.jetbrains.kotlin.jvm:
|
||||
# version: +
|
||||
#
|
||||
# 配置需要使用的插件依赖
|
||||
# 例如:
|
||||
# plugins:
|
||||
# org.jetbrains.kotlin.jvm:
|
||||
# version: +
|
||||
plugins:
|
||||
|
||||
# Configure libraries that need to be used
|
||||
# For example:
|
||||
# libraries:
|
||||
# com.google.code.gson:
|
||||
# gson:
|
||||
# version: +
|
||||
#
|
||||
# 配置需要使用的库依赖
|
||||
# 例如:
|
||||
# libraries:
|
||||
# com.google.code.gson:
|
||||
# gson:
|
||||
# version: +
|
||||
libraries:
|
||||
|
||||
"""
|
||||
|
||||
/** 默认文档内容 */
|
||||
internal val defaultContent = DEFAULT_CONTENT.trimIndent()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前偏好配置项文档实体
|
||||
* @return [PreferencesDocument]
|
||||
*/
|
||||
internal fun preferences() = preferences ?: PreferencesDocument()
|
||||
|
||||
/**
|
||||
* 获取当前存储库配置项文档实体
|
||||
* @return [RepositoryList]
|
||||
*/
|
||||
internal fun repositories() = repositories?.let {
|
||||
mutableListOf<RepositoryDocument>().apply {
|
||||
it.forEach { (name, repository) -> (repository ?: RepositoryDocument()).build(name).also { if (it.isEnable) add(it) } }
|
||||
}
|
||||
} ?: mutableListOf()
|
||||
|
||||
/**
|
||||
* 获取当前插件依赖数组
|
||||
* @param duplicate 允许重复 - 忽略处理后版本重复的异常 - 默认否
|
||||
* @return [DependencyMap]
|
||||
*/
|
||||
internal fun plugins(duplicate: Boolean = false) = createPlugins().resolveDependencies(typeName = "plugin", duplicate)
|
||||
|
||||
/**
|
||||
* 获取当前库依赖数组
|
||||
* @param duplicate 允许重复 - 忽略处理后版本重复的异常 - 默认否
|
||||
* @return [DependencyMap]
|
||||
*/
|
||||
internal fun libraries(duplicate: Boolean = false) = createLibraries().resolveDependencies(typeName = "library", duplicate)
|
||||
|
||||
/**
|
||||
* 处理依赖数组
|
||||
* @param typeName 依赖类型名称
|
||||
* @param duplicate 允许重复 - 忽略处理后版本重复的异常 - 默认否
|
||||
*/
|
||||
private fun DependencyMap.resolveDependencies(typeName: String, duplicate: Boolean = false) = apply {
|
||||
val firstTypeName = typeName.capitalize()
|
||||
val checkDuplicateAlias = mutableMapOf<String, String>()
|
||||
val refLibraries = mutableListOf<Triple<DependencyName, String, DependencyVersion>>()
|
||||
val ambiguousNames = mutableListOf<String>()
|
||||
eachDependencies { dependencyName, artifact ->
|
||||
artifact.alias.checkingName("$typeName \"$dependencyName\" alias", isCheckMultiName = true)
|
||||
artifact.versions().forEach { (name, _) -> name.checkingName("$typeName \"$dependencyName\" version alias") }
|
||||
if (artifact.alias.isNotBlank())
|
||||
if (checkDuplicateAlias.contains(artifact.alias).not())
|
||||
checkDuplicateAlias[artifact.alias] = dependencyName.current
|
||||
else SError.make(
|
||||
"Duplicated alias \"${artifact.alias}\", " +
|
||||
"already declared in $typeName \"${checkDuplicateAlias[artifact.alias]}\""
|
||||
)
|
||||
if (artifact.version().isNoSpecific && (artifact.versions().isNotEmpty() || artifact.versionRef.isNotBlank()))
|
||||
SError.make(
|
||||
"$firstTypeName \"$dependencyName\" has declared that it does not specify a version, " +
|
||||
"so it cannot use \"versions\" or \"version-ref\""
|
||||
)
|
||||
if (artifact.versionRef.isNotBlank() && artifact.versionRef.startsWith("<this>::"))
|
||||
artifact.versionRef = artifact.versionRef.replace("<this>:", dependencyName.groupId)
|
||||
refLibraries.add(Triple(dependencyName, artifact.alias, artifact.version()))
|
||||
}
|
||||
eachDependencies { dependencyName, artifact ->
|
||||
/** 处理版本引用 */
|
||||
fun resolveVersionRef() {
|
||||
refLibraries.firstOrNull { artifact.versionRef.let { e -> e == it.first.current || e == it.second } }?.also {
|
||||
if (dependencyName == it.first || dependencyName.current == it.second)
|
||||
SError.make("$firstTypeName \"$dependencyName\" declared \"version-ref\" from itself (recursive call found)")
|
||||
when {
|
||||
it.third.isNoSpecific -> SError.make(
|
||||
"$firstTypeName \"${it.first}\" does not specify a version, so it can no longer be " +
|
||||
"declared as \"version-ref\" by $typeName \"$dependencyName\""
|
||||
)
|
||||
it.third.isBlank -> SError.make(
|
||||
"$firstTypeName \"${it.first}\" already has \"version-ref\" declared, so it can no longer" +
|
||||
" be declared as \"version-ref\" by $typeName \"$dependencyName\" (recursive call found)"
|
||||
)
|
||||
}; artifact.updateVersion(it.third)
|
||||
} ?: SError.make(
|
||||
"Could not found any versions or dependencies associated with " +
|
||||
"version-ref \"${artifact.versionRef}\" of $typeName \"$dependencyName\""
|
||||
)
|
||||
}
|
||||
if (artifact.version().isNoSpecific) return@eachDependencies
|
||||
if (artifact.version().isBlank)
|
||||
if (artifact.versionRef.isNotBlank())
|
||||
versions()[artifact.versionRef]?.also { artifact.version = it } ?: resolveVersionRef()
|
||||
else SError.make("Missing declared version when configuring $typeName \"$dependencyName\"")
|
||||
else if (artifact.version().isBlank.not() && artifact.versionRef.isNotBlank() && duplicate.not())
|
||||
SError.make("$firstTypeName \"$dependencyName\" can only have one \"version\" or \"version-ref\" node, please delete one")
|
||||
}
|
||||
eachDependencies { dependencyName, artifact ->
|
||||
ambiguousNames.add(dependencyName.ambiguousName())
|
||||
if (artifact.alias.isNotBlank()) {
|
||||
artifact.alias.checkingName("$typeName \"$dependencyName\" alias", isCheckMultiName = true)
|
||||
ambiguousNames.add(artifact.alias.convertToDependencyAmbiguousName())
|
||||
}; this[dependencyName] = artifact
|
||||
}
|
||||
if (ambiguousNames.hasDuplicate()) ambiguousNames.findDuplicates().forEach {
|
||||
SError.make("Found ambiguous name \"$it\" in declared dependencies, please checking your $typeName aliases that your declared")
|
||||
} else ambiguousNames.clear()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前版本定义数组
|
||||
* @return [MutableMap]<[String], [String]>
|
||||
*/
|
||||
internal fun versions() = versions?.onEach { (name, _) -> name.checkingName("versions name") } ?: mutableMapOf()
|
||||
|
||||
/**
|
||||
* 重新创建 [plugins]
|
||||
* @return [DependencyMap]
|
||||
*/
|
||||
private fun createPlugins() = mutableMapOf<DependencyName, DependencyDocument>().apply {
|
||||
plugins?.forEach { (notation, artifact) -> this[DependencyName.plugin(notation)] = artifact }
|
||||
}
|
||||
|
||||
/**
|
||||
* 重新创建 [libraries]
|
||||
* @return [DependencyMap]
|
||||
*/
|
||||
private fun createLibraries() = mutableMapOf<DependencyName, DependencyDocument>().apply {
|
||||
libraries?.forEach { (groupId, libraries) ->
|
||||
libraries.forEach { (artifactId, artifact) -> this[DependencyName.library(groupId, artifactId)] = artifact }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 循环每项 [plugins]、[libraries]
|
||||
* @param result 回调每项结果
|
||||
*/
|
||||
private inline fun DependencyMap.eachDependencies(result: (dependencyName: DependencyName, artifact: DependencyDocument) -> Unit) =
|
||||
forEach { (dependencyName, artifact) -> result(dependencyName, artifact) }
|
||||
}
|
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* 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/9.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.document
|
||||
|
||||
import com.highcapable.sweetdependency.gradle.entity.DependencyVersion
|
||||
import com.highcapable.sweetdependency.manager.content.Repositories
|
||||
import com.highcapable.sweetdependency.utils.filter
|
||||
import com.highcapable.sweetdependency.utils.toSpaceList
|
||||
import com.highcapable.sweetdependency.utils.yaml.proxy.IYamlDocument
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
/**
|
||||
* 版本过滤器文档实体
|
||||
* @param isUseInternal 使用内置过滤器
|
||||
* @param exclusionList 排除列表
|
||||
*/
|
||||
@Serializable
|
||||
internal data class VersionFilterDocument(
|
||||
@SerialName("use-internal")
|
||||
internal var isUseInternal: Boolean = true,
|
||||
@SerialName("exclusion-list")
|
||||
internal var exclusionList: String = ""
|
||||
) : IYamlDocument {
|
||||
|
||||
/**
|
||||
* 版本排除列表实体
|
||||
* @param list 当前排除列表数组
|
||||
*/
|
||||
internal class ExclusionList internal constructor(private val list: MutableList<String>) {
|
||||
|
||||
/**
|
||||
* 获取当前排除列表数组
|
||||
* @return [MutableList]<[String]>
|
||||
*/
|
||||
internal fun all() = list
|
||||
|
||||
/**
|
||||
* 当前是否存在排除列表
|
||||
* @return [Boolean]
|
||||
*/
|
||||
internal fun isEmpty() = all().isEmpty()
|
||||
|
||||
/**
|
||||
* 当前是否不存在排除列表
|
||||
* @return [Boolean]
|
||||
*/
|
||||
internal fun isNotEmpty() = isEmpty().not()
|
||||
|
||||
/**
|
||||
* 依赖于当前 [version] 提供的版本并在 [all] 中排除 (不区分大小写)
|
||||
*
|
||||
* 此操作会调用 [clone] 创建一个新实例并返回
|
||||
* @param version 当前版本
|
||||
* @return [ExclusionList]
|
||||
*/
|
||||
internal fun depends(version: DependencyVersion) = clone().apply {
|
||||
if (version.isAutowire.not() && version.isBlank.not()) all().removeAll { version.deployed.lowercase().contains(it.lowercase()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用 [all] 过滤当前版本字符串 (不区分大小写)
|
||||
* @param versions 当前版本字符串数组
|
||||
* @return [MutableList]<[DependencyVersion]>
|
||||
*/
|
||||
internal fun filter(versions: MutableList<DependencyVersion>) =
|
||||
if (all().isEmpty()) versions else versions.filter { version -> all().none { version.current.lowercase().contains(it.lowercase()) } }
|
||||
|
||||
/**
|
||||
* 克隆并创建一个新实例
|
||||
* @return [ExclusionList]
|
||||
*/
|
||||
private fun clone() = ExclusionList(mutableListOf<String>().apply { addAll(all()) })
|
||||
|
||||
override fun toString() = all().toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取排除列表
|
||||
* @return [ExclusionList]
|
||||
*/
|
||||
internal fun exclusionList() = ExclusionList(mutableListOf<String>().apply {
|
||||
if (isUseInternal) addAll(Repositories.defaultVersionFilterExclusionList)
|
||||
addAll(exclusionList.toSpaceList())
|
||||
})
|
||||
}
|
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* 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/31.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.document.factory
|
||||
|
||||
import com.highcapable.sweetdependency.document.DependencyDocument
|
||||
import com.highcapable.sweetdependency.document.PreferencesDocument
|
||||
import com.highcapable.sweetdependency.document.RepositoryDocument
|
||||
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.isUnSafeExtName
|
||||
import com.highcapable.sweetdependency.utils.debug.SError
|
||||
import com.highcapable.sweetdependency.utils.firstNumberToLetter
|
||||
|
||||
/** 存储库文档实体类型定义 */
|
||||
internal typealias RepositoryList = MutableList<RepositoryDocument>
|
||||
|
||||
/** 依赖文档实体类型定义 */
|
||||
internal typealias DependencyMap = MutableMap<DependencyName, DependencyDocument>
|
||||
|
||||
/** 依赖文档更新实体类型定义 */
|
||||
internal typealias DependencyUpdateMap = MutableMap<String, Pair<DependencyName, DependencyVersion>>
|
||||
|
||||
/** 依赖文档查找条件类型定义 */
|
||||
internal typealias DependenciesCondition = (dependencyName: DependencyName, artifact: DependencyDocument) -> Boolean
|
||||
|
||||
/**
|
||||
* 转换 [PreferencesDocument.AutowireOnSyncMode] 到 [DependencyUpdateMode]
|
||||
*
|
||||
* 如果为 [PreferencesDocument.AutowireOnSyncMode.OFF] 则会返回 null
|
||||
* @return [DependencyUpdateMode] or null
|
||||
*/
|
||||
internal fun PreferencesDocument.AutowireOnSyncMode.toUpdateMode() = when (this) {
|
||||
PreferencesDocument.AutowireOnSyncMode.UPDATE_OPTIONAL_DEPENDENCIES ->
|
||||
DependencyUpdateMode(DependencyUpdateMode.DependencyType.ALL, DependencyUpdateMode.UpdateType.UPDATE_OPTIONAL)
|
||||
PreferencesDocument.AutowireOnSyncMode.UPDATE_ALL_DEPENDENCIES ->
|
||||
DependencyUpdateMode(DependencyUpdateMode.DependencyType.ALL, DependencyUpdateMode.UpdateType.UPDATE_ALL)
|
||||
PreferencesDocument.AutowireOnSyncMode.ONLY_AUTOWIRE_DEPENDENCIES ->
|
||||
DependencyUpdateMode(DependencyUpdateMode.DependencyType.ALL, DependencyUpdateMode.UpdateType.ONLY_AUTOWIRE)
|
||||
PreferencesDocument.AutowireOnSyncMode.UPDATE_OPTIONAL_PLUGINS ->
|
||||
DependencyUpdateMode(DependencyUpdateMode.DependencyType.PLUGINS, DependencyUpdateMode.UpdateType.UPDATE_OPTIONAL)
|
||||
PreferencesDocument.AutowireOnSyncMode.UPDATE_ALL_PLUGINS ->
|
||||
DependencyUpdateMode(DependencyUpdateMode.DependencyType.PLUGINS, DependencyUpdateMode.UpdateType.UPDATE_ALL)
|
||||
PreferencesDocument.AutowireOnSyncMode.ONLY_AUTOWIRE_PLUGINS ->
|
||||
DependencyUpdateMode(DependencyUpdateMode.DependencyType.PLUGINS, DependencyUpdateMode.UpdateType.ONLY_AUTOWIRE)
|
||||
PreferencesDocument.AutowireOnSyncMode.UPDATE_OPTIONAL_LIBRARIES ->
|
||||
DependencyUpdateMode(DependencyUpdateMode.DependencyType.LIBRARIES, DependencyUpdateMode.UpdateType.UPDATE_OPTIONAL)
|
||||
PreferencesDocument.AutowireOnSyncMode.UPDATE_ALL_LIBRARIES ->
|
||||
DependencyUpdateMode(DependencyUpdateMode.DependencyType.LIBRARIES, DependencyUpdateMode.UpdateType.UPDATE_ALL)
|
||||
PreferencesDocument.AutowireOnSyncMode.ONLY_AUTOWIRE_LIBRARIES ->
|
||||
DependencyUpdateMode(DependencyUpdateMode.DependencyType.LIBRARIES, DependencyUpdateMode.UpdateType.ONLY_AUTOWIRE)
|
||||
PreferencesDocument.AutowireOnSyncMode.OFF -> null
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并到依赖名称
|
||||
* @param groupId Group ID
|
||||
* @param artifactId Artifact ID
|
||||
* @return [String]
|
||||
*/
|
||||
internal fun spliceToDependencyNotation(groupId: String, artifactId: String) = "$groupId:$artifactId"
|
||||
|
||||
/**
|
||||
* 分离到依赖名称数组
|
||||
*
|
||||
* "com.mylibrary:library-core" → "com.mylibrary" | "library-core"
|
||||
* @return [List]<[String]>
|
||||
*/
|
||||
internal fun String.splitToDependencyNames() = trim().split(":").apply { if (size != 2) SError.make("Invalid dependency name \"$this\"") }
|
||||
|
||||
/**
|
||||
* 分离到依赖生成名称数组
|
||||
*
|
||||
* "com.mylibrary:library-core" → "com" | "mylibrary" | "library" | "core"
|
||||
* @return [List]<[String]>
|
||||
*/
|
||||
internal fun String.splitToDependencyGenerateNames() =
|
||||
trim().replace("_", "|").replace(".", "|").replace(":", "|").replace("-", "|").split("|").filter { it.isNotBlank() }
|
||||
|
||||
/**
|
||||
* 转换到依赖 URL 名称
|
||||
*
|
||||
* "com.mylibrary:library-core" → "com/mylibrary/library-core"
|
||||
* @return [String]
|
||||
*/
|
||||
internal fun String.convertToDependencyUrlName() = splitToDependencyNames().let { "${it[0].replace(".", "/")}/${it[1]}" }
|
||||
|
||||
/**
|
||||
* 转换到依赖模糊分离名称 (使用 [symbol] 进行分离)
|
||||
*
|
||||
* "com.mylibrary:library-core" → "com[symbol]mylibrary[symbol]library[symbol]core"
|
||||
* @param symbol 分隔符 - 默认 "."
|
||||
* @param isReplaceFirstChar 是否使用 [firstNumberToLetter] 替换每一段第一个字符 - 默认否
|
||||
* @param isLowerCase 是否全部转换为小写 - 默认是
|
||||
* @return [String]
|
||||
*/
|
||||
internal fun String.convertToDependencyAmbiguousName(symbol: String = ".", isReplaceFirstChar: Boolean = false, isLowerCase: Boolean = true) =
|
||||
mutableListOf<String>().apply {
|
||||
trim().replace(".", "|").replace("_", "|").replace(":", "|").replace("-", "|").split("|").forEach {
|
||||
add(if (isReplaceFirstChar) it.firstNumberToLetter() else it)
|
||||
}
|
||||
}.joinToString(symbol).let { if (isLowerCase) it.lowercase() else it }
|
||||
|
||||
/**
|
||||
* 检查名称、别名是否合法
|
||||
*
|
||||
* - 只能包含:'0-9'、'A-Z'、'a-z'、'.'、'_'、'-' 且必须以字母开头 (长度至少为 3 位)
|
||||
* - 不能是 [isUnSafeExtName]
|
||||
* @param content 内容
|
||||
* @param isCheckExtName 是否同时检查是否为 Gradle 使用的关键字名称 - 默认否
|
||||
* @param isCheckMultiName 是否同时检查是否可被 [splitToDependencyGenerateNames] 分割为两位及以上名称 - 默认否
|
||||
* @throws IllegalArgumentException 如果名称、别名不合法
|
||||
*/
|
||||
internal fun String.checkingName(content: String, isCheckExtName: Boolean = false, isCheckMultiName: Boolean = false) {
|
||||
if (isBlank()) return
|
||||
if (length < 3) SError.make("Illegal $content \"$this\", the length of $content must be >= 3")
|
||||
/**
|
||||
* 检查是否为 Gradle 使用的关键字名称
|
||||
* @param isEnable 默认跟随 [isCheckExtName]
|
||||
* @throws IllegalArgumentException 如果名称、别名不合法
|
||||
*/
|
||||
fun String.checkUnSafeExtName(isEnable: Boolean = isCheckExtName) {
|
||||
if (isEnable && isUnSafeExtName()) SError.make("This $content \"$this\" of \"${this@checkingName}\" is a Gradle built-in extension")
|
||||
}
|
||||
checkUnSafeExtName()
|
||||
if (isCheckMultiName) splitToDependencyGenerateNames().also { splitedNames ->
|
||||
if (splitedNames.isEmpty()) SError.make("This $content \"$this\" cannot be split, please check and try again")
|
||||
if (splitedNames.size < 2) SError.make("This $content \"$this\" must be able to be split into at least 2 parts")
|
||||
splitedNames[0].checkUnSafeExtName(isEnable = true)
|
||||
splitedNames.forEach {
|
||||
if (it.first() !in 'A'..'Z' && it.first() !in 'a'..'z')
|
||||
SError.make("Illegal $content \"$it\" of \"$this\", it must start with a letter")
|
||||
}
|
||||
}
|
||||
forEachIndexed { index, char ->
|
||||
if ((char !in 'A'..'Z' && char !in 'a'..'z' && index == 0) ||
|
||||
(char !in 'A'..'Z' && char !in 'a'..'z' &&
|
||||
char !in '0'..'9' && char != '_' && char != '-' && char != '.')
|
||||
) SError.make("Illegal $content \"$this\", it only allow 26 letters (upper and lower case) and '.', '_', '-' and must start with a letter")
|
||||
}
|
||||
}
|
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* 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.document.mapping
|
||||
|
||||
import com.highcapable.sweetdependency.document.RootConfigDocument
|
||||
import com.highcapable.sweetdependency.document.factory.DependencyUpdateMap
|
||||
import com.highcapable.sweetdependency.document.factory.spliceToDependencyNotation
|
||||
import com.highcapable.sweetdependency.document.mapping.entity.DependencyMapping
|
||||
import com.highcapable.sweetdependency.exception.SweetDependencyUnresolvedException
|
||||
import com.highcapable.sweetdependency.gradle.entity.DependencyName
|
||||
import com.highcapable.sweetdependency.plugin.config.proxy.ISweetDependencyConfigs
|
||||
import com.highcapable.sweetdependency.utils.debug.SError
|
||||
import com.highcapable.sweetdependency.utils.debug.SLog
|
||||
import com.highcapable.sweetdependency.utils.filter
|
||||
import com.highcapable.sweetdependency.utils.joinToContent
|
||||
import com.highcapable.sweetdependency.utils.toFile
|
||||
import com.highcapable.sweetdependency.utils.yaml.Yaml
|
||||
import com.highcapable.sweetdependency.utils.yaml.factory.asMap
|
||||
import com.highcapable.sweetdependency.utils.yaml.factory.isKeyExist
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* [RootConfigDocument] 的测绘实例实现类
|
||||
* @param configs 当前配置
|
||||
*/
|
||||
internal class RootConfigDocumentMapping internal constructor(private val configs: ISweetDependencyConfigs) {
|
||||
|
||||
private companion object {
|
||||
|
||||
/** 偏好设置节点名称 */
|
||||
private const val PREFERENCES_NODE_NAME = "preferences:"
|
||||
|
||||
/** 存储库节点名称 */
|
||||
private const val REPOSITORIES_NODE_NAME = "repositories:"
|
||||
|
||||
/** 版本节点名称 */
|
||||
private const val VERSIONS_NODE_NAME = "versions:"
|
||||
|
||||
/** 插件依赖节点名称 */
|
||||
private const val PLUGINS_NODE_NAME = "plugins:"
|
||||
|
||||
/** 库依赖节点名称 */
|
||||
private const val LIBRARIES_NODE_NAME = "libraries:"
|
||||
|
||||
/** 依赖版本起始内容 */
|
||||
private const val VERSION_NODE_CONTENT = "version:"
|
||||
|
||||
/** 依赖版本引用节点名称 (不包括结尾的“:”) */
|
||||
private const val VERSION_REF_NODE_NAME = "version-ref"
|
||||
|
||||
/** 4 个空格 (缩进) 内容 */
|
||||
private const val SPACE_OF_4 = " "
|
||||
|
||||
/** 6 个空格 (缩进) 内容 */
|
||||
private const val SPACE_OF_6 = " "
|
||||
}
|
||||
|
||||
/** 当前配置文件 */
|
||||
private var configFile: File? = null
|
||||
|
||||
/** 配置文件行内容数组 */
|
||||
private val configFileContents = mutableListOf<String>()
|
||||
|
||||
/** 插件依赖测绘实体数组 */
|
||||
private val pluginsMapping = mutableListOf<DependencyMapping>()
|
||||
|
||||
/** 库依赖测绘实体数组 */
|
||||
private val librariesMapping = mutableListOf<DependencyMapping>()
|
||||
|
||||
init {
|
||||
runCatching { createMapping() }.onFailure {
|
||||
when (it) {
|
||||
is SweetDependencyUnresolvedException -> throw it
|
||||
else -> SLog.error("Failed to create config file's mapping, this will cause problem")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 创建测绘数据 */
|
||||
private fun createMapping() {
|
||||
configFileContents.clear()
|
||||
configFileContents.addAll(configs.configFilePath.toFile().apply { configFile = this }.readText().split("\n"))
|
||||
var isFoundPluginsStartLine = false
|
||||
var pluginsStartLine = -1
|
||||
var pluginsLine = 0
|
||||
var isFoundLibrariesStartLine = false
|
||||
var librariesStartLine = -1
|
||||
var librariesLine = 0
|
||||
val pluginsContents = mutableListOf<String>()
|
||||
val librariesContents = mutableListOf<String>()
|
||||
configFileContents.forEachIndexed { index, content ->
|
||||
if (content.contains("\"\"")) SError.make("Character declared like -> \"\" <- are not allowed, detected at line ${index + 1}")
|
||||
}
|
||||
configFileContents.forEachIndexed { index, content ->
|
||||
if (content.startsWith(PREFERENCES_NODE_NAME) ||
|
||||
content.startsWith(REPOSITORIES_NODE_NAME) ||
|
||||
content.startsWith(VERSIONS_NODE_NAME) ||
|
||||
content.startsWith(LIBRARIES_NODE_NAME)
|
||||
) {
|
||||
isFoundPluginsStartLine = false
|
||||
return@forEachIndexed
|
||||
}
|
||||
if (content.startsWith(PLUGINS_NODE_NAME)) {
|
||||
isFoundPluginsStartLine = true
|
||||
pluginsStartLine = index
|
||||
}
|
||||
if (isFoundPluginsStartLine) pluginsContents.add(content)
|
||||
}
|
||||
configFileContents.forEachIndexed { index, content ->
|
||||
if (content.startsWith(PREFERENCES_NODE_NAME) ||
|
||||
content.startsWith(REPOSITORIES_NODE_NAME) ||
|
||||
content.startsWith(VERSIONS_NODE_NAME) ||
|
||||
content.startsWith(PLUGINS_NODE_NAME)
|
||||
) {
|
||||
isFoundLibrariesStartLine = false
|
||||
return@forEachIndexed
|
||||
}
|
||||
if (content.startsWith(LIBRARIES_NODE_NAME)) {
|
||||
isFoundLibrariesStartLine = true
|
||||
librariesStartLine = index
|
||||
}
|
||||
if (isFoundLibrariesStartLine) librariesContents.add(content)
|
||||
}
|
||||
if (pluginsContents.isNotEmpty())
|
||||
Yaml.loadFromStringAsNode(pluginsContents.joinToContent()).forEach { (_, rootNode) ->
|
||||
rootNode.asMap()?.forEach { (notation, artifactNode) ->
|
||||
if (artifactNode.asMap()?.isKeyExist(VERSION_REF_NODE_NAME) == false)
|
||||
pluginsMapping.add(DependencyMapping(notation.content))
|
||||
}
|
||||
}
|
||||
if (librariesContents.isNotEmpty())
|
||||
Yaml.loadFromStringAsNode(librariesContents.joinToContent()).forEach { (_, rootNode) ->
|
||||
rootNode.asMap()?.forEach { (groupId, libraryNode) ->
|
||||
libraryNode.asMap()?.forEach { (artifactId, artifactNode) ->
|
||||
val notation = spliceToDependencyNotation(groupId.content, artifactId.content)
|
||||
if (artifactNode.asMap()?.isKeyExist(VERSION_REF_NODE_NAME) == false)
|
||||
librariesMapping.add(DependencyMapping(notation))
|
||||
}
|
||||
}
|
||||
}
|
||||
pluginsContents.onEachIndexed { index, content ->
|
||||
if ((content.trim().startsWith(VERSION_NODE_CONTENT) && content.startsWith(SPACE_OF_4)).not()) return@onEachIndexed
|
||||
pluginsMapping[pluginsLine].versionLine = index + pluginsStartLine
|
||||
pluginsLine++
|
||||
}.clear()
|
||||
librariesContents.onEachIndexed { index, content ->
|
||||
if ((content.trim().startsWith(VERSION_NODE_CONTENT) && content.startsWith(SPACE_OF_6)).not()) return@onEachIndexed
|
||||
librariesMapping[librariesLine].versionLine = index + librariesStartLine
|
||||
librariesLine++
|
||||
}.clear()
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用测绘数据更新依赖版本内容
|
||||
* @param dependencies 需要更新的依赖名称和版本数组
|
||||
*/
|
||||
internal fun updateDependencies(dependencies: DependencyUpdateMap) {
|
||||
/**
|
||||
* 写入更新的依赖数据到文件内容
|
||||
* @param dependencies 依赖数组
|
||||
* @param spaceContent 空格内容
|
||||
*/
|
||||
fun List<DependencyMapping>.dumpToContents(dependencies: DependencyUpdateMap, spaceContent: String) =
|
||||
filter { dependencies.containsKey(it.notation) }.forEach {
|
||||
var codeNote = ""
|
||||
val originContent = configFileContents[it.versionLine]
|
||||
if (originContent.contains("#")) originContent.indexOf("#")
|
||||
.also { e -> if (e > 0) codeNote = originContent.substring(e - 1..originContent.lastIndex) }
|
||||
configFileContents[it.versionLine] = "$spaceContent$VERSION_NODE_CONTENT ${dependencies[it.notation]?.second?.mapped}$codeNote"
|
||||
}
|
||||
|
||||
val plugins = dependencies.filter { it.value.first.type == DependencyName.Type.PLUGIN }
|
||||
val libraries = dependencies.filter { it.value.first.type == DependencyName.Type.LIBRARY }
|
||||
if (plugins.isNotEmpty()) pluginsMapping.dumpToContents(plugins, SPACE_OF_4)
|
||||
if (libraries.isNotEmpty()) librariesMapping.dumpToContents(libraries, SPACE_OF_6)
|
||||
if (configFileContents.isNotEmpty()) configFile?.writeText(buildString { configFileContents.forEach { append("$it\n") } }.trim())
|
||||
}
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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.document.mapping.entity
|
||||
|
||||
/**
|
||||
* 每项依赖测绘实体
|
||||
* @param notation 依赖名称或 ID
|
||||
* @param versionLine 版本所处行号
|
||||
*/
|
||||
internal data class DependencyMapping(internal var notation: String = "", internal var versionLine: Int = -1)
|
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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/28.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.environment
|
||||
|
||||
import com.highcapable.sweetdependency.SweetDependency
|
||||
import com.highcapable.sweetdependency.generated.SweetDependencyProperties
|
||||
import com.highcapable.sweetdependency.gradle.helper.GradleHelper
|
||||
import com.highcapable.sweetdependency.utils.toFile
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* [SweetDependency] 环境工具类
|
||||
*/
|
||||
internal object Environment {
|
||||
|
||||
/** [SweetDependency] 缓存存放目录 */
|
||||
private const val MEMORY_DIR_PATH = ".gradle/${SweetDependencyProperties.PROJECT_MODULE_NAME}"
|
||||
|
||||
/** [SweetDependency] 功能存放目录 */
|
||||
private const val RESOURCES_DIR_PATH = "gradle/${SweetDependencyProperties.PROJECT_MODULE_NAME}"
|
||||
|
||||
/**
|
||||
* 获取 [SweetDependency] 缓存存放目录
|
||||
* @return [File]
|
||||
*/
|
||||
private val memoryDir get() = "${GradleHelper.rootDir.absolutePath}/$MEMORY_DIR_PATH".toFile().also { if (it.exists().not()) it.mkdirs() }
|
||||
|
||||
/**
|
||||
* 获取 [SweetDependency] 功能存放目录
|
||||
* @return [File]
|
||||
*/
|
||||
private val resourcesDir get() = "${GradleHelper.rootDir.absolutePath}/$RESOURCES_DIR_PATH".toFile().also { if (it.exists().not()) it.mkdirs() }
|
||||
|
||||
/**
|
||||
* 获取系统信息
|
||||
* @return [String]
|
||||
*/
|
||||
internal val systemInfo get() = "${System.getProperty("os.name")} ${System.getProperty("os.version")}"
|
||||
|
||||
/**
|
||||
* 获取字符集名称
|
||||
* @return [String]
|
||||
*/
|
||||
internal val characterEncoding get() = System.getProperty("file.encoding")
|
||||
|
||||
/**
|
||||
* 获取 Java 版本
|
||||
* @return [String]
|
||||
*/
|
||||
internal val javaVersion get() = System.getProperty("java.version")
|
||||
|
||||
/**
|
||||
* 获取 [SweetDependency] 缓存存放目录
|
||||
* @param dirOrFileName 子路径目录、文件名称数组
|
||||
* @return [File]
|
||||
*/
|
||||
internal fun memoryDir(vararg dirOrFileName: String) = memoryDir.parseDir(*dirOrFileName)
|
||||
|
||||
/**
|
||||
* 获取 [SweetDependency] 功能存放目录
|
||||
* @param dirOrFileName 子路径目录、文件名称数组
|
||||
* @return [File]
|
||||
*/
|
||||
internal fun resourcesDir(vararg dirOrFileName: String) = resourcesDir.parseDir(*dirOrFileName)
|
||||
|
||||
/**
|
||||
* 解析 [SweetDependency] 存放目录
|
||||
* @param dirOrFileName 子路径目录、文件名称数组
|
||||
* @return [File]
|
||||
*/
|
||||
private fun File.parseDir(vararg dirOrFileName: String): File {
|
||||
var splitPath = ""
|
||||
dirOrFileName.forEach { splitPath += "$it/" }
|
||||
return "$absolutePath/${splitPath.ifBlank { "/" }.dropLast(1)}".toFile()
|
||||
}
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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/31.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.exception
|
||||
|
||||
import com.highcapable.sweetdependency.SweetDependency
|
||||
import com.highcapable.sweetdependency.utils.dumpToString
|
||||
|
||||
/**
|
||||
* [SweetDependency] 异常定义类
|
||||
* @param msg 异常内容
|
||||
* @param parent 父级异常 - 默认空
|
||||
*/
|
||||
internal class SweetDependencyUnresolvedException internal constructor(private val msg: String, parent: Throwable? = null) : Exception(
|
||||
("[${SweetDependency.TAG}] The project initialization could not be completed, please check the following for errors\n" +
|
||||
"If you need help, visit ${SweetDependency.PROJECT_URL}\n" +
|
||||
"* What went wrong:\n" +
|
||||
"$msg\n${if (parent != null) (when (parent) {
|
||||
is SweetDependencyUnresolvedException -> "* Caused by:"
|
||||
else -> "* Exception is:"
|
||||
} + "\n${parent.dumpToString()}") else ""}").trim()
|
||||
) {
|
||||
override fun toString() = "${javaClass.simpleName}: $msg"
|
||||
}
|
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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/26.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.gradle.delegate
|
||||
|
||||
import com.highcapable.sweetdependency.gradle.helper.GradleHelper
|
||||
import com.highcapable.sweetdependency.gradle.proxy.IGradleLifecycle
|
||||
import com.highcapable.sweetdependency.utils.debug.SError
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.initialization.Settings
|
||||
|
||||
/**
|
||||
* Gradle 代理工具类
|
||||
*/
|
||||
internal object GradleDelegate {
|
||||
|
||||
/** 当前 Gradle 生命周期接口实例 */
|
||||
private var lifecycle: IGradleLifecycle? = null
|
||||
|
||||
/**
|
||||
* 创建 Gradle 生命周期 (插件) [T]
|
||||
* @param settings 当前设置
|
||||
*/
|
||||
internal inline fun <reified T : IGradleLifecycle> create(settings: Settings) {
|
||||
runCatching {
|
||||
lifecycle = T::class.java.getConstructor().newInstance()
|
||||
}.onFailure { SError.make("Failed to create Gradle lifecycle of \"${T::class.java}\"") }
|
||||
GradleHelper.attach(settings)
|
||||
callOnSettingsLoaded(settings)
|
||||
settings.gradle.settingsEvaluated { callOnSettingsEvaluate(settings = this) }
|
||||
settings.gradle.projectsLoaded {
|
||||
callOnProjectLoaded(rootProject, isRoot = true)
|
||||
rootProject.afterEvaluate { callOnProjectEvaluate(project = this, isRoot = true) }
|
||||
rootProject.subprojects.forEach {
|
||||
callOnProjectLoaded(it, isRoot = false)
|
||||
it.afterEvaluate { callOnProjectEvaluate(project = this, isRoot = false) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用 Gradle 开始装载事件
|
||||
* @param settings 当前实例
|
||||
*/
|
||||
private fun callOnSettingsLoaded(settings: Settings) {
|
||||
lifecycle?.onSettingsLoaded(settings)
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用 Gradle 装载完成事件
|
||||
* @param settings 当前实例
|
||||
*/
|
||||
private fun callOnSettingsEvaluate(settings: Settings) {
|
||||
lifecycle?.onSettingsEvaluate(settings)
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用 Gradle 开始装载项目事件
|
||||
* @param project 当前项目
|
||||
* @param isRoot 是否为根项目
|
||||
*/
|
||||
private fun callOnProjectLoaded(project: Project, isRoot: Boolean) {
|
||||
if (isRoot) GradleHelper.cachingProjectList(project)
|
||||
lifecycle?.onProjectLoaded(project, isRoot)
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用 Gradle 项目装载完成事件
|
||||
* @param project 当前项目
|
||||
* @param isRoot 是否为根项目
|
||||
*/
|
||||
private fun callOnProjectEvaluate(project: Project, isRoot: Boolean) {
|
||||
GradleHelper.cachingDependencyList(project, isRoot)
|
||||
lifecycle?.onProjectEvaluate(project, isRoot)
|
||||
}
|
||||
}
|
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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/29.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.gradle.delegate
|
||||
|
||||
import org.gradle.api.Project
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
/**
|
||||
* 项目事务实例实现类
|
||||
*/
|
||||
internal class ProjectTransaction {
|
||||
|
||||
internal companion object {
|
||||
|
||||
/** 当前项目 (当前生命周期静态) */
|
||||
internal var current by Delegates.notNull<Project>()
|
||||
|
||||
/** 是否为根项目 (当前生命周期静态) */
|
||||
internal var isRoot by Delegates.notNull<Boolean>()
|
||||
}
|
||||
|
||||
/** 当前装载实例方法体数组 */
|
||||
internal val evaluateCallbacks = mutableSetOf<((Project, Boolean) -> Unit)>()
|
||||
|
||||
/**
|
||||
* 获取当前项目
|
||||
* @return [Project]
|
||||
*/
|
||||
internal val current get() = Companion.current
|
||||
|
||||
/**
|
||||
* 获取是否为根项目
|
||||
* @return [Boolean]
|
||||
*/
|
||||
internal val isRoot get() = Companion.isRoot
|
||||
|
||||
/**
|
||||
* 创建装载实例监听
|
||||
* @param evaluate 回调装载监听 - ([Project] 当前项目,[Boolean] 师傅为根项目)
|
||||
*/
|
||||
internal fun evaluation(evaluate: (project: Project, isRoot: Boolean) -> Unit) {
|
||||
evaluateCallbacks.add(evaluate)
|
||||
}
|
||||
}
|
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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("USELESS_ELVIS", "KotlinRedundantDiagnosticSuppress")
|
||||
|
||||
package com.highcapable.sweetdependency.gradle.delegate.entity
|
||||
|
||||
import com.highcapable.sweetdependency.document.factory.spliceToDependencyNotation
|
||||
import com.highcapable.sweetdependency.gradle.entity.DependencyVersion
|
||||
import com.highcapable.sweetdependency.manager.GradleTaskManager
|
||||
import com.highcapable.sweetdependency.utils.debug.SError
|
||||
import org.gradle.api.internal.artifacts.dependencies.DefaultExternalModuleDependency
|
||||
|
||||
/**
|
||||
* 外部存储库依赖实体代理类
|
||||
*
|
||||
* 代理 [DefaultExternalModuleDependency]
|
||||
* @param groupId Group ID
|
||||
* @param artifactId Artifact ID
|
||||
* @param version 版本
|
||||
*/
|
||||
internal open class ExternalDependencyDelegate internal constructor(
|
||||
@get:JvmName("getDelegateGroupId")
|
||||
@set:JvmName("setDelegateGroupId")
|
||||
var groupId: String,
|
||||
@get:JvmName("getDelegateArtifactId")
|
||||
@set:JvmName("setDelegateArtifactId")
|
||||
var artifactId: String,
|
||||
@get:JvmName("getDelegateVersion")
|
||||
@set:JvmName("setDelegateVersion")
|
||||
var version: String
|
||||
) : DefaultExternalModuleDependency(groupId, artifactId, version) {
|
||||
|
||||
override fun getVersion(): String {
|
||||
val notation = spliceToDependencyNotation(groupId, artifactId)
|
||||
if (version == DependencyVersion.AUTOWIRE_VERSION_NAME && GradleTaskManager.isInternalRunningTask.not()) SError.make(
|
||||
"""
|
||||
This library "$notation" is not autowired and cannot be deployed
|
||||
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_LIBRARIES_TASK_NAME}" task and re-run Gradle Sync
|
||||
3. Fill an existing version for dependency "$notation" and re-run Gradle Sync
|
||||
If you get this error again after doing the above, maybe the currently set repositories cannot find this library
|
||||
""".trimIndent()
|
||||
); return super.getVersion() ?: version
|
||||
}
|
||||
|
||||
override fun toString() = "ExternalDependencyDelegate(groupId = $groupId, artifactId = $artifactId, version = $version)"
|
||||
}
|
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* 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/8/16.
|
||||
*/
|
||||
@file:Suppress("unused", "MemberVisibilityCanBePrivate")
|
||||
|
||||
package com.highcapable.sweetdependency.gradle.entity
|
||||
|
||||
import com.highcapable.sweetdependency.document.factory.convertToDependencyAmbiguousName
|
||||
import com.highcapable.sweetdependency.document.factory.convertToDependencyUrlName
|
||||
import com.highcapable.sweetdependency.document.factory.spliceToDependencyNotation
|
||||
import com.highcapable.sweetdependency.document.factory.splitToDependencyNames
|
||||
import com.highcapable.sweetdependency.utils.firstNumberToLetter
|
||||
|
||||
/**
|
||||
* 依赖名称实体类
|
||||
* @param type 名称类型
|
||||
* @param groupId Group ID
|
||||
* @param artifactId Artifact ID
|
||||
*/
|
||||
internal class DependencyName private constructor(internal val type: Type, internal val groupId: String, internal val artifactId: String) {
|
||||
|
||||
internal companion object {
|
||||
|
||||
/** 标识 Gradle 插件后缀名称 */
|
||||
private const val GRADLE_PLUGIN_SUFFIX = "gradle.plugin"
|
||||
|
||||
/**
|
||||
* 创建为插件依赖名称
|
||||
* @param notation 完整名称
|
||||
*/
|
||||
internal fun plugin(notation: String) = DependencyName(Type.PLUGIN, notation, "$notation.$GRADLE_PLUGIN_SUFFIX")
|
||||
|
||||
/**
|
||||
* 创建为库依赖名称
|
||||
* @param notation 完整名称
|
||||
*/
|
||||
internal fun library(notation: String) = notation.splitToDependencyNames().let { names -> DependencyName(Type.LIBRARY, names[0], names[1]) }
|
||||
|
||||
/**
|
||||
* 创建为库依赖名称
|
||||
* @param groupId Group ID
|
||||
* @param artifactId Artifact ID
|
||||
*/
|
||||
internal fun library(groupId: String, artifactId: String) = DependencyName(Type.LIBRARY, groupId, artifactId)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前模糊分离名称 (使用 [symbol] 进行分离)
|
||||
* @param symbol 分隔符 - 默认 "."
|
||||
* @param isReplaceFirstChar 是否使用 [firstNumberToLetter] 替换每一段第一个字符 - 默认否
|
||||
* @param isLowerCase 是否全部转换为小写 - 默认是
|
||||
* @return [String]
|
||||
*/
|
||||
internal fun ambiguousName(symbol: String = ".", isReplaceFirstChar: Boolean = false, isLowerCase: Boolean = true) =
|
||||
current.convertToDependencyAmbiguousName(symbol, isReplaceFirstChar, isLowerCase)
|
||||
|
||||
/**
|
||||
* 获取当前 URL 名称
|
||||
* @return [String]
|
||||
*/
|
||||
internal val urlName get() = notation.convertToDependencyUrlName()
|
||||
|
||||
/**
|
||||
* 获取当前描述内容
|
||||
* @return [String]
|
||||
*/
|
||||
internal val description get() = "$typeName \"$current\""
|
||||
|
||||
/**
|
||||
* 获取当前类型名称
|
||||
* @return [String]
|
||||
*/
|
||||
internal val typeName get() = when (type) {
|
||||
Type.PLUGIN -> "Plugin"
|
||||
Type.LIBRARY -> "Library"
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前名称
|
||||
* @return [String]
|
||||
*/
|
||||
internal val current get() = when (type) {
|
||||
Type.PLUGIN -> groupId
|
||||
Type.LIBRARY -> notation
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前完整名称
|
||||
* @return [String]
|
||||
*/
|
||||
internal val notation get() = spliceToDependencyNotation(groupId, artifactId)
|
||||
|
||||
override fun equals(other: Any?) = other.toString() == toString()
|
||||
|
||||
override fun hashCode() = toString().hashCode()
|
||||
|
||||
override fun toString() = current
|
||||
|
||||
/**
|
||||
* 名称类型定义类
|
||||
*/
|
||||
internal enum class Type {
|
||||
/** 插件依赖 */
|
||||
PLUGIN,
|
||||
|
||||
/** 库依赖 */
|
||||
LIBRARY
|
||||
}
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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/8/18.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.gradle.entity
|
||||
|
||||
/**
|
||||
* 依赖更新模式实体类
|
||||
* @param dependencyType 依赖类型
|
||||
* @param updateType 依赖更新模式
|
||||
*/
|
||||
internal data class DependencyUpdateMode(internal var dependencyType: DependencyType, internal var updateType: UpdateType) {
|
||||
|
||||
/**
|
||||
* 依赖类型定义类
|
||||
*/
|
||||
internal enum class DependencyType {
|
||||
/** 全部类型 */
|
||||
ALL,
|
||||
|
||||
/** 插件依赖 */
|
||||
PLUGINS,
|
||||
|
||||
/** 库依赖 */
|
||||
LIBRARIES,
|
||||
}
|
||||
|
||||
/**
|
||||
* 依赖更新模式类型定义类
|
||||
*/
|
||||
internal enum class UpdateType {
|
||||
/** 可选更新 */
|
||||
UPDATE_OPTIONAL,
|
||||
|
||||
/** 全部更新 */
|
||||
UPDATE_ALL,
|
||||
|
||||
/** 仅自动装配 */
|
||||
ONLY_AUTOWIRE,
|
||||
}
|
||||
}
|
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* 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/16.
|
||||
*/
|
||||
@file:Suppress("MemberVisibilityCanBePrivate")
|
||||
|
||||
package com.highcapable.sweetdependency.gradle.entity
|
||||
|
||||
import com.highcapable.sweetdependency.utils.debug.SError
|
||||
|
||||
/**
|
||||
* 依赖版本实体类
|
||||
* @param actual 当前实际版本 - 如果为 [DependencyVersion.isOptional] 则会显示在第一位
|
||||
* @param optionalType 可选更新类型 - 默认为 [DependencyVersion.OptionalUpdateType.NONE]
|
||||
*/
|
||||
internal class DependencyVersion(internal var actual: String, optionalType: OptionalUpdateType = OptionalUpdateType.NONE) {
|
||||
|
||||
internal companion object {
|
||||
|
||||
/** 标识自动装配版本的名称 */
|
||||
const val AUTOWIRE_VERSION_NAME = "+"
|
||||
|
||||
/** 标识不指定版本的名称 */
|
||||
const val NO_SPECIFIC_VERSION_NAME = "<no-spec>"
|
||||
|
||||
/** 标识当前最新版本的名称 */
|
||||
const val LATEST_VERSION_NAME = "<latest>"
|
||||
|
||||
/** 标识常规可选更新版本前缀名称 */
|
||||
private const val OPTIONAL_VERSION_NORMAL_PREFIX = "^"
|
||||
|
||||
/** 标识常驻可选更新版本前缀名称 */
|
||||
private const val OPTIONAL_VERSION_PERMANENT_PREFIX = "^^"
|
||||
}
|
||||
|
||||
init {
|
||||
if (current.startsWith("<") && current.endsWith(">"))
|
||||
if (current != NO_SPECIFIC_VERSION_NAME && current != LATEST_VERSION_NAME)
|
||||
SError.make("The parameter \"$current\" is not recognized as any available function")
|
||||
if (isOptional.not()) when (optionalType) {
|
||||
OptionalUpdateType.NONE -> {}
|
||||
OptionalUpdateType.NORMAL -> actual = "$OPTIONAL_VERSION_NORMAL_PREFIX$actual"
|
||||
OptionalUpdateType.PERMANENT -> actual = "$OPTIONAL_VERSION_PERMANENT_PREFIX$actual"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前版本
|
||||
* @return [String]
|
||||
*/
|
||||
internal val current get() = actual.replace(OPTIONAL_VERSION_PERMANENT_PREFIX, "").replace(OPTIONAL_VERSION_NORMAL_PREFIX, "")
|
||||
|
||||
/**
|
||||
* 获取当前测绘数据使用的版本
|
||||
*
|
||||
* 它会自动识别 [optionalType] 决定是否继续保留可选更新的符号
|
||||
* @return [String]
|
||||
*/
|
||||
internal val mapped get() = when (optionalType) {
|
||||
OptionalUpdateType.PERMANENT -> actual
|
||||
else -> current
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取部署版本
|
||||
*
|
||||
* 如果为 [isNoSpecific] 则会返回空
|
||||
* @return [String]
|
||||
*/
|
||||
internal val deployed get() = current.takeIf { isNoSpecific.not() } ?: ""
|
||||
|
||||
/**
|
||||
* 获取存在版本
|
||||
*
|
||||
* 如果为空则会返回 [NO_SPECIFIC_VERSION_NAME]
|
||||
* @return [String]
|
||||
*/
|
||||
internal val existed get() = current.ifBlank { NO_SPECIFIC_VERSION_NAME }
|
||||
|
||||
/**
|
||||
* 是否为空白
|
||||
* @return [Boolean]
|
||||
*/
|
||||
internal val isBlank get() = current.isBlank()
|
||||
|
||||
/**
|
||||
* 是否为自动装配版本
|
||||
* @return [Boolean]
|
||||
*/
|
||||
internal val isAutowire get() = current == AUTOWIRE_VERSION_NAME
|
||||
|
||||
/**
|
||||
* 是否为不指定版本
|
||||
* @return [Boolean]
|
||||
*/
|
||||
internal val isNoSpecific get() = current == NO_SPECIFIC_VERSION_NAME
|
||||
|
||||
/**
|
||||
* 是否为可选更新版本
|
||||
* @return [Boolean]
|
||||
*/
|
||||
internal val isOptional get() = optionalType != OptionalUpdateType.NONE
|
||||
|
||||
/**
|
||||
* 获取当前可选更新类型
|
||||
* @return [OptionalUpdateType]
|
||||
*/
|
||||
internal val optionalType get() = when {
|
||||
actual.startsWith(OPTIONAL_VERSION_PERMANENT_PREFIX) -> OptionalUpdateType.PERMANENT
|
||||
actual.startsWith(OPTIONAL_VERSION_NORMAL_PREFIX) -> OptionalUpdateType.NORMAL
|
||||
else -> OptionalUpdateType.NONE
|
||||
}
|
||||
|
||||
/**
|
||||
* 克隆为新的 [DependencyVersion] 实体
|
||||
* @param version 当前版本
|
||||
* @return [DependencyVersion]
|
||||
*/
|
||||
internal fun clone(version: String) = DependencyVersion(version, optionalType)
|
||||
|
||||
override fun equals(other: Any?) = other.toString() == toString()
|
||||
|
||||
override fun hashCode() = toString().hashCode()
|
||||
|
||||
override fun toString() = current
|
||||
|
||||
/**
|
||||
* 可选更新类型定义类
|
||||
*/
|
||||
internal enum class OptionalUpdateType {
|
||||
/** 无 */
|
||||
NONE,
|
||||
|
||||
/** 常规 */
|
||||
NORMAL,
|
||||
|
||||
/** 常驻 */
|
||||
PERMANENT,
|
||||
}
|
||||
}
|
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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/23.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.gradle.entity
|
||||
|
||||
/**
|
||||
* 外部存储库依赖实体类
|
||||
* @param dependencyName 依赖名称
|
||||
* @param version 版本
|
||||
*/
|
||||
internal data class ExternalDependency(private val dependencyName: DependencyName, internal val version: DependencyVersion) {
|
||||
|
||||
/**
|
||||
* 获取 Group ID
|
||||
* @return [String]
|
||||
*/
|
||||
internal val groupId get() = dependencyName.groupId
|
||||
|
||||
/**
|
||||
* 获取 Artifact ID
|
||||
* @return [String]
|
||||
*/
|
||||
internal val artifactId get() = dependencyName.artifactId
|
||||
|
||||
override fun toString() = dependencyName.current
|
||||
}
|
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* 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/27.
|
||||
*/
|
||||
@file:Suppress("unused", "USELESS_CAST", "KotlinRedundantDiagnosticSuppress")
|
||||
|
||||
package com.highcapable.sweetdependency.gradle.factory
|
||||
|
||||
import com.highcapable.sweetdependency.exception.SweetDependencyUnresolvedException
|
||||
import com.highcapable.sweetdependency.utils.camelcase
|
||||
import com.highcapable.sweetdependency.utils.debug.SError
|
||||
import org.gradle.api.Action
|
||||
import org.gradle.api.plugins.ExtensionAware
|
||||
|
||||
/**
|
||||
* 创建、获取扩展方法
|
||||
* @param name 方法名称 - 自动调用 [toSafeExtName]
|
||||
* @param clazz 目标对象 [Class]
|
||||
* @param args 方法参数
|
||||
* @return [ExtensionAware]
|
||||
*/
|
||||
internal fun ExtensionAware.getOrCreate(name: String, clazz: Class<*>, vararg args: Any?) = name.toSafeExtName().let { sName ->
|
||||
runCatching { extensions.create(sName, clazz, *args).asExtension() }.getOrElse {
|
||||
if ((it is IllegalArgumentException && it.message?.startsWith("Cannot add extension with name") == true).not()) throw it
|
||||
runCatching { extensions.getByName(sName).asExtension() }.getOrNull() ?: SError.make("Create or get extension failed with name \"$sName\"")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建、获取扩展方法 - 目标对象 [T]
|
||||
* @param name 方法名称 - 自动调用 [toSafeExtName]
|
||||
* @param args 方法参数
|
||||
* @return [T]
|
||||
*/
|
||||
internal inline fun <reified T> ExtensionAware.getOrCreate(name: String, vararg args: Any?) = name.toSafeExtName().let { sName ->
|
||||
runCatching { extensions.create(sName, T::class.java, *args) as T }.getOrElse {
|
||||
if ((it is IllegalArgumentException && it.message?.startsWith("Cannot add extension with name") == true).not()) throw it
|
||||
runCatching { extensions.getByName(sName) as? T? }.getOrNull() ?: SError.make("Create or get extension failed with name \"$sName\"")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取扩展方法
|
||||
* @param name 方法名称
|
||||
* @return [ExtensionAware]
|
||||
*/
|
||||
internal fun ExtensionAware.get(name: String) =
|
||||
runCatching { extensions.getByName(name).asExtension() }.getOrNull() ?: SError.make("Could not get extension with name \"$name\"")
|
||||
|
||||
/**
|
||||
* 获取扩展方法 - 目标对象 [T]
|
||||
* @param name 方法名称
|
||||
* @return [T]
|
||||
*/
|
||||
internal inline fun <reified T> ExtensionAware.get(name: String) =
|
||||
runCatching { extensions.getByName(name) as T }.getOrNull() ?: SError.make("Could not get extension with name \"$name\"")
|
||||
|
||||
/**
|
||||
* 获取扩展方法 - 目标对象 [T]
|
||||
* @return [T]
|
||||
*/
|
||||
internal inline fun <reified T> ExtensionAware.get() =
|
||||
runCatching { extensions.getByType(T::class.java) as T }.getOrNull() ?: SError.make("Could not get extension with type ${T::class.java}")
|
||||
|
||||
/**
|
||||
* 配置扩展方法 - 目标对象 [T]
|
||||
* @param name 方法名称
|
||||
* @param configure 配置方法体
|
||||
*/
|
||||
internal inline fun <reified T> ExtensionAware.configure(name: String, configure: Action<T>) = extensions.configure(name, configure)
|
||||
|
||||
/**
|
||||
* 是否存在扩展方法
|
||||
* @param name 方法名称
|
||||
* @return [Boolean]
|
||||
*/
|
||||
internal fun ExtensionAware.hasExtension(name: String) = runCatching { extensions.getByName(name); true }.getOrNull() ?: false
|
||||
|
||||
/**
|
||||
* 转换到扩展方法类型 [ExtensionAware]
|
||||
* @return [ExtensionAware]
|
||||
* @throws SweetDependencyUnresolvedException 如果类型不是 [ExtensionAware]
|
||||
*/
|
||||
internal fun Any.asExtension() = this as? ExtensionAware? ?: SError.make("This instance \"$this\" is not a valid Extension")
|
||||
|
||||
/**
|
||||
* 由于 Gradle 存在一个 [ExtensionAware] 的扩展
|
||||
*
|
||||
* 此功能用于检测当前字符串是否为 Gradle 使用的关键字名称
|
||||
* @return [Boolean]
|
||||
*/
|
||||
internal fun String.isUnSafeExtName() = camelcase().let { it == "ext" || it == "extra" || it == "extraProperties" || it == "extensions" }
|
||||
|
||||
/**
|
||||
* 由于 Gradle 存在一个 [ExtensionAware] 的扩展
|
||||
*
|
||||
* 此功能用于转换不符合规定的字符串到 "{字符串}s"
|
||||
* @return [String]
|
||||
*/
|
||||
internal fun String.toSafeExtName() = if (isUnSafeExtName()) "${this}s" else this
|
@@ -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/2.
|
||||
*/
|
||||
@file:Suppress("USELESS_ELVIS", "KotlinRedundantDiagnosticSuppress", "UselessCallOnNotNull")
|
||||
|
||||
package com.highcapable.sweetdependency.gradle.factory
|
||||
|
||||
import com.highcapable.sweetdependency.gradle.helper.GradleHelper
|
||||
import com.highcapable.sweetdependency.gradle.wrapper.LibraryDependencyWrapper
|
||||
import com.highcapable.sweetdependency.gradle.wrapper.PluginDependencyWrapper
|
||||
import com.highcapable.sweetdependency.plugin.task.base.BaseTask
|
||||
import com.highcapable.sweetdependency.utils.code.entity.MavenPomData
|
||||
import com.highcapable.sweetdependency.utils.debug.SError
|
||||
import com.highcapable.sweetdependency.utils.noBlank
|
||||
import com.highcapable.sweetdependency.utils.orEmpty
|
||||
import com.highcapable.sweetdependency.utils.toFile
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.Dependency
|
||||
import org.gradle.api.artifacts.ExternalDependency
|
||||
import org.gradle.api.artifacts.FileCollectionDependency
|
||||
import org.gradle.api.internal.GeneratedSubclasses
|
||||
import org.gradle.api.internal.plugins.PluginManagerInternal
|
||||
import org.gradle.api.plugins.PluginManager
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.provider.ProviderConvertible
|
||||
import org.gradle.kotlin.dsl.buildscript
|
||||
import org.gradle.kotlin.dsl.repositories
|
||||
import org.gradle.plugin.use.PluginDependenciesSpec
|
||||
import org.gradle.plugin.use.PluginDependency
|
||||
|
||||
/**
|
||||
* 获取指定项目的完整名称
|
||||
* @return [String]
|
||||
*/
|
||||
internal val Project.fullName
|
||||
get(): String {
|
||||
val baseNames = mutableListOf<String>()
|
||||
|
||||
/**
|
||||
* 递归子项目
|
||||
* @param project 当前项目
|
||||
*/
|
||||
fun fetchChild(project: Project) {
|
||||
project.parent?.also { if (it != it.rootProject) fetchChild(it) }
|
||||
baseNames.add(project.name)
|
||||
}
|
||||
fetchChild(project = this)
|
||||
return buildString { baseNames.onEach { append(":$it") }.clear() }.drop(1)
|
||||
}
|
||||
|
||||
/**
|
||||
* 向构建脚本添加自定义依赖
|
||||
* @param repositoryPath 存储库路径
|
||||
* @param pomData Maven POM 实体
|
||||
*/
|
||||
internal fun Project.addDependencyToBuildScript(repositoryPath: String, pomData: MavenPomData) =
|
||||
buildscript {
|
||||
repositories {
|
||||
maven {
|
||||
url = repositoryPath.toFile().toURI()
|
||||
mavenContent { includeGroup(pomData.groupId) }
|
||||
}
|
||||
}; dependencies { classpath("${pomData.groupId}:${pomData.artifactId}:${pomData.version}") }
|
||||
}
|
||||
|
||||
/**
|
||||
* 装载构建脚本的 [Class]
|
||||
* @param name [Class] 完整名称
|
||||
* @return [Class]
|
||||
*/
|
||||
internal fun Project.loadBuildScriptClass(name: String) = buildscript.classLoader.loadClass(name)
|
||||
|
||||
/**
|
||||
* 获取指定项目部署的插件依赖数组 (实时)
|
||||
*
|
||||
* @param isUseCache 是否使用缓存 - 默认启用 - 启用后将使用 [GradleHelper.projectPlugins] 进行获取
|
||||
* @return [MutableList]<[PluginDependencyWrapper]>
|
||||
*/
|
||||
internal fun Project.plugins(isUseCache: Boolean = true) =
|
||||
if (isUseCache) GradleHelper.projectPlugins[this].orEmpty() else mutableListOf<PluginDependencyWrapper>().apply {
|
||||
plugins.configureEach {
|
||||
pluginManager.findPluginId(this).noBlank()?.also { add(PluginDependencyWrapper(instance = this, it)) }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定项目部署的库依赖数组 (实时)
|
||||
*
|
||||
* @param isUseCache 是否使用缓存 - 默认启用 - 启用后将使用 [GradleHelper.projectLibraries] 进行获取
|
||||
* @return [MutableList]<[LibraryDependencyWrapper]>
|
||||
*/
|
||||
internal fun Project.libraries(isUseCache: Boolean = true) =
|
||||
if (isUseCache) GradleHelper.projectLibraries[this].orEmpty() else mutableListOf<LibraryDependencyWrapper>().apply {
|
||||
/**
|
||||
* 检查依赖是否有效
|
||||
* @return [Boolean]
|
||||
*/
|
||||
fun Dependency.checkingValid() = when (this) {
|
||||
is ExternalDependency -> group.isNullOrBlank().not() && name.isNullOrBlank().not()
|
||||
is FileCollectionDependency -> runCatching { files.files.isNotEmpty() }.getOrNull() ?: false
|
||||
else -> true
|
||||
}
|
||||
/** 在一些项目 (例如 Kotlin Multiplatform 中会发生异常 [java.util.ConcurrentModificationException] - 这里直接做拦截处理 */
|
||||
runCatching {
|
||||
configurations.forEach { config ->
|
||||
config.dependencies.forEach { if (it.checkingValid()) add(LibraryDependencyWrapper(it, config.name ?: "")) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 等待并监听当指定插件被添加时回调
|
||||
* @param id 插件 ID
|
||||
* @param action 回调插件实例
|
||||
*/
|
||||
internal fun Project.waitForPluginAdded(id: String, action: (Plugin<*>) -> Unit) {
|
||||
plugins.whenPluginAdded { if (pluginManager.findPluginId(this) == id) action(this) }
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 Gradle Task [T]
|
||||
* @param group Task 分组
|
||||
* @param name Task 名称
|
||||
* @return [T]
|
||||
*/
|
||||
internal inline fun <reified T : BaseTask> Project.createTask(group: String, name: String) = runCatching {
|
||||
T::class.java.getConstructor().newInstance().also { instance ->
|
||||
task(name) {
|
||||
this.group = group
|
||||
outputs.upToDateWhen { false }
|
||||
doFirst { instance.onTransaction() }
|
||||
}
|
||||
}
|
||||
}.getOrNull() ?: SError.make("Gradle task \"$name\" with group \"$group\" create failed")
|
||||
|
||||
/**
|
||||
* 应用插件
|
||||
* @param id 插件 ID
|
||||
* @param version 版本
|
||||
*/
|
||||
internal fun PluginDependenciesSpec.applyPlugin(id: String, version: String) =
|
||||
id(id).apply { if (version.isNotBlank()) version(version) } ?: SError.make("Plugin \"$id\" not apply")
|
||||
|
||||
/**
|
||||
* 应用插件
|
||||
* @param alias 别名实例
|
||||
*/
|
||||
internal fun PluginDependenciesSpec.applyPlugin(alias: Any) = when (alias) {
|
||||
is Provider<*> ->
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
alias(alias as? Provider<PluginDependency> ?: SError.make("The $alias is not a valid plugin"))
|
||||
?: SError.make("Plugin $alias not apply")
|
||||
is ProviderConvertible<*> ->
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
alias(alias as? ProviderConvertible<PluginDependency> ?: SError.make("The $alias is not a valid plugin"))
|
||||
?: SError.make("Plugin $alias not apply")
|
||||
else -> SError.make("The $alias is not a valid plugin (unknown type)")
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过 [PluginManager] 查找 [Plugin] 真实 ID
|
||||
*
|
||||
* 如果找不到会返回空字符串
|
||||
* @param plugin 当前实例
|
||||
* @return [String]
|
||||
*/
|
||||
private fun PluginManager.findPluginId(plugin: Plugin<*>) = runCatching {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val pluginIds = (this as PluginManagerInternal).findPluginIdForClass(GeneratedSubclasses.unpackType(plugin) as Class<Plugin<*>>)
|
||||
if (pluginIds.isEmpty.not()) pluginIds.get() else null
|
||||
}.getOrNull()?.id ?: ""
|
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* 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/19.
|
||||
*/
|
||||
@file:Suppress("MemberVisibilityCanBePrivate")
|
||||
|
||||
package com.highcapable.sweetdependency.gradle.helper
|
||||
|
||||
import com.highcapable.sweetdependency.gradle.factory.libraries
|
||||
import com.highcapable.sweetdependency.gradle.factory.plugins
|
||||
import com.highcapable.sweetdependency.gradle.wrapper.LibraryDependencyWrapper
|
||||
import com.highcapable.sweetdependency.gradle.wrapper.PluginDependencyWrapper
|
||||
import com.highcapable.sweetdependency.utils.debug.SError
|
||||
import com.highcapable.sweetdependency.utils.parseFileSeparator
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.initialization.Settings
|
||||
import org.gradle.api.invocation.Gradle
|
||||
import java.io.File
|
||||
import java.io.FileReader
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Gradle 工具类
|
||||
*/
|
||||
internal object GradleHelper {
|
||||
|
||||
/** Gradle 配置文件名称 */
|
||||
private const val GRADLE_PROPERTIES_FILE_NAME = "gradle.properties"
|
||||
|
||||
/** 当前 [Gradle] 静态实例 */
|
||||
private var instance: Gradle? = null
|
||||
|
||||
/** 当前 [Settings] 静态实例 */
|
||||
private var settings: Settings? = null
|
||||
|
||||
/** 当前装载的所有项目 */
|
||||
internal val allProjects = mutableSetOf<Project>()
|
||||
|
||||
/** 当前装载的项目插件依赖数组 */
|
||||
internal val projectPlugins = mutableMapOf<Project, MutableList<PluginDependencyWrapper>>()
|
||||
|
||||
/** 当前装载的项目库依赖数组 */
|
||||
internal val projectLibraries = mutableMapOf<Project, MutableList<LibraryDependencyWrapper>>()
|
||||
|
||||
/**
|
||||
* 绑定当前使用的 [Settings] 静态实例
|
||||
* @param settings 当前设置
|
||||
*/
|
||||
internal fun attach(settings: Settings) {
|
||||
instance = settings.also { this.settings = it }.gradle
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存所有项目列表
|
||||
* @param rootProject 当前根项目
|
||||
*/
|
||||
internal fun cachingProjectList(rootProject: Project) {
|
||||
allProjects.clear()
|
||||
allProjects.addAll(rootProject.allprojects)
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存所有依赖列表
|
||||
* @param project 当前项目
|
||||
* @param isRoot 是否为根项目
|
||||
*/
|
||||
internal fun cachingDependencyList(project: Project, isRoot: Boolean) {
|
||||
if (isRoot) {
|
||||
projectPlugins.clear()
|
||||
projectLibraries.clear()
|
||||
}
|
||||
project.plugins(isUseCache = false).forEach {
|
||||
if (projectPlugins[project] == null) projectPlugins[project] = mutableListOf()
|
||||
projectPlugins[project]?.add(it)
|
||||
}
|
||||
project.libraries(isUseCache = false).forEach {
|
||||
if (projectLibraries[project] == null) projectLibraries[project] = mutableListOf()
|
||||
projectLibraries[project]?.add(it)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户目录的 [Properties]
|
||||
* @return [Properties] or null
|
||||
*/
|
||||
internal val userProperties get() = createProperties(instance?.gradleUserHomeDir)
|
||||
|
||||
/**
|
||||
* 获取当前项目的 [Properties]
|
||||
* @return [Properties] or null
|
||||
*/
|
||||
internal val projectProperties get() = createProperties(settings?.rootDir)
|
||||
|
||||
/**
|
||||
* 获取当前 Gradle 项目的根目录
|
||||
* @return [File]
|
||||
*/
|
||||
internal val rootDir get() = rootProject?.projectDir ?: settings?.rootDir ?: SError.make("Gradle is unavailable")
|
||||
|
||||
/**
|
||||
* 获取当前 Gradle 项目的根项目 (Root Project)
|
||||
* @return [Project] or null
|
||||
*/
|
||||
internal val rootProject get() = runCatching { instance?.rootProject }.getOrNull()
|
||||
|
||||
/**
|
||||
* 获取当前 Gradle 版本
|
||||
* @return [String]
|
||||
*/
|
||||
internal val version get() = instance?.gradle?.gradleVersion ?: ""
|
||||
|
||||
/**
|
||||
* 获取当前 Gradle 是否处于离线模式
|
||||
* @return [Boolean]
|
||||
*/
|
||||
internal val isOfflineMode get() = instance?.startParameter?.isOffline == true
|
||||
|
||||
/**
|
||||
* 获取当前 Gradle 是否处于同步模式
|
||||
* @return [Boolean]
|
||||
*/
|
||||
internal val isSyncMode get() = runningTaskNames.isNullOrEmpty()
|
||||
|
||||
/**
|
||||
* 获取当前正在运行的 Task 名称数组
|
||||
* @return [MutableList]<[String]> or null
|
||||
*/
|
||||
internal val runningTaskNames get() = instance?.startParameter?.taskRequests?.getOrNull(0)?.args
|
||||
|
||||
/**
|
||||
* 创建新的 [Properties]
|
||||
* @param dir 当前目录
|
||||
* @return [Properties] or null
|
||||
*/
|
||||
private fun createProperties(dir: File?) = runCatching {
|
||||
Properties().apply { load(FileReader(dir?.resolve(GRADLE_PROPERTIES_FILE_NAME)?.absolutePath?.parseFileSeparator() ?: "")) }
|
||||
}.getOrNull()
|
||||
}
|
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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/26.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.gradle.proxy
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.initialization.Settings
|
||||
|
||||
/**
|
||||
* Gradle 生命周期接口
|
||||
*/
|
||||
internal interface IGradleLifecycle {
|
||||
|
||||
/**
|
||||
* 当 Gradle 开始装载时回调
|
||||
* @param settings 当前设置
|
||||
*/
|
||||
fun onSettingsLoaded(settings: Settings)
|
||||
|
||||
/**
|
||||
* 当 Gradle 装载完成时回调
|
||||
* @param settings 当前设置
|
||||
*/
|
||||
fun onSettingsEvaluate(settings: Settings)
|
||||
|
||||
/**
|
||||
* 当 Gradle 开始装载项目时回调
|
||||
* @param project 当前项目
|
||||
* @param isRoot 是否为根项目
|
||||
*/
|
||||
fun onProjectLoaded(project: Project, isRoot: Boolean)
|
||||
|
||||
/**
|
||||
* 当 Gradle 项目装载完成时回调
|
||||
* @param project 当前项目
|
||||
* @param isRoot 是否为根项目
|
||||
*/
|
||||
fun onProjectEvaluate(project: Project, isRoot: Boolean)
|
||||
}
|
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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/28.
|
||||
*/
|
||||
@file:Suppress("USELESS_ELVIS", "KotlinRedundantDiagnosticSuppress")
|
||||
|
||||
package com.highcapable.sweetdependency.gradle.wrapper
|
||||
|
||||
import com.highcapable.sweetdependency.document.factory.spliceToDependencyNotation
|
||||
import com.highcapable.sweetdependency.gradle.delegate.entity.ExternalDependencyDelegate
|
||||
import com.highcapable.sweetdependency.gradle.entity.DependencyVersion
|
||||
import com.highcapable.sweetdependency.gradle.wrapper.type.LibraryDependencyType
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.Dependency
|
||||
import org.gradle.api.artifacts.ExternalDependency
|
||||
import org.gradle.api.artifacts.FileCollectionDependency
|
||||
import org.gradle.api.artifacts.ProjectDependency
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* 库依赖包装实例实现类
|
||||
* @param instance 当前实例
|
||||
* @param configurationName 配置名称
|
||||
*/
|
||||
internal data class LibraryDependencyWrapper internal constructor(private val instance: Dependency, internal val configurationName: String) {
|
||||
|
||||
/**
|
||||
* 获取当前依赖类型
|
||||
* @return [LibraryDependencyType]
|
||||
*/
|
||||
val type
|
||||
get() = when (instance) {
|
||||
is ExternalDependencyDelegate -> LibraryDependencyType.EXTERNAL_DELEGATE
|
||||
is ExternalDependency -> LibraryDependencyType.EXTERNAL
|
||||
is ProjectDependency -> LibraryDependencyType.PROJECT
|
||||
is FileCollectionDependency -> LibraryDependencyType.FILES
|
||||
else -> LibraryDependencyType.OTHERS
|
||||
}
|
||||
|
||||
/**
|
||||
* 依赖的文件数组
|
||||
*
|
||||
* - [type] 需要为 [LibraryDependencyType.FILES] 否则始终为 null
|
||||
* @return [MutableSet]<[File]> or null
|
||||
*/
|
||||
val files get() = runCatching { (instance as? FileCollectionDependency?)?.files?.files?.toMutableSet() }.getOrNull()
|
||||
|
||||
/**
|
||||
* 依赖的项目
|
||||
*
|
||||
* - [type] 需要为 [LibraryDependencyType.PROJECT] 否则始终为 null
|
||||
* @return [Project] or null
|
||||
*/
|
||||
val project get() = runCatching { (instance as? ProjectDependency?)?.dependencyProject }.getOrNull()
|
||||
|
||||
/**
|
||||
* Group ID
|
||||
* @return [String]
|
||||
*/
|
||||
val groupId get() = instance.group ?: ""
|
||||
|
||||
/**
|
||||
* Artifact ID
|
||||
* @return [String]
|
||||
*/
|
||||
val artifactId get() = instance.name ?: ""
|
||||
|
||||
/**
|
||||
* 版本
|
||||
* @return [DependencyVersion]
|
||||
*/
|
||||
val version get() = DependencyVersion(instance.version ?: "")
|
||||
|
||||
override fun toString() = spliceToDependencyNotation(groupId, artifactId)
|
||||
}
|
@@ -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/8/17.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.gradle.wrapper
|
||||
|
||||
import org.gradle.api.Plugin
|
||||
|
||||
/**
|
||||
* 插件依赖包装实例实现类
|
||||
* @param instance 当前实例
|
||||
* @param id 插件 ID
|
||||
*/
|
||||
internal data class PluginDependencyWrapper internal constructor(private val instance: Plugin<*>, internal val id: String) {
|
||||
|
||||
override fun toString() = id
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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/10.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.gradle.wrapper.type
|
||||
|
||||
/**
|
||||
* 库依赖类型定义类
|
||||
*/
|
||||
internal enum class LibraryDependencyType {
|
||||
/** 其它类型 */
|
||||
OTHERS,
|
||||
|
||||
/** 外部存储库 */
|
||||
EXTERNAL,
|
||||
|
||||
/** 外部存储库 (代理) */
|
||||
EXTERNAL_DELEGATE,
|
||||
|
||||
/** 项目 */
|
||||
PROJECT,
|
||||
|
||||
/** 文件 */
|
||||
FILES
|
||||
}
|
@@ -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-*/"
|
||||
}
|
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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/19.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.plugin
|
||||
|
||||
import com.highcapable.sweetdependency.SweetDependency
|
||||
import com.highcapable.sweetdependency.gradle.delegate.ProjectTransaction
|
||||
import com.highcapable.sweetdependency.gradle.factory.getOrCreate
|
||||
import com.highcapable.sweetdependency.gradle.proxy.IGradleLifecycle
|
||||
import com.highcapable.sweetdependency.manager.GradleTaskManager
|
||||
import com.highcapable.sweetdependency.plugin.extension.dsl.configure.SweetDependencyConfigureExtension
|
||||
import com.highcapable.sweetdependency.plugin.impl.SweetDependencyExtensionImpl
|
||||
import com.highcapable.sweetdependency.utils.debug.SError
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.initialization.Settings
|
||||
|
||||
/**
|
||||
* [SweetDependency] 插件扩展类
|
||||
*/
|
||||
internal class SweetDependencyExtension internal constructor() : IGradleLifecycle {
|
||||
|
||||
/** 当前配置方法体实例 */
|
||||
private var configure: SweetDependencyConfigureExtension? = null
|
||||
|
||||
/** 当前扩展实现实例 */
|
||||
private var impl: SweetDependencyExtensionImpl? = null
|
||||
|
||||
/** 当前项目事务实例 */
|
||||
private var transaction: ProjectTransaction? = null
|
||||
|
||||
override fun onSettingsLoaded(settings: Settings) {
|
||||
configure = settings.getOrCreate<SweetDependencyConfigureExtension>(SweetDependencyConfigureExtension.NAME)
|
||||
}
|
||||
|
||||
override fun onSettingsEvaluate(settings: Settings) {
|
||||
impl = SweetDependencyExtensionImpl()
|
||||
impl?.onInitialization(settings, configure?.build() ?: SError.make("Settings lifecycle is broken"))
|
||||
}
|
||||
|
||||
override fun onProjectLoaded(project: Project, isRoot: Boolean) {
|
||||
ProjectTransaction.current = project
|
||||
ProjectTransaction.isRoot = isRoot
|
||||
if (transaction == null) transaction = ProjectTransaction()
|
||||
if (isRoot) GradleTaskManager.register(project)
|
||||
transaction?.also { impl?.onTransaction(it) }
|
||||
}
|
||||
|
||||
override fun onProjectEvaluate(project: Project, isRoot: Boolean) {
|
||||
transaction?.evaluateCallbacks?.forEach { it(project, isRoot) }
|
||||
}
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
@file:Suppress("unused")
|
||||
|
||||
package com.highcapable.sweetdependency.plugin
|
||||
|
||||
import com.highcapable.sweetdependency.SweetDependency
|
||||
import com.highcapable.sweetdependency.gradle.delegate.GradleDelegate
|
||||
import com.highcapable.sweetdependency.utils.debug.SError
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.initialization.Settings
|
||||
import org.gradle.api.plugins.ExtensionAware
|
||||
|
||||
/**
|
||||
* [SweetDependency] 插件定义类
|
||||
*/
|
||||
class SweetDependencyPlugin<T : ExtensionAware> internal constructor() : Plugin<T> {
|
||||
|
||||
override fun apply(target: T) = when (target) {
|
||||
is Settings -> GradleDelegate.create<SweetDependencyExtension>(target)
|
||||
else -> SError.make("${SweetDependency.TAG} can only applied in settings.gradle/settings.gradle.kts, but current is $target")
|
||||
}
|
||||
}
|
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.plugin.config.content
|
||||
|
||||
import com.highcapable.sweetdependency.SweetDependency
|
||||
import com.highcapable.sweetdependency.document.RootConfigDocument
|
||||
import com.highcapable.sweetdependency.document.mapping.RootConfigDocumentMapping
|
||||
import com.highcapable.sweetdependency.exception.SweetDependencyUnresolvedException
|
||||
import com.highcapable.sweetdependency.plugin.config.factory.build
|
||||
import com.highcapable.sweetdependency.plugin.config.proxy.ISweetDependencyConfigs
|
||||
import com.highcapable.sweetdependency.utils.debug.SError
|
||||
import com.highcapable.sweetdependency.utils.debug.SLog
|
||||
import com.highcapable.sweetdependency.utils.yaml.factory.YamlException
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
/**
|
||||
* [SweetDependency] 配置类实现类
|
||||
*/
|
||||
internal object SweetDependencyConfigs {
|
||||
|
||||
/** 当前配置 */
|
||||
internal var configs by Delegates.notNull<ISweetDependencyConfigs>()
|
||||
|
||||
/** 当前文档实体 */
|
||||
internal var document by Delegates.notNull<RootConfigDocument>()
|
||||
|
||||
/** 当前文档测绘实例 */
|
||||
internal var documentMapping by Delegates.notNull<RootConfigDocumentMapping>()
|
||||
|
||||
/**
|
||||
* 插件启用后执行
|
||||
* @param block 方法体
|
||||
*/
|
||||
internal inline fun withPluginEnable(block: () -> Unit) {
|
||||
if (configs.isEnable) block() else SLog.warn("${SweetDependency.TAG} is disabled (won't do anything)", noRepeat = true)
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化配置 (从文件)
|
||||
* @param configs 当前配置
|
||||
* @param isThrowOnError 是否在发生错误的时候抛出异常 - 默认是
|
||||
* @throws SweetDependencyUnresolvedException 如果设置了 [isThrowOnError] 且发生错误
|
||||
*/
|
||||
internal fun initialize(configs: ISweetDependencyConfigs, isThrowOnError: Boolean = true) {
|
||||
this.configs = configs
|
||||
runCatching {
|
||||
configs.build().also {
|
||||
document = it.first
|
||||
documentMapping = it.second
|
||||
}
|
||||
}.onFailure {
|
||||
if (isThrowOnError) when (it) {
|
||||
is YamlException -> SError.make("Failed to parse config file: ${configs.configFilePath}\nPlease check if there are syntax errors", it)
|
||||
is SweetDependencyUnresolvedException -> throw it
|
||||
else -> SError.make("Failed to load config file: ${configs.configFilePath}", it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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.plugin.config.factory
|
||||
|
||||
import com.highcapable.sweetdependency.document.RootConfigDocument
|
||||
import com.highcapable.sweetdependency.document.mapping.RootConfigDocumentMapping
|
||||
import com.highcapable.sweetdependency.plugin.config.proxy.ISweetDependencyConfigs
|
||||
import com.highcapable.sweetdependency.utils.debug.SError
|
||||
import com.highcapable.sweetdependency.utils.debug.SLog
|
||||
import com.highcapable.sweetdependency.utils.toFile
|
||||
import com.highcapable.sweetdependency.utils.yaml.Yaml
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* 获取并解析配置文件 [RootConfigDocument] 实体和 [RootConfigDocumentMapping]
|
||||
* @return [Pair]<[RootConfigDocument], [RootConfigDocumentMapping]>
|
||||
*/
|
||||
internal fun ISweetDependencyConfigs.build() = configFilePath.loadOrCreateEmpty() to RootConfigDocumentMapping(this)
|
||||
|
||||
/**
|
||||
* 通过字符串路径获取或创建配置文件 [RootConfigDocument] 实体
|
||||
* @return [RootConfigDocument]
|
||||
*/
|
||||
private fun String.loadOrCreateEmpty(): RootConfigDocument {
|
||||
toFile().apply {
|
||||
if (name.endsWith(".yaml").not() && name.endsWith(".yml").not())
|
||||
SError.make("Config file name must be end with \".yaml\" or \".yml\"")
|
||||
}.createTemplateFileOrNot()
|
||||
return Yaml.loadFromFile<RootConfigDocument>(path = this)
|
||||
}
|
||||
|
||||
/** 自动创建模版配置文件 */
|
||||
private fun File.createTemplateFileOrNot() {
|
||||
fun createTemplateFile() {
|
||||
writeText(RootConfigDocument.defaultContent)
|
||||
SLog.info("Automatically created config file: $absolutePath")
|
||||
}
|
||||
runCatching {
|
||||
when {
|
||||
exists().not() && parentFile.exists().not() -> {
|
||||
parentFile.mkdirs()
|
||||
createTemplateFile()
|
||||
}
|
||||
exists().not() -> createTemplateFile()
|
||||
exists() && isDirectory -> SError.make("Tries to create file path is a directory")
|
||||
}
|
||||
}.onFailure { SError.make("Could not automatically created config file: $absolutePath", it) }
|
||||
}
|
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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.plugin.config.proxy
|
||||
|
||||
import com.highcapable.sweetdependency.SweetDependency
|
||||
|
||||
/**
|
||||
* [SweetDependency] 配置类接口类
|
||||
*/
|
||||
internal interface ISweetDependencyConfigs {
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* 默认的配置文件名称
|
||||
*
|
||||
* "sweet-dependency-config.yaml"
|
||||
*/
|
||||
internal const val DEFAULT_CONFIG_FILE_NAME = "sweet-dependency-config.yaml"
|
||||
}
|
||||
|
||||
/** 是否启用插件 */
|
||||
val isEnable: Boolean
|
||||
|
||||
/** [SweetDependency] 的配置文件路径 */
|
||||
val configFilePath: String
|
||||
|
||||
/** 是否启用依赖自动装配日志 */
|
||||
val isEnableDependenciesAutowireLog: Boolean
|
||||
|
||||
/** 是否启用详细模式 */
|
||||
val isEnableVerboseMode: Boolean
|
||||
}
|
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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/19.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.plugin.extension.accessors.proxy
|
||||
|
||||
/**
|
||||
* 扩展可访问 [Class] 定义空间接口
|
||||
*/
|
||||
internal interface IExtensionAccessors
|
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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/26.
|
||||
*/
|
||||
@file:Suppress("MemberVisibilityCanBePrivate")
|
||||
|
||||
package com.highcapable.sweetdependency.plugin.extension.dsl.configure
|
||||
|
||||
import com.highcapable.sweetdependency.SweetDependency
|
||||
import com.highcapable.sweetdependency.environment.Environment
|
||||
import com.highcapable.sweetdependency.plugin.config.proxy.ISweetDependencyConfigs
|
||||
|
||||
/**
|
||||
* [SweetDependency] 配置方法体实现类
|
||||
*/
|
||||
open class SweetDependencyConfigureExtension internal constructor() {
|
||||
|
||||
internal companion object {
|
||||
|
||||
/** [SweetDependencyConfigureExtension] 扩展名称 */
|
||||
internal const val NAME = "sweetDependency"
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否启用插件
|
||||
*
|
||||
* 默认启用 - 如果你想关闭插件 - 在这里设置就可以了
|
||||
*/
|
||||
var isEnable = true
|
||||
@JvmName("enable") set
|
||||
|
||||
/**
|
||||
* [SweetDependency] 配置文件名称
|
||||
*
|
||||
* 默认为 [ISweetDependencyConfigs.DEFAULT_CONFIG_FILE_NAME]
|
||||
*/
|
||||
var configFileName = ISweetDependencyConfigs.DEFAULT_CONFIG_FILE_NAME
|
||||
@JvmName("configFileName") set
|
||||
|
||||
/**
|
||||
* 是否启用依赖自动装配日志
|
||||
*
|
||||
* 此功能默认启用 - 会在当前根项目 (Root Project) 的 build 目录下创建日志文件
|
||||
*/
|
||||
var isEnableDependenciesAutowireLog = true
|
||||
@JvmName("enableDependenciesAutowireLog") set
|
||||
|
||||
/**
|
||||
* 是否启用详细模式
|
||||
*
|
||||
* 此功能默认启用 - 关闭后 [SweetDependency] 将会在非必要情况下保持安静 (省略非必要日志)
|
||||
*/
|
||||
var isEnableVerboseMode = true
|
||||
@JvmName("enableVerboseMode") set
|
||||
|
||||
/**
|
||||
* 构造 [ISweetDependencyConfigs]
|
||||
* @return [ISweetDependencyConfigs]
|
||||
*/
|
||||
internal fun build(): ISweetDependencyConfigs {
|
||||
val currentEnable = isEnable
|
||||
val currentConfigFilePath = Environment.resourcesDir(configFileName).absolutePath
|
||||
val currentEnableDependenciesAutowireLog = isEnableDependenciesAutowireLog
|
||||
val currentEnableVerboseMode = isEnableVerboseMode
|
||||
return object : ISweetDependencyConfigs {
|
||||
override val isEnable get() = currentEnable
|
||||
override val configFilePath get() = currentConfigFilePath
|
||||
override val isEnableDependenciesAutowireLog get() = currentEnableDependenciesAutowireLog
|
||||
override val isEnableVerboseMode get() = currentEnableVerboseMode
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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/26.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.plugin.extension.dsl.manager
|
||||
|
||||
import com.highcapable.sweetdependency.manager.helper.DependencyDeployHelper
|
||||
import org.gradle.api.Project
|
||||
|
||||
/**
|
||||
* 依赖扩展功能配置方法体实现类
|
||||
* @param project 当前项目
|
||||
*/
|
||||
open class SweetDependencyAutowireExtension internal constructor(private val project: Project) {
|
||||
|
||||
internal companion object {
|
||||
|
||||
/** [SweetDependencyAutowireExtension] 扩展名称 */
|
||||
internal const val NAME = "sweet"
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动装配依赖
|
||||
* @param params 参数数组
|
||||
* @return [Any]
|
||||
*/
|
||||
fun autowire(vararg params: String) = DependencyDeployHelper.resolveAutowire(project, params)
|
||||
}
|
@@ -0,0 +1,433 @@
|
||||
/*
|
||||
* 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/8/13.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.plugin.generator
|
||||
|
||||
import com.highcapable.sweetdependency.SweetDependency
|
||||
import com.highcapable.sweetdependency.document.DependencyDocument
|
||||
import com.highcapable.sweetdependency.document.factory.splitToDependencyGenerateNames
|
||||
import com.highcapable.sweetdependency.exception.SweetDependencyUnresolvedException
|
||||
import com.highcapable.sweetdependency.generated.SweetDependencyProperties
|
||||
import com.highcapable.sweetdependency.gradle.delegate.entity.ExternalDependencyDelegate
|
||||
import com.highcapable.sweetdependency.gradle.entity.ExternalDependency
|
||||
import com.highcapable.sweetdependency.manager.content.Dependencies
|
||||
import com.highcapable.sweetdependency.plugin.config.content.SweetDependencyConfigs
|
||||
import com.highcapable.sweetdependency.plugin.extension.accessors.proxy.IExtensionAccessors
|
||||
import com.highcapable.sweetdependency.utils.camelcase
|
||||
import com.highcapable.sweetdependency.utils.capitalize
|
||||
import com.highcapable.sweetdependency.utils.debug.SError
|
||||
import com.highcapable.sweetdependency.utils.firstNumberToLetter
|
||||
import com.highcapable.sweetdependency.utils.toNonJavaName
|
||||
import com.highcapable.sweetdependency.utils.uncapitalize
|
||||
import com.highcapable.sweetdependency.utils.uppercamelcase
|
||||
import com.squareup.javapoet.ClassName
|
||||
import com.squareup.javapoet.FieldSpec
|
||||
import com.squareup.javapoet.JavaFile
|
||||
import com.squareup.javapoet.MethodSpec
|
||||
import com.squareup.javapoet.TypeSpec
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import javax.lang.model.element.Modifier
|
||||
|
||||
/**
|
||||
* 库依赖可访问 [Class] 生成实现类
|
||||
*/
|
||||
internal class LibrariesAccessorsGenerator {
|
||||
|
||||
private companion object {
|
||||
|
||||
/** 生成的 [Class] 所在包名 */
|
||||
private const val ACCESSORS_PACKAGE_NAME = "${SweetDependencyProperties.PROJECT_GROUP_NAME}.plugin.extension.accessors.generated"
|
||||
|
||||
/** 生成的 [Class] 后缀名 */
|
||||
private const val CLASS_SUFFIX_NAME = "Accessors"
|
||||
|
||||
/** 生成的首位 [Class] 名称 */
|
||||
private const val TOP_CLASS_NAME = "Libraries$CLASS_SUFFIX_NAME"
|
||||
|
||||
/** 标识首位生成的 [Class] TAG */
|
||||
private const val TOP_SUCCESSIVE_NAME = "_top_successive_name"
|
||||
}
|
||||
|
||||
/** 生成的依赖库 [Class] 构建器数组 */
|
||||
private val classSpecs = mutableMapOf<String, TypeSpec.Builder>()
|
||||
|
||||
/** 生成的依赖库构造方法构建器数组 */
|
||||
private val constructorSpecs = mutableMapOf<String, MethodSpec.Builder>()
|
||||
|
||||
/** 生成的依赖库预添加的构造方法名称数组 */
|
||||
private val preAddConstructorSpecNames = mutableListOf<Pair<String, String>>()
|
||||
|
||||
/** 生成的依赖库 [Class] 扩展类名数组 */
|
||||
private val memoryExtensionClasses = mutableListOf<Pair<String, String>>()
|
||||
|
||||
/** 生成的依赖库连续名称记录数组 */
|
||||
private val grandSuccessiveNames = mutableListOf<String>()
|
||||
|
||||
/** 生成的依赖库连续名称重复次数数组 */
|
||||
private val grandSuccessiveDuplicateIndexs = mutableMapOf<String, Int>()
|
||||
|
||||
/** 生成的依赖库不重复 TAG 数组 */
|
||||
private val usedSuccessiveTags = mutableSetOf<String>()
|
||||
|
||||
/**
|
||||
* 不重复调用
|
||||
* @param tags 当前 TAG 数组
|
||||
* @param block 执行的方法块
|
||||
*/
|
||||
private inline fun noRepeated(vararg tags: String, block: () -> Unit) {
|
||||
val allTag = tags.joinToString("-")
|
||||
if (usedSuccessiveTags.contains(allTag).not()) block()
|
||||
usedSuccessiveTags.add(allTag)
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串首字母大写并添加 [CLASS_SUFFIX_NAME] 后缀
|
||||
* @return [String]
|
||||
*/
|
||||
private fun String.capitalized() = "${capitalize()}$CLASS_SUFFIX_NAME"
|
||||
|
||||
/**
|
||||
* 字符串首字母小写并添加 [CLASS_SUFFIX_NAME] 后缀
|
||||
* @return [String]
|
||||
*/
|
||||
private fun String.uncapitalized() = "${uncapitalize()}$CLASS_SUFFIX_NAME"
|
||||
|
||||
/**
|
||||
* 字符串类名转换为 [ClassName]
|
||||
* @param packageName 包名 - 默认空
|
||||
* @return [ClassName]
|
||||
*/
|
||||
private fun String.asClassType(packageName: String = "") = ClassName.get(packageName, this)
|
||||
|
||||
/**
|
||||
* 通过 [TypeSpec] 创建 [JavaFile]
|
||||
* @return [JavaFile]
|
||||
*/
|
||||
private fun TypeSpec.createJavaFile(packageName: String) = JavaFile.builder(packageName, this).build()
|
||||
|
||||
/**
|
||||
* 创建扩展类完整名称 (含包名)
|
||||
* @param name 子类名 - 默认空
|
||||
* @return [String]
|
||||
*/
|
||||
private fun createAccessorsName(name: String = "") =
|
||||
"$ACCESSORS_PACKAGE_NAME.$TOP_CLASS_NAME${if (name.isNotBlank()) "\$${name.capitalized()}" else ""}"
|
||||
|
||||
/**
|
||||
* 创建通用构建器描述类
|
||||
* @param name 名称
|
||||
* @param accessors 接续对象 - 没有默认值
|
||||
* @param isInner 是否为内部类 - 默认是
|
||||
* @return [TypeSpec.Builder]
|
||||
*/
|
||||
private fun createClassSpec(name: String, accessors: Any = Any(), isInner: Boolean = true) =
|
||||
TypeSpec.classBuilder(if (isInner) name.capitalized() else name).apply {
|
||||
if (isInner) {
|
||||
val actual = when (accessors) {
|
||||
is ExternalDependency -> "\"$accessors\" library"
|
||||
else -> "\"$accessors\" accessors"
|
||||
}; addJavadoc("The $actual")
|
||||
addSuperinterface(IExtensionAccessors::class.java)
|
||||
addModifiers(Modifier.PUBLIC, Modifier.STATIC)
|
||||
} else {
|
||||
addJavadoc(
|
||||
"""
|
||||
This class is generated by ${SweetDependency.TAG} at ${SimpleDateFormat.getDateTimeInstance().format(Date())}
|
||||
<br/>
|
||||
The content here is automatically generated according to the dependencies of your projects
|
||||
<br/>
|
||||
You can visit <a href="${SweetDependency.PROJECT_URL}">here</a> for more help
|
||||
""".trimIndent()
|
||||
)
|
||||
addModifiers(Modifier.PUBLIC)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建通用构造方法构建器描述类
|
||||
* @return [MethodSpec.Builder]
|
||||
*/
|
||||
private fun createConstructorSpec() = MethodSpec.constructorBuilder().addModifiers(Modifier.PUBLIC)
|
||||
|
||||
/**
|
||||
* 向通用构建器描述类添加变量
|
||||
* @param accessors 接续对象
|
||||
* @param className 类名
|
||||
* @return [TypeSpec.Builder]
|
||||
*/
|
||||
private fun TypeSpec.Builder.addSuccessiveField(accessors: Any, className: String) = addField(
|
||||
FieldSpec.builder(className.capitalized().asClassType(), className.uncapitalized(), Modifier.PRIVATE, Modifier.FINAL)
|
||||
.apply {
|
||||
val actual = when (accessors) {
|
||||
is ExternalDependency -> "\"$accessors\" library"
|
||||
else -> "\"$accessors\" accessors"
|
||||
}; addJavadoc("Create the $actual")
|
||||
}.build()
|
||||
)
|
||||
|
||||
/**
|
||||
* 向通用构建器描述类添加方法
|
||||
* @param accessors 接续对象
|
||||
* @param methodName 方法名
|
||||
* @param className 类名
|
||||
* @return [TypeSpec.Builder]
|
||||
*/
|
||||
private fun TypeSpec.Builder.addSuccessiveMethod(accessors: Any, methodName: String, className: String) =
|
||||
addMethod(
|
||||
MethodSpec.methodBuilder("get${methodName.capitalize()}")
|
||||
.apply {
|
||||
val actual = when (accessors) {
|
||||
is ExternalDependency -> "\"$accessors\" library"
|
||||
else -> "\"$accessors\" accessors"
|
||||
}; addJavadoc("Resolve the $actual")
|
||||
}.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
|
||||
.returns(className.capitalized().asClassType())
|
||||
.addStatement("return ${className.uncapitalized()}")
|
||||
.build()
|
||||
)
|
||||
|
||||
/**
|
||||
* 向通用构建器描述类添加依赖描述器
|
||||
* @param dependency 外部存储库依赖实体
|
||||
* @param artifact 依赖文档实体
|
||||
* @return [TypeSpec.Builder]
|
||||
*/
|
||||
private fun TypeSpec.Builder.addLibraryClass(dependency: ExternalDependency, artifact: DependencyDocument) = apply {
|
||||
superclass(ExternalDependencyDelegate::class.java)
|
||||
artifact.versions().forEach { (alias, _) ->
|
||||
addField(
|
||||
FieldSpec.builder(ExternalDependencyDelegate::class.java, alias.camelcase(), Modifier.PRIVATE, Modifier.FINAL)
|
||||
.addJavadoc("Create the \"$dependency\" version alias \"$alias\"")
|
||||
.build()
|
||||
)
|
||||
addMethod(
|
||||
MethodSpec.methodBuilder("get${alias.uppercamelcase()}")
|
||||
.addJavadoc("Resolve the \"$dependency\" version alias \"$alias\"")
|
||||
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
|
||||
.returns(ExternalDependencyDelegate::class.java)
|
||||
.addStatement("return ${alias.camelcase()}")
|
||||
.build()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 向通用构造方法构建器描述类添加变量实例化语句
|
||||
* @param className 类名
|
||||
* @return [MethodSpec.Builder]
|
||||
*/
|
||||
private fun MethodSpec.Builder.addSuccessiveStatement(className: String) =
|
||||
addStatement("${className.uncapitalized()} = new ${className.capitalized()}()")
|
||||
|
||||
/**
|
||||
* 向通用构造方法构建器描述类添加依赖描述器
|
||||
* @param dependency 外部存储库依赖实体
|
||||
* @param artifact 依赖文档实体
|
||||
* @return [MethodSpec.Builder]
|
||||
*/
|
||||
private fun MethodSpec.Builder.addLibraryStatement(dependency: ExternalDependency, artifact: DependencyDocument) = apply {
|
||||
addStatement("super(\"${dependency.groupId}\", \"${dependency.artifactId}\", \"${dependency.version.deployed}\")")
|
||||
artifact.versions().forEach { (alias, version) ->
|
||||
addStatement(
|
||||
"${alias.camelcase()} = new ${ExternalDependencyDelegate::class.java.simpleName}" +
|
||||
"(\"${dependency.groupId}\", \"${dependency.artifactId}\", \"$version\")"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取、创建通用构建器描述类
|
||||
* @param name 名称
|
||||
* @param accessors 接续对象
|
||||
* @return [TypeSpec.Builder]
|
||||
*/
|
||||
private fun getOrCreateClassSpec(name: String, accessors: Any) =
|
||||
classSpecs[name] ?: createClassSpec(name, accessors).also { classSpecs[name] = it }
|
||||
|
||||
/**
|
||||
* 获取、创建通用构造方法构建器描述类
|
||||
* @param name 名称
|
||||
* @return [MethodSpec.Builder]
|
||||
*/
|
||||
private fun getOrCreateConstructorSpec(name: String) = constructorSpecs[name] ?: createConstructorSpec().also { constructorSpecs[name] = it }
|
||||
|
||||
/**
|
||||
* 解析并生成所有类的构建器 (核心方法)
|
||||
*
|
||||
* 解析开始前需要确保已调用 [createTopClassSpec] 并调用一次 [clearGeneratedData] 防止数据混淆
|
||||
*
|
||||
* 解析完成后需要调用 [releaseParseTypeSpec] 完成解析
|
||||
* @param successiveName 连续的名称
|
||||
* @param dependency 外部存储库依赖实体
|
||||
* @param artifact 依赖文档实体
|
||||
*/
|
||||
private fun parseTypeSpec(successiveName: String, dependency: ExternalDependency, artifact: DependencyDocument) {
|
||||
/**
|
||||
* 获取生成的依赖库连续名称重复次数
|
||||
* @return [Int]
|
||||
*/
|
||||
fun String.duplicateGrandSuccessiveIndex() = lowercase().let { name ->
|
||||
if (grandSuccessiveDuplicateIndexs.contains(name)) {
|
||||
grandSuccessiveDuplicateIndexs[name] = (grandSuccessiveDuplicateIndexs[name] ?: 1) + 1
|
||||
grandSuccessiveDuplicateIndexs[name] ?: 2
|
||||
} else 2.also { grandSuccessiveDuplicateIndexs[name] = it }
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 (拆分) 名称到数组
|
||||
*
|
||||
* 形如 "com.mytest" → "ComMytest" → "mytest"
|
||||
* @return [List]<[Triple]<[String], [String], [String]>>
|
||||
*/
|
||||
fun String.parseSuccessiveNames(): List<Triple<String, String, String>> {
|
||||
var grandAcccessorsName = ""
|
||||
var grandSuccessiveName = ""
|
||||
val successiveNames = mutableListOf<Triple<String, String, String>>()
|
||||
val splitNames = splitToDependencyGenerateNames()
|
||||
splitNames.forEach { eachName ->
|
||||
val name = eachName.capitalize().toNonJavaName().firstNumberToLetter()
|
||||
grandAcccessorsName += if (grandAcccessorsName.isNotBlank()) ".$eachName" else eachName
|
||||
grandSuccessiveName += name
|
||||
if (grandSuccessiveNames.any { it != grandSuccessiveName && it.lowercase() == grandSuccessiveName.lowercase() })
|
||||
grandSuccessiveName += duplicateGrandSuccessiveIndex().toString()
|
||||
grandSuccessiveNames.add(grandSuccessiveName)
|
||||
successiveNames.add(Triple(grandAcccessorsName, grandSuccessiveName, name))
|
||||
}; return successiveNames
|
||||
}
|
||||
val successiveNames = successiveName.parseSuccessiveNames()
|
||||
successiveNames.forEachIndexed { index, (accessorsName, className, methodName) ->
|
||||
val nextItem = successiveNames.getOrNull(index + 1)
|
||||
val nextAccessorsName = nextItem?.first ?: ""
|
||||
val nextClassName = nextItem?.second ?: ""
|
||||
val nextMethodName = nextItem?.third ?: ""
|
||||
val isPreLastIndex = index == successiveNames.lastIndex - 1
|
||||
val nextAccessors: Any = if (isPreLastIndex) dependency else nextAccessorsName
|
||||
if (index == successiveNames.lastIndex) {
|
||||
getOrCreateClassSpec(className, dependency)?.addLibraryClass(dependency, artifact)
|
||||
getOrCreateConstructorSpec(className)?.addLibraryStatement(dependency, artifact)
|
||||
} else {
|
||||
if (index == 0) noRepeated(TOP_SUCCESSIVE_NAME, methodName, className) {
|
||||
getOrCreateClassSpec(TOP_SUCCESSIVE_NAME, accessorsName)
|
||||
.addSuccessiveField(accessorsName, className)
|
||||
.addSuccessiveMethod(accessorsName, methodName, className)
|
||||
getOrCreateConstructorSpec(TOP_SUCCESSIVE_NAME)
|
||||
.addSuccessiveStatement(className)
|
||||
memoryExtensionClasses.add(methodName.uncapitalize() to createAccessorsName(className))
|
||||
}
|
||||
noRepeated(className, nextMethodName, nextClassName) {
|
||||
getOrCreateClassSpec(className, accessorsName)
|
||||
.addSuccessiveField(nextAccessors, nextClassName)
|
||||
.addSuccessiveMethod(nextAccessors, nextMethodName, nextClassName)
|
||||
preAddConstructorSpecNames.add(className to nextClassName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 完成生成所有类的构建器 (释放) */
|
||||
private fun releaseParseTypeSpec() =
|
||||
preAddConstructorSpecNames.onEach { (topClassName, innerClassName) ->
|
||||
getOrCreateConstructorSpec(topClassName)?.addSuccessiveStatement(innerClassName)
|
||||
}.clear()
|
||||
|
||||
/**
|
||||
* 解析并生成所有类的构建器
|
||||
* @return [TypeSpec]
|
||||
*/
|
||||
private fun buildTypeSpec(): TypeSpec {
|
||||
classSpecs.forEach { (name, typeSpec) ->
|
||||
constructorSpecs[name]?.build()?.let { typeSpec.addMethod(it) }
|
||||
if (name != TOP_SUCCESSIVE_NAME) classSpecs[TOP_SUCCESSIVE_NAME]?.addType(typeSpec.build())
|
||||
}; return classSpecs[TOP_SUCCESSIVE_NAME]?.build() ?: SError.make("Merge accessors classes failed")
|
||||
}
|
||||
|
||||
/** 创建首位构建器 */
|
||||
private fun createTopClassSpec() {
|
||||
classSpecs[TOP_SUCCESSIVE_NAME] = createClassSpec(TOP_CLASS_NAME, isInner = false)
|
||||
constructorSpecs[TOP_SUCCESSIVE_NAME] = createConstructorSpec()
|
||||
}
|
||||
|
||||
/** 清空所有已生成的数据 */
|
||||
private fun clearGeneratedData() {
|
||||
classSpecs.clear()
|
||||
constructorSpecs.clear()
|
||||
preAddConstructorSpecNames.clear()
|
||||
memoryExtensionClasses.clear()
|
||||
grandSuccessiveNames.clear()
|
||||
grandSuccessiveDuplicateIndexs.clear()
|
||||
usedSuccessiveTags.clear()
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 [JavaFile]
|
||||
* @return [JavaFile]
|
||||
* @throws SweetDependencyUnresolvedException 如果生成失败
|
||||
*/
|
||||
internal fun build() = runCatching {
|
||||
clearGeneratedData()
|
||||
createTopClassSpec()
|
||||
Dependencies.libraries().forEach { (dependencyName, artifact) ->
|
||||
val dependency = ExternalDependency(dependencyName, artifact.version())
|
||||
parseTypeSpec(dependencyName.current, dependency, artifact)
|
||||
if (artifact.alias.isNotBlank()) parseTypeSpec(artifact.alias, dependency, artifact)
|
||||
releaseParseTypeSpec()
|
||||
}; buildTypeSpec().createJavaFile(ACCESSORS_PACKAGE_NAME)
|
||||
}.getOrElse { SError.make("Failed to generated accessors classes, please checking your config file", it) }
|
||||
|
||||
/**
|
||||
* 获取参与编译的 Stub [JavaFile] 数组
|
||||
* @return [List]<[JavaFile]>
|
||||
*/
|
||||
internal val compileStubFiles get(): List<JavaFile> {
|
||||
val stubFiles = mutableListOf<JavaFile>()
|
||||
val iExtensionAccessorsFile =
|
||||
TypeSpec.interfaceBuilder(IExtensionAccessors::class.java.simpleName)
|
||||
.addModifiers(Modifier.PUBLIC)
|
||||
.build().createJavaFile(IExtensionAccessors::class.java.packageName)
|
||||
val externalDependencyDelegateFile =
|
||||
TypeSpec.classBuilder(ExternalDependencyDelegate::class.java.simpleName)
|
||||
.addModifiers(Modifier.PUBLIC)
|
||||
.addMethod(
|
||||
MethodSpec.constructorBuilder()
|
||||
.addModifiers(Modifier.PUBLIC)
|
||||
.addParameter(String::class.java, "groupId")
|
||||
.addParameter(String::class.java, "artifactId")
|
||||
.addParameter(String::class.java, "version")
|
||||
.build()
|
||||
).build().createJavaFile(ExternalDependencyDelegate::class.java.packageName)
|
||||
stubFiles.add(iExtensionAccessorsFile)
|
||||
stubFiles.add(externalDependencyDelegateFile)
|
||||
return stubFiles
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取扩展功能预置 [Class] 数组 (依赖)
|
||||
*
|
||||
* 需要调用 [build] 生成后才可以使用 - 否则可能会返回空数组
|
||||
* @return [List]<[Pair]<[String], [String]>>
|
||||
*/
|
||||
internal val librariesClasses get() =
|
||||
SweetDependencyConfigs.document.preferences().dependenciesNamespace.libraries().let { namespace ->
|
||||
if (namespace.isNotBlank()) listOf(namespace to createAccessorsName())
|
||||
else memoryExtensionClasses
|
||||
}
|
||||
}
|
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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/7/30.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.plugin.helper
|
||||
|
||||
import com.highcapable.sweetdependency.SweetDependency
|
||||
import com.highcapable.sweetdependency.generated.SweetDependencyProperties
|
||||
import com.highcapable.sweetdependency.gradle.helper.GradleHelper
|
||||
import com.highcapable.sweetdependency.utils.debug.SLog
|
||||
import com.highcapable.sweetdependency.utils.executeUrlBody
|
||||
|
||||
/**
|
||||
* 插件自身检查更新工具类
|
||||
*/
|
||||
internal object PluginUpdateHelper {
|
||||
|
||||
private const val REPO_NAME = SweetDependencyProperties.PROJECT_NAME
|
||||
private const val AUTHOR_NAME = SweetDependencyProperties.PROJECT_DEVELOPER_NAME
|
||||
|
||||
/** 检查更新 URL 地址 */
|
||||
private const val RELEASE_URL = "https://github.com/$AUTHOR_NAME/$REPO_NAME"
|
||||
|
||||
/** 检查更新 */
|
||||
internal fun checkingForUpdate() {
|
||||
if (GradleHelper.isOfflineMode) return
|
||||
val latestVersion = RELEASE_URL.executeUrlBody(isShowFailure = false).findVersionName()
|
||||
if (latestVersion.isNotBlank() && latestVersion != SweetDependency.VERSION)
|
||||
SLog.note(
|
||||
"""
|
||||
Plugin update is available, the current version is ${SweetDependency.VERSION}, please update to $latestVersion
|
||||
You can modify your plugin version in your project's settings.gradle / settings.gradle.kts
|
||||
plugins {
|
||||
id("${SweetDependencyProperties.PROJECT_GROUP_NAME}") version "$latestVersion"
|
||||
...
|
||||
}
|
||||
For more information, you can visit ${SweetDependency.PROJECT_URL}
|
||||
""".trimIndent(), SLog.UP
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 JSON 并查找字符串版本 "name"
|
||||
* @return [String]
|
||||
*/
|
||||
private fun String.findVersionName() =
|
||||
runCatching { trim().split("href=\"/$AUTHOR_NAME/$REPO_NAME/releases/tag/")[1].split("\"")[0] }.getOrNull() ?: ""
|
||||
}
|
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* 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/27.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.plugin.impl
|
||||
|
||||
import com.highcapable.sweetdependency.SweetDependency
|
||||
import com.highcapable.sweetdependency.document.PreferencesDocument
|
||||
import com.highcapable.sweetdependency.document.factory.toUpdateMode
|
||||
import com.highcapable.sweetdependency.environment.Environment
|
||||
import com.highcapable.sweetdependency.gradle.delegate.ProjectTransaction
|
||||
import com.highcapable.sweetdependency.gradle.helper.GradleHelper
|
||||
import com.highcapable.sweetdependency.manager.DependencyManager
|
||||
import com.highcapable.sweetdependency.manager.RepositoryManager
|
||||
import com.highcapable.sweetdependency.plugin.config.content.SweetDependencyConfigs
|
||||
import com.highcapable.sweetdependency.plugin.config.proxy.ISweetDependencyConfigs
|
||||
import com.highcapable.sweetdependency.plugin.helper.PluginUpdateHelper
|
||||
import com.highcapable.sweetdependency.plugin.impl.base.BaseExtensionImpl
|
||||
import com.highcapable.sweetdependency.utils.debug.SError
|
||||
import com.highcapable.sweetdependency.utils.debug.SLog
|
||||
import org.gradle.api.initialization.Settings
|
||||
|
||||
/**
|
||||
* [SweetDependency] 扩展实现类
|
||||
*/
|
||||
internal class SweetDependencyExtensionImpl : BaseExtensionImpl() {
|
||||
|
||||
private companion object {
|
||||
|
||||
/** 插件是否已经装载 - 在 Gradle 守护程序启动后进程不会被结束 */
|
||||
private var isPluginLoaded = false
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查兼容性
|
||||
*
|
||||
* 目前仅支持 Gradle 7.x.x and 8.x.x 版本
|
||||
*/
|
||||
private fun checkingCompatibility() {
|
||||
Environment.characterEncoding?.also {
|
||||
if (it.lowercase() != "utf-8") SLog.warn(
|
||||
"""
|
||||
!!! WARNING !!!
|
||||
The current character encoding is not UTF-8, it is currently $it
|
||||
This will cause some characters cannot be displayed, please change the console character encoding
|
||||
""".trimIndent(), noTag = true
|
||||
)
|
||||
}
|
||||
if (GradleHelper.version.let { it.startsWith("7.") || it.startsWith("8.") }.not()) SError.make(
|
||||
"${SweetDependency.TAG} ${SweetDependency.VERSION} " +
|
||||
"does not support Gradle ${GradleHelper.version}, please update Gradle or plugin version"
|
||||
)
|
||||
}
|
||||
|
||||
override fun onInitialization(settings: Settings, configs: ISweetDependencyConfigs) {
|
||||
checkingCompatibility()
|
||||
configureProject(configs)
|
||||
SweetDependencyConfigs.initialize(configs)
|
||||
SweetDependencyConfigs.withPluginEnable {
|
||||
configureRepositoriesAndDependencies(settings) { autowireOnSyncMode ->
|
||||
autowireOnSyncMode.toUpdateMode()?.also { DependencyManager.autowireAndUpdate(it) }
|
||||
}; PluginUpdateHelper.checkingForUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTransaction(transaction: ProjectTransaction) {
|
||||
if (transaction.isRoot) DependencyManager.resolve(transaction.current)
|
||||
transaction.evaluation { project, isRoot -> if (isRoot) DependencyManager.deploy(project) }
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置项目
|
||||
* @param configs 当前配置
|
||||
*/
|
||||
private fun configureProject(configs: ISweetDependencyConfigs) {
|
||||
SLog.isVerboseMode = configs.isEnableVerboseMode
|
||||
if (isPluginLoaded.not() || GradleHelper.isSyncMode.not()) SLog.verbose(SweetDependency.bannerContent, noTag = true)
|
||||
if (isPluginLoaded) return
|
||||
isPluginLoaded = true
|
||||
SLog.verbose("Welcome to ${SweetDependency.TAG} ${SweetDependency.VERSION}! Using Gradle ${GradleHelper.version}")
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置存储库和依赖
|
||||
* @param settings 当前设置
|
||||
* @param autowire 自回调动装配方法体
|
||||
*/
|
||||
private inline fun configureRepositoriesAndDependencies(settings: Settings, autowire: (PreferencesDocument.AutowireOnSyncMode) -> Unit) {
|
||||
RepositoryManager.generateAndApply(settings)
|
||||
DependencyManager.generateAndApply()
|
||||
if (GradleHelper.isSyncMode) autowire(SweetDependencyConfigs.document.preferences().autowireOnSyncMode)
|
||||
DependencyManager.generateAndApply(settings)
|
||||
}
|
||||
}
|
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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/27.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.plugin.impl.base
|
||||
|
||||
import com.highcapable.sweetdependency.gradle.delegate.ProjectTransaction
|
||||
import com.highcapable.sweetdependency.plugin.config.proxy.ISweetDependencyConfigs
|
||||
import org.gradle.api.initialization.Settings
|
||||
|
||||
/**
|
||||
* 扩展父类实现类
|
||||
*/
|
||||
internal abstract class BaseExtensionImpl internal constructor() {
|
||||
|
||||
/**
|
||||
* 当初始化时回调
|
||||
* @param settings 当前设置
|
||||
* @param configs 当前配置
|
||||
*/
|
||||
internal abstract fun onInitialization(settings: Settings, configs: ISweetDependencyConfigs)
|
||||
|
||||
/**
|
||||
* 当开始事务时回调
|
||||
* @param transaction 当前实例
|
||||
*/
|
||||
internal abstract fun onTransaction(transaction: ProjectTransaction)
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.plugin.task
|
||||
|
||||
import com.highcapable.sweetdependency.gradle.entity.DependencyUpdateMode
|
||||
import com.highcapable.sweetdependency.manager.DependencyManager
|
||||
import com.highcapable.sweetdependency.plugin.config.content.SweetDependencyConfigs
|
||||
import com.highcapable.sweetdependency.plugin.task.base.BaseTask
|
||||
|
||||
/**
|
||||
* 依赖自动装配 Gradle Task
|
||||
*/
|
||||
internal class AutowireDependenciesTask : BaseTask() {
|
||||
|
||||
override fun onTransaction() = SweetDependencyConfigs.withPluginEnable {
|
||||
DependencyManager.autowireAndUpdate(
|
||||
DependencyUpdateMode(
|
||||
DependencyUpdateMode.DependencyType.ALL,
|
||||
DependencyUpdateMode.UpdateType.ONLY_AUTOWIRE
|
||||
), isRunningOnSync = false
|
||||
)
|
||||
}
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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/8/16.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.plugin.task
|
||||
|
||||
import com.highcapable.sweetdependency.gradle.entity.DependencyUpdateMode
|
||||
import com.highcapable.sweetdependency.manager.DependencyManager
|
||||
import com.highcapable.sweetdependency.plugin.config.content.SweetDependencyConfigs
|
||||
import com.highcapable.sweetdependency.plugin.task.base.BaseTask
|
||||
|
||||
/**
|
||||
* 依赖自动装配 Gradle Task
|
||||
*/
|
||||
internal class AutowireLibrariesTask : BaseTask() {
|
||||
|
||||
override fun onTransaction() = SweetDependencyConfigs.withPluginEnable {
|
||||
DependencyManager.autowireAndUpdate(
|
||||
DependencyUpdateMode(
|
||||
DependencyUpdateMode.DependencyType.LIBRARIES,
|
||||
DependencyUpdateMode.UpdateType.ONLY_AUTOWIRE
|
||||
), isRunningOnSync = false
|
||||
)
|
||||
}
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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/8/16.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.plugin.task
|
||||
|
||||
import com.highcapable.sweetdependency.gradle.entity.DependencyUpdateMode
|
||||
import com.highcapable.sweetdependency.manager.DependencyManager
|
||||
import com.highcapable.sweetdependency.plugin.config.content.SweetDependencyConfigs
|
||||
import com.highcapable.sweetdependency.plugin.task.base.BaseTask
|
||||
|
||||
/**
|
||||
* 依赖自动装配 Gradle Task
|
||||
*/
|
||||
internal class AutowirePluginsTask : BaseTask() {
|
||||
|
||||
override fun onTransaction() = SweetDependencyConfigs.withPluginEnable {
|
||||
DependencyManager.autowireAndUpdate(
|
||||
DependencyUpdateMode(
|
||||
DependencyUpdateMode.DependencyType.PLUGINS,
|
||||
DependencyUpdateMode.UpdateType.ONLY_AUTOWIRE
|
||||
), isRunningOnSync = false
|
||||
)
|
||||
}
|
||||
}
|
@@ -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/29.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.plugin.task
|
||||
|
||||
import com.highcapable.sweetdependency.manager.transaction.DependencyMigrationTemplateTransaction
|
||||
import com.highcapable.sweetdependency.plugin.config.content.SweetDependencyConfigs
|
||||
import com.highcapable.sweetdependency.plugin.task.base.BaseTask
|
||||
|
||||
/**
|
||||
* 创建依赖迁移模板 Gradle Task
|
||||
*/
|
||||
internal class CreateDependenciesMigrationTemplateTask : BaseTask() {
|
||||
|
||||
override fun onTransaction() = SweetDependencyConfigs.withPluginEnable { DependencyMigrationTemplateTransaction.createTemplate() }
|
||||
}
|
@@ -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/29.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.plugin.task
|
||||
|
||||
import com.highcapable.sweetdependency.manager.transaction.RuntimeDebugTransaction
|
||||
import com.highcapable.sweetdependency.plugin.config.content.SweetDependencyConfigs
|
||||
import com.highcapable.sweetdependency.plugin.task.base.BaseTask
|
||||
|
||||
/**
|
||||
* 调试 Gradle Task
|
||||
*/
|
||||
internal class SweetDependencyDebugTask : BaseTask() {
|
||||
|
||||
override fun onTransaction() = SweetDependencyConfigs.withPluginEnable { RuntimeDebugTransaction.dump() }
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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/8/14.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.plugin.task
|
||||
|
||||
import com.highcapable.sweetdependency.gradle.entity.DependencyUpdateMode
|
||||
import com.highcapable.sweetdependency.manager.DependencyManager
|
||||
import com.highcapable.sweetdependency.plugin.config.content.SweetDependencyConfigs
|
||||
import com.highcapable.sweetdependency.plugin.task.base.BaseTask
|
||||
|
||||
/**
|
||||
* 依赖自动装配、更新 (全部) Gradle Task
|
||||
*/
|
||||
internal class UpdateAllDependenciesTask : BaseTask() {
|
||||
|
||||
override fun onTransaction() = SweetDependencyConfigs.withPluginEnable {
|
||||
DependencyManager.autowireAndUpdate(
|
||||
DependencyUpdateMode(
|
||||
DependencyUpdateMode.DependencyType.ALL,
|
||||
DependencyUpdateMode.UpdateType.UPDATE_ALL
|
||||
), isRunningOnSync = false
|
||||
)
|
||||
}
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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/8/16.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.plugin.task
|
||||
|
||||
import com.highcapable.sweetdependency.gradle.entity.DependencyUpdateMode
|
||||
import com.highcapable.sweetdependency.manager.DependencyManager
|
||||
import com.highcapable.sweetdependency.plugin.config.content.SweetDependencyConfigs
|
||||
import com.highcapable.sweetdependency.plugin.task.base.BaseTask
|
||||
|
||||
/**
|
||||
* 依赖自动装配、更新 (全部) Gradle Task
|
||||
*/
|
||||
internal class UpdateAllLibrariesTask : BaseTask() {
|
||||
|
||||
override fun onTransaction() = SweetDependencyConfigs.withPluginEnable {
|
||||
DependencyManager.autowireAndUpdate(
|
||||
DependencyUpdateMode(
|
||||
DependencyUpdateMode.DependencyType.LIBRARIES,
|
||||
DependencyUpdateMode.UpdateType.UPDATE_ALL
|
||||
), isRunningOnSync = false
|
||||
)
|
||||
}
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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/8/16.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.plugin.task
|
||||
|
||||
import com.highcapable.sweetdependency.gradle.entity.DependencyUpdateMode
|
||||
import com.highcapable.sweetdependency.manager.DependencyManager
|
||||
import com.highcapable.sweetdependency.plugin.config.content.SweetDependencyConfigs
|
||||
import com.highcapable.sweetdependency.plugin.task.base.BaseTask
|
||||
|
||||
/**
|
||||
* 依赖自动装配、更新 (全部) Gradle Task
|
||||
*/
|
||||
internal class UpdateAllPluginsTask : BaseTask() {
|
||||
|
||||
override fun onTransaction() = SweetDependencyConfigs.withPluginEnable {
|
||||
DependencyManager.autowireAndUpdate(
|
||||
DependencyUpdateMode(
|
||||
DependencyUpdateMode.DependencyType.PLUGINS,
|
||||
DependencyUpdateMode.UpdateType.UPDATE_ALL
|
||||
), isRunningOnSync = false
|
||||
)
|
||||
}
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.plugin.task
|
||||
|
||||
import com.highcapable.sweetdependency.gradle.entity.DependencyUpdateMode
|
||||
import com.highcapable.sweetdependency.manager.DependencyManager
|
||||
import com.highcapable.sweetdependency.plugin.config.content.SweetDependencyConfigs
|
||||
import com.highcapable.sweetdependency.plugin.task.base.BaseTask
|
||||
|
||||
/**
|
||||
* 依赖自动装配、更新 (可选) Gradle Task
|
||||
*/
|
||||
internal class UpdateOptionalDependenciesTask : BaseTask() {
|
||||
|
||||
override fun onTransaction() = SweetDependencyConfigs.withPluginEnable {
|
||||
DependencyManager.autowireAndUpdate(
|
||||
DependencyUpdateMode(
|
||||
DependencyUpdateMode.DependencyType.ALL,
|
||||
DependencyUpdateMode.UpdateType.UPDATE_OPTIONAL
|
||||
), isRunningOnSync = false
|
||||
)
|
||||
}
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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/8/16.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.plugin.task
|
||||
|
||||
import com.highcapable.sweetdependency.gradle.entity.DependencyUpdateMode
|
||||
import com.highcapable.sweetdependency.manager.DependencyManager
|
||||
import com.highcapable.sweetdependency.plugin.config.content.SweetDependencyConfigs
|
||||
import com.highcapable.sweetdependency.plugin.task.base.BaseTask
|
||||
|
||||
/**
|
||||
* 依赖自动装配、更新 (可选) Gradle Task
|
||||
*/
|
||||
internal class UpdateOptionalLibrariesTask : BaseTask() {
|
||||
|
||||
override fun onTransaction() = SweetDependencyConfigs.withPluginEnable {
|
||||
DependencyManager.autowireAndUpdate(
|
||||
DependencyUpdateMode(
|
||||
DependencyUpdateMode.DependencyType.LIBRARIES,
|
||||
DependencyUpdateMode.UpdateType.UPDATE_OPTIONAL
|
||||
), isRunningOnSync = false
|
||||
)
|
||||
}
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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/8/16.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.plugin.task
|
||||
|
||||
import com.highcapable.sweetdependency.gradle.entity.DependencyUpdateMode
|
||||
import com.highcapable.sweetdependency.manager.DependencyManager
|
||||
import com.highcapable.sweetdependency.plugin.config.content.SweetDependencyConfigs
|
||||
import com.highcapable.sweetdependency.plugin.task.base.BaseTask
|
||||
|
||||
/**
|
||||
* 依赖自动装配、更新 (可选) Gradle Task
|
||||
*/
|
||||
internal class UpdateOptionalPluginsTask : BaseTask() {
|
||||
|
||||
override fun onTransaction() = SweetDependencyConfigs.withPluginEnable {
|
||||
DependencyManager.autowireAndUpdate(
|
||||
DependencyUpdateMode(
|
||||
DependencyUpdateMode.DependencyType.PLUGINS,
|
||||
DependencyUpdateMode.UpdateType.UPDATE_OPTIONAL
|
||||
), isRunningOnSync = false
|
||||
)
|
||||
}
|
||||
}
|
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.plugin.task.base
|
||||
|
||||
/**
|
||||
* Gradle Task 父类实现类
|
||||
*/
|
||||
internal abstract class BaseTask internal constructor() {
|
||||
|
||||
/** 当开始事务时回调 */
|
||||
internal abstract fun onTransaction()
|
||||
}
|
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* 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/17.
|
||||
*/
|
||||
@file:Suppress("unused")
|
||||
|
||||
package com.highcapable.sweetdependency.utils
|
||||
|
||||
import com.highcapable.sweetdependency.utils.debug.SError
|
||||
import java.io.File
|
||||
import java.nio.file.Paths
|
||||
import java.util.zip.ZipFile
|
||||
|
||||
/**
|
||||
* 字符串路径转换为文件
|
||||
*
|
||||
* 自动调用 [parseFileSeparator]
|
||||
* @return [File]
|
||||
*/
|
||||
internal fun String.toFile() = File(parseFileSeparator())
|
||||
|
||||
/**
|
||||
* 格式化到当前操作系统的文件分隔符
|
||||
* @return [String]
|
||||
*/
|
||||
internal fun String.parseFileSeparator() = replace("/", File.separator).replace("\\", File.separator)
|
||||
|
||||
/**
|
||||
* 格式化到 Unix 操作系统的文件分隔符
|
||||
* @return [String]
|
||||
*/
|
||||
internal fun String.parseUnixFileSeparator() = replace("\\", "/")
|
||||
|
||||
/**
|
||||
* 字符串文件路径转换到相对文件路径
|
||||
* @param basePath 基于路径
|
||||
* @param rootPath 根路径 - 不填将不校验完整路径
|
||||
* @return [String]
|
||||
*/
|
||||
internal fun String.toRelativeFilePath(basePath: String, rootPath: String = "") =
|
||||
parseFileSeparator().runCatching {
|
||||
if (rootPath.isNotBlank() && contains(rootPath).not()) return this
|
||||
return Paths.get(basePath).relativize(Paths.get(this)).toString()
|
||||
}.getOrNull() ?: parseFileSeparator()
|
||||
|
||||
/**
|
||||
* 字符串文件路径转换到绝对文件路径
|
||||
* @param basePath 基于路径
|
||||
* @return [String]
|
||||
*/
|
||||
internal fun String.toAbsoluteFilePath(basePath: String) =
|
||||
parseFileSeparator().runCatching {
|
||||
if (Paths.get(this).isAbsolute) return this
|
||||
Paths.get(basePath).resolve(Paths.get(this)).normalize().toString()
|
||||
}.getOrNull() ?: parseFileSeparator()
|
||||
|
||||
/**
|
||||
* 字符串文件路径转换到绝对文件路径数组
|
||||
* @param basePath 基于路径
|
||||
* @return [MutableList]<[String]>
|
||||
*/
|
||||
internal fun String.toAbsoluteFilePaths(basePath: String) =
|
||||
toAbsoluteFilePath(basePath).let { path ->
|
||||
mutableListOf<String>().apply {
|
||||
when {
|
||||
path.toFile().let { it.exists() && it.isFile } -> add(path)
|
||||
path.toFile().let { it.exists() && it.isDirectory } -> SError.make("The file path $path is a directory")
|
||||
else -> {
|
||||
/**
|
||||
* 是否匹配文件扩展名
|
||||
* @param condition 条件
|
||||
* @return [Boolean]
|
||||
*/
|
||||
fun String.isMatch(condition: String) =
|
||||
condition.let { if (it == "*") "*.*" else it }.replace(".", "\\.").replace("*", ".*").toRegex().matches(this)
|
||||
val condition = path.split(File.separator)
|
||||
if (path.contains(File.separator) && condition[condition.lastIndex].contains("*"))
|
||||
path.toFile().parentFile?.listFiles()?.forEach { if (it.name.isMatch(condition[condition.lastIndex])) add(it.absolutePath) }
|
||||
else SError.make("Could not resolve file path $path")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查文件是否为合法的压缩包文件
|
||||
*
|
||||
* - 如果不是文件 (可能是目录) - 返回 true
|
||||
* - 如果文件不存在 - 返回 false
|
||||
* @return [Boolean]
|
||||
*/
|
||||
internal fun File.isValidZip(): Boolean {
|
||||
if (isFile.not()) return true
|
||||
if (exists().not()) return false
|
||||
return runCatching { ZipFile(this).use {}; true }.getOrNull() ?: false
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查目录是否为空
|
||||
*
|
||||
* - 如果不是目录 (可能是文件) - 返回 true
|
||||
* - 如果文件不存在 - 返回 true
|
||||
* @return [Boolean]
|
||||
*/
|
||||
internal fun File.isEmpty() = exists().not() || isDirectory.not() || listFiles().isNullOrEmpty()
|
||||
|
||||
/** 删除目录下的空子目录 */
|
||||
internal fun File.deleteEmptyRecursively() {
|
||||
listFiles { file -> file.isDirectory }?.forEach { subDir ->
|
||||
subDir.deleteEmptyRecursively()
|
||||
if (subDir.listFiles()?.isEmpty() == true) subDir.delete()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前文件内容的字符串内容 (同步)
|
||||
* @return [String]
|
||||
*/
|
||||
internal fun String.executeFileBody() = runCatching { toFile().readText() }.getOrNull() ?: ""
|
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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/15.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.utils
|
||||
|
||||
import com.highcapable.sweetdependency.utils.debug.SError
|
||||
import com.highcapable.sweetdependency.utils.debug.SLog
|
||||
import okhttp3.Credentials
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/**
|
||||
* 获取当前 URL 地址的请求体字符串内容 (GET) (同步)
|
||||
* @param username 用户名
|
||||
* @param password 密码
|
||||
* @param isShowFailure 是否显示错误 - 默认是
|
||||
* @return [String]
|
||||
*/
|
||||
internal fun String.executeUrlBody(username: String = "", password: String = "", isShowFailure: Boolean = true) = runCatching {
|
||||
OkHttpClient()
|
||||
.newBuilder()
|
||||
.connectTimeout(10000, TimeUnit.MILLISECONDS)
|
||||
.authenticator { _, response ->
|
||||
if (response.code == 400 || response.code == 401)
|
||||
response.request.newBuilder()
|
||||
.header("Authorization", Credentials.basic(username, password))
|
||||
.build()
|
||||
else null
|
||||
}.build().newCall(
|
||||
Request.Builder().url(when {
|
||||
startsWith("https://") -> "https://" + replace("https://", "").replace("//", "/")
|
||||
startsWith("http://") -> "http://" + replace("http://", "").replace("//", "/")
|
||||
else -> SError.make("Invalid URL: $this")
|
||||
}).get().build()
|
||||
).execute().let {
|
||||
if (it.code == 200 || it.code == 404) it.body?.string() ?: ""
|
||||
else SError.make("Request failed with code ${it.code}")
|
||||
}
|
||||
}.onFailure { if (isShowFailure) SLog.error("Failed to connect to $this\n$it") }.getOrNull() ?: ""
|
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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/7/16.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.utils
|
||||
|
||||
import java.util.concurrent.ExecutorService
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
/**
|
||||
* 创建当前线程池服务
|
||||
* @return [ExecutorService]
|
||||
*/
|
||||
private val currentThreadPool get() = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors())
|
||||
|
||||
/**
|
||||
* 启动 [Thread] 延迟等待 [block] 的结果 [T]
|
||||
* @param delayMs 延迟毫秒 - 默认 1 ms
|
||||
* @param block 方法块
|
||||
* @return [T]
|
||||
*/
|
||||
internal inline fun <T> T.await(delayMs: Long = 1, crossinline block: (T) -> Unit): T {
|
||||
currentThreadPool.apply {
|
||||
execute {
|
||||
if (delayMs > 0) Thread.sleep(delayMs)
|
||||
block(this@await)
|
||||
shutdown()
|
||||
}
|
||||
}; return this
|
||||
}
|
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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/19.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.utils
|
||||
|
||||
import java.io.PrintWriter
|
||||
import java.io.StringWriter
|
||||
|
||||
/**
|
||||
* 写出异常堆栈到字符串
|
||||
* @return [String]
|
||||
*/
|
||||
internal fun Throwable.dumpToString() = StringWriter().apply { printStackTrace(PrintWriter(this).apply { flush() }) }.toString()
|
@@ -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/14.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.utils
|
||||
|
||||
/**
|
||||
* 允许 [MutableList] 进行 [orEmpty] 操作后返回 [MutableList]
|
||||
* @return [MutableList]<[T]>
|
||||
*/
|
||||
internal fun <T> MutableList<T>?.orEmpty() = this ?: emptyList<T>().toMutableList()
|
||||
|
||||
/**
|
||||
* 允许 [MutableList] 进行 [filter] 操作后返回 [MutableList]
|
||||
* @param predicate 方法体
|
||||
* @return [MutableList]<[T]>
|
||||
*/
|
||||
internal inline fun <T> MutableList<out T>.filter(predicate: (T) -> Boolean) = filterTo(mutableListOf(), predicate).toMutableList()
|
||||
|
||||
/**
|
||||
* 允许 [MutableMap] 进行 [filter] 操作后返回 [MutableMap]
|
||||
* @param predicate 方法体
|
||||
* @return [MutableMap]<[K], [V]>
|
||||
*/
|
||||
internal inline fun <K, V> MutableMap<out K, V>.filter(predicate: (Map.Entry<K, V>) -> Boolean) = filterTo(mutableMapOf(), predicate).toMutableMap()
|
||||
|
||||
/**
|
||||
* 获取 [MutableMap] 第一位元素 (数组为空返回 null)
|
||||
* @return [MutableMap.MutableEntry]<[K], [V]> or null
|
||||
*/
|
||||
internal fun <K, V> MutableMap<K, V>.single() = entries.firstOrNull()
|
||||
|
||||
/**
|
||||
* 当数组不为空时返回非空
|
||||
* @return [T] or null
|
||||
*/
|
||||
internal inline fun <reified T : Collection<*>> T.noEmpty() = takeIf { it.isNotEmpty() }
|
||||
|
||||
/**
|
||||
* 当字符串不为空白时返回非空
|
||||
* @return [T] or null
|
||||
*/
|
||||
internal inline fun <reified T : CharSequence> T.noBlank() = takeIf { it.isNotBlank() }
|
||||
|
||||
/**
|
||||
* 判断数组中是否存在重复元素
|
||||
* @return [Boolean]
|
||||
*/
|
||||
internal fun List<*>.hasDuplicate() = distinct().size != size
|
||||
|
||||
/**
|
||||
* 查找数组中的重复元素
|
||||
* @return [List]<[T]>
|
||||
*/
|
||||
internal inline fun <reified T> List<T>.findDuplicates() = distinct().filter { e -> count { it == e } > 1 }.distinct()
|
||||
|
||||
/**
|
||||
* 字符串数组转换为内容字符串
|
||||
* @return [String]
|
||||
*/
|
||||
internal fun List<String>.joinToContent() = joinToString("\n").trim()
|
||||
|
||||
/**
|
||||
* 空格字符串数组转换为 [MutableList]
|
||||
* @return [MutableList]<[String]>
|
||||
*/
|
||||
internal fun String.toSpaceList() = when {
|
||||
contains(" ") -> replace("\\s+".toRegex(), " ").split(" ").toMutableList()
|
||||
isNotBlank() -> mutableListOf(this)
|
||||
else -> mutableListOf()
|
||||
}
|
||||
|
||||
/**
|
||||
* 下划线、分隔线、点、空格命名字符串转小驼峰命名字符串
|
||||
* @return [String]
|
||||
*/
|
||||
internal fun String.camelcase() = runCatching {
|
||||
split("_", ".", "-", " ").map { it.replaceFirstChar { e -> e.titlecase() } }.let { words ->
|
||||
words.first().replaceFirstChar { it.lowercase() } + words.drop(1).joinToString("")
|
||||
}
|
||||
}.getOrNull() ?: this
|
||||
|
||||
/**
|
||||
* 下划线、分隔线、点、空格命名字符串转大驼峰命名字符串
|
||||
* @return [String]
|
||||
*/
|
||||
internal fun String.uppercamelcase() = camelcase().capitalize()
|
||||
|
||||
/**
|
||||
* 字符串首字母大写
|
||||
* @return [String]
|
||||
*/
|
||||
internal fun String.capitalize() = replaceFirstChar { it.uppercaseChar() }
|
||||
|
||||
/**
|
||||
* 字符串首字母小写
|
||||
* @return [String]
|
||||
*/
|
||||
internal fun String.uncapitalize() = replaceFirstChar { it.lowercaseChar() }
|
||||
|
||||
/**
|
||||
* 转换字符串第一位数字到外观近似大写字母
|
||||
* @return [String]
|
||||
*/
|
||||
internal fun String.firstNumberToLetter() =
|
||||
if (isNotBlank()) (mapOf(
|
||||
'0' to 'O', '1' to 'I',
|
||||
'2' to 'Z', '3' to 'E',
|
||||
'4' to 'A', '5' to 'S',
|
||||
'6' to 'G', '7' to 'T',
|
||||
'8' to 'B', '9' to 'P'
|
||||
)[first()] ?: first()) + substring(1)
|
||||
else this
|
||||
|
||||
/**
|
||||
* 转换字符串为非 Java 关键方法引用名称
|
||||
* @return [String]
|
||||
*/
|
||||
internal fun String.toNonJavaName() = if (lowercase() == "class") replace("lass", "lazz") else this
|
||||
|
||||
/**
|
||||
* 字符串中是否存在插值符号 ${...}
|
||||
* @return [Boolean]
|
||||
*/
|
||||
internal fun String.hasInterpolation() = contains("\${") && contains("}")
|
||||
|
||||
/**
|
||||
* 替换字符串中的插值符号 ${...}
|
||||
* @param result 回调结果
|
||||
* @return [String]
|
||||
*/
|
||||
internal fun String.replaceInterpolation(result: (groupValue: String) -> CharSequence) =
|
||||
"\\$\\{(.+?)}".toRegex().replace(this) { result(it.groupValues[1]) }
|
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* 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/8/6.
|
||||
*/
|
||||
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 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
|
||||
import javax.tools.ToolProvider
|
||||
|
||||
/**
|
||||
* 代码编译处理类
|
||||
*/
|
||||
internal object CodeCompiler {
|
||||
|
||||
/** Maven 模型版本 */
|
||||
private const val MAVEN_MODEL_VERSION = "4.0.0"
|
||||
|
||||
/**
|
||||
* 编译 [JavaFileObject] 为 Maven 依赖
|
||||
* @param pomData Maven POM 实体
|
||||
* @param outputDirPath 编译输出目录路径
|
||||
* @param files [JavaFileObject] 数组
|
||||
* @param compileOnlyFiles [JavaFileObject] 仅编译数组 - 默认空
|
||||
* @throws SweetDependencyExtension 如果编译失败
|
||||
*/
|
||||
internal fun compile(
|
||||
pomData: MavenPomData,
|
||||
outputDirPath: String,
|
||||
files: List<JavaFileObject>,
|
||||
compileOnlyFiles: List<JavaFileObject> = mutableListOf()
|
||||
) {
|
||||
val outputDir = outputDirPath.toFile()
|
||||
if (files.isEmpty()) {
|
||||
if (outputDir.exists()) outputDir.deleteRecursively()
|
||||
return
|
||||
} else outputDir.also { if (it.exists().not()) it.mkdirs() }
|
||||
val outputBuildDir = "$outputDirPath/build".toFile().also { if (it.exists()) it.deleteRecursively(); it.mkdirs() }
|
||||
val outputClassesDir = "${outputBuildDir.absolutePath}/classes".toFile().apply { mkdirs() }
|
||||
val outputSourcesDir = "${outputBuildDir.absolutePath}/sources".toFile().apply { mkdirs() }
|
||||
val compiler = ToolProvider.getSystemJavaCompiler()
|
||||
val diagnostics = DiagnosticCollector<JavaFileObject>()
|
||||
val fileManager = compiler.getStandardFileManager(diagnostics, null, null)
|
||||
fileManager.setLocation(StandardLocation.CLASS_OUTPUT, listOf(outputClassesDir))
|
||||
val task = compiler.getTask(null, fileManager, diagnostics, null, null, compileOnlyFiles + files)
|
||||
val result = task.call()
|
||||
var diagnosticsMessage = ""
|
||||
diagnostics.diagnostics?.forEach { diagnostic ->
|
||||
diagnosticsMessage += " > Error on line ${diagnostic.lineNumber} in ${diagnostic.source?.toUri()}\n"
|
||||
diagnosticsMessage += " ${diagnostic.getMessage(null)}\n"
|
||||
}
|
||||
runCatching { fileManager.close() }
|
||||
if (result) {
|
||||
compileOnlyFiles.forEach { "${outputClassesDir.absolutePath}/${it.name}".replace(".java", ".class").toFile().delete() }
|
||||
files.forEach {
|
||||
it.toFiles(outputSourcesDir).also { (sourceDir, sourceFile) ->
|
||||
sourceDir.mkdirs()
|
||||
sourceFile.writeText(it.getCharContent(true).toString())
|
||||
}
|
||||
}; outputClassesDir.deleteEmptyRecursively()
|
||||
writeMetaInf(outputClassesDir.absolutePath)
|
||||
writeMetaInf(outputSourcesDir.absolutePath)
|
||||
createJarAndPom(pomData, outputDir, outputBuildDir, outputClassesDir, outputSourcesDir)
|
||||
} else SError.make("Failed to compile java files into path: $outputDirPath\n$diagnosticsMessage")
|
||||
}
|
||||
|
||||
/**
|
||||
* 打包 JAR 并写入 POM
|
||||
* @param pomData Maven POM 实体
|
||||
* @param outputDir 编译输出目录
|
||||
* @param buildDir 编译目录
|
||||
* @param classesDir 编译二进制目录
|
||||
* @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() }
|
||||
packageToJar(classesDir, pomDir, pomData, isSourcesJar = false)
|
||||
packageToJar(sourcesDir, pomDir, pomData, isSourcesJar = true)
|
||||
writePom(pomDir.absolutePath, pomData)
|
||||
buildDir.deleteRecursively()
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入 META-INF/MANIFEST.MF
|
||||
* @param dirPath 当前目录路径
|
||||
*/
|
||||
private fun writeMetaInf(dirPath: String) {
|
||||
val metaInfFile = "$dirPath/META-INF".toFile().apply { mkdirs() }
|
||||
"${metaInfFile.absolutePath}/MANIFEST.MF".toFile().writeText("Manifest-Version: 1.0")
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入 POM
|
||||
* @param dirPath 当前目录路径
|
||||
* @param pomData Maven POM 实体
|
||||
*/
|
||||
private fun writePom(dirPath: String, pomData: MavenPomData) =
|
||||
"$dirPath/${pomData.artifactId}-${pomData.version}.pom".toFile().writeText(
|
||||
"""
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project
|
||||
xmlns="http://maven.apache.org/POM/$MAVEN_MODEL_VERSION"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/$MAVEN_MODEL_VERSION https://maven.apache.org/xsd/maven-$MAVEN_MODEL_VERSION.xsd"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>$MAVEN_MODEL_VERSION</modelVersion>
|
||||
<groupId>${pomData.groupId}</groupId>
|
||||
<artifactId>${pomData.artifactId}</artifactId>
|
||||
<version>${pomData.version}</version>
|
||||
</project>
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
/**
|
||||
* 转换到 [MavenPomData] 目录名称
|
||||
* @return [String]
|
||||
*/
|
||||
private fun String.toPomPathName() = trim().replace(".", "/").replace("_", "/").replace(":", "/").replace("-", "/")
|
||||
|
||||
/**
|
||||
* 转换到文件
|
||||
* @param outputDir 输出目录
|
||||
* @return [Pair]<[File], [File]>
|
||||
*/
|
||||
private fun JavaFileObject.toFiles(outputDir: File): Pair<File, File> {
|
||||
val outputDirPath = outputDir.absolutePath
|
||||
val separator = if (name.contains("/")) "/" else "\\"
|
||||
val names = name.split(separator)
|
||||
val fileName = names[names.lastIndex]
|
||||
val folderName = name.replace(fileName, "")
|
||||
return "$outputDirPath/$folderName".toFile() to "$outputDirPath/$name".toFile()
|
||||
}
|
||||
|
||||
/**
|
||||
* 打包编译输出目录到 JAR
|
||||
* @param buildDir 编译目录
|
||||
* @param outputDir 输出目录
|
||||
* @param pomData Maven POM 实体
|
||||
* @param isSourcesJar 是否为源码 JAR
|
||||
* @throws SweetDependencyExtension 如果编译输出目录不存在
|
||||
*/
|
||||
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()
|
||||
if (jarFile.exists()) jarFile.delete()
|
||||
jarFile.outputStream().use { fos -> JarOutputStream(fos).use { jos -> buildDir.addToJar(jos) } }
|
||||
}
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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/8/24.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.utils.code.entity
|
||||
|
||||
/**
|
||||
* Maven POM 实体
|
||||
* @param groupId Group ID
|
||||
* @param artifactId Artifact Id
|
||||
* @param version 版本
|
||||
*/
|
||||
internal data class MavenPomData(internal val groupId: String, internal val artifactId: String, internal val version: String)
|
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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/8/6.
|
||||
*/
|
||||
@file:Suppress("unused")
|
||||
|
||||
package com.highcapable.sweetdependency.utils.code.factory
|
||||
|
||||
import com.highcapable.sweetdependency.plugin.SweetDependencyExtension
|
||||
import com.highcapable.sweetdependency.utils.code.CodeCompiler
|
||||
import com.highcapable.sweetdependency.utils.code.entity.MavenPomData
|
||||
import com.squareup.javapoet.JavaFile
|
||||
import javax.tools.JavaFileObject
|
||||
|
||||
/**
|
||||
* 编译 [JavaFile] 为 Maven 依赖
|
||||
* @param pomData Maven POM 实体
|
||||
* @param outputDirPath 编译输出目录路径
|
||||
* @param compileOnlyFiles [JavaFile] 仅编译数组 - 默认空
|
||||
* @throws SweetDependencyExtension 如果编译失败
|
||||
*/
|
||||
@JvmName("compileWithJavaFile")
|
||||
internal fun JavaFile.compile(pomData: MavenPomData, outputDirPath: String, compileOnlyFiles: List<JavaFile> = mutableListOf()) =
|
||||
CodeCompiler.compile(
|
||||
pomData = pomData,
|
||||
outputDirPath = outputDirPath,
|
||||
files = listOf(toJavaFileObject()),
|
||||
compileOnlyFiles = mutableListOf<JavaFileObject>().also { compileOnlyFiles.forEach { e -> it.add(e.toJavaFileObject()) } }
|
||||
)
|
||||
|
||||
/**
|
||||
* 编译 [JavaFile] 为 Maven 依赖
|
||||
* @param pomData Maven POM 实体
|
||||
* @param outputDirPath 编译输出目录路径
|
||||
* @param compileOnlyFiles [JavaFile] 仅编译数组 - 默认空
|
||||
* @throws SweetDependencyExtension 如果编译失败
|
||||
*/
|
||||
@JvmName("compileWithJavaFile")
|
||||
internal fun List<JavaFile>.compile(pomData: MavenPomData, outputDirPath: String, compileOnlyFiles: List<JavaFile> = mutableListOf()) =
|
||||
CodeCompiler.compile(
|
||||
pomData = pomData,
|
||||
outputDirPath = outputDirPath,
|
||||
files = mutableListOf<JavaFileObject>().also { forEach { e -> it.add(e.toJavaFileObject()) } },
|
||||
compileOnlyFiles = mutableListOf<JavaFileObject>().also { compileOnlyFiles.forEach { e -> it.add(e.toJavaFileObject()) } }
|
||||
)
|
||||
|
||||
/**
|
||||
* 编译 [JavaFileObject] 为 Maven 依赖
|
||||
* @param pomData Maven POM 实体
|
||||
* @param outputDirPath 编译输出目录路径
|
||||
* @param compileOnlyFiles [JavaFileObject] 仅编译数组 - 默认空
|
||||
* @throws SweetDependencyExtension 如果编译失败
|
||||
*/
|
||||
@JvmName("compileWithJavaFileObject")
|
||||
internal fun JavaFileObject.compile(pomData: MavenPomData, outputDirPath: String, compileOnlyFiles: List<JavaFileObject> = mutableListOf()) =
|
||||
CodeCompiler.compile(pomData, outputDirPath, listOf(this), compileOnlyFiles)
|
||||
|
||||
/**
|
||||
* 编译 [JavaFileObject] 为 Maven 依赖
|
||||
* @param pomData Maven POM 实体
|
||||
* @param outputDirPath 编译输出目录路径
|
||||
* @param compileOnlyFiles [JavaFileObject] 仅编译数组 - 默认空
|
||||
* @throws SweetDependencyExtension 如果编译失败
|
||||
*/
|
||||
@JvmName("compileWithJavaFileObject")
|
||||
internal fun List<JavaFileObject>.compile(pomData: MavenPomData, outputDirPath: String, compileOnlyFiles: List<JavaFileObject> = mutableListOf()) =
|
||||
CodeCompiler.compile(pomData, outputDirPath, files = this, compileOnlyFiles)
|
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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/31.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.utils.debug
|
||||
|
||||
import com.highcapable.sweetdependency.exception.SweetDependencyUnresolvedException
|
||||
|
||||
/**
|
||||
* 全局异常管理类
|
||||
*/
|
||||
internal object SError {
|
||||
|
||||
/**
|
||||
* 抛出异常
|
||||
* @param msg 消息内容
|
||||
* @throws e 异常内容 - 默认空
|
||||
* @throws SweetDependencyUnresolvedException
|
||||
*/
|
||||
internal fun make(msg: String, e: Throwable? = null): Nothing = throw SweetDependencyUnresolvedException(msg, e)
|
||||
}
|
@@ -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/5/25.
|
||||
*/
|
||||
@file:Suppress("MemberVisibilityCanBePrivate")
|
||||
|
||||
package com.highcapable.sweetdependency.utils.debug
|
||||
|
||||
import com.highcapable.sweetdependency.SweetDependency
|
||||
import com.highcapable.sweetdependency.utils.await
|
||||
import org.apache.log4j.Logger
|
||||
|
||||
/**
|
||||
* 全局 Log 管理类
|
||||
*/
|
||||
internal object SLog {
|
||||
|
||||
internal const val DONE = "✅"
|
||||
internal const val IGNORE = "❎"
|
||||
internal const val ERROR = "❌"
|
||||
internal const val WARN = "⚠️"
|
||||
internal const val LINK = "➡️"
|
||||
internal const val WIRE = "⚙️"
|
||||
internal const val UP = "⬆️"
|
||||
internal const val ROTATE = "\uD83D\uDD04"
|
||||
internal const val ANLZE = "\uD83D\uDD0D"
|
||||
internal const val STRNG = "\uD83D\uDCAA"
|
||||
|
||||
/** 当前日志输出对象 */
|
||||
private val logger = Logger.getLogger(SLog::class.java)
|
||||
|
||||
/** 短时间内不重复的日志内容 */
|
||||
private var noRepeatInThisTimeContent = ""
|
||||
|
||||
/** 是否启用详细模式 */
|
||||
internal var isVerboseMode = true
|
||||
|
||||
/**
|
||||
* 打印 Verbose 级别 Log (无颜色)
|
||||
* @param msg 消息内容
|
||||
* @param symbol 前缀符号 - 仅限非 [noTag] - 默认无
|
||||
* @param noTag 无标签 - 默认否
|
||||
* @param noRepeat 短时间内不重复输出 - 默认否
|
||||
*/
|
||||
internal fun verbose(msg: Any, symbol: String = "", noTag: Boolean = false, noRepeat: Boolean = false) {
|
||||
if (isVerboseMode) info(msg, symbol, noTag, noRepeat)
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印 Info (提醒) 级别 Log (绿色)
|
||||
* @param msg 消息内容
|
||||
* @param symbol 前缀符号 - 仅限非 [noTag] - 默认无
|
||||
* @param noTag 无标签 - 默认否
|
||||
* @param noRepeat 短时间内不重复输出 - 默认否
|
||||
*/
|
||||
internal fun note(msg: Any, symbol: String = "", noTag: Boolean = false, noRepeat: Boolean = false) =
|
||||
log(if (noTag) msg else msg.createSymbolMsg(symbol), color = "38;5;10", noRepeat = noRepeat)
|
||||
|
||||
/**
|
||||
* 打印 Info 级别 Log (无颜色)
|
||||
* @param msg 消息内容
|
||||
* @param symbol 前缀符号 - 仅限非 [noTag] - 默认无
|
||||
* @param noTag 无标签 - 默认否
|
||||
* @param noRepeat 短时间内不重复输出 - 默认否
|
||||
*/
|
||||
internal fun info(msg: Any, symbol: String = "", noTag: Boolean = false, noRepeat: Boolean = false) =
|
||||
log(if (noTag) msg else msg.createSymbolMsg(symbol), noRepeat = noRepeat)
|
||||
|
||||
/**
|
||||
* 打印 Warn 级别 Log (黄色)
|
||||
* @param msg 消息内容
|
||||
* @param symbol 前缀符号 - 仅限非 [noTag] - 默认 [WARN]
|
||||
* @param noTag 无标签 - 默认否
|
||||
* @param noRepeat 短时间内不重复输出 - 默认否
|
||||
*/
|
||||
internal fun warn(msg: Any, symbol: String = WARN, noTag: Boolean = false, noRepeat: Boolean = false) =
|
||||
log(if (noTag) msg else msg.createSymbolMsg(symbol), color = "33", noRepeat = noRepeat)
|
||||
|
||||
/**
|
||||
* 打印 Error 级别 Log (红色)
|
||||
* @param msg 消息内容
|
||||
* @param symbol 前缀符号 - 仅限非 [noTag] - 默认 [ERROR]
|
||||
* @param noTag 无标签 - 默认否
|
||||
* @param noRepeat 短时间内不重复输出 - 默认否
|
||||
*/
|
||||
internal fun error(msg: Any, symbol: String = ERROR, noTag: Boolean = false, noRepeat: Boolean = false) =
|
||||
log(if (noTag) msg else msg.createSymbolMsg(symbol), isError = true, noRepeat = noRepeat)
|
||||
|
||||
/**
|
||||
* 创建符号消息内容
|
||||
* @param symbol 前缀符号
|
||||
* @return [String]
|
||||
*/
|
||||
private fun Any.createSymbolMsg(symbol: String) =
|
||||
if (symbol.isNotBlank()) "[${SweetDependency.TAG}] $symbol $this" else "[${SweetDependency.TAG}] $this"
|
||||
|
||||
/**
|
||||
* 打印 Log
|
||||
* @param msg 消息内容
|
||||
* @param color 颜色代码 - 默认无颜色
|
||||
* @param isError 是否强制为错误日志 - 默认否
|
||||
* @param noRepeat 短时间内不重复输出 - 默认否
|
||||
*/
|
||||
private fun log(msg: Any, color: String = "0", isError: Boolean = false, noRepeat: Boolean = false) {
|
||||
if (noRepeat && noRepeatInThisTimeContent == msg.toString()) return
|
||||
noRepeatInThisTimeContent = msg.toString()
|
||||
when {
|
||||
isError -> logger.error(msg)
|
||||
color != "0" -> println("\u001B[${color}m$msg\u001B[0m")
|
||||
else -> println(msg)
|
||||
}
|
||||
if (noRepeat) await(1500) { noRepeatInThisTimeContent = "" } else noRepeatInThisTimeContent = ""
|
||||
}
|
||||
}
|
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* 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/17.
|
||||
*/
|
||||
@file:Suppress("unused")
|
||||
|
||||
package com.highcapable.sweetdependency.utils.yaml
|
||||
|
||||
import com.charleskorn.kaml.YamlConfiguration
|
||||
import com.charleskorn.kaml.yamlMap
|
||||
import com.highcapable.sweetdependency.gradle.helper.GradleHelper
|
||||
import com.highcapable.sweetdependency.utils.hasInterpolation
|
||||
import com.highcapable.sweetdependency.utils.replaceInterpolation
|
||||
import com.highcapable.sweetdependency.utils.toFile
|
||||
import com.highcapable.sweetdependency.utils.yaml.factory.YamlMapEntries
|
||||
import com.highcapable.sweetdependency.utils.yaml.proxy.IYamlDocument
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.serializer
|
||||
import com.charleskorn.kaml.Yaml as Kaml
|
||||
|
||||
/**
|
||||
* YAML 文档处理类
|
||||
*/
|
||||
internal object Yaml {
|
||||
|
||||
/**
|
||||
* 获取 [Kaml] 对象
|
||||
* @return [Kaml]
|
||||
*/
|
||||
private val kaml by lazy { Kaml(configuration = YamlConfiguration(encodeDefaults = false)) }
|
||||
|
||||
/**
|
||||
* 从文件解析到 [IYamlDocument]
|
||||
* @param path 文件路径
|
||||
* @return [T]
|
||||
*/
|
||||
internal inline fun <reified T : IYamlDocument> loadFromFile(path: String) = loadFromString<T>(path.toFile().readText())
|
||||
|
||||
/**
|
||||
* 从字符串解析到 [IYamlDocument]
|
||||
* @param string 字符串
|
||||
* @return [T]
|
||||
*/
|
||||
internal inline fun <reified T : IYamlDocument> loadFromString(string: String) = kaml.decodeFromString<T>(string.flattened())
|
||||
|
||||
/**
|
||||
* 从文件解析到 [YamlMapEntries]
|
||||
* @param path 文件路径
|
||||
* @return [YamlMapEntries]
|
||||
*/
|
||||
internal fun loadFromFileAsNode(path: String) = loadFromStringAsNode(path.toFile().readText())
|
||||
|
||||
/**
|
||||
* 从字符串解析到 [YamlMapEntries]
|
||||
* @param string 字符串
|
||||
* @return [YamlMapEntries]
|
||||
*/
|
||||
internal fun loadFromStringAsNode(string: String) = kaml.parseToYamlNode(string.flattened()).yamlMap.entries
|
||||
|
||||
/**
|
||||
* 序列化 [IYamlDocument] 到文件
|
||||
* @param path 文件路径
|
||||
* @param formatter 回调字符串格式化方式
|
||||
*/
|
||||
internal inline fun <reified T : IYamlDocument> parseToFile(doc: T, path: String, formatter: String.() -> String = { this }) =
|
||||
path.toFile().writeText(kaml.encodeToString(serializer(), doc).let(formatter))
|
||||
|
||||
/**
|
||||
* 字符串平坦化处理
|
||||
*
|
||||
* - 去除字符串中以 # 开头的注释行并去除空行
|
||||
* - 调用 [interpFromEnv] 解析可被插值的字符串
|
||||
* @return [String]
|
||||
*/
|
||||
private fun String.flattened() = trimIndent()
|
||||
.replace("(^|\\s)#.*".toRegex(), "")
|
||||
.replace("(?m)^\\s*$(\\n|\\r\\n?)".toRegex(), "")
|
||||
.let { if (it.hasInterpolation()) it.interpFromEnv() else it }
|
||||
.trim()
|
||||
|
||||
/**
|
||||
* 将系统属性资源值插入到当前字符串中
|
||||
*
|
||||
* 形如:${...}
|
||||
*
|
||||
* 会按照以下顺序进行查找 ↓
|
||||
*
|
||||
* - 项目 properties
|
||||
* - 用户 properties
|
||||
* - 系统 properties
|
||||
* - 系统环境变量
|
||||
* @return [String]
|
||||
*/
|
||||
private fun String.interpFromEnv() = replaceInterpolation { key ->
|
||||
GradleHelper.projectProperties?.get(key)?.toString()
|
||||
?: GradleHelper.userProperties?.get(key)?.toString()
|
||||
?: runCatching { System.getProperties()[key]?.toString() }.getOrNull()
|
||||
?: runCatching { System.getenv(key) }.getOrNull() ?: ""
|
||||
}
|
||||
}
|
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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/19.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.utils.yaml.factory
|
||||
|
||||
import com.charleskorn.kaml.YamlException
|
||||
import com.charleskorn.kaml.YamlMap
|
||||
import com.charleskorn.kaml.YamlNode
|
||||
import com.charleskorn.kaml.YamlScalar
|
||||
|
||||
/** YAML 异常类型定义 */
|
||||
internal typealias YamlException = YamlException
|
||||
|
||||
/** YAML 节点数组类型定义 */
|
||||
internal typealias YamlMapEntries = Map<YamlScalar, YamlNode>
|
||||
|
||||
/**
|
||||
* 转换为 YAML 节点数组
|
||||
* @return [YamlMapEntries] or null
|
||||
*/
|
||||
internal fun YamlNode.asMap() = (this as? YamlMap)?.entries
|
||||
|
||||
/**
|
||||
* 获取 YAML 节点是否存在
|
||||
* @param key 节点名称
|
||||
* @return [Boolean]
|
||||
*/
|
||||
internal fun YamlMapEntries.isKeyExist(key: String) = keys.singleOrNull { it.content == key } != null
|
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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/20.
|
||||
*/
|
||||
package com.highcapable.sweetdependency.utils.yaml.proxy
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
/**
|
||||
* YAML 文档接口
|
||||
*/
|
||||
internal interface IYamlDocument : Serializable
|
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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", "UnusedReceiverParameter")
|
||||
|
||||
package org.gradle.kotlin.dsl
|
||||
|
||||
import com.highcapable.sweetdependency.manager.helper.DependencyDeployHelper
|
||||
import org.gradle.api.artifacts.dsl.DependencyHandler
|
||||
import org.gradle.plugin.use.PluginDependenciesSpec
|
||||
import org.gradle.plugin.use.PluginDependencySpec
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler
|
||||
|
||||
/**
|
||||
* 自动装配插件依赖
|
||||
* @param params 参数数组
|
||||
* @return [PluginDependencySpec]
|
||||
*/
|
||||
fun PluginDependenciesSpec.autowire(vararg params: Any) = DependencyDeployHelper.resolveAutowire(spec = this, params)
|
||||
|
||||
/**
|
||||
* 自动装配依赖
|
||||
* @param params 参数数组
|
||||
* @return [Any]
|
||||
*/
|
||||
fun DependencyHandler.autowire(vararg params: String) = DependencyDeployHelper.resolveAutowire(params = params)
|
||||
|
||||
/**
|
||||
* 自动装配依赖
|
||||
* @param params 参数数组
|
||||
* @return [Any]
|
||||
*/
|
||||
fun KotlinDependencyHandler.autowire(vararg params: String) = DependencyDeployHelper.resolveAutowire(project, params)
|
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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/3.
|
||||
*/
|
||||
@file:Suppress("unused")
|
||||
|
||||
package org.gradle.kotlin.dsl
|
||||
|
||||
import com.highcapable.sweetdependency.gradle.factory.configure
|
||||
import com.highcapable.sweetdependency.gradle.factory.get
|
||||
import com.highcapable.sweetdependency.plugin.extension.dsl.configure.SweetDependencyConfigureExtension
|
||||
import org.gradle.api.Action
|
||||
import org.gradle.api.initialization.Settings
|
||||
|
||||
/**
|
||||
* WORKAROUND: for some reason a type-safe accessor is not generated for the extension,
|
||||
* even though it is present in the extension container where the plugin is applied.
|
||||
* This seems to work fine, and the extension methods are only available when the plugin
|
||||
* is actually applied.
|
||||
*
|
||||
* See related link [here](https://stackoverflow.com/questions/72627792/gradle-settings-plugin-extension)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Retrieves the [SweetDependencyConfigureExtension] extension.
|
||||
* @return [SweetDependencyConfigureExtension]
|
||||
*/
|
||||
val Settings.sweetDependency get() = get<SweetDependencyConfigureExtension>(SweetDependencyConfigureExtension.NAME)
|
||||
|
||||
/**
|
||||
* Configures the [SweetDependencyConfigureExtension] extension.
|
||||
* @param configure
|
||||
*/
|
||||
fun Settings.sweetDependency(configure: Action<SweetDependencyConfigureExtension>) = configure(SweetDependencyConfigureExtension.NAME, configure)
|
Reference in New Issue
Block a user