11package org.jmailen.gradle.kotlinter
22
33import com.android.build.gradle.BaseExtension
4+ import com.android.build.gradle.api.AndroidSourceSet
45import org.gradle.api.Plugin
56import org.gradle.api.Project
6- import org.gradle.api.file.FileCollection
77import org.gradle.api.file.FileTree
88import org.gradle.api.file.SourceDirectorySet
99import org.gradle.api.internal.HasConvention
1010import org.gradle.api.plugins.JavaPluginConvention
1111import org.gradle.api.tasks.SourceSet
12+ import org.gradle.api.tasks.SourceSetContainer
1213import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
1314import org.jmailen.gradle.kotlinter.support.reporterFileExtension
1415import org.jmailen.gradle.kotlinter.tasks.FormatTask
1516import org.jmailen.gradle.kotlinter.tasks.LintTask
17+ import java.io.File
1618
1719class KotlinterPlugin : Plugin <Project > {
1820
1921 val extendablePlugins = mapOf (
20- " org.jetbrains.kotlin.jvm" to this ::kotlinSourceSets ,
21- " kotlin-android" to this ::androidSourceSets )
22+ " org.jetbrains.kotlin.jvm" to KotlinJvmSourceSetResolver ,
23+ " kotlin-android" to AndroidSourceSetResolver )
2224
2325 override fun apply (project : Project ) {
24- val kotlinterExtention = project.extensions.create(" kotlinter" , KotlinterExtension ::class .java)
26+ val kotlinterExtension = project.extensions.create(" kotlinter" , KotlinterExtension ::class .java)
2527
2628 // for known kotlin plugins, create tasks by convention.
27- val kotlinApplier = KotlinterApplier (project)
29+ val taskCreator = TaskCreator (project)
2830 extendablePlugins.forEach { pluginId, sourceResolver ->
2931 project.plugins.withId(pluginId) {
30- val sourceSets = sourceResolver(project)
31- kotlinApplier.createTasks(sourceSets)
32+
33+ sourceResolver.applyToAll(project) { id, files ->
34+ taskCreator.createSourceSetTasks(id, files)
35+ }
3236 }
3337 }
38+ taskCreator.createParentTasks()
3439
3540 project.afterEvaluate {
36- kotlinApplier .lintTasks.forEach { lintTask ->
37- lintTask.ignoreFailures = kotlinterExtention .ignoreFailures
38- lintTask.indentSize = kotlinterExtention .indentSize
39- lintTask.continuationIndentSize = kotlinterExtention .continuationIndentSize
40- lintTask.reports = kotlinterExtention .reporters().associate { reporter ->
41+ taskCreator .lintTasks.forEach { lintTask ->
42+ lintTask.ignoreFailures = kotlinterExtension .ignoreFailures
43+ lintTask.indentSize = kotlinterExtension .indentSize
44+ lintTask.continuationIndentSize = kotlinterExtension .continuationIndentSize
45+ lintTask.reports = kotlinterExtension .reporters().associate { reporter ->
4146 reporter to project.reportFile(" ${lintTask.sourceSetId} -lint.${reporterFileExtension(reporter)} " )
4247 }
4348 }
44- kotlinApplier.formatTasks.forEach { formatTask ->
45- formatTask.indentSize = kotlinterExtention.indentSize
46- formatTask.continuationIndentSize = kotlinterExtention.continuationIndentSize
47- }
48- }
49- }
50-
51- private fun kotlinSourceSets (project : Project ): List <SourceSetInfo > {
52- return project.sourceSets().map { it.kotlin }.filterNotNull().map {
53- SourceSetInfo (it.name, it.sourceDirectories)
54- }
55- }
56-
57- private fun androidSourceSets (project : Project ): List <SourceSetInfo > {
58- val android = project.extensions.findByName(" android" )
59- val sourceSetInfos = (android as ? BaseExtension )?.let {
60- it.sourceSets.map { androidSourceSet ->
61-
62- val kotlinSourceTree = androidSourceSet.java.srcDirs.map { dir ->
63- project.fileTree(dir) {
64- it.include(" **/*.kt" )
65- }
66- }.reduce { merged: FileTree , tree ->
67- merged.plus(tree)
68- }
69-
70- SourceSetInfo (androidSourceSet.name, kotlinSourceTree)
49+ taskCreator.formatTasks.forEach { formatTask ->
50+ formatTask.indentSize = kotlinterExtension.indentSize
51+ formatTask.continuationIndentSize = kotlinterExtension.continuationIndentSize
7152 }
7253 }
73- return sourceSetInfos ? : emptyList()
7454 }
75-
76- private fun Project.sourceSets () = convention.getPlugin(JavaPluginConvention ::class .java).sourceSets
77-
78- private val SourceSet .kotlin: SourceDirectorySet ?
79- get() = ((getConvention(" kotlin" ) ? : getConvention(" kotlin2js" )) as ? KotlinSourceSet )?.kotlin
80-
81- private fun Any.getConvention (name : String ): Any? =
82- (this as HasConvention ).convention.plugins[name]
8355}
8456
85- class KotlinterApplier ( val project : Project ) {
57+ class TaskCreator ( private val project : Project ) {
8658
8759 val formatTasks = mutableListOf<FormatTask >()
8860 val lintTasks = mutableListOf<LintTask >()
8961
90- fun createTasks ( kotlinSourceSets : List < SourceSetInfo >) {
62+ fun createSourceSetTasks ( id : String , files : Set < File >) {
9163
92- formatTasks + = kotlinSourceSets.map { createFormatTask(it) }
64+ formatTasks + = project.tasks.create(" formatKotlin${id.capitalize()} " , FormatTask ::class .java) {
65+ it.source(files)
66+ it.report = project.reportFile(" $id -format.txt" )
67+ }
9368
69+ lintTasks + = project.tasks.create(" lintKotlin${id.capitalize()} " , LintTask ::class .java) {
70+ it.source(files)
71+ it.sourceSetId = id
72+ }
73+ }
74+
75+ fun createParentTasks () {
9476 project.tasks.create(" formatKotlin" ) {
9577 it.group = " formatting"
9678 it.description = " Formats the Kotlin source files."
9779 it.dependsOn(formatTasks)
9880 }
9981
100- lintTasks + = kotlinSourceSets.map { createLintTask(it) }
101-
10282 val lintKotlin = project.tasks.create(" lintKotlin" ) {
10383 it.group = " formatting"
10484 it.description = " Runs lint on the Kotlin source files."
@@ -109,25 +89,64 @@ class KotlinterApplier(val project: Project) {
10989 it.dependsOn(lintKotlin)
11090 }
11191 }
92+ }
11293
113- fun createFormatTask (sourceSet : SourceSetInfo ) =
114- project.tasks.create(" formatKotlin${sourceSet.id().capitalize()} " , FormatTask ::class .java) {
115- it.source(sourceSet.files())
116- it.report = project.reportFile(" ${sourceSet.id()} -format.txt" )
117- }
94+ typealias SourceSetAction = (String , Set <File >) -> Unit
95+
96+ interface SourceSetResolver {
97+ fun applyToAll (project : Project , action : SourceSetAction )
98+ }
99+
100+ object KotlinJvmSourceSetResolver : SourceSetResolver {
118101
119- fun createLintTask ( sourceSet : SourceSetInfo ) =
120- project.tasks.create( " lintKotlin ${sourceSet.id().capitalize()} " , LintTask :: class .java) {
121- it.source (sourceSet. files())
122- it.sourceSetId = sourceSet.id( )
102+ override fun applyToAll ( project : Project , action : SourceSetAction ) {
103+ getSourceSets(project).all { sourceSet ->
104+ getKotlinFiles (sourceSet)?. let { files ->
105+ action(getSourceSetName( sourceSet) !! .id, files )
123106 }
107+ }
108+ }
109+
110+ private fun getSourceSets (project : Project ): SourceSetContainer =
111+ project.convention.getPlugin(JavaPluginConvention ::class .java).sourceSets
112+
113+ private fun getSourceSetName (sourceSet : SourceSet ) = sourceSet.kotlin?.name
114+
115+ private fun getKotlinFiles (sourceSet : SourceSet ) = sourceSet.kotlin?.files
116+
117+ private val SourceSet .kotlin: SourceDirectorySet ?
118+ get() = ((getConvention(" kotlin" ) ? : getConvention(" kotlin2js" )) as ? KotlinSourceSet )?.kotlin
119+
120+ private fun SourceSet.getConvention (name : String ): Any? =
121+ (this as HasConvention ).convention.plugins[name]
124122}
125123
126- class SourceSetInfo (val name : String , val sourceDirectories : FileCollection ) {
127124
128- fun id () = name.split( " " ).first()
125+ object AndroidSourceSetResolver : SourceSetResolver {
129126
130- fun files () = sourceDirectories.files
127+ override fun applyToAll (project : Project , action : SourceSetAction ) {
128+ val android = project.extensions.findByName(" android" )
129+ (android as ? BaseExtension )?.let {
130+ it.sourceSets.all { sourceSet ->
131+ val id = sourceSet.name.id
132+ val files = getKotlinFiles(project, sourceSet)
133+ if (files.isNotEmpty()) {
134+ action(id, files)
135+ }
136+ }
137+ }
138+ }
139+
140+ private fun getKotlinFiles (project : Project , sourceSet : AndroidSourceSet ) = sourceSet.java.srcDirs.map { dir ->
141+ project.fileTree(dir) {
142+ it.include(" **/*.kt" )
143+ }
144+ }.reduce { merged: FileTree , tree ->
145+ merged.plus(tree)
146+ }.files
131147}
132148
149+ val String .id
150+ get() = split(" " ).first()
151+
133152fun Project.reportFile (name : String ) = file(" ${project.buildDir} /reports/ktlint/$name " )
0 commit comments