Skip to content

Commit

Permalink
Centralize dependency files for the common case.
Browse files Browse the repository at this point in the history
  • Loading branch information
autonomousapps committed Feb 1, 2024
1 parent 46c0d5e commit cd5c0db
Show file tree
Hide file tree
Showing 9 changed files with 73 additions and 19 deletions.
12 changes: 7 additions & 5 deletions src/main/kotlin/com/autonomousapps/internal/OutputPaths.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,19 @@

package com.autonomousapps.internal

import com.autonomousapps.internal.OutputPaths.Companion.ROOT_DIR
import org.gradle.api.Project

internal const val ROOT_DIR = "reports/dependency-analysis"

internal class OutputPaths(
private val project: Project,
variantName: String
variantName: String,
) {

internal companion object {
const val ROOT_DIR = "reports/dependency-analysis"
}

private fun file(path: String) = project.layout.buildDirectory.file(path)
private fun dir(path: String) = project.layout.buildDirectory.dir(path)

private val variantDirectory = "$ROOT_DIR/$variantName"
private val intermediatesDir = "${variantDirectory}/intermediates"
Expand All @@ -37,7 +39,7 @@ internal class OutputPaths(
val declaredProcPath = file("${intermediatesDir}/procs-declared.json")
val abiAnalysisPath = file("${intermediatesDir}/abi.json")
val abiDumpPath = file("${variantDirectory}/abi-dump.txt")
val dependenciesDir = dir("${variantDirectory}/dependencies")
val dependencies = file("${variantDirectory}/dependencies.txt")
val explodedSourcePath = file("${intermediatesDir}/exploded-source.json")
val explodingBytecodePath = file("${intermediatesDir}/exploding-bytecode.json")
val syntheticProjectPath = file("${intermediatesDir}/synthetic-project.json")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ internal class AndroidLibAnalyzer(
): TaskProvider<AndroidScoreTask> {
return project.tasks.register<AndroidScoreTask>("computeAndroidScore$taskNameSuffix") {
dependencies.set(synthesizeDependenciesTask.flatMap { it.outputDir })
dependenciesList.set(synthesizeDependenciesTask.flatMap { it.output })
syntheticProject.set(synthesizeProjectViewTask.flatMap { it.output })
output.set(outputPaths.androidScorePath)
}
Expand Down
11 changes: 8 additions & 3 deletions src/main/kotlin/com/autonomousapps/model/ProjectVariant.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import com.autonomousapps.internal.utils.fromJson
import com.autonomousapps.model.CodeSource.Kind
import com.autonomousapps.model.declaration.Variant
import com.squareup.moshi.JsonClass
import com.squareup.moshi.JsonEncodingException
import org.gradle.api.file.Directory

/** Represents a variant-specific view of the project under analysis. */
Expand All @@ -22,7 +23,7 @@ data class ProjectVariant(
val sources: Set<Source>,
val classpath: Set<Coordinates>,
val annotationProcessors: Set<Coordinates>,
val testInstrumentationRunner: String?
val testInstrumentationRunner: String?,
) {

val usedClassesBySrc: Set<String> by unsafeLazy {
Expand Down Expand Up @@ -93,9 +94,13 @@ data class ProjectVariant(
.map {
val file = dependenciesDir.file(it.toFileName())
if (file.asFile.exists()) {
file.fromJson<Dependency>()
try {
file.fromJson<Dependency>()
} catch (e: JsonEncodingException) {
throw IllegalStateException("Couldn't deserialize '${file.asFile}'", e)
}
} else {
error("No file ${it.toFileName()}")
error("No file '${it.toFileName()}'")
}
}
.toSet()
Expand Down
12 changes: 11 additions & 1 deletion src/main/kotlin/com/autonomousapps/services/InMemoryCache.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package com.autonomousapps.services

import com.autonomousapps.Flags.cacheSize
import com.autonomousapps.internal.OutputPaths.Companion.ROOT_DIR
import com.autonomousapps.model.InlineMemberCapability
import com.autonomousapps.model.intermediates.AnnotationProcessorDependency
import com.autonomousapps.model.intermediates.ExplodingJar
Expand All @@ -13,6 +14,7 @@ import com.autonomousapps.tasks.KotlinCapabilities
import com.github.benmanes.caffeine.cache.Cache
import com.github.benmanes.caffeine.cache.Caffeine
import org.gradle.api.Project
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.invocation.Gradle
import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider
Expand All @@ -23,6 +25,7 @@ abstract class InMemoryCache : BuildService<InMemoryCache.Params> {

interface Params : BuildServiceParameters {
val cacheSize: Property<Long>
val dependenciesDir: DirectoryProperty
}

private val cacheSize = parameters.cacheSize.get()
Expand Down Expand Up @@ -53,7 +56,7 @@ abstract class InMemoryCache : BuildService<InMemoryCache.Params> {
procs.asMap().putIfAbsent(procName, proc)
}

companion object {
internal companion object {
private const val SHARED_SERVICES_IN_MEMORY_CACHE = "inMemoryCache"
private const val DEFAULT_CACHE_VALUE = -1L

Expand Down Expand Up @@ -92,6 +95,13 @@ abstract class InMemoryCache : BuildService<InMemoryCache.Params> {
.sharedServices
.registerIfAbsent(SHARED_SERVICES_IN_MEMORY_CACHE, InMemoryCache::class.java) {
parameters.cacheSize.set(project.cacheSize(DEFAULT_CACHE_VALUE))
parameters.dependenciesDir.set(project.layout.buildDirectory.dir("${ROOT_DIR}/dependencies"))

// TODO I wonder how this works in the context of a composite build. Maybe I should create a new service just
// for this, and _not_ share that service across builds?
if (project != project.rootProject) {
project.logger.warn("Creating global dependencies output directory in '${project.path}'")
}
}
}
}
8 changes: 6 additions & 2 deletions src/main/kotlin/com/autonomousapps/subplugin/ProjectPlugin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -671,7 +671,9 @@ internal class ProjectPlugin(private val project: Project) {

val synthesizeDependenciesTask =
tasks.register<SynthesizeDependenciesTask>("synthesizeDependencies$taskNameSuffix") {
inMemoryCache.set(InMemoryCache.register(project))
val cache = InMemoryCache.register(project)

inMemoryCache.set(cache)
projectPath.set(thisProjectPath)
compileDependencies.set(graphViewTask.flatMap { it.outputNodes })
physicalArtifacts.set(artifactsReport.flatMap { it.output })
Expand All @@ -686,7 +688,8 @@ internal class ProjectPlugin(private val project: Project) {
findNativeLibsTask?.let { task -> nativeLibs.set(task.flatMap { it.output }) }
findAndroidAssetsTask?.let { task -> androidAssets.set(task.flatMap { it.output }) }

outputDir.set(outputPaths.dependenciesDir)
outputDir.set(cache.flatMap { it.parameters.dependenciesDir })
output.set(outputPaths.dependencies)
}

/* ******************************
Expand Down Expand Up @@ -770,6 +773,7 @@ internal class ProjectPlugin(private val project: Project) {
graph.set(graphViewTask.flatMap { it.output })
declarations.set(findDeclarationsTask.flatMap { it.output })
dependencies.set(synthesizeDependenciesTask.flatMap { it.outputDir })
dependenciesList.set(synthesizeDependenciesTask.flatMap { it.output })
syntheticProject.set(synthesizeProjectViewTask.flatMap { it.output })
kapt.set(isKaptApplied())
output.set(outputPaths.dependencyTraceReportPath)
Expand Down
8 changes: 5 additions & 3 deletions src/main/kotlin/com/autonomousapps/subplugin/RootPlugin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import com.autonomousapps.internal.advice.DslKind
import com.autonomousapps.internal.artifacts.DagpArtifacts
import com.autonomousapps.internal.artifacts.Resolver.Companion.interProjectResolver
import com.autonomousapps.internal.utils.log
import com.autonomousapps.services.InMemoryCache
import com.autonomousapps.tasks.BuildHealthTask
import com.autonomousapps.tasks.ComputeDuplicateDependenciesTask
import com.autonomousapps.tasks.GenerateBuildHealthTask
Expand All @@ -23,9 +24,7 @@ import org.gradle.kotlin.dsl.register

internal const val DEPENDENCY_ANALYSIS_PLUGIN = "com.autonomousapps.dependency-analysis"

/**
* This "plugin" is applied to the root project only.
*/
/** This "plugin" is applied to the root project only. */
internal class RootPlugin(private val project: Project) {

init {
Expand Down Expand Up @@ -87,6 +86,9 @@ internal class RootPlugin(private val project: Project) {
private fun Project.configureRootProject() {
val paths = RootOutputPaths(this)

// Register this in the root project to centralize dependency synthesis files
InMemoryCache.register(this)

val computeDuplicatesTask = tasks.register<ComputeDuplicateDependenciesTask>("computeDuplicateDependencies") {
resolvedDependenciesReports.setFrom(resolvedDepsResolver.internal)
output.set(paths.duplicateDependenciesPath)
Expand Down
10 changes: 8 additions & 2 deletions src/main/kotlin/com/autonomousapps/tasks/AndroidScoreTask.kt
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,16 @@ abstract class AndroidScoreTask @Inject constructor(
@get:InputFile
abstract val syntheticProject: RegularFileProperty

@get:PathSensitive(PathSensitivity.NONE)
@get:InputDirectory
/**
* TODO: docs
*/
@get:Internal
abstract val dependencies: DirectoryProperty

@get:PathSensitive(PathSensitivity.NONE)
@get:InputFile
abstract val dependenciesList: RegularFileProperty

@get:OutputFile
abstract val output: RegularFileProperty

Expand Down
14 changes: 12 additions & 2 deletions src/main/kotlin/com/autonomousapps/tasks/ComputeUsagesTask.kt
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,20 @@ abstract class ComputeUsagesTask @Inject constructor(
@get:InputFile
abstract val declarations: RegularFileProperty

@get:PathSensitive(PathSensitivity.NONE)
@get:InputDirectory
/**
* This contains all of the [Dependencies][Dependency] used by this project. It cannot be a task input because it is
* a globally shared directory that many tasks write to and read from. See also [dependenciesList].
*/
@get:Internal
abstract val dependencies: DirectoryProperty

/**
* Only for task snapshotting. A simplified representation of [dependencies].
*/
@get:PathSensitive(PathSensitivity.NONE)
@get:InputFile
abstract val dependenciesList: RegularFileProperty

@get:PathSensitive(PathSensitivity.NONE)
@get:InputFile
abstract val syntheticProject: RegularFileProperty
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,14 @@ abstract class SynthesizeDependenciesTask @Inject constructor(
@get:InputFile
abstract val androidAssets: RegularFileProperty

// TODO: Maybe this should not be an OutputDirectory anymore, but just Internal? Since multiple tasks will write to it
@get:OutputDirectory
abstract val outputDir: DirectoryProperty

/** A simplified representation of [outputDir] for task snapshotting purposes only. */
@get:OutputFile
abstract val output: RegularFileProperty

@TaskAction fun action() {
workerExecutor.noIsolation().submit(SynthesizeDependenciesWorkAction::class.java) {
inMemoryCache.set(this@SynthesizeDependenciesTask.inMemoryCache)
Expand All @@ -105,6 +110,7 @@ abstract class SynthesizeDependenciesTask @Inject constructor(
nativeLibs.set(this@SynthesizeDependenciesTask.nativeLibs)
androidAssets.set(this@SynthesizeDependenciesTask.androidAssets)
outputDir.set(this@SynthesizeDependenciesTask.outputDir)
output.set(this@SynthesizeDependenciesTask.output)
}
}

Expand All @@ -125,6 +131,7 @@ abstract class SynthesizeDependenciesTask @Inject constructor(
val androidAssets: RegularFileProperty

val outputDir: DirectoryProperty
val output: RegularFileProperty
}

abstract class SynthesizeDependenciesWorkAction : WorkAction<SynthesizeDependenciesParameters> {
Expand All @@ -133,6 +140,7 @@ abstract class SynthesizeDependenciesTask @Inject constructor(

override fun execute() {
val outputDir = parameters.outputDir
val output = parameters.output.getAndDelete()

val dependencies = parameters.compileDependencies.fromJson<CoordinatesContainer>().coordinates
val physicalArtifacts = parameters.physicalArtifacts.fromJsonSet<PhysicalArtifact>()
Expand Down Expand Up @@ -192,7 +200,13 @@ abstract class SynthesizeDependenciesTask @Inject constructor(
.map { it.build() }
.forEach { dependency ->
val coordinates = dependency.coordinates
outputDir.file(coordinates.toFileName()).get().asFile.bufferWriteJson(dependency)
val file = outputDir.file(coordinates.toFileName()).get().asFile
if (!file.exists()) {
file.bufferWriteJson(dependency)
}

// This is the task output for snapshotting purposes
output.appendText("${coordinates.gav()}\n")
}
}

Expand Down

0 comments on commit cd5c0db

Please sign in to comment.