Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -151,19 +151,10 @@ abstract class AffectedModuleDetector {

val logger =
ToStringLogger.createWithLifecycle(
gradle
) { log ->
config.logFolder?.let {
val distDir = File(it)
if (!distDir.exists()) {
distDir.mkdirs()
}
val outputFile =
distDir.resolve(config.logFilename)
outputFile.appendText(log)
println("Wrote dependency log to ${outputFile.absolutePath}")
}
}
rootProject,
config.logFilename,
config.logFolder
)

val modules =
getModulesProperty(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,52 +20,95 @@

package com.dropbox.affectedmoduledetector

import org.gradle.BuildAdapter
import org.gradle.BuildResult
import org.gradle.api.invocation.Gradle
import org.gradle.api.Project
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.logging.LogLevel
import org.gradle.api.logging.Logger
import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider
import org.gradle.api.services.BuildService
import org.gradle.api.services.BuildServiceParameters
import org.gradle.internal.build.event.BuildEventListenerRegistryInternal
import org.gradle.internal.logging.slf4j.OutputEventListenerBackedLogger
import org.gradle.internal.logging.slf4j.OutputEventListenerBackedLoggerContext
import org.gradle.internal.operations.*
import org.gradle.internal.time.Clock
import org.gradle.invocation.DefaultGradle
import java.io.File

/**
* Gradle logger that logs to a string.
*/
class ToStringLogger(
private val stringBuilder: StringBuilder = StringBuilder()
internal open class ToStringLogger(
private val loggerProvider: Provider<ToStringLoggerBuildService>?
) : OutputEventListenerBackedLogger(
"amd",
OutputEventListenerBackedLoggerContext(
Clock {
System.currentTimeMillis()
}
).also {
OutputEventListenerBackedLoggerContext {
System.currentTimeMillis()
}.also {
it.level = LogLevel.DEBUG
it.setOutputEventListener {
stringBuilder.appendln(it.toString())
it.setOutputEventListener { outputEvent ->
loggerProvider?.get()?.parameters?.getStringBuilderProperty()?.get()?.appendLine(outputEvent.toString())
}
},
Clock {
System.currentTimeMillis()
}
) {

/**
* Returns the current log.
*/
fun buildString() = stringBuilder.toString()
fun buildString() = loggerProvider?.get()?.parameters?.getStringBuilderProperty()?.get()?.toString()

@Suppress("UnstableApiUsage") // BuildService is not yet stable
companion object {
internal abstract class ToStringLoggerBuildService : BuildService<ToStringLoggerBuildService.ToStringLoggerBuildServiceParameters>, BuildOperationListener, AutoCloseable {
interface ToStringLoggerBuildServiceParameters : BuildServiceParameters {
fun getStringBuilderProperty(): Property<StringBuilder>
fun getOutputFileProperty(): RegularFileProperty
}

override fun started(p0: BuildOperationDescriptor, p1: OperationStartEvent) { }

override fun progress(p0: OperationIdentifier, p1: OperationProgressEvent) { }

override fun finished(buildOperationDescriptor: BuildOperationDescriptor, operationFinishEvent: OperationFinishEvent) { }

override fun close() {
val outputFile = parameters.getOutputFileProperty().orNull?.asFile ?: return
outputFile.appendText(parameters.getStringBuilderProperty().get().toString())
println("Wrote dependency log to ${outputFile.absolutePath}")
}
}

/**
* Creates the [ToStringLogger]
*
* @param project the current project to apply to
* @param logFilename the filename for the logs to go
* @param logFolder the path to where the log should output. if null doesn't output
*/
fun createWithLifecycle(
gradle: Gradle,
onComplete: (String) -> Unit
project: Project,
logFilename: String,
logFolder: String? = null
): Logger {
val logger = ToStringLogger()
gradle.addBuildListener(object : BuildAdapter() {
override fun buildFinished(result: BuildResult) {
onComplete(logger.buildString())
val gradle = project.gradle
val stringBuilder = StringBuilder()
val toStringLoggerBuildService = gradle.sharedServices.registerIfAbsent("to-string-logger-build-listener", ToStringLoggerBuildService::class.java) { service ->
service.parameters.getStringBuilderProperty().set(stringBuilder)
if (logFolder != null) {
val distDir = File(logFolder)
if (!distDir.exists()) {
distDir.mkdirs()
}
val outputFile = distDir.resolve(logFilename)
service.parameters.getOutputFileProperty().set(outputFile)
}
})
}
val logger = ToStringLogger(toStringLoggerBuildService)
(gradle as DefaultGradle).services[BuildEventListenerRegistryInternal::class.java].onOperationCompletion(toStringLoggerBuildService)
return logger
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.dropbox.affectedmoduledetector

import com.nhaarman.mockito_kotlin.mock
import org.gradle.api.provider.Provider
import org.junit.rules.TestRule
import org.junit.runner.Description
import org.junit.runners.model.Statement
Expand All @@ -8,7 +10,7 @@ import org.junit.runners.model.Statement
* Special rule for dependency detector tests that will attach logs to a failure.
*/
class AttachLogsTestRule : TestRule {
val logger = ToStringLogger()
internal val logger = mock<ToStringLogger> { }
override fun apply(base: Statement, description: Description): Statement {
return object : Statement() {
override fun evaluate() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package com.dropbox.affectedmoduledetector.mocks
import com.dropbox.affectedmoduledetector.GitClient
import com.dropbox.affectedmoduledetector.ToStringLogger

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

fun addReply(command: String, response: String) {
Expand Down