From be44db7bd39cebac03b4a87de350ecb9a5e60712 Mon Sep 17 00:00:00 2001 From: Alexey Tsvetkov Date: Tue, 16 Feb 2016 22:50:16 +0300 Subject: [PATCH] Rebuild and compare output class files in gradle incremental tests KT-8487 --- .../testingUtils/classFilesComparison.kt | 8 +-- libraries/pom.xml | 1 + .../tools/kotlin-build-common-test/pom.xml | 49 +++++++++++++++++++ .../jetbrains/kotlin/gradle/tasks/Tasks.kt | 25 ++++++++++ libraries/tools/kotlin-gradle-plugin/pom.xml | 6 +++ .../kotlin/gradle/BaseIncrementalGradleIT.kt | 21 +++++++- 6 files changed, 105 insertions(+), 5 deletions(-) create mode 100644 libraries/tools/kotlin-build-common-test/pom.xml diff --git a/build-common/test/org/jetbrains/kotlin/incremental/testingUtils/classFilesComparison.kt b/build-common/test/org/jetbrains/kotlin/incremental/testingUtils/classFilesComparison.kt index df823f730cf..6fc36e55bc6 100644 --- a/build-common/test/org/jetbrains/kotlin/incremental/testingUtils/classFilesComparison.kt +++ b/build-common/test/org/jetbrains/kotlin/incremental/testingUtils/classFilesComparison.kt @@ -82,13 +82,15 @@ private fun getDirectoryString(dir: File, interestingPaths: List): Strin p.pushIndent() val listFiles = dir.listFiles() - assertNotNull(listFiles) + assertNotNull("$dir does not exist", listFiles) val children = listFiles!!.sortedWith(compareBy({ it.isDirectory }, { it.name })) for (child in children) { if (child.isDirectory) { - p.println(child.name) - addDirContent(child) + if ((child.list()?.isNotEmpty() ?: false)) { + p.println(child.name) + addDirContent(child) + } } else { p.println(child.name, " ", child.hash()) diff --git a/libraries/pom.xml b/libraries/pom.xml index 5bc09764a7a..d0337dec091 100644 --- a/libraries/pom.xml +++ b/libraries/pom.xml @@ -74,6 +74,7 @@ tools/kotlin-compiler tools/kotlin-compiler-embeddable tools/kotlin-build-common + tools/kotlin-build-common-test tools/kotlin-maven-plugin tools/runtime diff --git a/libraries/tools/kotlin-build-common-test/pom.xml b/libraries/tools/kotlin-build-common-test/pom.xml new file mode 100644 index 00000000000..83fe30596a6 --- /dev/null +++ b/libraries/tools/kotlin-build-common-test/pom.xml @@ -0,0 +1,49 @@ + + + + 4.0.0 + + 1.4.1 + 3.0.4 + + + + org.jetbrains.kotlin + kotlin-project + 0.1-SNAPSHOT + ../../pom.xml + + + kotlin-build-common-test + jar + + Testing utils (for incremental compilation mostly) + + + + + org.apache.maven.plugins + maven-antrun-plugin + + + copy-jar + package + + + + + + + run + + + + + + + + diff --git a/libraries/tools/kotlin-gradle-plugin-core/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt b/libraries/tools/kotlin-gradle-plugin-core/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt index d664aee30c6..4bd40547fb6 100644 --- a/libraries/tools/kotlin-gradle-plugin-core/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt +++ b/libraries/tools/kotlin-gradle-plugin-core/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt @@ -55,6 +55,8 @@ val ANNOTATIONS_PLUGIN_NAME = "org.jetbrains.kotlin.kapt" abstract class AbstractKotlinCompile() : AbstractCompile() { abstract protected val compiler: CLICompiler abstract protected fun createBlankArgs(): T + open protected fun beforeCompileHook(args: T) { + } open protected fun afterCompileHook(args: T) { } abstract protected fun populateTargetSpecificArgs(args: T) @@ -98,6 +100,7 @@ abstract class AbstractKotlinCompile() : AbstractCo populateTargetSpecificArgs(args) compilerCalled = true val cachesDir = File(project.buildDir, "kotlin-caches") + beforeCompileHook(args) callCompiler(args, sources, inputs.isIncremental, modified, removed, cachesDir) afterCompileHook(args) } @@ -138,6 +141,7 @@ abstract class AbstractKotlinCompile() : AbstractCo open class KotlinCompile() : AbstractKotlinCompile() { override val compiler = K2JVMCompiler() override fun createBlankArgs(): K2JVMCompilerArguments = K2JVMCompilerArguments() + private val kotlinClassFiles = HashSet() // Should be SourceDirectorySet or File val srcDirsSources = HashSet() @@ -500,6 +504,10 @@ open class KotlinCompile() : AbstractKotlinCompile() { private fun File.isJavaFile() = extension.equals(JavaFileType.INSTANCE.defaultExtension, ignoreCase = true) + override fun beforeCompileHook(args: K2JVMCompilerArguments) { + kotlinClassFiles.addAll(listClassFiles(compilerDestinationDir)) + } + override fun afterCompileHook(args: K2JVMCompilerArguments) { logger.debug("Copying resulting files to classes") @@ -508,6 +516,20 @@ open class KotlinCompile() : AbstractKotlinCompile() { if (outputDirFile.exists()) { FileUtils.copyDirectory(outputDirFile, destinationDir) } + + kotlinClassFiles.removeAll(listClassFiles(outputDirPath)) + if (kotlinClassFiles.isNotEmpty()) { + // some classes were removed during compilation + val filesToRemove = kotlinClassFiles.map { + val relativePath = it.relativeTo(outputDirFile).path + File(destinationDir, relativePath) + } + + val notRemoved = filesToRemove.filter { !it.delete() } + if (notRemoved.isNotEmpty()) { + logger.kotlinDebug("Could not delete classfiles: $notRemoved") + } + } } // override setSource to track source directory sets and files (for generated android folders) @@ -679,3 +701,6 @@ internal fun Logger.kotlinInfo(message: String) { internal fun Logger.kotlinDebug(message: String) { this.debug("[KOTLIN] $message") } + +internal fun listClassFiles(path: String): Sequence = + File(path).walk().filter { it.isFile && it.extension.toLowerCase() == "class" } diff --git a/libraries/tools/kotlin-gradle-plugin/pom.xml b/libraries/tools/kotlin-gradle-plugin/pom.xml index b3f7e32c57c..9159bf56592 100644 --- a/libraries/tools/kotlin-gradle-plugin/pom.xml +++ b/libraries/tools/kotlin-gradle-plugin/pom.xml @@ -58,6 +58,12 @@ ${project.version} test + + org.jetbrains.kotlin + kotlin-build-common-test + ${project.version} + test + diff --git a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/BaseIncrementalGradleIT.kt b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/BaseIncrementalGradleIT.kt index 30636cfa0e6..0f14ed1c781 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/BaseIncrementalGradleIT.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/BaseIncrementalGradleIT.kt @@ -4,10 +4,12 @@ import org.gradle.api.logging.LogLevel import org.jetbrains.kotlin.gradle.incremental.BuildStep import org.jetbrains.kotlin.gradle.incremental.parseTestBuildLog import org.jetbrains.kotlin.incremental.testingUtils.TouchPolicy +import org.jetbrains.kotlin.incremental.testingUtils.assertEqualDirectories import org.jetbrains.kotlin.incremental.testingUtils.copyTestSources import org.jetbrains.kotlin.incremental.testingUtils.getModificationsToPerform import org.junit.Assume import java.io.File +import kotlin.test.assertEquals import kotlin.test.assertNotNull abstract class BaseIncrementalGradleIT : BaseGradleIT() { @@ -55,14 +57,15 @@ abstract class BaseIncrementalGradleIT : BaseGradleIT() { println("<--- Expected build log stage: ${if (it.compileSucceeded) "succeeded" else "failed"}: kotlin: ${it.compiledKotlinFiles} java: ${it.compiledJavaFiles}") } - for ((modificationStep, buildLogStep) in modifications.zip(buildLogSteps)) { modificationStep.forEach { it.perform(projectDir, mapWorkingToOriginalFile) } buildAndAssertStageResults(buildLogStep, weakTesting = weakTesting) } + + rebuildAndCompareOutput(rebuildSucceedExpected = buildLogSteps.last().compileSucceeded) } - fun JpsTestProject.buildAndAssertStageResults(expected: BuildStep, options: BuildOptions = defaultBuildOptions(), weakTesting: Boolean = false) { + private fun JpsTestProject.buildAndAssertStageResults(expected: BuildStep, options: BuildOptions = defaultBuildOptions(), weakTesting: Boolean = false) { build("build", options = options) { if (expected.compileSucceeded) { assertSuccessful() @@ -74,6 +77,20 @@ abstract class BaseIncrementalGradleIT : BaseGradleIT() { } } } + + private fun JpsTestProject.rebuildAndCompareOutput(rebuildSucceedExpected: Boolean) { + val outDir = File(File(projectDir, "build"), "classes") + val incrementalOutDir = File(workingDir, "kotlin-classes-incremental") + incrementalOutDir.mkdirs() + copyDirRecursively(outDir, incrementalOutDir) + + build("clean", "build") { + val rebuildSucceed = resultCode == 0 + assertEquals(rebuildSucceed, rebuildSucceedExpected, "Rebuild exit code differs from incremental exit code") + outDir.mkdirs() + assertEqualDirectories(outDir, incrementalOutDir, forgiveExtraFiles = !rebuildSucceed) + } + } } fun isJpsTestProject(projectRoot: File): Boolean = projectRoot.listFiles { f: File -> f.name.endsWith("build.log") }?.any() ?: false