From b6d6a57b7501eeb618b44dba48cbfecba09ebd7c Mon Sep 17 00:00:00 2001 From: Sergey Vlasenko Date: Fri, 22 Mar 2024 01:33:25 +0300 Subject: [PATCH] feature incremental api generator, small fix string generator --- .../main/java/apigen/ApiGeneratorPlugin.kt | 91 +++++++++++++++++-- gradle/scripts/stringGenerator.gradle | 8 +- 2 files changed, 88 insertions(+), 11 deletions(-) diff --git a/gradle/plugins/src/main/java/apigen/ApiGeneratorPlugin.kt b/gradle/plugins/src/main/java/apigen/ApiGeneratorPlugin.kt index fcaf17a..afe3ee4 100644 --- a/gradle/plugins/src/main/java/apigen/ApiGeneratorPlugin.kt +++ b/gradle/plugins/src/main/java/apigen/ApiGeneratorPlugin.kt @@ -1,11 +1,24 @@ package apigen +import org.gradle.api.DefaultTask import org.gradle.api.Plugin import org.gradle.api.Project -import org.gradle.api.Task +import org.gradle.api.file.FileTree +import org.gradle.api.file.FileType +import org.gradle.api.tasks.InputFiles +import org.gradle.api.tasks.Internal +import org.gradle.api.tasks.OutputFiles +import org.gradle.api.tasks.TaskAction import org.gradle.kotlin.dsl.create import org.gradle.kotlin.dsl.dependencies +import org.gradle.kotlin.dsl.register import org.gradle.kotlin.dsl.repositories +import org.gradle.work.ChangeType +import org.gradle.work.Incremental +import org.gradle.work.InputChanges +import java.io.File +import java.nio.file.Files +import java.nio.file.Path abstract class ApiGeneratorPlugin : Plugin { @@ -34,23 +47,78 @@ abstract class ApiGeneratorPlugin : Plugin { extensions.create(API_GENERATOR_EXT_NAME) - val apiGenTask = createApiGeneratorTask() + val apiGenTask = tasks.register(API_GENERATOR_CONFIG, ApiGeneratorTask::class) gradle.projectsEvaluated { tasks.getByName("preBuild").dependsOn(apiGenTask) } } } +} - protected fun Project.getExtension(): ApiGeneratorExtension = extensions.getByName(API_GENERATOR_EXT_NAME) as ApiGeneratorExtension +fun Project.getExtension(): ApiGeneratorExtension = extensions.getByName(ApiGeneratorPlugin.API_GENERATOR_EXT_NAME) as ApiGeneratorExtension - private fun Project.createApiGeneratorTask(): Task = tasks.create(API_GENERATOR_CONFIG).doLast { +abstract class ApiGeneratorTask: DefaultTask() { - val extension = getExtension() + private companion object { + const val TEMP_API_PATH = "Temp-api-path" + } - val pathToApiSchemes = extension.pathToApiSchemes ?: throw IllegalStateException("Configure path to api schemes for api generator plugin") - val outputLanguage = extension.outputLanguage ?: throw IllegalStateException("Configure output language code for api generator plugin") + @Internal + val pathToApiScheme: Path = project.getExtension().pathToApiSchemes?.toPath() + ?: throw IllegalStateException("Configure path to api schemes for api generator plugin") + @Internal + val extension: ApiGeneratorExtension = project.getExtension() + + @Incremental + @InputFiles + val inputFiles: FileTree = project.files(pathToApiScheme).asFileTree + + @OutputFiles + val outputFiles: FileTree = project.files(extension.outputDirPath).asFileTree + + @TaskAction + fun generateApi(inputChanges: InputChanges): Unit = with(project) { + val tempApiDirectory = getTempApiDirectory().toString() + + inputChanges.getFileChanges(inputFiles).forEach { change -> + when { + change.fileType == FileType.DIRECTORY -> Unit + + change.changeType == ChangeType.REMOVED -> { + outputFiles.find { it.nameWithoutExtension == change.file.nameWithoutExtension }?.delete() + } + + else -> copyFileToTempDir( + sourceFilePath = change.normalizedPath.toPath(), + tempApiDirectory = tempApiDirectory, + path = pathToApiScheme.relativize(change.normalizedPath.toPath()).toString() + ) + } + } + + val outputLanguage = extension.outputLanguage + ?: throw IllegalStateException("Configure output language code for api generator plugin") + + generateApi( + pathToApi = tempApiDirectory, + outputLanguage = outputLanguage + ) + } + + private fun copyFileToTempDir(sourceFilePath: Path, tempApiDirectory: String, path: String) { + val newFile = Path.of(tempApiDirectory, path).toFile() + if (!newFile.parentFile.exists()) newFile.parentFile.mkdirs() + newFile.createNewFile() + + Files.copy(sourceFilePath, newFile.outputStream()) + } + + private fun generateApi( + pathToApi: String, + outputLanguage: OutputLanguage + ) = with(project) { javaexec { main = "-jar" workingDir = rootDir @@ -60,7 +128,7 @@ abstract class ApiGeneratorPlugin : Plugin { "--output-language", outputLanguage.argName, "--specification-path", - pathToApiSchemes, + pathToApi, "--kotlin-methods-generation-mode".takeIf { outputLanguage.methodOutputType != null }, outputLanguage.methodOutputType?.argName, "--output-path", @@ -71,6 +139,13 @@ abstract class ApiGeneratorPlugin : Plugin { extension.recreateOutputDir.toString() ) } + + File(pathToApi).deleteRecursively() } + private fun getTempApiDirectory() = Files.createTempDirectory(getProjectName() + TEMP_API_PATH) + + private fun getProjectName() = project.rootDir.absolutePath.substringAfterLast(File.separator) + + private fun String.toPath(): Path = Path.of(this) } diff --git a/gradle/scripts/stringGenerator.gradle b/gradle/scripts/stringGenerator.gradle index 9c47e90..683b3f2 100644 --- a/gradle/scripts/stringGenerator.gradle +++ b/gradle/scripts/stringGenerator.gradle @@ -1,9 +1,11 @@ import groovy.json.JsonSlurper import groovy.xml.MarkupBuilder -task stringGenerator { - generate(android.languageMap, project) - println("Strings generated!") +tasks.register('stringGenerator') { + doLast { + generate(android.languageMap, project) + println("Strings generated!") + } } private def generate(Map sources, Project project) {