Skip to content

Commit c18ef5d

Browse files
Merge pull request #151 from dropbox/jfein/fix-config-cache-issues
Make `ToStringLogger` config cacheable
2 parents 974485f + 3770503 commit c18ef5d

File tree

4 files changed

+71
-35
lines changed

4 files changed

+71
-35
lines changed

affectedmoduledetector/src/main/kotlin/com/dropbox/affectedmoduledetector/AffectedModuleDetector.kt

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -151,19 +151,10 @@ abstract class AffectedModuleDetector {
151151

152152
val logger =
153153
ToStringLogger.createWithLifecycle(
154-
gradle
155-
) { log ->
156-
config.logFolder?.let {
157-
val distDir = File(it)
158-
if (!distDir.exists()) {
159-
distDir.mkdirs()
160-
}
161-
val outputFile =
162-
distDir.resolve(config.logFilename)
163-
outputFile.appendText(log)
164-
println("Wrote dependency log to ${outputFile.absolutePath}")
165-
}
166-
}
154+
rootProject,
155+
config.logFilename,
156+
config.logFolder
157+
)
167158

168159
val modules =
169160
getModulesProperty(

affectedmoduledetector/src/main/kotlin/com/dropbox/affectedmoduledetector/ToStringLogger.kt

Lines changed: 63 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,52 +20,95 @@
2020

2121
package com.dropbox.affectedmoduledetector
2222

23-
import org.gradle.BuildAdapter
24-
import org.gradle.BuildResult
25-
import org.gradle.api.invocation.Gradle
23+
import org.gradle.api.Project
24+
import org.gradle.api.file.RegularFileProperty
2625
import org.gradle.api.logging.LogLevel
2726
import org.gradle.api.logging.Logger
27+
import org.gradle.api.provider.Property
28+
import org.gradle.api.provider.Provider
29+
import org.gradle.api.services.BuildService
30+
import org.gradle.api.services.BuildServiceParameters
31+
import org.gradle.internal.build.event.BuildEventListenerRegistryInternal
2832
import org.gradle.internal.logging.slf4j.OutputEventListenerBackedLogger
2933
import org.gradle.internal.logging.slf4j.OutputEventListenerBackedLoggerContext
34+
import org.gradle.internal.operations.*
3035
import org.gradle.internal.time.Clock
36+
import org.gradle.invocation.DefaultGradle
37+
import java.io.File
3138

3239
/**
3340
* Gradle logger that logs to a string.
3441
*/
35-
class ToStringLogger(
36-
private val stringBuilder: StringBuilder = StringBuilder()
42+
internal open class ToStringLogger(
43+
private val loggerProvider: Provider<ToStringLoggerBuildService>?
3744
) : OutputEventListenerBackedLogger(
3845
"amd",
39-
OutputEventListenerBackedLoggerContext(
40-
Clock {
41-
System.currentTimeMillis()
42-
}
43-
).also {
46+
OutputEventListenerBackedLoggerContext {
47+
System.currentTimeMillis()
48+
}.also {
4449
it.level = LogLevel.DEBUG
45-
it.setOutputEventListener {
46-
stringBuilder.appendln(it.toString())
50+
it.setOutputEventListener { outputEvent ->
51+
loggerProvider?.get()?.parameters?.getStringBuilderProperty()?.get()?.appendLine(outputEvent.toString())
4752
}
4853
},
4954
Clock {
5055
System.currentTimeMillis()
5156
}
5257
) {
58+
5359
/**
5460
* Returns the current log.
5561
*/
56-
fun buildString() = stringBuilder.toString()
62+
fun buildString() = loggerProvider?.get()?.parameters?.getStringBuilderProperty()?.get()?.toString()
5763

64+
@Suppress("UnstableApiUsage") // BuildService is not yet stable
5865
companion object {
66+
internal abstract class ToStringLoggerBuildService : BuildService<ToStringLoggerBuildService.ToStringLoggerBuildServiceParameters>, BuildOperationListener, AutoCloseable {
67+
interface ToStringLoggerBuildServiceParameters : BuildServiceParameters {
68+
fun getStringBuilderProperty(): Property<StringBuilder>
69+
fun getOutputFileProperty(): RegularFileProperty
70+
}
71+
72+
override fun started(p0: BuildOperationDescriptor, p1: OperationStartEvent) { }
73+
74+
override fun progress(p0: OperationIdentifier, p1: OperationProgressEvent) { }
75+
76+
override fun finished(buildOperationDescriptor: BuildOperationDescriptor, operationFinishEvent: OperationFinishEvent) { }
77+
78+
override fun close() {
79+
val outputFile = parameters.getOutputFileProperty().orNull?.asFile ?: return
80+
outputFile.appendText(parameters.getStringBuilderProperty().get().toString())
81+
println("Wrote dependency log to ${outputFile.absolutePath}")
82+
}
83+
}
84+
85+
/**
86+
* Creates the [ToStringLogger]
87+
*
88+
* @param project the current project to apply to
89+
* @param logFilename the filename for the logs to go
90+
* @param logFolder the path to where the log should output. if null doesn't output
91+
*/
5992
fun createWithLifecycle(
60-
gradle: Gradle,
61-
onComplete: (String) -> Unit
93+
project: Project,
94+
logFilename: String,
95+
logFolder: String? = null
6296
): Logger {
63-
val logger = ToStringLogger()
64-
gradle.addBuildListener(object : BuildAdapter() {
65-
override fun buildFinished(result: BuildResult) {
66-
onComplete(logger.buildString())
97+
val gradle = project.gradle
98+
val stringBuilder = StringBuilder()
99+
val toStringLoggerBuildService = gradle.sharedServices.registerIfAbsent("to-string-logger-build-listener", ToStringLoggerBuildService::class.java) { service ->
100+
service.parameters.getStringBuilderProperty().set(stringBuilder)
101+
if (logFolder != null) {
102+
val distDir = File(logFolder)
103+
if (!distDir.exists()) {
104+
distDir.mkdirs()
105+
}
106+
val outputFile = distDir.resolve(logFilename)
107+
service.parameters.getOutputFileProperty().set(outputFile)
67108
}
68-
})
109+
}
110+
val logger = ToStringLogger(toStringLoggerBuildService)
111+
(gradle as DefaultGradle).services[BuildEventListenerRegistryInternal::class.java].onOperationCompletion(toStringLoggerBuildService)
69112
return logger
70113
}
71114
}

affectedmoduledetector/src/test/kotlin/com/dropbox/affectedmoduledetector/AttachLogsTestRule.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.dropbox.affectedmoduledetector
22

3+
import com.nhaarman.mockito_kotlin.mock
4+
import org.gradle.api.provider.Provider
35
import org.junit.rules.TestRule
46
import org.junit.runner.Description
57
import org.junit.runners.model.Statement
@@ -8,7 +10,7 @@ import org.junit.runners.model.Statement
810
* Special rule for dependency detector tests that will attach logs to a failure.
911
*/
1012
class AttachLogsTestRule : TestRule {
11-
val logger = ToStringLogger()
13+
internal val logger = mock<ToStringLogger> { }
1214
override fun apply(base: Statement, description: Description): Statement {
1315
return object : Statement() {
1416
override fun evaluate() {

affectedmoduledetector/src/test/kotlin/com/dropbox/affectedmoduledetector/mocks/MockCommandRunner.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package com.dropbox.affectedmoduledetector.mocks
33
import com.dropbox.affectedmoduledetector.GitClient
44
import com.dropbox.affectedmoduledetector.ToStringLogger
55

6-
class MockCommandRunner(private val logger: ToStringLogger) : GitClient.CommandRunner {
6+
internal class MockCommandRunner(private val logger: ToStringLogger) : GitClient.CommandRunner {
77
private val replies = mutableMapOf<String, List<String>>()
88

99
fun addReply(command: String, response: String) {

0 commit comments

Comments
 (0)