summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt96
-rw-r--r--tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt6
-rw-r--r--tools/protologtool/src/com/android/protolog/tool/ViewerConfigBuilder.kt55
-rw-r--r--tools/protologtool/tests/com/android/protolog/tool/ViewerConfigBuilderTest.kt82
4 files changed, 125 insertions, 114 deletions
diff --git a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
index 70ac0bee59b3..a8b9839a6226 100644
--- a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
@@ -18,11 +18,14 @@ package com.android.protolog.tool
import com.android.protolog.tool.CommandOptions.Companion.USAGE
import com.github.javaparser.ParseProblemException
+import com.github.javaparser.ParserConfiguration
import com.github.javaparser.StaticJavaParser
import com.github.javaparser.ast.CompilationUnit
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Executors
import java.util.jar.JarOutputStream
import java.util.zip.ZipEntry
import kotlin.system.exitProcess
@@ -45,30 +48,38 @@ object ProtoLogTool {
val outJar = JarOutputStream(out)
val processor = ProtoLogCallProcessor(command.protoLogClassNameArg,
command.protoLogGroupsClassNameArg, groups)
- val transformer = SourceTransformer(command.protoLogImplClassNameArg, processor)
-
- command.javaSourceArgs.forEach { path ->
- val file = File(path)
- val text = file.readText()
- val newPath = path
- val outSrc = try {
- val code = tryParse(text, path)
- if (containsProtoLogText(text, command.protoLogClassNameArg)) {
- transformer.processClass(text, newPath, code)
- } else {
+
+ val executor = newThreadPool()
+
+ command.javaSourceArgs.map { path ->
+ executor.submitCallable {
+ val transformer = SourceTransformer(command.protoLogImplClassNameArg, processor)
+ val file = File(path)
+ val text = file.readText()
+ val outSrc = try {
+ val code = tryParse(text, path)
+ if (containsProtoLogText(text, command.protoLogClassNameArg)) {
+ transformer.processClass(text, path, code)
+ } else {
+ text
+ }
+ } catch (ex: ParsingException) {
+ // If we cannot parse this file, skip it (and log why). Compilation will fail
+ // in a subsequent build step.
+ println("\n${ex.message}\n")
text
}
- } catch (ex: ParsingException) {
- // If we cannot parse this file, skip it (and log why). Compilation will fail
- // in a subsequent build step.
- println("\n${ex.message}\n")
- text
+ path to outSrc
}
- outJar.putNextEntry(ZipEntry(newPath))
+ }.map { future ->
+ val (path, outSrc) = future.get()
+ outJar.putNextEntry(ZipEntry(path))
outJar.write(outSrc.toByteArray())
outJar.closeEntry()
}
+ executor.shutdown()
+
outJar.close()
out.close()
}
@@ -92,23 +103,36 @@ object ProtoLogTool {
val processor = ProtoLogCallProcessor(command.protoLogClassNameArg,
command.protoLogGroupsClassNameArg, groups)
val builder = ViewerConfigBuilder(processor)
- command.javaSourceArgs.forEach { path ->
- val file = File(path)
- val text = file.readText()
- if (containsProtoLogText(text, command.protoLogClassNameArg)) {
- try {
- val code = tryParse(text, path)
- val pack = if (code.packageDeclaration.isPresent) code.packageDeclaration
- .get().nameAsString else ""
- val newPath = pack.replace('.', '/') + '/' + file.name
- builder.processClass(code, newPath)
- } catch (ex: ParsingException) {
- // If we cannot parse this file, skip it (and log why). Compilation will fail
- // in a subsequent build step.
- println("\n${ex.message}\n")
+
+ val executor = newThreadPool()
+
+ command.javaSourceArgs.map { path ->
+ executor.submitCallable {
+ val file = File(path)
+ val text = file.readText()
+ if (containsProtoLogText(text, command.protoLogClassNameArg)) {
+ try {
+ val code = tryParse(text, path)
+ val pack = if (code.packageDeclaration.isPresent) code.packageDeclaration
+ .get().nameAsString else ""
+ val newPath = pack.replace('.', '/') + '/' + file.name
+ builder.findLogCalls(code, newPath)
+ } catch (ex: ParsingException) {
+ // If we cannot parse this file, skip it (and log why). Compilation will fail
+ // in a subsequent build step.
+ println("\n${ex.message}\n")
+ null
+ }
+ } else {
+ null
}
}
+ }.forEach { future ->
+ builder.addLogCalls(future.get() ?: return@forEach)
}
+
+ executor.shutdown()
+
val out = FileOutputStream(command.viewerConfigJsonArg)
out.write(builder.build().toByteArray())
out.close()
@@ -122,6 +146,11 @@ object ProtoLogTool {
@JvmStatic
fun main(args: Array<String>) {
+ StaticJavaParser.setConfiguration(ParserConfiguration().apply {
+ setLanguageLevel(ParserConfiguration.LanguageLevel.RAW)
+ setAttributeComments(false)
+ })
+
try {
val command = CommandOptions(args)
when (command.command) {
@@ -138,3 +167,8 @@ object ProtoLogTool {
}
}
}
+
+private fun <T> ExecutorService.submitCallable(f: () -> T) = submit(f)
+
+private fun newThreadPool() = Executors.newFixedThreadPool(
+ Runtime.getRuntime().availableProcessors())
diff --git a/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt b/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt
index 00fd038079f9..9a3877323048 100644
--- a/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt
@@ -42,7 +42,6 @@ import com.github.javaparser.ast.type.PrimitiveType
import com.github.javaparser.ast.type.Type
import com.github.javaparser.printer.PrettyPrinter
import com.github.javaparser.printer.PrettyPrinterConfiguration
-import com.github.javaparser.printer.lexicalpreservation.LexicalPreservingPrinter
class SourceTransformer(
protoLogImplClassName: String,
@@ -135,7 +134,8 @@ class SourceTransformer(
// Inline the new statement.
val printedIfStmt = inlinePrinter.print(ifStmt)
// Append blank lines to preserve line numbering in file (to allow debugging)
- val newLines = LexicalPreservingPrinter.print(parentStmt).count { c -> c == '\n' }
+ val parentRange = parentStmt.range.get()
+ val newLines = parentRange.end.line - parentRange.begin.line
val newStmt = printedIfStmt.substringBeforeLast('}') + ("\n".repeat(newLines)) + '}'
// pre-workaround code, see explanation below
/*
@@ -224,9 +224,7 @@ class SourceTransformer(
fileName = path
processedCode = code.split('\n').toMutableList()
offsets = IntArray(processedCode.size)
- LexicalPreservingPrinter.setup(compilationUnit)
protoLogCallProcessor.process(compilationUnit, this, fileName)
- // return LexicalPreservingPrinter.print(compilationUnit)
return processedCode.joinToString("\n")
}
}
diff --git a/tools/protologtool/src/com/android/protolog/tool/ViewerConfigBuilder.kt b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigBuilder.kt
index 941455a24ec8..c1008263c083 100644
--- a/tools/protologtool/src/com/android/protolog/tool/ViewerConfigBuilder.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigBuilder.kt
@@ -23,39 +23,52 @@ import com.github.javaparser.ast.expr.MethodCallExpr
import java.io.StringWriter
class ViewerConfigBuilder(
- private val protoLogCallVisitor: ProtoLogCallProcessor
-) : ProtoLogCallVisitor {
- override fun processCall(
- call: MethodCallExpr,
- messageString: String,
- level: LogLevel,
- group: LogGroup
- ) {
+ private val processor: ProtoLogCallProcessor
+) {
+ private fun addLogCall(logCall: LogCall, context: ParsingContext) {
+ val group = logCall.logGroup
+ val messageString = logCall.messageString
if (group.enabled) {
- val position = fileName
- val key = CodeUtils.hash(position, messageString, level, group)
+ val key = logCall.key()
if (statements.containsKey(key)) {
- if (statements[key] != LogCall(messageString, level, group, position)) {
+ if (statements[key] != logCall) {
throw HashCollisionException(
"Please modify the log message \"$messageString\" " +
- "or \"${statements[key]}\" - their hashes are equal.",
- ParsingContext(fileName, call))
+ "or \"${statements[key]}\" - their hashes are equal.", context)
}
} else {
groups.add(group)
- statements[key] = LogCall(messageString, level, group, position)
- call.range.isPresent
+ statements[key] = logCall
}
}
}
private val statements: MutableMap<Int, LogCall> = mutableMapOf()
private val groups: MutableSet<LogGroup> = mutableSetOf()
- private var fileName: String = ""
- fun processClass(unit: CompilationUnit, fileName: String) {
- this.fileName = fileName
- protoLogCallVisitor.process(unit, this, fileName)
+ fun findLogCalls(unit: CompilationUnit, fileName: String): List<Pair<LogCall, ParsingContext>> {
+ val calls = mutableListOf<Pair<LogCall, ParsingContext>>()
+ val visitor = object : ProtoLogCallVisitor {
+ override fun processCall(
+ call: MethodCallExpr,
+ messageString: String,
+ level: LogLevel,
+ group: LogGroup
+ ) {
+ val logCall = LogCall(messageString, level, group, fileName)
+ val context = ParsingContext(fileName, call)
+ calls.add(logCall to context)
+ }
+ }
+ processor.process(unit, visitor, fileName)
+
+ return calls
+ }
+
+ fun addLogCalls(calls: List<Pair<LogCall, ParsingContext>>) {
+ calls.forEach { (logCall, context) ->
+ addLogCall(logCall, context)
+ }
}
fun build(): String {
@@ -101,5 +114,7 @@ class ViewerConfigBuilder(
val logLevel: LogLevel,
val logGroup: LogGroup,
val position: String
- )
+ ) {
+ fun key() = CodeUtils.hash(position, messageString, logLevel, logGroup)
+ }
}
diff --git a/tools/protologtool/tests/com/android/protolog/tool/ViewerConfigBuilderTest.kt b/tools/protologtool/tests/com/android/protolog/tool/ViewerConfigBuilderTest.kt
index 2b6abcdee7ed..a24761aed9db 100644
--- a/tools/protologtool/tests/com/android/protolog/tool/ViewerConfigBuilderTest.kt
+++ b/tools/protologtool/tests/com/android/protolog/tool/ViewerConfigBuilderTest.kt
@@ -17,8 +17,7 @@
package com.android.protolog.tool
import com.android.json.stream.JsonReader
-import com.github.javaparser.ast.CompilationUnit
-import com.github.javaparser.ast.expr.MethodCallExpr
+import com.android.protolog.tool.ViewerConfigBuilder.LogCall
import org.junit.Assert.assertEquals
import org.junit.Test
import org.mockito.Mockito
@@ -34,14 +33,12 @@ class ViewerConfigBuilderTest {
private val GROUP1 = LogGroup("TEST_GROUP", true, true, TAG1)
private val GROUP2 = LogGroup("DEBUG_GROUP", true, true, TAG2)
private val GROUP3 = LogGroup("DEBUG_GROUP", true, true, TAG2)
+ private val GROUP_DISABLED = LogGroup("DEBUG_GROUP", false, true, TAG2)
+ private val GROUP_TEXT_DISABLED = LogGroup("DEBUG_GROUP", true, false, TAG2)
private const val PATH = "/tmp/test.java"
}
- private val processor: ProtoLogCallProcessor = Mockito.mock(ProtoLogCallProcessor::class.java)
- private val configBuilder = ViewerConfigBuilder(processor)
- private val dummyCompilationUnit = CompilationUnit()
-
- private fun <T> any(type: Class<T>): T = Mockito.any<T>(type)
+ private val configBuilder = ViewerConfigBuilder(Mockito.mock(ProtoLogCallProcessor::class.java))
private fun parseConfig(json: String): Map<Int, ViewerConfigParser.ConfigEntry> {
return ViewerConfigParser().parseConfig(JsonReader(StringReader(json)))
@@ -49,22 +46,10 @@ class ViewerConfigBuilderTest {
@Test
fun processClass() {
- Mockito.`when`(processor.process(any(CompilationUnit::class.java),
- any(ProtoLogCallVisitor::class.java), any(String::class.java)))
- .thenAnswer { invocation ->
- val visitor = invocation.arguments[1] as ProtoLogCallVisitor
-
- visitor.processCall(MethodCallExpr(), TEST1.messageString, LogLevel.INFO,
- GROUP1)
- visitor.processCall(MethodCallExpr(), TEST2.messageString, LogLevel.DEBUG,
- GROUP2)
- visitor.processCall(MethodCallExpr(), TEST3.messageString, LogLevel.ERROR,
- GROUP3)
-
- invocation.arguments[0] as CompilationUnit
- }
-
- configBuilder.processClass(dummyCompilationUnit, PATH)
+ configBuilder.addLogCalls(listOf(
+ LogCall(TEST1.messageString, LogLevel.INFO, GROUP1, PATH),
+ LogCall(TEST2.messageString, LogLevel.DEBUG, GROUP2, PATH),
+ LogCall(TEST3.messageString, LogLevel.ERROR, GROUP3, PATH)).withContext())
val parsedConfig = parseConfig(configBuilder.build())
assertEquals(3, parsedConfig.size)
@@ -78,22 +63,10 @@ class ViewerConfigBuilderTest {
@Test
fun processClass_nonUnique() {
- Mockito.`when`(processor.process(any(CompilationUnit::class.java),
- any(ProtoLogCallVisitor::class.java), any(String::class.java)))
- .thenAnswer { invocation ->
- val visitor = invocation.arguments[1] as ProtoLogCallVisitor
-
- visitor.processCall(MethodCallExpr(), TEST1.messageString, LogLevel.INFO,
- GROUP1)
- visitor.processCall(MethodCallExpr(), TEST1.messageString, LogLevel.INFO,
- GROUP1)
- visitor.processCall(MethodCallExpr(), TEST1.messageString, LogLevel.INFO,
- GROUP1)
-
- invocation.arguments[0] as CompilationUnit
- }
-
- configBuilder.processClass(dummyCompilationUnit, PATH)
+ configBuilder.addLogCalls(listOf(
+ LogCall(TEST1.messageString, LogLevel.INFO, GROUP1, PATH),
+ LogCall(TEST1.messageString, LogLevel.INFO, GROUP1, PATH),
+ LogCall(TEST1.messageString, LogLevel.INFO, GROUP1, PATH)).withContext())
val parsedConfig = parseConfig(configBuilder.build())
assertEquals(1, parsedConfig.size)
@@ -103,28 +76,19 @@ class ViewerConfigBuilderTest {
@Test
fun processClass_disabled() {
- Mockito.`when`(processor.process(any(CompilationUnit::class.java),
- any(ProtoLogCallVisitor::class.java), any(String::class.java)))
- .thenAnswer { invocation ->
- val visitor = invocation.arguments[1] as ProtoLogCallVisitor
-
- visitor.processCall(MethodCallExpr(), TEST1.messageString, LogLevel.INFO,
- GROUP1)
- visitor.processCall(MethodCallExpr(), TEST2.messageString, LogLevel.DEBUG,
- LogGroup("DEBUG_GROUP", false, true, TAG2))
- visitor.processCall(MethodCallExpr(), TEST3.messageString, LogLevel.ERROR,
- LogGroup("DEBUG_GROUP", true, false, TAG2))
-
- invocation.arguments[0] as CompilationUnit
- }
-
- configBuilder.processClass(dummyCompilationUnit, PATH)
+ configBuilder.addLogCalls(listOf(
+ LogCall(TEST1.messageString, LogLevel.INFO, GROUP1, PATH),
+ LogCall(TEST2.messageString, LogLevel.DEBUG, GROUP_DISABLED, PATH),
+ LogCall(TEST3.messageString, LogLevel.ERROR, GROUP_TEXT_DISABLED, PATH))
+ .withContext())
val parsedConfig = parseConfig(configBuilder.build())
assertEquals(2, parsedConfig.size)
- assertEquals(TEST1, parsedConfig[CodeUtils.hash(PATH, TEST1.messageString,
- LogLevel.INFO, GROUP1)])
- assertEquals(TEST3, parsedConfig[CodeUtils.hash(PATH, TEST3.messageString,
- LogLevel.ERROR, LogGroup("DEBUG_GROUP", true, false, TAG2))])
+ assertEquals(TEST1, parsedConfig[CodeUtils.hash(
+ PATH, TEST1.messageString, LogLevel.INFO, GROUP1)])
+ assertEquals(TEST3, parsedConfig[CodeUtils.hash(
+ PATH, TEST3.messageString, LogLevel.ERROR, GROUP_TEXT_DISABLED)])
}
+
+ private fun List<LogCall>.withContext() = map { it to ParsingContext() }
}