From a339e7af198294324494dcdafe86e9bbeb291370 Mon Sep 17 00:00:00 2001 From: Sergey Rostov Date: Thu, 9 Jan 2020 11:38:42 +0300 Subject: [PATCH] build.gradle.kts: tests and docs for LastModifiedFiles collection --- .../gradle/GradleScriptInputsWatcher.kt | 38 ++-------- .../scripting/gradle/LastModifiedFiles.kt | 43 +++++++++++ .../scripting/gradle/LastModifiedFilesTest.kt | 75 +++++++++++++++++++ 3 files changed, 125 insertions(+), 31 deletions(-) create mode 100644 idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/LastModifiedFiles.kt create mode 100644 idea/idea-gradle/tests/org/jetbrains/kotlin/idea/scripting/gradle/LastModifiedFilesTest.kt diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptInputsWatcher.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptInputsWatcher.kt index c47fd2dfc47..a80dae808b6 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptInputsWatcher.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptInputsWatcher.kt @@ -14,6 +14,8 @@ import com.intellij.openapi.vfs.newvfs.BulkFileListener import com.intellij.openapi.vfs.newvfs.events.VFileEvent import com.intellij.util.PathUtil import org.jetbrains.annotations.TestOnly +import org.junit.Assert.assertEquals +import org.junit.Test @State( name = "KotlinBuildScriptsModificationInfo", @@ -44,43 +46,17 @@ class GradleScriptInputsWatcher(val project: Project) : PersistentStateComponent return storage.lastModifiedTimeStampExcept(file) < timeStamp } - class Storage( - private var lastModifiedTS: Long = 0, - private var lastModifiedFiles: MutableSet = hashSetOf(), - private var previousModifiedTS: Long = 0, - private var previousModifiedFiles: MutableSet = hashSetOf() - ) { + class Storage { + private val lastModifiedFiles = LastModifiedFiles() + fun lastModifiedTimeStampExcept(file: VirtualFile): Long { val fileId = getFileId(file) - synchronized(this) { - if (lastModifiedFiles.contains(fileId) && lastModifiedFiles.size == 1) { - return previousModifiedTS - } - return lastModifiedTS - } - + return lastModifiedFiles.lastModifiedTimeStampExcept(fileId) } fun fileChanged(file: VirtualFile, ts: Long) { val fileId = getFileId(file) - synchronized(this) { - when { - ts > lastModifiedTS -> { - previousModifiedFiles = lastModifiedFiles - previousModifiedTS = lastModifiedTS - - lastModifiedFiles = hashSetOf(fileId) - lastModifiedTS = ts - } - ts == lastModifiedTS -> { - lastModifiedFiles.add(fileId) - } - ts == previousModifiedTS -> { - previousModifiedFiles.add(fileId) - } - else -> {} - } - } + lastModifiedFiles.fileChanged(ts, fileId) } private fun getFileId(file: VirtualFile): String { diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/LastModifiedFiles.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/LastModifiedFiles.kt new file mode 100644 index 00000000000..c4b18e8a559 --- /dev/null +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/LastModifiedFiles.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.scripting.gradle + +/** + * Optimized collection for storing last modified files with ability to + * get time of last modified file expect given one ([lastModifiedTimeStampExcept]). + * + * This is required since Gradle scripts configurations should be updated on + * each other script changes (but not on the given script changes itself). + * + * Actually works by storing two last timestamps with the set of files modified at this times. + */ +class LastModifiedFiles { + private var last: SimultaneouslyChangedFiles = SimultaneouslyChangedFiles() + private var previous: SimultaneouslyChangedFiles = SimultaneouslyChangedFiles() + + class SimultaneouslyChangedFiles( + val ts: Long = Long.MIN_VALUE, + val fileIds: MutableSet = mutableSetOf() + ) + + @Synchronized + fun fileChanged(ts: Long, fileId: String) { + when { + ts > last.ts -> { + previous = last + last = SimultaneouslyChangedFiles(ts, hashSetOf(fileId)) + } + ts == last.ts -> last.fileIds.add(fileId) + ts == previous.ts -> previous.fileIds.add(fileId) + } + } + + @Synchronized + fun lastModifiedTimeStampExcept(fileId: String): Long = when { + last.fileIds.size == 1 && last.fileIds.contains(fileId) -> previous.ts + else -> last.ts + } +} \ No newline at end of file diff --git a/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/scripting/gradle/LastModifiedFilesTest.kt b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/scripting/gradle/LastModifiedFilesTest.kt new file mode 100644 index 00000000000..059394a37e8 --- /dev/null +++ b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/scripting/gradle/LastModifiedFilesTest.kt @@ -0,0 +1,75 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.scripting.gradle + +import org.junit.Test +import kotlin.test.assertEquals + +class LastModifiedFilesTest { + val files = LastModifiedFiles() + + @Test + fun testSimple0() { + assertEquals(Long.MIN_VALUE, files.lastModifiedTimeStampExcept("x")) + } + + @Test + fun testSimple1() { + files.fileChanged(1, "x") + assertEquals(Long.MIN_VALUE, files.lastModifiedTimeStampExcept("x")) + assertEquals(1, files.lastModifiedTimeStampExcept("y")) + } + + @Test + fun testSimple2() { + files.fileChanged(1, "x") + files.fileChanged(2, "y") + assertEquals(2, files.lastModifiedTimeStampExcept("x")) + assertEquals(1, files.lastModifiedTimeStampExcept("y")) + } + + @Test + fun testSimple3() { + files.fileChanged(1, "x") + files.fileChanged(2, "y") + files.fileChanged(3, "z") + assertEquals(3, files.lastModifiedTimeStampExcept("x")) + assertEquals(3, files.lastModifiedTimeStampExcept("y")) + assertEquals(2, files.lastModifiedTimeStampExcept("z")) + } + + @Test + fun testSame2() { + files.fileChanged(1, "x") + files.fileChanged(1, "y") + assertEquals(1, files.lastModifiedTimeStampExcept("x")) + assertEquals(1, files.lastModifiedTimeStampExcept("y")) + } + + @Test + fun testSame3() { + files.fileChanged(1, "x") + files.fileChanged(1, "y") + files.fileChanged(2, "z") + assertEquals(2, files.lastModifiedTimeStampExcept("x")) + assertEquals(2, files.lastModifiedTimeStampExcept("y")) + assertEquals(1, files.lastModifiedTimeStampExcept("z")) + } + + @Test + fun testSame4() { + files.fileChanged(1, "x") + files.fileChanged(1, "y") + files.fileChanged(2, "z") + files.fileChanged(3, "a") + files.fileChanged(3, "b") + assertEquals(3, files.lastModifiedTimeStampExcept("x")) + assertEquals(3, files.lastModifiedTimeStampExcept("y")) + assertEquals(3, files.lastModifiedTimeStampExcept("z")) + assertEquals(3, files.lastModifiedTimeStampExcept("a")) + assertEquals(3, files.lastModifiedTimeStampExcept("b")) + } +} \ No newline at end of file