Introduce ScriptDependenciesFileAttribute to persist script dependencies

This commit is contained in:
Pavel V. Talanov
2017-06-14 16:37:12 +03:00
parent a2aeda7b2c
commit fb0e0e3767
3 changed files with 100 additions and 5 deletions
@@ -17,11 +17,13 @@
package org.jetbrains.kotlin.idea.caches
import com.intellij.openapi.vfs.VirtualFile
import java.io.DataInput
import java.io.DataOutput
data class CachedAttributeData<out T>(val value: T, val timeStamp: Long)
interface FileAttributeService {
fun register(id: String, version: Int) {}
fun register(id: String, version: Int, fixedSize: Boolean = true) {}
fun <T: Enum<T>> writeEnumAttribute(id: String, file: VirtualFile, value: T): CachedAttributeData<T> =
CachedAttributeData(value, timeStamp = file.timeStamp)
@@ -32,4 +34,8 @@ interface FileAttributeService {
CachedAttributeData(value, timeStamp = file.timeStamp)
fun readBooleanAttribute(id: String, file: VirtualFile): CachedAttributeData<Boolean>? = null
fun <T> write(file: VirtualFile, id: String, value: T, writeValueFun: (DataOutput, T) -> Unit): CachedAttributeData<T>
fun <T> read(file: VirtualFile, id: String, readValueFun: (DataInput) -> T): CachedAttributeData<T>?
}
@@ -0,0 +1,89 @@
/*
* Copyright 2010-2017 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.idea.core.script
import com.intellij.openapi.components.service
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.VirtualFileWithId
import com.intellij.util.io.DataInputOutputUtil.readSeq
import com.intellij.util.io.DataInputOutputUtil.writeSeq
import com.intellij.util.io.IOUtil.readUTF
import com.intellij.util.io.IOUtil.writeUTF
import org.jetbrains.kotlin.idea.caches.FileAttributeService
import java.io.DataInput
import java.io.DataOutput
import java.io.File
import kotlin.script.dependencies.KotlinScriptExternalDependencies
// TODO_R: write nullable, write version
object ScriptDependenciesFileAttribute {
private val VERSION = 1
private val ID = "kotlin-script-dependencies"
private val fileAttributeService = service<FileAttributeService>()
init {
fileAttributeService.register(ID, VERSION, false)
}
fun write(virtualFile: VirtualFile, dependencies: KotlinScriptExternalDependencies) {
if (virtualFile !is VirtualFileWithId) return
fileAttributeService.write(virtualFile, ID, dependencies) { output, dep ->
with(dep) {
output.writeFileList(classpath)
output.writeStringList(imports)
// TODO: actually read/write nullable
output.writeString(javaHome ?: "")
output.writeFileList(scripts)
output.writeFileList(sources)
}
}
}
fun read(virtualFile: VirtualFile): KotlinScriptExternalDependencies? {
if (virtualFile !is VirtualFileWithId) return null
return fileAttributeService.read(virtualFile, ID) { input ->
SerializedScriptDependencies(
classpath = input.readFileList(),
imports = input.readStringList(),
javaHome = input.readString(),
scripts = input.readFileList(),
sources = input.readFileList()
)
}?.value
}
}
private fun DataInput.readStringList(): List<String> = readSeq(this) { readString() }
private fun DataInput.readFileList() = readStringList().map { File(it) }
private fun DataInput.readString() = readUTF(this)
private fun DataOutput.writeFileList(iterable: Iterable<File>) = writeSeq(this, iterable.toList()) { writeFile(it) }
private fun DataOutput.writeFile(it: File) = writeString(it.canonicalPath)
private fun DataOutput.writeString(string: String) = writeUTF(this, string)
private fun DataOutput.writeStringList(iterable: Iterable<String>) = writeSeq(this, iterable.toList()) { writeString(it) }
private class SerializedScriptDependencies(
override val classpath: Iterable<File>,
override val imports: Iterable<String>,
override val javaHome: String?,
override val scripts: Iterable<File>,
override val sources: Iterable<File>
) : KotlinScriptExternalDependencies
@@ -26,8 +26,8 @@ import java.io.DataOutput
class FileAttributeServiceImpl : FileAttributeService {
val attributes: MutableMap<String, FileAttribute> = ContainerUtil.newConcurrentMap()
override fun register(id: String, version: Int) {
attributes[id] = FileAttribute(id, version, true)
override fun register(id: String, version: Int, fixedSize: Boolean) {
attributes[id] = FileAttribute(id, version, fixedSize)
}
override fun <T: Enum<T>> writeEnumAttribute(id: String, file: VirtualFile, value: T): CachedAttributeData<T> {
@@ -55,7 +55,7 @@ class FileAttributeServiceImpl : FileAttributeService {
}
}
private inline fun <T> write(file: VirtualFile, id: String, value: T, writeValueFun: (DataOutput, T) -> Unit): CachedAttributeData<T> {
override fun <T> write(file: VirtualFile, id: String, value: T, writeValueFun: (DataOutput, T) -> Unit): CachedAttributeData<T> {
val attribute = attributes[id] ?: throw IllegalArgumentException("Attribute with $id wasn't registered")
val data = CachedAttributeData(value, timeStamp = file.timeStamp)
@@ -68,7 +68,7 @@ class FileAttributeServiceImpl : FileAttributeService {
return data
}
private inline fun <T> read(file: VirtualFile, id: String, readValueFun: (DataInput) -> T): CachedAttributeData<T>? {
override fun <T> read(file: VirtualFile, id: String, readValueFun: (DataInput) -> T): CachedAttributeData<T>? {
val attribute = attributes[id] ?: throw IllegalArgumentException("Attribute with $id wasn't registered")
val stream = attribute.readAttribute(file) ?: return null