Move IC tests to compiler
Fixing IC after moving it from Gradle to the compiler in commit f40a3eff20
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin
|
||||
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import java.io.File
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
abstract class TestWithWorkingDir {
|
||||
protected var workingDir: File by Delegates.notNull()
|
||||
private set
|
||||
|
||||
@Before
|
||||
open fun setUp() {
|
||||
workingDir = FileUtil.createTempDirectory(this.javaClass.simpleName, null)
|
||||
}
|
||||
|
||||
@After
|
||||
open fun tearDown() {
|
||||
workingDir.deleteRecursively()
|
||||
}
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.incremental
|
||||
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.Parameterized
|
||||
import java.io.File
|
||||
|
||||
@RunWith(Parameterized::class)
|
||||
class BuildLogParserParametrizedTest {
|
||||
|
||||
@Parameterized.Parameter
|
||||
@JvmField
|
||||
var testDirName: String = ""
|
||||
|
||||
@Test
|
||||
fun testParser() {
|
||||
val testDir = File(TEST_ROOT, testDirName)
|
||||
val logFile = File(testDir, LOG_FILE_NAME)
|
||||
assert(logFile.isFile) { "Log file: $logFile does not exist" }
|
||||
|
||||
val actualNormalized = dumpBuildLog(parseTestBuildLog(logFile)).replace("\r\n", "\n").trim()
|
||||
val expectedFile = File(testDir, EXPECTED_PARSED_LOG_FILE_NAME)
|
||||
|
||||
if (!expectedFile.isFile) {
|
||||
expectedFile.createNewFile()
|
||||
expectedFile.writeText(actualNormalized)
|
||||
|
||||
throw AssertionError("Expected file log did not exist, created: $expectedFile")
|
||||
}
|
||||
|
||||
val expectedNormalized = expectedFile.readText().replace("\r\n", "\n").trim()
|
||||
Assert.assertEquals("Parsed content was unexpected: ", expectedNormalized, actualNormalized)
|
||||
|
||||
// parse expected, dump again and compare (to check that dumped log can be parsed again)
|
||||
val reparsedActualNormalized = dumpBuildLog(parseTestBuildLog(expectedFile)).trim()
|
||||
Assert.assertEquals("Reparsed content was unexpected: ", expectedNormalized, reparsedActualNormalized)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val TEST_ROOT = File("compiler/incremental-compilation-impl/testData/buildLogsParserData")
|
||||
private val LOG_FILE_NAME = "build.log"
|
||||
private val EXPECTED_PARSED_LOG_FILE_NAME = "expected.txt"
|
||||
|
||||
@Suppress("unused")
|
||||
@Parameterized.Parameters(name = "{index}: {0}")
|
||||
@JvmStatic
|
||||
fun data(): List<Array<String>> {
|
||||
val directories = TEST_ROOT.listFiles().filter { it.isDirectory }
|
||||
return directories.map { arrayOf(it.name) }.toList()
|
||||
}
|
||||
}
|
||||
}
|
||||
+222
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.incremental
|
||||
|
||||
import org.jetbrains.kotlin.TestWithWorkingDir
|
||||
import org.jetbrains.kotlin.cli.common.ExitCode
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||
import com.intellij.util.containers.HashMap
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.jetbrains.kotlin.incremental.testingUtils.*
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.Parameterized
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
@RunWith(Parameterized::class)
|
||||
class KotlinStandaloneIncrementalCompilationTest : TestWithWorkingDir() {
|
||||
@Parameterized.Parameter
|
||||
lateinit var testDir: File
|
||||
|
||||
@Suppress("unused")
|
||||
@Parameterized.Parameter(value = 1)
|
||||
lateinit var readableName: String
|
||||
|
||||
@Test
|
||||
fun testFromJps() {
|
||||
fun Iterable<File>.relativePaths() =
|
||||
map { it.relativeTo(workingDir).path.replace('\\', '/') }
|
||||
|
||||
val srcDir = File(workingDir, "src").apply { mkdirs() }
|
||||
val cacheDir = File(workingDir, "incremental-data").apply { mkdirs() }
|
||||
val outDir = File(workingDir, "out").apply { mkdirs() }
|
||||
|
||||
val mapWorkingToOriginalFile = HashMap(copyTestSources(testDir, srcDir, filePrefix = ""))
|
||||
val sourceRoots = listOf(srcDir)
|
||||
val args = K2JVMCompilerArguments()
|
||||
args.destination = outDir.path
|
||||
args.moduleName = testDir.name
|
||||
args.classpath = compileClasspath()
|
||||
// initial build
|
||||
make(cacheDir, sourceRoots, args)
|
||||
|
||||
// modifications
|
||||
val buildLogFile = buildLogFinder.findBuildLog(testDir) ?: throw IllegalStateException("build log file not found in $workingDir")
|
||||
val buildLogSteps = parseTestBuildLog(buildLogFile)
|
||||
val modifications = getModificationsToPerform(testDir,
|
||||
moduleNames = null,
|
||||
allowNoFilesWithSuffixInTestData = false,
|
||||
touchPolicy = TouchPolicy.CHECKSUM)
|
||||
|
||||
assert(modifications.size == buildLogSteps.size) {
|
||||
"Modifications count (${modifications.size}) != expected build log steps count (${buildLogSteps.size})"
|
||||
}
|
||||
|
||||
// Sometimes error messages differ.
|
||||
// This needs to be fixed, but it does not really matter much (e.g extra lines),
|
||||
// The workaround is to compare logs without errors, then logs with errors.
|
||||
// (if logs without errors differ then either compiled files differ or exit codes differ)
|
||||
val expectedSB = StringBuilder()
|
||||
val actualSB = StringBuilder()
|
||||
val expectedSBWithoutErrors = StringBuilder()
|
||||
val actualSBWithoutErrors = StringBuilder()
|
||||
var step = 1
|
||||
for ((modificationStep, buildLogStep) in modifications.zip(buildLogSteps)) {
|
||||
modificationStep.forEach { it.perform(workingDir, mapWorkingToOriginalFile) }
|
||||
val (exitCode, compiledSources, compileErrors) = make(cacheDir, sourceRoots, args)
|
||||
|
||||
expectedSB.appendLine(stepLogAsString(step, buildLogStep.compiledKotlinFiles, buildLogStep.compileErrors))
|
||||
expectedSBWithoutErrors.appendLine(stepLogAsString(step, buildLogStep.compiledKotlinFiles, buildLogStep.compileErrors, includeErrors = false))
|
||||
actualSB.appendLine(stepLogAsString(step, compiledSources.relativePaths(), compileErrors))
|
||||
actualSBWithoutErrors.appendLine(stepLogAsString(step, compiledSources.relativePaths(), compileErrors, includeErrors = false))
|
||||
step++
|
||||
}
|
||||
|
||||
if (expectedSBWithoutErrors.toString() != actualSBWithoutErrors.toString()) {
|
||||
assertEquals(expectedSB.toString(), actualSB.toString())
|
||||
}
|
||||
|
||||
// todo: also compare caches
|
||||
run rebuildAndCompareOutput@ {
|
||||
val rebuildOutDir = File(workingDir, "rebuild-out").apply { mkdirs() }
|
||||
val rebuildCacheDir = File(workingDir, "rebuild-cache").apply { mkdirs() }
|
||||
args.destination = rebuildOutDir.path
|
||||
val rebuildResult = make(rebuildCacheDir, sourceRoots, args)
|
||||
|
||||
val rebuildExpectedToSucceed = buildLogSteps.last().compileSucceeded
|
||||
val rebuildSucceeded = rebuildResult.exitCode == ExitCode.OK
|
||||
assertEquals("Rebuild exit code differs from incremental exit code", rebuildExpectedToSucceed, rebuildSucceeded)
|
||||
|
||||
if (rebuildSucceeded) {
|
||||
assertEqualDirectories(outDir, rebuildOutDir, forgiveExtraFiles = rebuildSucceeded)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun compileClasspath(): String {
|
||||
val currentClasspath = System.getProperty("java.class.path").split(File.pathSeparator)
|
||||
val stdlib = currentClasspath.find { it.contains("kotlin-stdlib") }
|
||||
val runtime = currentClasspath.find { it.contains("kotlin-runtime") }
|
||||
return listOf(stdlib, runtime).joinToString(File.pathSeparator)
|
||||
}
|
||||
|
||||
data class CompilationResult(val exitCode: ExitCode, val compiledSources: Iterable<File>, val compileErrors: Collection<String>)
|
||||
|
||||
private fun make(cacheDir: File, sourceRoots: Iterable<File>, args: K2JVMCompilerArguments): CompilationResult {
|
||||
val compiledSources = arrayListOf<File>()
|
||||
var resultExitCode = ExitCode.OK
|
||||
|
||||
val reporter = object : ICReporter() {
|
||||
override fun report(message: ()->String) {
|
||||
}
|
||||
|
||||
override fun reportCompileIteration(sourceFiles: Iterable<File>, exitCode: ExitCode) {
|
||||
compiledSources.addAll(sourceFiles)
|
||||
resultExitCode = exitCode
|
||||
}
|
||||
}
|
||||
|
||||
val messageCollector = ErrorMessageCollector()
|
||||
makeIncrementally(cacheDir, sourceRoots, args, reporter = reporter, messageCollector = messageCollector)
|
||||
return CompilationResult(resultExitCode, compiledSources, messageCollector.errors)
|
||||
}
|
||||
|
||||
private fun stepLogAsString(step: Int, ktSources: Iterable<String>, errors: Collection<String>, includeErrors: Boolean = true): String {
|
||||
val sb = StringBuilder()
|
||||
|
||||
sb.appendLine("<======= STEP $step =======>")
|
||||
sb.appendLine()
|
||||
sb.appendLine("Compiled kotlin sources:")
|
||||
ktSources.toSet().toTypedArray().sortedArray().forEach { sb.appendLine(it) }
|
||||
sb.appendLine()
|
||||
|
||||
if (errors.isEmpty()) {
|
||||
sb.appendLine("SUCCESS")
|
||||
}
|
||||
else {
|
||||
sb.appendLine("FAILURE")
|
||||
if (includeErrors) {
|
||||
errors.filter(String::isNotEmpty).forEach { sb.appendLine(it) }
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
private fun StringBuilder.appendLine(line: String = "") {
|
||||
append(line)
|
||||
append('\n')
|
||||
}
|
||||
|
||||
private class ErrorMessageCollector : MessageCollector {
|
||||
val errors = ArrayList<String>()
|
||||
|
||||
override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageLocation) {
|
||||
if (severity.isError) {
|
||||
errors.add(message)
|
||||
}
|
||||
}
|
||||
|
||||
override fun clear() {
|
||||
errors.clear()
|
||||
}
|
||||
|
||||
override fun hasErrors(): Boolean =
|
||||
errors.isNotEmpty()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val jpsResourcesPath = File("jps-plugin/testData/incremental")
|
||||
private val ignoredDirs = setOf(File(jpsResourcesPath, "cacheVersionChanged"),
|
||||
File(jpsResourcesPath, "changeIncrementalOption"),
|
||||
File(jpsResourcesPath, "custom"),
|
||||
File(jpsResourcesPath, "lookupTracker"))
|
||||
private val buildLogFinder = BuildLogFinder(isExperimentalEnabled = true, isGradleEnabled = true)
|
||||
|
||||
@Suppress("unused")
|
||||
@Parameterized.Parameters(name = "{1}")
|
||||
@JvmStatic
|
||||
fun data(): List<Array<*>> {
|
||||
fun File.isValidTestDir(): Boolean {
|
||||
if (!isDirectory) return false
|
||||
|
||||
// multi-module tests
|
||||
val files = list()
|
||||
if ("dependencies.txt" in files) return false
|
||||
|
||||
val logFile = buildLogFinder.findBuildLog(this) ?: return false
|
||||
val parsedLog = parseTestBuildLog(logFile)
|
||||
// tests with java may be expected to fail in javac
|
||||
return files.none { it.endsWith(".java") } && parsedLog.all { it.compiledJavaFiles.isEmpty() }
|
||||
}
|
||||
|
||||
fun File.relativeToGrandfather() =
|
||||
relativeTo(parentFile.parentFile).path
|
||||
|
||||
return jpsResourcesPath.walk()
|
||||
.onEnter { it !in ignoredDirs }
|
||||
.filter(File::isValidTestDir)
|
||||
.map { arrayOf(it, it.relativeToGrandfather()) }
|
||||
.toList()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
package org.jetbrains.kotlin.incremental.snapshots
|
||||
|
||||
import org.jetbrains.kotlin.TestWithWorkingDir
|
||||
import org.junit.After
|
||||
import org.junit.Assert.*
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import java.io.File
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
class FileSnapshotMapTest : TestWithWorkingDir() {
|
||||
private var snapshotMap: FileSnapshotMap by Delegates.notNull()
|
||||
|
||||
@Before
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
val caches = File(workingDir, "caches").apply { mkdirs() }
|
||||
val snapshotMapFile = File(caches, "snapshots.tab")
|
||||
snapshotMap = FileSnapshotMap(snapshotMapFile)
|
||||
}
|
||||
|
||||
@After
|
||||
override fun tearDown() {
|
||||
snapshotMap.flush(false)
|
||||
snapshotMap.close()
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSnapshotMap() {
|
||||
val src = File(workingDir, "src").apply { mkdirs() }
|
||||
val foo = File(src, "foo").apply { mkdirs() }
|
||||
|
||||
val removedTxt = File(foo, "removed.txt").apply { writeText("removed") }
|
||||
val unchangedTxt = File(foo, "unchanged.txt").apply { writeText("unchanged") }
|
||||
val changedTxt = File(foo, "changed.txt").apply { writeText("changed") }
|
||||
|
||||
val diff1 = snapshotMap.compareAndUpdate(src.filesWithExt("txt"))
|
||||
|
||||
assertArrayEquals("diff1.removed",
|
||||
diff1.removed.toSortedPaths(),
|
||||
emptyArray<String>())
|
||||
assertArrayEquals("diff1.newOrModified",
|
||||
diff1.modified.toSortedPaths(),
|
||||
listOf(removedTxt, unchangedTxt, changedTxt).toSortedPaths())
|
||||
|
||||
removedTxt.delete()
|
||||
unchangedTxt.writeText("unchanged")
|
||||
changedTxt.writeText("degnahc")
|
||||
val newTxt = File(foo, "new.txt").apply { writeText("new") }
|
||||
|
||||
val diff2 = snapshotMap.compareAndUpdate(src.filesWithExt("txt"))
|
||||
assertArrayEquals("diff2.removed",
|
||||
diff2.removed.toSortedPaths(),
|
||||
listOf(removedTxt).toSortedPaths())
|
||||
assertArrayEquals("diff2.newOrModified",
|
||||
diff2.modified.toSortedPaths(),
|
||||
listOf(newTxt, changedTxt).toSortedPaths())
|
||||
}
|
||||
|
||||
private fun Iterable<File>.toSortedPaths(): Array<String> =
|
||||
map { it.canonicalPath }.sorted().toTypedArray()
|
||||
|
||||
private fun File.filesWithExt(ext: String): Iterable<File> =
|
||||
walk().filter { it.isFile && it.extension.equals(ext, ignoreCase = true) }.toList()
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
package org.jetbrains.kotlin.incremental.snapshots
|
||||
|
||||
import org.jetbrains.kotlin.TestWithWorkingDir
|
||||
import org.junit.Assert.*
|
||||
import org.junit.Test
|
||||
import java.io.*
|
||||
|
||||
class FileSnapshotTest : TestWithWorkingDir() {
|
||||
private val fileSnapshotProvider: FileSnapshotProvider
|
||||
get() = SimpleFileSnapshotProviderImpl()
|
||||
|
||||
@Test
|
||||
fun testExternalizer() {
|
||||
val file = File(workingDir, "1.txt")
|
||||
file.writeText("test")
|
||||
val snapshot = fileSnapshotProvider[file]
|
||||
val deserializedSnapshot = saveAndReadBack(snapshot)
|
||||
assertEquals(snapshot, deserializedSnapshot)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testEqualityNoChanges() {
|
||||
val file = File(workingDir, "1.txt").apply { writeText("file") }
|
||||
val oldSnapshot = fileSnapshotProvider[file]
|
||||
val newSnapshot = fileSnapshotProvider[file]
|
||||
assertEquals(oldSnapshot, newSnapshot)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testEqualityDifferentFile() {
|
||||
val file1 = File(workingDir, "1.txt").apply { writeText("file1") }
|
||||
val file2 = File(workingDir, "2.txt").apply {
|
||||
writeText(file1.readText())
|
||||
setLastModified(file1.lastModified())
|
||||
}
|
||||
val oldSnapshot = fileSnapshotProvider[file1]
|
||||
val newSnapshot = fileSnapshotProvider[file2]
|
||||
assertNotEquals(oldSnapshot, newSnapshot)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testEqualityDifferentTimestamp() {
|
||||
val text = "file"
|
||||
val file = File(workingDir, "1.txt").apply { writeText(text) }
|
||||
val oldSnapshot = fileSnapshotProvider[file]
|
||||
Thread.sleep(1000)
|
||||
file.writeText(text)
|
||||
val newSnapshot = fileSnapshotProvider[file]
|
||||
assertEquals(oldSnapshot, newSnapshot)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testEqualityDifferentSize() {
|
||||
val file = File(workingDir, "1.txt").apply { writeText("file") }
|
||||
val oldSnapshot = fileSnapshotProvider[file]
|
||||
file.writeText("file modified")
|
||||
val newSnapshot = fileSnapshotProvider[file]
|
||||
assertNotEquals(oldSnapshot, newSnapshot)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testEqualityDifferentHash() {
|
||||
val file = File(workingDir, "1.txt").apply { writeText("file") }
|
||||
val oldSnapshot = fileSnapshotProvider[file]
|
||||
file.writeText("main")
|
||||
val newSnapshot = fileSnapshotProvider[file]
|
||||
assertNotEquals(oldSnapshot, newSnapshot)
|
||||
}
|
||||
|
||||
private fun saveAndReadBack(snapshot: FileSnapshot): FileSnapshot {
|
||||
val byteOut = ByteArrayOutputStream()
|
||||
DataOutputStream(byteOut).use { FileSnapshotExternalizer.save(it, snapshot) }
|
||||
val byteIn = ByteArrayInputStream(byteOut.toByteArray())
|
||||
return DataInputStream(byteIn).use { FileSnapshotExternalizer.read(it) }
|
||||
}
|
||||
}
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.incremental
|
||||
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import java.io.File
|
||||
|
||||
private const val BEGIN_COMPILED_FILES = "Compiling files:"
|
||||
private const val END_COMPILED_FILES = "End of files"
|
||||
private const val BEGIN_ERRORS = "COMPILATION FAILED"
|
||||
|
||||
class BuildStep(
|
||||
val compiledKotlinFiles: MutableSet<String> = hashSetOf(),
|
||||
val compiledJavaFiles: MutableSet<String> = hashSetOf(),
|
||||
val compileErrors: MutableList<String> = arrayListOf()
|
||||
) {
|
||||
val compileSucceeded: Boolean
|
||||
get() = compileErrors.isEmpty()
|
||||
}
|
||||
|
||||
fun parseTestBuildLog(file: File): List<BuildStep> {
|
||||
fun splitSteps(lines: List<String>): List<List<String>> {
|
||||
val stepsLines = mutableListOf<MutableList<String>>()
|
||||
|
||||
for (line in lines) {
|
||||
when {
|
||||
line.matches("=+ Step #\\d+ =+".toRegex()) -> {
|
||||
stepsLines.add(mutableListOf())
|
||||
}
|
||||
else -> {
|
||||
stepsLines.lastOrNull()?.add(line)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return stepsLines
|
||||
}
|
||||
|
||||
fun BuildStep.parseStepCompiledFiles(stepLines: List<String>) {
|
||||
var readFiles = false
|
||||
|
||||
for (line in stepLines) {
|
||||
if (line.startsWith(BEGIN_COMPILED_FILES)) {
|
||||
readFiles = true
|
||||
continue
|
||||
}
|
||||
|
||||
if (readFiles && line.startsWith(END_COMPILED_FILES)) {
|
||||
readFiles = false
|
||||
continue
|
||||
}
|
||||
|
||||
if (readFiles) {
|
||||
val path = FileUtil.normalize(line.trim())
|
||||
|
||||
if (path.endsWith(".kt")) {
|
||||
compiledKotlinFiles.add(path)
|
||||
}
|
||||
else if (path.endsWith(".java")) {
|
||||
compiledJavaFiles.add(path)
|
||||
}
|
||||
else {
|
||||
throw IllegalStateException("Expected .kt or .java file, got: $path")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun BuildStep.parseErrors(stepLines: List<String>) {
|
||||
val startIndex = stepLines.indexOfLast { it.startsWith(BEGIN_ERRORS) }
|
||||
|
||||
if (startIndex > 0) {
|
||||
compileErrors.addAll(stepLines.subList(startIndex + 1, stepLines.size))
|
||||
}
|
||||
}
|
||||
|
||||
val stepsLines = splitSteps(file.readLines())
|
||||
|
||||
|
||||
return stepsLines.map { stepLines ->
|
||||
val buildStep = BuildStep()
|
||||
buildStep.parseStepCompiledFiles(stepLines)
|
||||
buildStep.parseErrors(stepLines)
|
||||
buildStep
|
||||
}
|
||||
}
|
||||
|
||||
// used in gradle integration tests
|
||||
@Suppress("unused")
|
||||
fun dumpBuildLog(buildSteps: Iterable<BuildStep>): String {
|
||||
val sb = StringBuilder()
|
||||
|
||||
for ((i, step) in buildSteps.withIndex()) {
|
||||
if (i > 0) {
|
||||
sb.appendln()
|
||||
}
|
||||
|
||||
sb.appendln("================ Step #${i+1} =================")
|
||||
sb.appendln()
|
||||
sb.appendln(BEGIN_COMPILED_FILES)
|
||||
step.compiledKotlinFiles.sorted().forEach { sb.appendln(it) }
|
||||
step.compiledJavaFiles.sorted().forEach { sb.appendln(it) }
|
||||
sb.appendln(END_COMPILED_FILES)
|
||||
sb.appendln("------------------------------------------")
|
||||
|
||||
if (!step.compileSucceeded) {
|
||||
sb.appendln(BEGIN_ERRORS)
|
||||
step.compileErrors.forEach { sb.appendln(it) }
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString()
|
||||
}
|
||||
Reference in New Issue
Block a user