stioner.plugin.2024.10.0.source-code.CollectQuestions.kt Maven / Gradle / Ivy
package edu.illinois.cs.cs125.questioner.plugin
import com.squareup.moshi.Types
import edu.illinois.cs.cs125.questioner.lib.Language
import edu.illinois.cs.cs125.questioner.lib.Question
import edu.illinois.cs.cs125.questioner.lib.loadQuestion
import edu.illinois.cs.cs125.questioner.lib.moshi.moshi
import edu.illinois.cs.cs125.questioner.plugin.parse.ParsedJavaFile
import io.kotest.inspectors.forAll
import org.gradle.api.DefaultTask
import org.gradle.api.file.FileCollection
import org.gradle.api.plugins.JavaPluginExtension
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import java.io.File
import java.nio.file.Path
import kotlin.io.path.exists
import kotlin.io.path.relativeTo
abstract class CollectQuestions : DefaultTask() {
@OutputFile
val outputFile: File = project.layout.buildDirectory.dir("questioner/questions.json").get().asFile
@InputFiles
val inputFiles: FileCollection = project.extensions.getByType(JavaPluginExtension::class.java)
.sourceSets.getByName("main")
.allSource.filter { file -> file.name == ".question.json" }
@TaskAction
fun collect() {
val questions = inputFiles.files
.map { file ->
val question = file.loadQuestion()!!
val correctPath = Path.of(file.path).parent.resolve("${question.published.klass}.java")
if (!correctPath.exists() || !ParsedJavaFile(correctPath.toFile()).isCorrect) {
logger.warn("Removing question file $file that matches no @Correct annotation")
file.delete()
return@map null
}
question.apply {
this.correctPath = correctPath.relativeTo(project.rootProject.projectDir.toPath()).toString()
}
}.filterNotNull()
.sortedBy { it.published.name }
check(questions.map { q -> q.published.contentHash }.toSet().size == questions.size) {
"Found duplicate question hash"
}
questions.map { q ->
"${q.published.path}${
if (q.published.author !== "") {
"/${q.published.author}"
} else {
""
}
}"
}
.groupingBy { path -> path }
.eachCount()
.filter { it.value > 1 }.let { duplicateList ->
check(duplicateList.isEmpty()) {
"Found questions with duplicate coordinates: ${duplicateList.map { it.key }.joinToString(",")}"
}
}
questions
.filter { q -> q.published.descriptions[Language.java] != null }
.groupBy { q -> q.published.descriptions[Language.java] }
.filterValues { it.size > 1 }
.forAll { (_, questions) ->
logger.warn("Found questions with identical Java descriptions: ${questions.joinToString { q -> q.published.name }}")
}
questions
.filter { q -> q.published.descriptions[Language.kotlin] != null }
.groupBy { q -> q.published.descriptions[Language.kotlin] }
.filterValues { it.size > 1 }
.forAll { (_, questions) ->
logger.warn("Found questions with identical Kotlin descriptions: ${questions.joinToString { q -> q.published.name }}")
}
questions.map { q -> q.metadata?.unusedFiles ?: listOf() }.flatten().forEach {
logger.warn("$it will not be included in the build")
}
questions.writeToFile(outputFile)
}
}
private fun Collection.writeToFile(file: File) {
file.writeText(
moshi.adapter>(
Types.newParameterizedType(List::class.java, Question::class.java),
).indent(" ").toJson(this.toList()),
)
}