name.remal.gradle_plugins.toolkit.build_logic.helpers.gradle Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of build-logic Show documentation
Show all versions of build-logic Show documentation
Remal Gradle plugins: toolkit: build-logic
import static org.gradle.api.attributes.Category.CATEGORY_ATTRIBUTE
import static org.gradle.api.attributes.Category.DOCUMENTATION
import static org.gradle.api.attributes.Category.ENFORCED_PLATFORM
import static org.gradle.api.attributes.Category.REGULAR_PLATFORM
import static org.gradle.api.attributes.Category.VERIFICATION
import java.lang.reflect.Method
import java.lang.reflect.Modifier
import java.security.MessageDigest
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ConcurrentMap
import org.gradle.util.GradleVersion
import org.json.JSONArray
import org.json.JSONObject
import org.json.JSONTokener
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
buildscript {
dependencies {
classpath "org.json:json:20240303"
classpath "org.jsoup:jsoup:1.18.1"
classpath "com.vdurmont:semver4j:3.1.0"
}
repositories {
mavenCentral()
}
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
Object MUTEX = new Object[0]
project.ext.isBuildSrcProject = rootProject.name == 'buildSrc'
allprojects {
project.ext.afterEvaluateOrNow = { Closure action ->
if (project.state.executed) {
project.configure(project, action)
} else {
project.afterEvaluate(action)
}
}
project.ext.withPluginAfterEvaluateOrNow = { String pluginId, Closure action ->
project.afterEvaluateOrNow {
project.pluginManager.withPlugin(pluginId) {
project.configure(project, action)
}
}
}
}
project.ext.startWithWord = { CharSequence untypedString, CharSequence untypedNeedle ->
if (untypedString == null || untypedNeedle == null) return false
if (untypedNeedle.length() == 0) return true
if (untypedString.length() == 0) return false
String string = untypedString.toString()
String needle = untypedNeedle.toString()
if (string == needle) return true
if (string.startsWith(needle)) {
String remaining = string.substring(needle.length())
char firstRemainingChar = remaining.charAt(0)
char lastNeedleChar = needle.charAt(needle.length() - 1)
if (Character.isDigit(lastNeedleChar)) {
return !Character.isDigit(firstRemainingChar)
} else if (Character.isLetter(lastNeedleChar)) {
if (!Character.isLetter(lastNeedleChar)) {
return true
} else if (Character.isUpperCase(firstRemainingChar) && !Character.isUpperCase(lastNeedleChar)) {
return true
} else if (Character.isLowerCase(firstRemainingChar) && !Character.isLowerCase(lastNeedleChar)) {
return true
} else {
return false
}
} else {
return Character.isLetter(firstRemainingChar)
}
}
return false
}
project.ext.isInstanceOf = { Object object, String parentClassName ->
if (object == null) return false
Class> parentClass = Class.forName(parentClassName, true, object.class.classLoader)
return parentClass.isInstance(object)
}
project.ext.disableTask = { Task task ->
task.enabled = false
task.onlyIf { false }
task.dependsOn = []
Iterator registeredFileProperties = task.inputs.registeredFileProperties.iterator()
while (registeredFileProperties.hasNext()) {
registeredFileProperties.next()
registeredFileProperties.remove()
}
}
project.ext.isVerificationTask = { Task task ->
if (task instanceof VerificationTask
|| task instanceof AbstractTestTask
|| task instanceof ValidatePlugins
|| task instanceof JacocoCoverageVerification
) {
return true
}
return false
}
List sourceSetGetConfigurationNameMethods = SourceSet.getMethods().findAll {
it.name.startsWith('get')
&& it.name.endsWith('ConfigurationName')
&& it.returnType == String
&& it.parameterCount == 0
&& !Modifier.isStatic(it.modifiers)
}
project.ext.getSourceSetConfigurationNames = { SourceSet sourceSet ->
return sourceSetGetConfigurationNameMethods.collect { it.invoke(sourceSet) }
.findAll { it != null }
.toSet()
}
allprojects {
project.ext.getAllSourceSetConfigurations = { SourceSet sourceSet ->
Collection sourceSetConfigurationNames = project.getSourceSetConfigurationNames(sourceSet)
return project.configurations.matching { sourceSetConfigurationNames.contains(it.name) }
}.memoize()
DomainObjectSet allSourceSetsConfigurations = project.ext.allSourceSetsConfigurations = project.objects.domainObjectSet(Configuration)
project.pluginManager.withPlugin('java') {
project.sourceSets.all { SourceSet sourceSet ->
project.getAllSourceSetConfigurations(sourceSet).all { allSourceSetsConfigurations.add(it) }
}
}
}
project.ext.getDependencyCategory = { Object dep ->
AttributeContainer attributes = null
if (dep instanceof ModuleDependency) {
attributes = dep.attributes
} else if (dep instanceof ResolvedDependencyResult) {
attributes = dep.resolvedVariant.attributes
} else if (dep instanceof UnresolvedDependencyResult) {
attributes = dep.attempted.attributes
} else if (dep instanceof Dependency) {
return false
} else {
throw new GradleException("Unsupported dependency type: ${dep.class}")
}
Attribute categoryAttribute = attributes.keySet().find { attr ->
if (attr instanceof String) {
return attr == CATEGORY_ATTRIBUTE.name
} else {
return attr.name == CATEGORY_ATTRIBUTE.name
}
}
if (categoryAttribute == null) {
return null;
}
Object value = attributes.getAttribute(categoryAttribute)
if (value instanceof String) {
return value
}
return value.name
}
project.ext.isPlatformDependency = { Object dep ->
String category = getDependencyCategory(dep)
return [REGULAR_PLATFORM, ENFORCED_PLATFORM].contains(category)
}
project.ext.isEnforcedPlatformDependency = { Object dep ->
String category = getDependencyCategory(dep)
return [ENFORCED_PLATFORM].contains(category)
}
project.ext.isDocumentationDependency = { Object dep ->
String category = getDependencyCategory(dep)
return [DOCUMENTATION].contains(category)
}
project.ext.isVerificationDependency = { Object dep ->
String category = getDependencyCategory(dep)
return [VERIFICATION].contains(category)
}
project.ext.calculateBaseJavaPackageFor = { Project project ->
String baseJavaPackage = project.ext.find('baseJavaPackage')
if (baseJavaPackage != null) return baseJavaPackage
List baseJavaPackageTokens = "${rootProject.group}:${rootProject.name}${project.path}".split(/[.:]+/)
.findAll { !it.isEmpty() }
int hiddenTokenPos = baseJavaPackageTokens.findIndexOf { it.contains('--') }
if (hiddenTokenPos >= 0) {
baseJavaPackageTokens = baseJavaPackageTokens.subList(0, hiddenTokenPos)
}
for (int index = 0; index < baseJavaPackageTokens.size() - 1; ++index) {
String token = baseJavaPackageTokens.get(index)
String nextToken = baseJavaPackageTokens.get(index + 1)
if (token == nextToken) {
baseJavaPackageTokens.remove(index)
--index
} else if ("${token}-root" == nextToken) {
baseJavaPackageTokens.remove(index + 1)
--index
} else if (token == "${nextToken}-root") {
baseJavaPackageTokens.remove(index)
--index
}
}
return baseJavaPackageTokens.join('.')
.replaceAll(/[^\w.]+/, '_')
.replaceAll(/_{2,}/, '_')
.replaceAll(/_\./, '.')
.replaceAll(/\._/, '.')
.replaceAll(/\.{2,}/, '.')
.replaceFirst(/^\./, '')
.replaceFirst(/\.$/, '')
}.memoize()
allprojects {
project.ext.calculateBaseJavaPackage = {
return project.calculateBaseJavaPackageFor(project)
}.memoize()
project.ext.calculateJavaModuleName = {
return project.findProperty('javaModuleName') ?: project.calculateBaseJavaPackage()
}.memoize()
}
allprojects {
Closure maybeRegisterTask = { String taskName, Closure configurer ->
try {
return tasks.named(taskName)
} catch (UnknownTaskException ignore) {
// do nothing
}
return tasks.register(taskName) { Task task -> configurer(task) }
}
Closure findSourceSet = { String sourceSetName, boolean isRequired = true ->
if (isRequired) {
return project.sourceSets.getByName(sourceSetName)
} else {
return project.sourceSets.findByName(sourceSetName)
}
}
project.ext.registerResolveSourceSetCompileClasspathTask = { String sourceSetName, boolean isRequired = true ->
String taskName = "resolve${sourceSetName.capitalize()}SourceSetCompileClasspath"
TaskProvider taskProvider = maybeRegisterTask(taskName) { Task task ->
task.ext.isRequired = false
task.dependsOn(project.provider { findSourceSet(sourceSetName, task.isRequired)?.with { project.configurations[it.compileClasspathConfigurationName].allDependencies } ?: [] })
task.doLast { findSourceSet(sourceSetName, task.isRequired)?.compileClasspath?.files }
}
if (isRequired) {
taskProvider.configure { Task task ->
task.ext.isRequired = true
}
}
return taskProvider
}
project.ext.registerResolveSourceSetRuntimeClasspathTask = { String sourceSetName, boolean isRequired = true ->
String taskName = "resolve${sourceSetName.capitalize()}SourceSetRuntimeClasspath"
TaskProvider taskProvider = maybeRegisterTask(taskName) { Task task ->
task.ext.isRequired = false
task.dependsOn(project.provider { findSourceSet(sourceSetName, task.isRequired)?.with { project.configurations[it.runtimeClasspathConfigurationName].allDependencies } ?: [] })
task.dependsOn(project.provider { findSourceSet(sourceSetName, task.isRequired)?.classesTaskName ?: [] })
task.doLast { findSourceSet(sourceSetName, task.isRequired)?.runtimeClasspath?.files }
}
if (isRequired) {
taskProvider.configure { Task task ->
task.ext.isRequired = true
}
}
return taskProvider
}
Closure findConfiguration = { String configurationName, boolean isRequired = true ->
if (isRequired) {
return project.configurations.getByName(configurationName)
} else {
return project.configurations.findByName(configurationName)
}
}
project.ext.registerResolveConfigurationTask = { String configurationName, boolean isRequired = true ->
String taskName = "resolve${configurationName.capitalize()}Configuration"
TaskProvider taskProvider = maybeRegisterTask(taskName) { Task task ->
task.ext.isRequired = false
task.dependsOn(project.provider { findConfiguration(configurationName, task.isRequired)?.allDependencies ?: [] })
task.doLast { findConfiguration(configurationName, task.isRequired)?.resolve() }
}
if (isRequired) {
taskProvider.configure { Task task ->
task.ext.isRequired = true
}
}
return taskProvider
}
}
Closure sha512hex = project.ext.sha512hex = { Object content ->
if (content instanceof CharSequence) {
content = content.toString().getBytes('UTF-8')
}
if (!(content instanceof byte[])) {
throw new IllegalAccessException("content must be instance of CharSequence or byte[]")
}
MessageDigest md = MessageDigest.getInstance("SHA-512")
byte[] hash = md.digest((byte[]) content)
StringBuilder hex = new StringBuilder(hash.length * 2)
for (byte b : hash) {
hex.append(String.format("%02x", b))
}
return hex.toString()
}
File downloadedContentCacheDir = project.layout.buildDirectory.dir('downloaded-content-cache').get().asFile
Closure getCacheFileForDownloadedUrl = project.ext.getCacheFileForDownloadedUrl = { Object untypedUrl, String cacheFileNameSuffix = null ->
URL url = project.uri(untypedUrl).toURL()
if (cacheFileNameSuffix == null) {
cacheFileNameSuffix = url.path.with { String path ->
path = new File(path).getName()
int dotPos = path.lastIndexOf('.')
return dotPos >= 0 ? path.substring(dotPos) : ''
}
}
return new File(downloadedContentCacheDir, sha512hex(url.toString()) + cacheFileNameSuffix)
}
Closure loadUrlContent = project.ext.loadUrlContent = { Object untypedUrl, String cacheFileNameSuffix = null ->
synchronized (MUTEX) {
File cacheFile = getCacheFileForDownloadedUrl(untypedUrl, cacheFileNameSuffix)
if (cacheFile.exists()) {
return cacheFile.bytes
}
URL url = project.uri(untypedUrl).toURL()
URLConnection connection = url.openConnection()
connection.connectTimeout = 5000
connection.readTimeout = 15000
connection.useCaches = false
try {
if (connection instanceof HttpURLConnection) {
if (connection.responseCode != 200) {
throw new GradleException("$url returned ${connection.responseCode} status")
}
}
byte[] content = connection.inputStream.bytes
cacheFile.parentFile.mkdirs()
cacheFile.bytes = content
return content
} finally {
if (connection instanceof HttpURLConnection) {
connection.disconnect()
}
}
}
}
Closure loadTextUrlContent = project.ext.loadTextUrlContent = { Object untypedUrl, String encoding = 'UTF-8', String cacheFileNameSuffix = null ->
byte[] content = loadUrlContent(untypedUrl, cacheFileNameSuffix)
return new String(content, encoding)
}
Closure loadJsonFromUrl = project.ext.loadJsonFromUrl = { Object untypedUrl, String encoding = 'UTF-8' ->
String content = loadTextUrlContent(untypedUrl, encoding, '.json')
return new JSONTokener(content).nextValue()
}
Closure loadHtmlFromUrl = project.ext.loadHtmlFromUrl = { Object untypedUrl, String encoding = 'UTF-8' ->
String content = loadTextUrlContent(untypedUrl, encoding, '.html')
return Jsoup.parse(content, project.uri(untypedUrl).toString())
}
Closure> getAllGradleVersions = project.ext.getAllGradleVersions = {
List result = []
JSONArray versionObjects = loadJsonFromUrl('https://services.gradle.org/versions/all')
for (JSONObject versionObject : versionObjects) {
if (versionObject.optBoolean('snapshot')) continue
if (versionObject.optBoolean('nightly')) continue
if (versionObject.optBoolean('releaseNightly')) continue
if (versionObject.optBoolean('broken')) continue
if (!versionObject.optString('milestoneFor').isEmpty()) continue
if (!versionObject.optBoolean('activeRc') && !versionObject.optString('rcFor').isEmpty()) continue
String version = versionObject.getString('version')
if (version.containsIgnoreCase('milestone')) continue
if (version.startsWith('0.')) continue
GradleVersion gradleVersion = GradleVersion.version(version)
if (gradleVersion.baseVersion == gradleVersion) {
result.add(gradleVersion)
}
}
result.sort(Comparator.reverseOrder())
return result
}.memoize()
Closure> getStableGradleVersions = project.ext.getStableGradleVersions = {
return getAllGradleVersions().findAll { it.baseVersion == it }
}.memoize()
Closure> getMinorGradleVersions = project.ext.getMinorGradleVersions = {
return getStableGradleVersions().findAll { it.version.count('.') == 1 }
}
Closure> getFilteredJavaRuntimeVersions = { Closure filter ->
List result = []
JSONArray versionObjects = loadJsonFromUrl('https://api.foojay.io/disco/v3.0/major_versions?ea=false&ga=true&discovery_scope_id=public&include_versions=false')['result']
for (JSONObject versionObject : versionObjects) {
if (versionObject.optBoolean('early_access_only')) continue
if (versionObject.optString('release_status') == 'ea') continue
if (!filter(versionObject)) continue
int version = versionObject.getInt('major_version')
if (version < 8) continue
result.add(version)
}
result.sort(Comparator.reverseOrder())
return result
}
Closure> getAllJavaRuntimeVersions = project.ext.getAllJavaRuntimeVersions = {
return getFilteredJavaRuntimeVersions { true }
}.memoize()
Closure> getLtsJavaRuntimeVersions = project.ext.getLtsJavaRuntimeVersions = {
return getFilteredJavaRuntimeVersions { JSONObject versionObject ->
versionObject.getString('term_of_support') == 'LTS'
}
}.memoize()
ConcurrentMap getGradleApiDependencyVersionCache = new ConcurrentHashMap<>()
allprojects {
project.ext.getGradleApiDependencyVersion = { String notation ->
return getGradleApiDependencyVersionCache.computeIfAbsent(notation) {
String gradleApiVersion = project.configurations.projectDependencyConstraints
.allDependencyConstraints
.find { "${it.group}:${it.name}" == 'name.remal.gradle-api:gradle-api' }
?.version
if (gradleApiVersion == null) throw new GradleException('Unknown Gradle API version')
Configuration tempConf = project.configurations.detachedConfiguration(
project.dependencies.create("name.remal.gradle-api:gradle-api:$gradleApiVersion")
)
String version = tempConf.resolvedConfiguration
.resolvedArtifacts
.collect { it.moduleVersion }
.collect { it.id }
.find { "${it.group}:*" == notation || "${it.group}:${it.name}" == notation }
?.version
if (version == null) throw new GradleException("Gradle API dependency not found: $notation")
return version
}
}
}
allprojects {
project.ext.fatJarWithDependentTaskNames = [
'classes',
'jar',
'sourcesJar',
'javadocJar',
]
Closure fatJarWithImpl = { Project otherProject ->
otherProject.tasks.withType(Javadoc).configureEach { enabled = false }
project.fatJarWithDependentTaskNames.forEach { String taskName ->
tasks.matching { it.name == taskName }.configureEach {
dependsOn(otherProject.tasks.matching { it.name == taskName })
}
}
sourceSets.main.allSource.srcDirs(otherProject.sourceSets.main.allSource.srcDirs)
otherProject.sourceSets.main.output.forEach { sourceSets.main.output.dir(it) }
tasks.withType(AbstractCopyTask).configureEach {
filesMatching(['**/package-info.class', '**/package-info.java']) {
duplicatesStrategy(DuplicatesStrategy.EXCLUDE)
}
}
tasks.withType(Javadoc).configureEach { Javadoc task ->
task.dependsOn(project.provider { otherProject.registerResolveConfigurationTask('optionalHidden') })
task.onlyIf {
task.classpath += otherProject.configurations.optionalHidden
otherProject.tasks.withType(Javadoc).forEach { Javadoc otherTask ->
task.classpath += otherTask.classpath
}
return true
}
Set processedPackageInfoResources = new LinkedHashSet<>()
task.exclude { FileTreeElement element ->
String path = element.path
if ("/$path".endsWith('/package-info.class') || "/$path".endsWith('/package-info.java')) {
return !processedPackageInfoResources.add(path)
}
}
task.source(
project.provider {
otherProject.tasks.withType(Javadoc)
.collect { it.source }
}
)
}
}
Set fatJarWithProjects = new LinkedHashSet<>()
project.ext.fatJarWith = { Project otherProject ->
if (!fatJarWithProjects.add(otherProject)) return
project.withPluginAfterEvaluateOrNow('java') {
otherProject.withPluginAfterEvaluateOrNow('java') {
fatJarWithImpl(otherProject)
}
}
}
}