diff --git a/plugin/src/functionalTest/kotlin/xyz/block/microfilm/MicrofilmPluginFunctionalTest.kt b/plugin/src/functionalTest/kotlin/xyz/block/microfilm/MicrofilmPluginFunctionalTest.kt index 5a513ee..5047360 100644 --- a/plugin/src/functionalTest/kotlin/xyz/block/microfilm/MicrofilmPluginFunctionalTest.kt +++ b/plugin/src/functionalTest/kotlin/xyz/block/microfilm/MicrofilmPluginFunctionalTest.kt @@ -239,6 +239,27 @@ class MicrofilmPluginFunctionalTest { .isFalse() } + @Test + fun `compress task succeeds when image pattern is provided`() { + val project = androidLibProject() + PNG_FIXTURE.copyToDirectory(directory = project.libResourcesDrawableDirectory) + PNG_FIXTURE.copyToDirectory( + directory = project.libResourcesDrawableDirectory, + name = PNG_LOSSY_NAME, + ) + + val result = project.build(":lib:compressMicrofilm", "--images=**/$PNG_NAME") + + assertThat(result).task(":lib:compressMicrofilm").succeeded() + assertThat(project.libResourcesDrawableDirectory.containsPng()).isFalse() + assertThat(project.libResourcesDrawableDirectory.containsWebp()).isTrue() + assertThat(project.libResourcesDrawableDirectory.containsFile(PNG_LOSSY_NAME)).isTrue() + assertThat(project.libResourcesDrawableDirectory.containsFile(WEBP_LOSSY_NAME)).isFalse() + assertThat(project.libMicrofilmDirectory.containsManifest()).isTrue() + assertThat(project.libMicrofilmDrawableDirectory.containsPng()).isTrue() + assertThat(project.libMicrofilmDrawableDirectory.containsFile(PNG_LOSSY_NAME)).isFalse() + } + @Test fun `compress task is compatible with configuration cache`() { val project = androidLibProject() @@ -332,6 +353,28 @@ class MicrofilmPluginFunctionalTest { assertThat(project.libMicrofilmDrawableDirectory.containsPng()).isFalse() } + @Test + fun `decompress task succeeds when image pattern is provided`() { + val project = androidLibProject() + PNG_FIXTURE.copyToDirectory(directory = project.libResourcesDrawableDirectory) + PNG_FIXTURE.copyToDirectory( + directory = project.libResourcesDrawableDirectory, + name = PNG_LOSSY_NAME, + ) + + project.build(":lib:compressMicrofilm") + val result = project.build(":lib:decompressMicrofilm", "--images=**/$PNG_LOSSY_NAME") + + assertThat(result).task(":lib:decompressMicrofilm").succeeded() + assertThat(project.libResourcesDrawableDirectory.containsPng()).isFalse() + assertThat(project.libResourcesDrawableDirectory.containsWebp()).isTrue() + assertThat(project.libResourcesDrawableDirectory.containsFile(PNG_LOSSY_NAME)).isTrue() + assertThat(project.libResourcesDrawableDirectory.containsFile(WEBP_LOSSY_NAME)).isFalse() + assertThat(project.libMicrofilmDirectory.containsManifest()).isTrue() + assertThat(project.libMicrofilmDrawableDirectory.containsPng()).isTrue() + assertThat(project.libMicrofilmDrawableDirectory.containsFile(PNG_LOSSY_NAME)).isFalse() + } + @Test fun `decompress task is compatible with configuration cache`() { val project = androidLibProject() @@ -470,6 +513,22 @@ class MicrofilmPluginFunctionalTest { assertThat(result).task(":lib:verifyMicrofilmMain").failed() } + @Test + fun `verify task succeeds when image pattern is provided`() { + val project = androidLibProject() + MANIFEST_FIXTURE.copyToDirectory(directory = project.libMicrofilmDirectory) + PNG_FIXTURE.copyToDirectory(directory = project.libMicrofilmDrawableDirectory) + PNG_FIXTURE.copyToDirectory( + directory = project.libResourcesDrawableDirectory, + name = PNG_LOSSY_NAME, + ) + WEBP_FIXTURE.copyToDirectory(directory = project.libResourcesDrawableDirectory) + + val result = project.build(":lib:verifyMicrofilm", "--images=**/$PNG_NAME") + + assertThat(result).task(":lib:verifyMicrofilm").succeeded() + } + @Test fun `verify task is compatible with configuration cache`() { val project = androidLibProject() diff --git a/plugin/src/main/kotlin/xyz/block/microfilm/ImagesLifecycleTask.kt b/plugin/src/main/kotlin/xyz/block/microfilm/ImagesLifecycleTask.kt new file mode 100644 index 0000000..2fe2874 --- /dev/null +++ b/plugin/src/main/kotlin/xyz/block/microfilm/ImagesLifecycleTask.kt @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2026 Block, Inc. + * + * 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 xyz.block.microfilm + +import org.gradle.api.DefaultTask +import org.gradle.api.provider.ListProperty +import org.gradle.api.tasks.Internal +import org.gradle.api.tasks.options.Option +import org.gradle.work.DisableCachingByDefault + +/** + * An empty task that acts as an aggregator for a group of source set tasks. + * + * Gradle binds options to the exact task named on the command line. So if you run something like: + * ``` + * ./gradlew compressMicrofilm --images drawable-mdpi/my_image.png + * ``` + * + * The --images argument will not automatically be passed on to the `compressMicrofilmMain` or + * `compressMicrofilmDebug` tasks. [ImagesLifecycleTask] exists to capture the arguments and expose + * them to the source set tasks + */ +@DisableCachingByDefault(because = "This task has no outputs of its own") +internal abstract class ImagesLifecycleTask : DefaultTask() { + @get:Internal + @get:Option( + option = "images", + description = + "Restrict the task to the images matching these glob patterns, relative to the res directory.", + ) + abstract val imagePatterns: ListProperty +} diff --git a/plugin/src/main/kotlin/xyz/block/microfilm/MicrofilmPlugin.kt b/plugin/src/main/kotlin/xyz/block/microfilm/MicrofilmPlugin.kt index 9d61446..687e597 100644 --- a/plugin/src/main/kotlin/xyz/block/microfilm/MicrofilmPlugin.kt +++ b/plugin/src/main/kotlin/xyz/block/microfilm/MicrofilmPlugin.kt @@ -93,17 +93,17 @@ public class MicrofilmPlugin : Plugin { // Register the tasks val compress = - tasks.register("compressMicrofilm") { task -> + tasks.register("compressMicrofilm", ImagesLifecycleTask::class.java) { task -> task.description = "Compresses source images and updates the manifest for all source sets" task.group = "microfilm" } val decompress = - tasks.register("decompressMicrofilm") { task -> + tasks.register("decompressMicrofilm", ImagesLifecycleTask::class.java) { task -> task.description = "Decompresses source images and removes the manifest for all source sets" task.group = "microfilm" } val verify = - tasks.register("verifyMicrofilm") { task -> + tasks.register("verifyMicrofilm", ImagesLifecycleTask::class.java) { task -> task.description = "Verifies that the manifest is up to date for all source sets" task.group = "microfilm" } @@ -140,9 +140,9 @@ public class MicrofilmPlugin : Plugin { private fun Project.configureSourceSets( extension: MicrofilmExtension, cwebpDirectory: FileCollection, - compress: TaskProvider<*>, - decompress: TaskProvider<*>, - verify: TaskProvider<*>, + compress: TaskProvider, + decompress: TaskProvider, + verify: TaskProvider, ) { extensions.getByType(CommonExtension::class.java).sourceSets.configureEach { sourceSet -> val name = sourceSet.name @@ -163,6 +163,7 @@ public class MicrofilmPlugin : Plugin { task.group = "microfilm" task.cwebpDirectory.from(cwebpDirectory) task.imageRules.set(extension.imageRules) + task.imagePatterns.convention(compress.flatMap { it.imagePatterns }) task.microfilmDirectory.set(microfilmDirectory) task.resourcesDirectory.set(resourcesDirectory) task.outputs.upToDateWhen { false } @@ -172,6 +173,7 @@ public class MicrofilmPlugin : Plugin { tasks.register("decompressMicrofilm$nameCapitalized", DecompressTask::class.java) { task -> task.description = "Decompresses source images for the '$name' source set" task.group = "microfilm" + task.imagePatterns.convention(decompress.flatMap { it.imagePatterns }) task.microfilmDirectory.set(microfilmDirectory) task.resourcesDirectory.set(resourcesDirectory) task.outputs.upToDateWhen { false } @@ -182,6 +184,7 @@ public class MicrofilmPlugin : Plugin { task.description = "Verifies that the manifest is up to date for the '$name' source set" task.group = "microfilm" task.cwebpDirectory.from(cwebpDirectory) + task.imagePatterns.convention(verify.flatMap { it.imagePatterns }) task.imageRules.set(extension.imageRules) task.microfilmDirectory.set(microfilmDirectory) task.resourcesDirectory.set(resourcesDirectory)