All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
name.remal.gradle_plugins.plugins.code_quality.findbugs.BaseFindBugsSettingsPlugin.kt Maven / Gradle / Ivy
package name.remal.gradle_plugins.plugins.code_quality.findbugs
import com.google.common.reflect.TypeToken
import name.remal.asClass
import name.remal.clearNamespaces
import name.remal.createParentDirectories
import name.remal.debug
import name.remal.default
import name.remal.escapeRegex
import name.remal.findMethod
import name.remal.forceDeleteRecursively
import name.remal.gradle_plugins.dsl.BaseReflectiveProjectPlugin
import name.remal.gradle_plugins.dsl.CreateExtensionsPluginAction
import name.remal.gradle_plugins.dsl.PluginAction
import name.remal.gradle_plugins.dsl.WithPluginClasses
import name.remal.gradle_plugins.dsl.extensions.addExtensionMethod
import name.remal.gradle_plugins.dsl.extensions.all
import name.remal.gradle_plugins.dsl.extensions.beforeResolve
import name.remal.gradle_plugins.dsl.extensions.convention
import name.remal.gradle_plugins.dsl.extensions.conventionWithSelf
import name.remal.gradle_plugins.dsl.extensions.create
import name.remal.gradle_plugins.dsl.extensions.doSetup
import name.remal.gradle_plugins.dsl.extensions.exclude
import name.remal.gradle_plugins.dsl.extensions.get
import name.remal.gradle_plugins.dsl.extensions.getRequiredResource
import name.remal.gradle_plugins.dsl.extensions.noSourceIf
import name.remal.gradle_plugins.dsl.utils.ProjectAware
import name.remal.gradle_plugins.dsl.utils.XML_PRETTY_OUTPUTTER
import name.remal.gradle_plugins.plugins.classes_relocation.ClassesRelocationPlugin
import name.remal.gradle_plugins.plugins.classes_relocation.relocatedClassesJavaPackageName
import name.remal.gradle_plugins.plugins.code_quality.ExcludesExtension
import name.remal.gradle_plugins.plugins.code_quality.findbugs.extensions.FindBugsSubplugin
import name.remal.gradle_plugins.plugins.code_quality.setupQualityTaskReporters
import name.remal.gradle_plugins.plugins.dependencies.TransitiveDependenciesExtension
import name.remal.gradle_plugins.plugins.dependencies.TransitiveDependenciesPlugin
import name.remal.loadServices
import name.remal.newTempFile
import name.remal.nullIfEmpty
import name.remal.setNoOpEntityResolver
import name.remal.setNoValidatingXMLReaderFactory
import name.remal.uncheckedCast
import name.remal.use
import name.remal.version.Version
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.artifacts.ConfigurationContainer
import org.gradle.api.artifacts.ExternalModuleDependency
import org.gradle.api.artifacts.dsl.DependencyHandler
import org.gradle.api.file.FileCollection
import org.gradle.api.model.ObjectFactory
import org.gradle.api.plugins.ExtensionContainer
import org.gradle.api.plugins.quality.CodeQualityExtension
import org.gradle.api.reporting.Reporting
import org.gradle.api.tasks.TaskContainer
import org.gradle.initialization.DefaultSettings.DEFAULT_BUILD_SRC_DIR
import org.jdom2.Document
import org.jdom2.Element
import org.jdom2.input.SAXBuilder
import java.io.File
import java.lang.reflect.ParameterizedType
import kotlin.collections.forEach
abstract class BaseFindBugsSettingsPlugin(
private val objectFactory: ObjectFactory
) : BaseReflectiveProjectPlugin() {
companion object {
@JvmStatic
protected val FINDBUGS_EXCLUDE_RESOURCE_URL = BaseFindBugsSettingsPlugin::class.java.getRequiredResource("exclude.xml")
private fun newSAXBuilder() = SAXBuilder().apply {
setNoValidatingXMLReaderFactory()
setNoOpEntityResolver()
}
}
protected lateinit var project: Project
@PluginAction(order = Int.MIN_VALUE, isHidden = true)
private fun populateProject(project: Project) {
this.project = project
}
protected abstract val toolName: String
protected open val extensionName: String get() = toolName.toLowerCase()
protected open val toolConfigurationName: String get() = extensionName
protected open val pluginsConfigurationName: String get() = "${extensionName}Plugins"
protected abstract val toolLatestVersion: String
protected abstract val toolArtifactGroup: String
protected abstract val toolArtifactIds: Set
protected abstract var TaskType.excludeFilterFile: File?
protected abstract val TaskType.classesDirs: FileCollection
protected val extensionType: Class = run {
val type = TypeToken.of(this.javaClass).getSupertype(BaseFindBugsSettingsPlugin::class.java).type
if (type !is ParameterizedType) throw IllegalStateException("$type is not instance of ParameterizedType")
return@run type.actualTypeArguments[0].asClass().uncheckedCast>()
}
protected val taskType: Class = run {
val type = TypeToken.of(this.javaClass).getSupertype(BaseFindBugsSettingsPlugin::class.java).type
if (type !is ParameterizedType) throw IllegalStateException("$type is not instance of ParameterizedType")
return@run type.actualTypeArguments[1].asClass().uncheckedCast>()
}
@CreateExtensionsPluginAction
fun ExtensionContainer.`Create 'excludes' extension for tool extension`() {
toolExtension.convention.add(
"excludes",
objectFactory.newInstance(ExcludesExtension::class.java)
)
}
@CreateExtensionsPluginAction
fun TaskContainer.`Create 'excludes' extension for each task`() {
all(taskType) { task ->
task.extensions.add(
"excludes",
objectFactory.newInstance(ExcludesExtension::class.java)
)
}
}
@PluginAction
@WithPluginClasses(ClassesRelocationPlugin::class)
fun ExtensionContainer.`Don't check relocated classes`(project: Project) {
globalExcludes.className(project.relocatedClassesJavaPackageName + ".*")
}
@PluginAction
fun ExtensionContainer.`Update tool version`() {
val toolExtension = this.toolExtension
val toolVersionStr = toolExtension.toolVersion
if (toolVersionStr.isNullOrEmpty()) {
toolExtension.toolVersion = toolLatestVersion
} else {
val toolVersion = Version.parseOrNull(toolVersionStr)
val buildVersion = Version.parseOrNull(toolLatestVersion)
if (toolVersion != null && buildVersion != null) {
if (toolVersion < buildVersion) {
toolExtension.toolVersion = buildVersion.toString()
}
}
}
}
@PluginAction
fun ConfigurationContainer.`Force tool dependencies to have the same version as toolVersion`(extensions: ExtensionContainer, dependencyHandler: DependencyHandler) {
val toolExtension = extensions.toolExtension
all {
it.resolutionStrategy {
it.eachDependency { dep ->
val toolVersion = toolExtension.toolVersion.nullIfEmpty() ?: return@eachDependency
with(dep.target) {
if (group == toolArtifactGroup && name in toolArtifactIds) {
if (version.isNullOrEmpty()) {
dep.useVersion(toolVersion)
}
}
}
}
}
it.beforeResolve { conf ->
val toolVersion = toolExtension.toolVersion.nullIfEmpty() ?: return@beforeResolve
val usedVersions = mutableMapOf>()
val dependenciesToForce = mutableListOf()
val forcedDependencies = mutableListOf()
conf.dependencies.forEach { dep ->
if (dep !is ExternalModuleDependency) return@forEach
if (dep.group != toolArtifactGroup || dep.name !in toolArtifactIds) return@forEach
val depKey = "${dep.group}:${dep.name}"
usedVersions.computeIfAbsent(depKey, { mutableSetOf() }).add(dep.version.default())
if (dep.isForce) {
forcedDependencies.add(depKey)
} else if (!dep.versionConstraint.preferredVersion.isNullOrEmpty()) {
forcedDependencies.add(depKey)
usedVersions.computeIfAbsent(depKey, { mutableSetOf() }).add(dep.versionConstraint.preferredVersion)
} else {
dependenciesToForce.add(depKey)
}
}
dependenciesToForce.removeAll(forcedDependencies)
dependenciesToForce.forEach { depKey ->
if (usedVersions[depKey]?.all { it == toolVersion } == true) return@forEach
conf.dependencies.add(dependencyHandler.create("$depKey:$toolVersion") {
it.isForce = true
})
}
}
}
}
@PluginAction
fun TaskContainer.`No-source if no classes exist`() {
all(taskType) {
it.noSourceIf { it.classesDirs.isEmpty }
}
}
@PluginAction
fun TaskContainer.`Setup task default filters`(project: Project) {
all(taskType) {
it.doSetup { task ->
if (task.excludeFilterFile == null) {
var rootDir: File = project.rootDir
if (rootDir.name == DEFAULT_BUILD_SRC_DIR) {
rootDir = rootDir.parentFile
}
val configFile = File(rootDir, "gradle/$extensionName/exclude.xml")
if (!configFile.isFile) {
synchronized(BaseFindBugsSettingsPlugin::class.java) {
if (!configFile.isFile) {
configFile.forceDeleteRecursively().createParentDirectories()
FINDBUGS_EXCLUDE_RESOURCE_URL.openStream().use { inputStream ->
configFile.outputStream().use { outputStream ->
inputStream.copyTo(outputStream)
}
}
}
}
}
task.excludeFilterFile = configFile
}
}
}
}
@PluginAction
@Suppress("ComplexMethod", "LongMethod")
fun TaskContainer.`Apply exclude rules`(extensions: ExtensionContainer) {
val globalExcludes = extensions.globalExcludes
all(taskType) {
it.doSetup(Int.MAX_VALUE) { task ->
val taskExcludes = task.taskExcludes
val classNames = sequenceOf(globalExcludes.classNames, taskExcludes.classNames).flatten().toSortedSet()
val sourcePaths = sequenceOf(globalExcludes.sources, taskExcludes.sources).flatten().toSortedSet()
val messages = sequenceOf(globalExcludes.messages, taskExcludes.messages).flatten().toSortedSet()
if (classNames.isEmpty() && sourcePaths.isEmpty() && messages.isEmpty()) return@doSetup
val newExcludeXmlFile = newTempFile("$extensionName-exclude-", ".xml")
task.doFirst {
val document = task.excludeFilterFile?.let { newSAXBuilder().build(it).clearNamespaces() }
?: Document().setRootElement(Element("FindBugsFilter"))
if (classNames.isNotEmpty()) {
document.rootElement.addContent(
Element("Match").addContent(
Element("Or").also { element ->
classNames.forEach { className ->
element.addContent(
Element("Class").setAttribute(
"name",
if (className.contains('*')) {
"~" + className.splitToSequence('*')
.map(::escapeRegex)
.joinToString(".*")
} else {
className
}
)
)
}
}
)
)
}
if (sourcePaths.isNotEmpty()) {
document.rootElement.addContent(
Element("Match").addContent(
Element("Or").also { element ->
sourcePaths.forEach { sourcePath ->
element.addContent(
Element("Source").setAttribute(
"name",
if (sourcePath.contains('*')) {
"~" + sourcePath.splitToSequence('*')
.map(::escapeRegex)
.joinToString(".*")
} else {
sourcePath
}
)
)
}
}
)
)
}
if (messages.isNotEmpty()) {
document.rootElement.addContent(
Element("Match").addContent(
Element("Or").also { element ->
messages.forEach { message ->
element.addContent(
Element("Bug").setAttribute(
"name",
if (message.contains('*')) {
"~" + message.splitToSequence('*')
.map(::escapeRegex)
.joinToString(".*")
} else {
message
}
)
)
}
}
)
)
}
newExcludeXmlFile.outputStream().use { outputStream ->
XML_PRETTY_OUTPUTTER.output(document, outputStream)
}
task.excludeFilterFile = newExcludeXmlFile
}
task.doLast {
newExcludeXmlFile.delete()
}
}
}
}
@PluginAction
fun TaskContainer.`Setup task reports`() {
all(taskType) {
setupQualityTaskReporters(it)
it.doSetup { task ->
task as Reporting<*>
task.reports.forEach { report ->
if ("xml" == report.name) {
report.isEnabled = true
try {
report.javaClass.findMethod("setWithMessages", Boolean::class.java)
?.apply { isAccessible = true }
?.invoke(report, true)
} catch (e: Exception) {
logger.debug(e)
}
} else {
report.isEnabled = false
}
}
}
}
}
@PluginAction
fun ExtensionContainer.`Add plugin extensions to the plugin extension`(dependencyHandler: DependencyHandler, project: Project) {
val toolExtension = this.toolExtension
loadServices(FindBugsSubplugin::class.java).toSortedSet().forEach { findBugsSubplugin ->
if (findBugsSubplugin is ProjectAware) {
findBugsSubplugin.project = project
}
toolExtension.conventionWithSelf.addExtensionMethod(findBugsSubplugin.extensionName) {
dependencyHandler.add(pluginsConfigurationName, findBugsSubplugin.dependencyNotation)
}
}
}
@PluginAction
fun TaskContainer.`Create plugins help task`() {
create("${extensionName}PluginsHelp", DisplayFindBugsPluginsHelp::class.java) {
it.toolName = [email protected]
}
}
@PluginAction
fun ConfigurationContainer.`Exclude tool from plugins configuration`() {
this[pluginsConfigurationName].apply {
exclude("com.google.code.findbugs", "findbugs")
exclude("com.google.code.findbugs", "annotations")
exclude("com.google.code.findbugs", "jsr305")
exclude("com.google.spotbugs", "spotbugs")
exclude("com.google.spotbugs", "spotbugs-annotations")
exclude("com.google.spotbugs", "annotations")
}
}
@PluginAction
@WithPluginClasses(TransitiveDependenciesPlugin::class)
fun ExtensionContainer.`Register tool configurations in 'transitiveDependencies' extension`() {
this[TransitiveDependenciesExtension::class.java].addConfigurationToProcess(
toolConfigurationName,
pluginsConfigurationName
)
}
protected val ExtensionContainer.toolExtension: ExtensionType get() = this[extensionType]
protected val ExtensionContainer.globalExcludes: ExcludesExtension get() = toolExtension.convention[ExcludesExtension::class.java]
protected val TaskType.taskExcludes: ExcludesExtension get() = this[ExcludesExtension::class.java]
}