1 /* <lambda>null2 * Copyright (C) 2021 The Dagger Authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package dagger.hilt.android.plugin.task 18 19 import dagger.hilt.android.plugin.root.AggregatedElementProxyGenerator 20 import dagger.hilt.android.plugin.root.ComponentTreeDepsGenerator 21 import dagger.hilt.android.plugin.root.ProcessedRootSentinelGenerator 22 import dagger.hilt.processor.internal.root.ir.AggregatedRootIrValidator 23 import dagger.hilt.processor.internal.root.ir.ComponentTreeDepsIrCreator 24 import javax.inject.Inject 25 import org.gradle.api.DefaultTask 26 import org.gradle.api.file.ConfigurableFileCollection 27 import org.gradle.api.file.DirectoryProperty 28 import org.gradle.api.provider.Property 29 import org.gradle.api.tasks.CacheableTask 30 import org.gradle.api.tasks.Classpath 31 import org.gradle.api.tasks.Input 32 import org.gradle.api.tasks.Optional 33 import org.gradle.api.tasks.OutputDirectory 34 import org.gradle.api.tasks.TaskAction 35 import org.gradle.work.InputChanges 36 import org.gradle.workers.WorkAction 37 import org.gradle.workers.WorkParameters 38 import org.gradle.workers.WorkerExecutor 39 import org.objectweb.asm.Opcodes 40 import org.slf4j.LoggerFactory 41 42 /** 43 * Aggregates Hilt component dependencies from the compile classpath and outputs Java sources 44 * with shareable component trees. 45 * 46 * The [compileClasspath] input is expected to contain jars or classes transformed by 47 * [dagger.hilt.android.plugin.util.AggregatedPackagesTransform]. 48 */ 49 @CacheableTask 50 abstract class AggregateDepsTask @Inject constructor( 51 private val workerExecutor: WorkerExecutor 52 ) : DefaultTask() { 53 54 // TODO(danysantiago): Make @Incremental and try to use @CompileClasspath 55 @get:Classpath 56 abstract val compileClasspath: ConfigurableFileCollection 57 58 @get:Input 59 @get:Optional 60 abstract val asmApiVersion: Property<Int> 61 62 @get:OutputDirectory 63 abstract val outputDir: DirectoryProperty 64 65 @get:Input 66 abstract val testEnvironment: Property<Boolean> 67 68 @get:Input 69 abstract val crossCompilationRootValidationDisabled: Property<Boolean> 70 71 @TaskAction 72 internal fun taskAction(@Suppress("UNUSED_PARAMETER") inputs: InputChanges) { 73 workerExecutor.noIsolation().submit(WorkerAction::class.java) { 74 it.compileClasspath.from(compileClasspath) 75 it.asmApiVersion.set(asmApiVersion) 76 it.outputDir.set(outputDir) 77 it.testEnvironment.set(testEnvironment) 78 it.crossCompilationRootValidationDisabled.set(crossCompilationRootValidationDisabled) 79 } 80 } 81 82 internal interface Parameters : WorkParameters { 83 val compileClasspath: ConfigurableFileCollection 84 val asmApiVersion: Property<Int> 85 val outputDir: DirectoryProperty 86 val testEnvironment: Property<Boolean> 87 val crossCompilationRootValidationDisabled: Property<Boolean> 88 } 89 90 abstract class WorkerAction : WorkAction<Parameters> { 91 override fun execute() { 92 // Logger is not an injectable service yet: https://github.com/gradle/gradle/issues/16991 93 val logger = LoggerFactory.getLogger(AggregateDepsTask::class.java) 94 val aggregator = Aggregator.from( 95 logger = logger, 96 asmApiVersion = parameters.asmApiVersion.getOrNull() ?: Opcodes.ASM7, 97 input = parameters.compileClasspath 98 ) 99 val rootsToProcess = AggregatedRootIrValidator.rootsToProcess( 100 isCrossCompilationRootValidationDisabled = 101 parameters.crossCompilationRootValidationDisabled.get(), 102 processedRoots = aggregator.processedRoots, 103 aggregatedRoots = aggregator.aggregatedRoots 104 ) 105 if (rootsToProcess.isEmpty()) { 106 return 107 } 108 val componentTrees = ComponentTreeDepsIrCreator.components( 109 isTest = parameters.testEnvironment.get(), 110 isSharedTestComponentsEnabled = true, 111 aggregatedRoots = rootsToProcess, 112 defineComponentDeps = aggregator.defineComponentDeps, 113 aliasOfDeps = aggregator.aliasOfDeps, 114 aggregatedDeps = aggregator.aggregatedDeps, 115 aggregatedUninstallModulesDeps = aggregator.uninstallModulesDeps, 116 aggregatedEarlyEntryPointDeps = aggregator.earlyEntryPointDeps, 117 ) 118 ComponentTreeDepsGenerator( 119 proxies = aggregator.allAggregatedDepProxies.associate { it.value to it.fqName }, 120 outputDir = parameters.outputDir.get().asFile 121 ).let { generator -> 122 componentTrees.forEach { generator.generate(it) } 123 } 124 AggregatedElementProxyGenerator(parameters.outputDir.get().asFile).let { generator -> 125 (aggregator.allAggregatedDepProxies - aggregator.aggregatedDepProxies).forEach { 126 generator.generate(it) 127 } 128 } 129 ProcessedRootSentinelGenerator(parameters.outputDir.get().asFile).let { generator -> 130 rootsToProcess.map { it.root }.forEach { generator.generate(it) } 131 } 132 } 133 } 134 } 135