Skip to content

Commit

Permalink
Wire resource configuration while keeping the Bazel project structure.
Browse files Browse the repository at this point in the history
RELNOTES=N/A
PiperOrigin-RevId: 711821126
  • Loading branch information
danysantiago authored and Dagger Team committed Jan 6, 2025
1 parent 3418609 commit 5c4bbb4
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 10 deletions.
69 changes: 69 additions & 0 deletions buildSrc/src/main/kotlin/dagger/gradle/build/ResourceCopyTask.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright (C) 2025 The Dagger Authors.
*
* 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 dagger.gradle.build

import org.gradle.api.DefaultTask
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.RegularFile
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.MapProperty
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.PathSensitive
import org.gradle.api.tasks.PathSensitivity
import org.gradle.api.tasks.TaskAction
import org.gradle.work.DisableCachingByDefault

/**
* A task for copying JAR resources files located in the repository structure into a generated resource source set
* that matches the JAR's resources structure. This is necessary due to the repository's structure not being the
* standard Gradle source set structure.
*/
@DisableCachingByDefault(because = "Not worth caching")
abstract class ResourceCopyTask : DefaultTask() {

/**
* Specifications of resource files to copy and their destination directory within the JAR.
*/
@get:Input
abstract val resourceSpecs: MapProperty<String, String>

@get:InputFiles
@get:PathSensitive(PathSensitivity.RELATIVE)
abstract val inputFiles: ListProperty<RegularFile>

@get:OutputDirectory
abstract val outputDirectory: DirectoryProperty

@TaskAction
fun execute() {
val specMap = resourceSpecs.get()
inputFiles.get().forEach { resourceFile ->
val inputFile = resourceFile.asFile
check(inputFile.exists()) {
"Resource file does not exist: $inputFile"
}
check(inputFile.isFile) {
"Resource file must be a file not a directory: $inputFile"
}
val jarOutputDir = specMap.getValue(inputFile.path)
val outputFile = outputDirectory.get().dir(jarOutputDir).file(inputFile.name).asFile
inputFile.copyTo(outputFile, overwrite = true)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Project
import org.gradle.api.file.SourceDirectorySet
import org.gradle.api.plugins.JavaPluginExtension
import org.gradle.api.tasks.TaskProvider
import org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import java.nio.file.Path
Expand All @@ -37,34 +38,111 @@ class DaggerSourceSet(
private val kotlinSourceSets: NamedDomainObjectContainer<KotlinSourceSet>,
private val javaSourceSets: NamedDomainObjectContainer<JavaSourceSet>,
) {
private val resourceCopyTask: TaskProvider<ResourceCopyTask> =
project.tasks.register("copyResources", ResourceCopyTask::class.java) {
outputDirectory.set(project.layout.buildDirectory.dir("generated/resources"))
}

init {
listOf(resourceCopyTask.map { it.outputDirectory }).let {
kotlinSourceSets.named("main").configure { resources.setSrcDirs(it) }
javaSourceSets.named("main").configure { resources.setSrcDirs(it) }
}
}

/**
* The main source set whose based path is `<root>/java`
*/
val main: SourceSet = object : SourceSet {
override fun setPackages(packages: List<String>) {
val packagePaths = packages.map { Path(it) }
kotlinSourceSets.getByName("main").kotlin
.includePackages("${project.rootDir}/java", packagePaths)
javaSourceSets.getByName("main").java
.includePackages("${project.rootDir}/java", packagePaths)
kotlinSourceSets.named("main").configure {
kotlin.includePackages("${project.rootDir}/java", packagePaths)
}
javaSourceSets.named("main").configure {
java.includePackages("${project.rootDir}/java", packagePaths)
}
}

override fun setResources(resources: Map<String, String>) {
resourceCopyTask.configure {
val baseDir = project.rootProject.layout.projectDirectory.dir("java")
resources.forEach { (resourceFilePath, jarDirectoryPath) ->
val resource = baseDir.file(resourceFilePath)
resourceSpecs.put(resource.asFile.path, jarDirectoryPath)
inputFiles.add(resource)
}
}
}
}

/**
* The main source set whose based path is `<root>/javatests`
*/
val test: SourceSet = object : SourceSet {
override fun setPackages(packages: List<String>) {
val packagePaths = packages.map { Path(it) }
kotlinSourceSets.getByName("test").kotlin
.includePackages("${project.rootDir}/javatests", packagePaths)
javaSourceSets.getByName("test").java
.includePackages("${project.rootDir}/javatests", packagePaths)
kotlinSourceSets.named("test").configure {
kotlin.includePackages("${project.rootDir}/javatests", packagePaths)
}
javaSourceSets.named("test").configure {
java.includePackages("${project.rootDir}/javatests", packagePaths)
}
}

override fun setResources(resources: Map<String, String>) {
throw UnsupportedOperationException(
"Resources are only configurable for the 'main' source set."
)
}
}

interface SourceSet {
/**
* Sets the list of source packages that are part of the project's source set.
*
* Only sources directly in those packages are included and not in its subpackages.
*
* Example usage:
* ```
* daggerSources {
* main.setPackages(
* listOf(
* "dagger",
* "dagger/assisted",
* "dagger/internal",
* "dagger/multibindings",
* )
* )
* }
* ```
* @see daggerSources
*/
fun setPackages(packages: List<String>)

/**
* Sets the resource file paths and their corresponding artifact location.
*
* Example usage:
* ```
* daggerSources {
* main.setResources(
* mapOf("dagger/r8.pro" to "META-INF/com.android.tools/r8/")
* )
* }
* ```
* @see daggerSources
*/
fun setResources(resources: Map<String, String>)
}
}

/**
* Configure project's source set based on Dagger's project structure.
*
* Specifically it will include sources in the packages specified by [DaggerSourceSet.SourceSet.setPackages].
* Specifically it will include sources in the packages specified by
* [DaggerSourceSet.SourceSet.setPackages] and resources as specified by
* [DaggerSourceSet.SourceSet.setResources].
*/
fun Project.daggerSources(block: DaggerSourceSet.() -> Unit) {
val kotlinExtension = extensions.findByType(KotlinProjectExtension::class.java)
Expand Down
7 changes: 6 additions & 1 deletion gradle-projects/dagger-runtime/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ plugins {
alias(libs.plugins.dagger.kotlinJvm)
}

// TODO(danysantiago): Add proguard files as META-INF resources
daggerSources {
main.setPackages(
listOf(
Expand All @@ -14,6 +13,12 @@ daggerSources {
"dagger/multibindings",
)
)
main.setResources(
mapOf(
"dagger/proguard.pro" to "META-INF/com.android.tools/proguard",
"dagger/r8.pro" to "META-INF/com.android.tools/r8"
)
)
test.setPackages(
listOf(
"dagger",
Expand Down

0 comments on commit 5c4bbb4

Please sign in to comment.