buildSrc/src/main/kotlin/SourceLicenseChecker.kt
changeset 119 684356cd6a7d
parent 111 f42cdc67a8e7
equal deleted inserted replaced
118:ceee12802fbc 119:684356cd6a7d
    20  * along with AboutOss.  If not, see <http://www.gnu.org/licenses/>.
    20  * along with AboutOss.  If not, see <http://www.gnu.org/licenses/>.
    21  */
    21  */
    22 package com.geekorum.build
    22 package com.geekorum.build
    23 
    23 
    24 import com.android.build.api.dsl.AndroidSourceSet
    24 import com.android.build.api.dsl.AndroidSourceSet
       
    25 import com.android.build.api.dsl.CommonExtension
    25 import com.android.build.gradle.BaseExtension
    26 import com.android.build.gradle.BaseExtension
    26 import com.android.build.gradle.DynamicFeaturePlugin
    27 import com.android.build.gradle.DynamicFeaturePlugin
    27 import com.android.build.gradle.TestPlugin
    28 import com.android.build.gradle.TestPlugin
    28 import com.hierynomus.gradle.license.LicenseBasePlugin
    29 import com.hierynomus.gradle.license.LicenseBasePlugin
    29 import com.hierynomus.gradle.license.tasks.LicenseCheck
    30 import com.hierynomus.gradle.license.tasks.LicenseCheck
    38 import org.gradle.kotlin.dsl.*
    39 import org.gradle.kotlin.dsl.*
    39 import org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension
    40 import org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension
    40 import org.jetbrains.kotlin.gradle.plugin.KotlinAndroidPluginWrapper
    41 import org.jetbrains.kotlin.gradle.plugin.KotlinAndroidPluginWrapper
    41 import org.jetbrains.kotlin.gradle.plugin.KotlinJsPluginWrapper
    42 import org.jetbrains.kotlin.gradle.plugin.KotlinJsPluginWrapper
    42 import org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformPluginWrapper
    43 import org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformPluginWrapper
       
    44 import java.io.File
    43 import java.util.Locale
    45 import java.util.Locale
    44 
    46 
    45 internal fun Project.configureSourceLicenseChecker() {
    47 internal fun Project.configureSourceLicenseChecker() {
    46     apply<LicensePlugin>()
    48     apply<LicensePlugin>()
    47 
    49 
    48     configure<LicenseExtension> {
    50     configure<LicenseExtension> {
    49         header = file("$rootDir/config/license/header.txt")
    51         header = file("$rootDir/config/license/header.txt")
    50         mapping("java", "SLASHSTAR_STYLE")
    52         mapping("java", "SLASHSTAR_STYLE")
       
    53         mapping("json", "SLASHSTAR_STYLE")
    51         mapping("kt", "SLASHSTAR_STYLE")
    54         mapping("kt", "SLASHSTAR_STYLE")
    52 
    55 
    53         excludes(listOf("**/*.webp", "**/*.png"))
    56         excludes(listOf("**/*.webp", "**/*.png", "**/*.jpeg", "**/*.jpg"))
    54     }
    57     }
    55 
    58 
    56     // the LicensePlugin doesn't configure itself properly on DynamicFeaturePlugin
    59     // the LicensePlugin doesn't configure itself properly on DynamicFeaturePlugin
    57     // Copied the code to configure it
    60     // Copied the code to configure it
    58     plugins.withType(DynamicFeaturePlugin::class.java) {
    61     plugins.withType<DynamicFeaturePlugin> {
    59         configureAndroid()
    62         configureAndroid()
    60     }
    63     }
    61 
    64 
    62     // the LicensePlugin doesn't configure itself properly on Android Test plugin
    65     // the LicensePlugin doesn't configure itself properly on Android Test plugin
    63     // Copied the code to configure it
    66     // Copied the code to configure it
    64     plugins.withType(TestPlugin::class.java) {
    67     plugins.withType<TestPlugin> {
    65         configureAndroid()
    68         configureAndroid()
    66     }
    69     }
    67 
    70 
    68     // make the license tasks looks for kotlin files in an Android project
    71     // make the license tasks looks for kotlin files in an Android project
    69     plugins.withType(KotlinAndroidPluginWrapper::class.java) {
    72     plugins.withType<KotlinAndroidPluginWrapper> {
    70         configureKotlinAndroid()
    73         configureKotlinAndroid()
    71     }
    74     }
    72 
    75 
    73     // make the license tasks for kotlin js project
    76     // make the license tasks for kotlin js project
    74     plugins.withType(KotlinJsPluginWrapper::class.java) {
    77     plugins.withType<KotlinJsPluginWrapper> {
    75         configureKotlin()
    78         configureKotlin()
    76     }
    79     }
    77 
    80 
    78     plugins.withType(KotlinMultiplatformPluginWrapper::class.java) {
    81     plugins.withType<KotlinMultiplatformPluginWrapper> {
    79         configureKotlin()
    82         configureKotlin()
    80     }
    83         configureComposeResources()
    81 }
    84     }
    82 
    85 
    83 @OptIn(ExperimentalStdlibApi::class)
    86     tasks.withType<License>().configureEach {
       
    87         notCompatibleWithConfigurationCache("License tasks calls getProject() at execution time")
       
    88     }
       
    89 }
       
    90 
    84 private fun Project.configureKotlin() {
    91 private fun Project.configureKotlin() {
    85     val kotlin = the<KotlinProjectExtension>()
    92     val kotlin = the<KotlinProjectExtension>()
    86     val taskInfix = ""
    93     val taskInfix = ""
    87     kotlin.sourceSets.configureEach {
    94     kotlin.sourceSets.configureEach {
    88         val kotlinSource = this
    95         val kotlinSource = this
   112             source(kotlinSource.kotlin)
   119             source(kotlinSource.kotlin)
   113             exclude {
   120             exclude {
   114                 // exclude generated files, notably protobuf, ksp, hilt
   121                 // exclude generated files, notably protobuf, ksp, hilt
   115                 "/generated/" in it.file.path
   122                 "/generated/" in it.file.path
   116             }
   123             }
       
   124         }
       
   125         val sourceSetFormatTaskName =
       
   126             "${LicenseBasePlugin.getFORMAT_TASK_BASE_NAME()}${taskInfix}${name.capitalize()}"
       
   127         if (sourceSetFormatTaskName in tasks.names) {
       
   128             // tasks may have already been added by configuration for the Android plugin
       
   129             logger.info("Tasks $sourceSetFormatTaskName already exists. configure it")
       
   130             tasks.named(sourceSetFormatTaskName, LicenseFormat::class.java, configureLicenseFormatTaskLambda)
       
   131         } else {
       
   132             logger.info("Adding ${project.name}:$sourceSetFormatTaskName task for sourceSet ${kotlinSource.name}")
       
   133             tasks.register(sourceSetFormatTaskName, LicenseFormat::class.java, configureLicenseFormatTaskLambda)
       
   134         }
       
   135     }
       
   136 }
       
   137 
       
   138 private fun Project.configureComposeResources() {
       
   139     val kotlin = the<KotlinProjectExtension>()
       
   140     val taskInfix = "ComposeResources"
       
   141     kotlin.sourceSets.configureEach {
       
   142         val kotlinSource = this
       
   143         val sourceSetTaskName =
       
   144             "${LicenseBasePlugin.getLICENSE_TASK_BASE_NAME()}${taskInfix}${name.capitalize()}"
       
   145         if (name.startsWith("generated")) {
       
   146             logger.info("Skip sourceSet $name because it's generated code")
       
   147             return@configureEach
       
   148         }
       
   149         val resourceDir = kotlinSource.resources.sourceDirectories.files.first()
       
   150         val composeResourceDir = File(resourceDir, "../composeResources")
       
   151 
       
   152         val configureLicenseCheckTaskLambda: LicenseCheck.() -> Unit = {
       
   153             source(composeResourceDir)
       
   154         }
       
   155         if (sourceSetTaskName in tasks.names) {
       
   156             // tasks may have already been added by configuration for the Android plugin
       
   157             logger.info("Tasks $sourceSetTaskName already exists. configure it")
       
   158             tasks.named(sourceSetTaskName, LicenseCheck::class.java, configureLicenseCheckTaskLambda)
       
   159         } else {
       
   160             logger.info("Adding ${project.name}:$sourceSetTaskName task for sourceSet ${kotlinSource.name}")
       
   161             tasks.register(sourceSetTaskName, LicenseCheck::class.java, configureLicenseCheckTaskLambda)
       
   162         }
       
   163 
       
   164         val configureLicenseFormatTaskLambda: LicenseFormat.() -> Unit = {
       
   165             source(composeResourceDir)
   117         }
   166         }
   118         val sourceSetFormatTaskName =
   167         val sourceSetFormatTaskName =
   119             "${LicenseBasePlugin.getFORMAT_TASK_BASE_NAME()}${taskInfix}${name.capitalize()}"
   168             "${LicenseBasePlugin.getFORMAT_TASK_BASE_NAME()}${taskInfix}${name.capitalize()}"
   120         if (sourceSetFormatTaskName in tasks.names) {
   169         if (sourceSetFormatTaskName in tasks.names) {
   121             // tasks may have already been added by configuration for the Android plugin
   170             // tasks may have already been added by configuration for the Android plugin
   157     }
   206     }
   158 }
   207 }
   159 
   208 
   160 
   209 
   161 private fun Project.configureAndroid() {
   210 private fun Project.configureAndroid() {
   162     val android = the<BaseExtension>()
   211     val android = the<CommonExtension>()
   163     configureSourceSetRule(android.sourceSets, "Android") { ss ->
   212     configureSourceSetRule(android.sourceSets, "Android") { ss ->
   164         @Suppress("DEPRECATION")
   213         @Suppress("DEPRECATION")
   165         when (ss) {
   214         when (ss) {
   166             // the dsl.AndroidSourceSet don't expose any getter, so we still need to cast it
   215             // the dsl.AndroidSourceSet don't expose any getter, so we still need to cast it
   167             is com.android.build.gradle.api.AndroidSourceSet -> {
   216             is com.android.build.gradle.api.AndroidSourceSet -> {
   168         ss.java.getSourceFiles() + ss.res.getSourceFiles() + fileTree(ss.manifest.srcFile)
   217                 val kotlinFileTrees  = ss.kotlin.directories.foldIndexed(fileTree() as FileTree) { index, acc, n ->
       
   218                     if (index == 0) { // skip first as it's an empty tree created for typing
       
   219                         fileTree(n)
       
   220                     } else {
       
   221                         acc + fileTree(n)
       
   222                     }
       
   223                 }
       
   224                 ss.java.getSourceFiles() + ss.res.getSourceFiles() + fileTree(ss.manifest.srcFile) + kotlinFileTrees
   169             }
   225             }
   170             else -> fileTree()
   226             else -> fileTree()
   171         }
   227         }
   172     }
   228     }
   173 }
   229 }