init
This commit is contained in:
243
fluent-icons-generator/tasks/IconGenerationTask.kt
Normal file
243
fluent-icons-generator/tasks/IconGenerationTask.kt
Normal file
@ -0,0 +1,243 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package androidx.compose.material.icons.generator.tasks
|
||||
|
||||
import androidx.compose.material.icons.generator.Icon
|
||||
import androidx.compose.material.icons.generator.IconProcessor
|
||||
import com.android.build.gradle.LibraryExtension
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.tasks.CacheableTask
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.InputDirectory
|
||||
import org.gradle.api.tasks.InputFile
|
||||
import org.gradle.api.tasks.Optional
|
||||
import org.gradle.api.tasks.OutputDirectory
|
||||
import org.gradle.api.tasks.OutputFile
|
||||
import org.gradle.api.tasks.PathSensitive
|
||||
import org.gradle.api.tasks.PathSensitivity
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.api.tasks.Internal
|
||||
import org.gradle.api.tasks.TaskProvider
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||
import java.io.File
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
* Base [org.gradle.api.Task] for tasks relating to icon generation.
|
||||
*/
|
||||
@CacheableTask
|
||||
abstract class IconGenerationTask : DefaultTask() {
|
||||
|
||||
/**
|
||||
* Directory containing raw drawables. These icons will be processed to generate programmatic
|
||||
* representations.
|
||||
*/
|
||||
@PathSensitive(PathSensitivity.RELATIVE)
|
||||
@InputDirectory
|
||||
val allIconsDirectory =
|
||||
project.rootProject.project(GeneratorProject).projectDir.resolve("raw-icons")
|
||||
|
||||
/**
|
||||
* Specific theme to generate icons for, or null to generate all
|
||||
*/
|
||||
@Optional
|
||||
@Input
|
||||
var themeName: String? = null
|
||||
|
||||
/**
|
||||
* Specific icon directories to use in this task
|
||||
*/
|
||||
@Internal
|
||||
fun getIconDirectories(): List<File> {
|
||||
val themeName = themeName
|
||||
if (themeName != null) {
|
||||
return listOf(allIconsDirectory.resolve(themeName))
|
||||
} else {
|
||||
return allIconsDirectory.listFiles()!!.filter { it.isDirectory }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checked-in API file for the generator module, where we will track all the generated icons
|
||||
*/
|
||||
@PathSensitive(PathSensitivity.NONE)
|
||||
@InputFile
|
||||
val expectedApiFile =
|
||||
project.rootProject.project(GeneratorProject).projectDir.resolve("api/icons.txt")
|
||||
|
||||
/**
|
||||
* Root build directory for this task, where outputs will be placed into.
|
||||
*/
|
||||
@OutputDirectory
|
||||
lateinit var buildDirectory: File
|
||||
|
||||
/**
|
||||
* Generated API file that will be placed in the build directory. This can be copied manually
|
||||
* to [expectedApiFile] to confirm that API changes were intended.
|
||||
*/
|
||||
@get:OutputFile
|
||||
val generatedApiFile: File
|
||||
get() = buildDirectory.resolve("api/icons.txt")
|
||||
|
||||
/**
|
||||
* @return a list of all processed [Icon]s from [getIconDirectories].
|
||||
*/
|
||||
fun loadIcons(): List<Icon> {
|
||||
// material-icons-core loads and verifies all of the icons from all of the themes:
|
||||
// both that all icons are present in all themes, and also that no icons have been removed.
|
||||
// So, when we're loading just one theme, we don't need to verify it
|
||||
val verifyApi = themeName == null
|
||||
return IconProcessor(
|
||||
getIconDirectories(),
|
||||
expectedApiFile,
|
||||
generatedApiFile,
|
||||
verifyApi
|
||||
).process()
|
||||
}
|
||||
|
||||
@get:OutputDirectory
|
||||
val generatedSrcMainDirectory: File
|
||||
get() = buildDirectory.resolve(GeneratedSrcMain)
|
||||
|
||||
@get:OutputDirectory
|
||||
val generatedSrcAndroidTestDirectory: File
|
||||
get() = buildDirectory.resolve(GeneratedSrcAndroidTest)
|
||||
|
||||
@get:OutputDirectory
|
||||
val generatedResourceDirectory: File
|
||||
get() = buildDirectory.resolve(GeneratedResource)
|
||||
|
||||
/**
|
||||
* The action for this task
|
||||
*/
|
||||
@TaskAction
|
||||
abstract fun run()
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Registers the core [project]. The core project contains only the icons defined in
|
||||
* [androidx.compose.material.icons.generator.CoreIcons], and no tests.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun registerCoreIconProject(
|
||||
project: Project,
|
||||
libraryExtension: LibraryExtension,
|
||||
isMpp: Boolean
|
||||
) {
|
||||
if (isMpp) {
|
||||
CoreIconGenerationTask.register(project, null)
|
||||
} else {
|
||||
libraryExtension.libraryVariants.all { variant ->
|
||||
CoreIconGenerationTask.register(project, variant)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the extended [project]. The core project contains all icons except for the
|
||||
* icons defined in [androidx.compose.material.icons.generator.CoreIcons], as well as a
|
||||
* bitmap comparison test for every icon in both the core and extended project.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun registerExtendedIconThemeProject(
|
||||
project: Project,
|
||||
libraryExtension: LibraryExtension,
|
||||
isMpp: Boolean
|
||||
) {
|
||||
if (isMpp) {
|
||||
ExtendedIconGenerationTask.register(project, null)
|
||||
} else {
|
||||
libraryExtension.libraryVariants.all { variant ->
|
||||
ExtendedIconGenerationTask.register(project, variant)
|
||||
}
|
||||
}
|
||||
|
||||
// b/175401659 - disable lint as it takes a long time, and most errors should
|
||||
// be caught by lint on material-icons-core anyway
|
||||
project.afterEvaluate {
|
||||
project.tasks.named("lintAnalyzeDebug") { t ->
|
||||
t.enabled = false
|
||||
}
|
||||
project.tasks.named("lintDebug") { t ->
|
||||
t.enabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun registerExtendedIconMainProject(
|
||||
project: Project,
|
||||
libraryExtension: LibraryExtension
|
||||
) {
|
||||
libraryExtension.testVariants.all { variant ->
|
||||
IconTestingGenerationTask.register(project, variant)
|
||||
}
|
||||
}
|
||||
|
||||
const val GeneratedSrcMain = "src/commonMain/kotlin"
|
||||
|
||||
const val GeneratedSrcAndroidTest = "src/androidAndroidTest/kotlin"
|
||||
|
||||
const val GeneratedResource = "generatedIcons/res"
|
||||
}
|
||||
}
|
||||
|
||||
// Path to the generator project
|
||||
private const val GeneratorProject = ":compose:material:material:icons:generator"
|
||||
|
||||
/**
|
||||
* Registers a new [T] in [this], and sets [IconGenerationTask.buildDirectory] depending on
|
||||
* [variant].
|
||||
*
|
||||
* @param variant the [com.android.build.gradle.api.BaseVariant] to associate this task with, or
|
||||
* `null` if this task does not change between variants.
|
||||
* @return a [Pair] of the created [TaskProvider] of [T] of [IconGenerationTask], and the [File]
|
||||
* for the directory that files will be generated to
|
||||
*/
|
||||
@Suppress("DEPRECATION") // BaseVariant
|
||||
fun <T : IconGenerationTask> Project.registerGenerationTask(
|
||||
taskName: String,
|
||||
taskClass: Class<T>,
|
||||
variant: com.android.build.gradle.api.BaseVariant? = null
|
||||
): Pair<TaskProvider<T>, File> {
|
||||
val variantName = variant?.name ?: "allVariants"
|
||||
|
||||
val themeName = if (project.name.contains("material-icons-extended-")) {
|
||||
project.name.replace("material-icons-extended-", "")
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
val buildDirectory = project.buildDir.resolve("generatedIcons/$variantName")
|
||||
|
||||
return tasks.register("$taskName${variantName.capitalize(Locale.getDefault())}", taskClass) {
|
||||
it.themeName = themeName
|
||||
it.buildDirectory = buildDirectory
|
||||
} to buildDirectory
|
||||
}
|
||||
|
||||
fun Project.getMultiplatformSourceSet(name: String): KotlinSourceSet {
|
||||
val sourceSet = project.multiplatformExtension!!.sourceSets.find { it.name == name }
|
||||
return requireNotNull(sourceSet) {
|
||||
"No source sets found matching $name"
|
||||
}
|
||||
}
|
||||
|
||||
private val Project.multiplatformExtension
|
||||
get() = extensions.findByType(KotlinMultiplatformExtension::class.java)
|
||||
164
fluent-icons-generator/tasks/IconSourceTasks.kt
Normal file
164
fluent-icons-generator/tasks/IconSourceTasks.kt
Normal file
@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package androidx.compose.material.icons.generator.tasks
|
||||
|
||||
import androidx.compose.material.icons.generator.CoreIcons
|
||||
import androidx.compose.material.icons.generator.IconWriter
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.tasks.CacheableTask
|
||||
import org.gradle.api.tasks.TaskProvider
|
||||
import org.gradle.api.tasks.bundling.Jar
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* Task responsible for converting core icons from xml to a programmatic representation.
|
||||
*/
|
||||
@CacheableTask
|
||||
open class CoreIconGenerationTask : IconGenerationTask() {
|
||||
override fun run() =
|
||||
IconWriter(loadIcons()).generateTo(generatedSrcMainDirectory) { it in CoreIcons }
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Registers [CoreIconGenerationTask] in [project].
|
||||
*/
|
||||
@Suppress("DEPRECATION") // BaseVariant
|
||||
fun register(project: Project, variant: com.android.build.gradle.api.BaseVariant? = null) {
|
||||
val (task, buildDirectory) = project.registerGenerationTask(
|
||||
"generateCoreIcons",
|
||||
CoreIconGenerationTask::class.java,
|
||||
variant
|
||||
)
|
||||
// Multiplatform
|
||||
if (variant == null) {
|
||||
registerIconGenerationTask(project, task, buildDirectory)
|
||||
}
|
||||
// AGP
|
||||
else variant.registerIconGenerationTask(project, task, buildDirectory)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Task responsible for converting extended icons from xml to a programmatic representation.
|
||||
*/
|
||||
@CacheableTask
|
||||
open class ExtendedIconGenerationTask : IconGenerationTask() {
|
||||
override fun run() =
|
||||
IconWriter(loadIcons()).generateTo(generatedSrcMainDirectory) { it !in CoreIcons }
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Registers [ExtendedIconGenerationTask] in [project]. (for use with mpp)
|
||||
*/
|
||||
@Suppress("DEPRECATION") // BaseVariant
|
||||
fun register(project: Project, variant: com.android.build.gradle.api.BaseVariant? = null) {
|
||||
val (task, buildDirectory) = project.registerGenerationTask(
|
||||
"generateExtendedIcons",
|
||||
ExtendedIconGenerationTask::class.java,
|
||||
variant
|
||||
)
|
||||
// Multiplatform
|
||||
if (variant == null) {
|
||||
registerIconGenerationTask(project, task, buildDirectory)
|
||||
}
|
||||
// AGP
|
||||
else variant.registerIconGenerationTask(project, task, buildDirectory)
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the icon generation task just for source jar generation, and not for
|
||||
* compilation. This is temporarily needed since we manually parallelize compilation in
|
||||
* material-icons-extended for the AGP build. When we remove that parallelization code,
|
||||
* we can remove this too.
|
||||
*/
|
||||
@JvmStatic
|
||||
@Suppress("DEPRECATION") // BaseVariant
|
||||
fun registerSourceJarOnly(
|
||||
project: Project,
|
||||
variant: com.android.build.gradle.api.BaseVariant
|
||||
) {
|
||||
// Setup the source jar task if this is the release variant
|
||||
if (variant.name == "release") {
|
||||
val (task, buildDirectory) = project.registerGenerationTask(
|
||||
"generateExtendedIcons",
|
||||
ExtendedIconGenerationTask::class.java,
|
||||
variant
|
||||
)
|
||||
val generatedSrcMainDirectory = buildDirectory.resolve(GeneratedSrcMain)
|
||||
project.addToSourceJar(generatedSrcMainDirectory, task)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to register [task] that outputs to [buildDirectory] as the Kotlin source generating
|
||||
* task for [project].
|
||||
*/
|
||||
private fun registerIconGenerationTask(
|
||||
project: Project,
|
||||
task: TaskProvider<*>,
|
||||
buildDirectory: File
|
||||
) {
|
||||
val sourceSet = project.getMultiplatformSourceSet(KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME)
|
||||
val generatedSrcMainDirectory = buildDirectory.resolve(IconGenerationTask.GeneratedSrcMain)
|
||||
sourceSet.kotlin.srcDir(project.files(generatedSrcMainDirectory).builtBy(task))
|
||||
// add it to the multiplatform sources as well.
|
||||
project.tasks.named("multiplatformSourceJar", Jar::class.java).configure {
|
||||
it.from(task.map { generatedSrcMainDirectory })
|
||||
}
|
||||
project.addToSourceJar(generatedSrcMainDirectory, task)
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to register [task] as the java source generating task that outputs to [buildDirectory].
|
||||
*/
|
||||
@Suppress("DEPRECATION") // BaseVariant
|
||||
private fun com.android.build.gradle.api.BaseVariant.registerIconGenerationTask(
|
||||
project: Project,
|
||||
task: TaskProvider<*>,
|
||||
buildDirectory: File
|
||||
) {
|
||||
val generatedSrcMainDirectory = buildDirectory.resolve(IconGenerationTask.GeneratedSrcMain)
|
||||
registerJavaGeneratingTask(task, generatedSrcMainDirectory)
|
||||
// Setup the source jar task if this is the release variant
|
||||
if (name == "release") {
|
||||
project.addToSourceJar(generatedSrcMainDirectory, task)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the contents of [buildDirectory] to the source jar generated for this [Project] by [task]
|
||||
*/
|
||||
// TODO: b/191485164 remove when AGP lets us get generated sources from a TestedExtension or
|
||||
// similar, then we can just add generated sources in SourceJarTaskHelper for all projects,
|
||||
// instead of needing one-off support here.
|
||||
private fun Project.addToSourceJar(buildDirectory: File, task: TaskProvider<*>) {
|
||||
afterEvaluate {
|
||||
val sourceJar = tasks.named("sourceJarRelease", Jar::class.java)
|
||||
sourceJar.configure {
|
||||
// Generating source jars requires the generation task to run first. This shouldn't
|
||||
// be needed for the MPP build because we use builtBy to set up the dependency
|
||||
// (https://github.com/gradle/gradle/issues/17250) but the path is different for AGP,
|
||||
// so we will still need this for the AGP build.
|
||||
it.dependsOn(task)
|
||||
it.from(buildDirectory)
|
||||
}
|
||||
}
|
||||
}
|
||||
77
fluent-icons-generator/tasks/IconTestingGenerationTask.kt
Normal file
77
fluent-icons-generator/tasks/IconTestingGenerationTask.kt
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package androidx.compose.material.icons.generator.tasks
|
||||
|
||||
import androidx.compose.material.icons.generator.IconTestingManifestGenerator
|
||||
import java.io.File
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.tasks.CacheableTask
|
||||
import org.gradle.api.tasks.OutputDirectory
|
||||
|
||||
/**
|
||||
* Task responsible for generating files related to testing.
|
||||
*
|
||||
* - Generates a list of all icons mapped to the drawable ID used in testing, so we can bitmap
|
||||
* compare the programmatic icon with the original source drawable.
|
||||
*
|
||||
* - Flattens all the source drawables into a drawable folder that will be used in comparison tests.
|
||||
*/
|
||||
@CacheableTask
|
||||
open class IconTestingGenerationTask : IconGenerationTask() {
|
||||
/**
|
||||
* Directory to generate the flattened drawables used for testing to.
|
||||
*/
|
||||
@get:OutputDirectory
|
||||
val drawableDirectory: File
|
||||
get() = generatedResourceDirectory.resolve("drawable")
|
||||
|
||||
override fun run() {
|
||||
// Copy all drawables to the drawable directory
|
||||
loadIcons().forEach { icon ->
|
||||
drawableDirectory.resolve("${icon.xmlFileName}.xml").apply {
|
||||
createNewFile()
|
||||
writeText(icon.fileContent)
|
||||
}
|
||||
}
|
||||
|
||||
// Generate the testing manifest to the androidTest directory
|
||||
IconTestingManifestGenerator(loadIcons()).generateTo(generatedSrcAndroidTestDirectory)
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Registers [IconTestingGenerationTask] in [project] for [variant].
|
||||
*/
|
||||
@Suppress("DEPRECATION") // BaseVariant
|
||||
fun register(project: Project, variant: com.android.build.gradle.api.BaseVariant) {
|
||||
val (task, buildDirectory) = project.registerGenerationTask(
|
||||
"generateTestFiles",
|
||||
IconTestingGenerationTask::class.java,
|
||||
variant
|
||||
)
|
||||
|
||||
val generatedResourceDirectory = buildDirectory.resolve(GeneratedResource)
|
||||
|
||||
variant.registerGeneratedResFolders(
|
||||
project.files(generatedResourceDirectory).builtBy(task)
|
||||
)
|
||||
|
||||
val generatedSrcAndroidTestDirectory = buildDirectory.resolve(GeneratedSrcAndroidTest)
|
||||
variant.registerJavaGeneratingTask(task, generatedSrcAndroidTestDirectory)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user