diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt index 55c7edc6bb0..7264946b685 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt @@ -185,9 +185,10 @@ class KotlinCoreEnvironment private constructor( scriptDefinitionProvider.setScriptDefinitions( configuration.getList(JVMConfigurationKeys.SCRIPT_DEFINITIONS)) - KotlinScriptExternalImportsProvider.getInstance(project)?.run { + KotlinScriptExternalImportsProvider.getInstance(project)?.let { importsProvider -> configuration.addJvmClasspathRoots( - getCombinedClasspathFor(sourceFiles) + sourceFiles.mapNotNull(importsProvider::getExternalImports) + .flatMap { it.classpath } .distinctBy { it.absolutePath }) } } diff --git a/compiler/frontend.script/src/org/jetbrains/kotlin/script/KotlinScriptExternalImportsProviderImpl.kt b/compiler/frontend.script/src/org/jetbrains/kotlin/script/KotlinScriptExternalImportsProviderImpl.kt index 39b8c83da6a..9c0a2cace3c 100644 --- a/compiler/frontend.script/src/org/jetbrains/kotlin/script/KotlinScriptExternalImportsProviderImpl.kt +++ b/compiler/frontend.script/src/org/jetbrains/kotlin/script/KotlinScriptExternalImportsProviderImpl.kt @@ -20,8 +20,6 @@ import com.intellij.openapi.components.ServiceManager import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.project.Project import java.io.File -import java.lang.management.ManagementFactory -import java.util.concurrent.TimeUnit import java.util.concurrent.locks.ReentrantReadWriteLock import kotlin.concurrent.read import kotlin.concurrent.write @@ -39,10 +37,6 @@ class KotlinScriptExternalImportsProviderImpl( calculateExternalDependencies(file) } - fun getExternalImports(files: Iterable): List = cacheLock.read { - files.mapNotNull { calculateExternalDependencies(it) } - } - private fun calculateExternalDependencies(file: TF): KotlinScriptExternalDependencies? { val path = getFilePath(file) val cached = cache[path] @@ -62,107 +56,6 @@ class KotlinScriptExternalImportsProviderImpl( } } - // optimized for initial caching, additional handling of possible duplicates to save a call to distinct - // returns list of cached files - override fun cacheExternalImports(files: Iterable): Iterable = cacheLock.write { - var filesCount = 0 - var additionsCount = 0 - val (res, time) = measureThreadTimeMillis { - files.mapNotNull { file -> - filesCount += 1 - val scriptDef = scriptDefinitionProvider.findScriptDefinition(file) - if (scriptDef != null) { - val path = getFilePath(file) - if (isValidFile(file) && !cache.containsKey(path)) { - val deps = scriptDef.getDependenciesFor(file, project, null) - cache.put(path, deps) - if (deps != null) { - log.info("[kts] cached deps for $path: ${deps.classpath.joinToString(File.pathSeparator)}") - additionsCount += 1 - file - } - else null - } - else null - } - else null - } - } - log.info("[kts] cache creation: $filesCount checked, $additionsCount added (in ${time}ms)") - res - } - - // optimized for update, no special duplicates handling - // returns files with valid script definition (or deleted from cache - which in fact should have script def too) - // TODO: this is the badly designed contract, since it mixes the entities, but these files are needed on the calling site now. Find out other solution - override fun updateExternalImportsCache(files: Iterable): Iterable = cacheLock.write { - var filesCount = 0 - var updatesCount = 0 - val (res, time) = measureThreadTimeMillis { - files.mapNotNull { file -> - filesCount += 1 - val scriptDef = scriptDefinitionProvider.findScriptDefinition(file) - if (scriptDef != null) { - val path = getFilePath(file) - if (!isValidFile(file)) { - if (cache.remove(path) != null) { - log.debug("[kts] removed deps for file $path") - updatesCount += 1 - file - } // cleared - else null // unknown - } - else { - val oldDeps = cache[path] - val deps = scriptDef.getDependenciesFor(file, project, oldDeps) - when { - deps != null && (oldDeps == null || - !deps.classpath.isSamePathListAs(oldDeps.classpath) || !deps.sources.isSamePathListAs(oldDeps.sources)) -> { - // changed or new - log.info("[kts] updated/new cached deps for $path: ${deps.classpath.joinToString(File.pathSeparator)}") - cache.put(path, deps) - updatesCount += 1 - file - } - deps != null -> { - // same as before - null - } - cache.remove(path) != null -> { - log.debug("[kts] removed deps for $path") - updatesCount += 1 - file - } - else -> null // unknown - } - } - } - else null // not a script - } - } - if (updatesCount > 0) { - log.info("[kts] cache update check: $filesCount checked, $updatesCount updated (in ${time}ms)") - } - res - } - - override fun invalidateCaches() { - cacheLock.write(cache::clear) - } - - override fun getKnownCombinedClasspath(): List = cacheLock.read { - cache.values.flatMap { it?.classpath ?: emptyList() } - }.distinct() - - override fun getKnownSourceRoots(): List = cacheLock.read { - cache.values.flatMap { it?.sources ?: emptyList() } - }.distinct() - - override fun getCombinedClasspathFor(files: Iterable): List = - getExternalImports(files) - .flatMap { it.classpath } - .distinct() - companion object { @JvmStatic fun getInstance(project: Project): KotlinScriptExternalImportsProvider? = @@ -170,18 +63,3 @@ class KotlinScriptExternalImportsProviderImpl( internal val log = Logger.getInstance(KotlinScriptExternalImportsProvider::class.java) } } - -private fun Iterable.isSamePathListAs(other: Iterable): Boolean = - with (Pair(iterator(), other.iterator())) { - while (first.hasNext() && second.hasNext()) { - if (first.next().canonicalPath != second.next().canonicalPath) return false - } - !(first.hasNext() || second.hasNext()) - } - -private inline fun measureThreadTimeMillis(body: () -> T): Pair { - val mxBeans = ManagementFactory.getThreadMXBean() - val startTime = mxBeans.currentThreadCpuTime - val res = body() - return res to TimeUnit.NANOSECONDS.toMillis(mxBeans.currentThreadCpuTime - startTime) -} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/script/KotlinScriptExternalImportsProvider.kt b/compiler/frontend/src/org/jetbrains/kotlin/script/KotlinScriptExternalImportsProvider.kt index c736996dc59..42c16e5f4bb 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/script/KotlinScriptExternalImportsProvider.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/script/KotlinScriptExternalImportsProvider.kt @@ -19,23 +19,16 @@ package org.jetbrains.kotlin.script import com.intellij.openapi.components.ServiceManager import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.VirtualFile -import java.io.File import kotlin.script.dependencies.KotlinScriptExternalDependencies interface KotlinScriptExternalImportsProvider { fun getExternalImports(file: TF): KotlinScriptExternalDependencies? - fun cacheExternalImports(files: Iterable): Iterable - fun updateExternalImportsCache(files: Iterable): Iterable - fun invalidateCaches() - fun getKnownCombinedClasspath(): List - fun getKnownSourceRoots(): List - fun getCombinedClasspathFor(files: Iterable): List companion object { - fun getInstance(project: Project): KotlinScriptExternalImportsProvider? = + fun getInstance(project: Project): KotlinScriptExternalImportsProvider = ServiceManager.getService(project, KotlinScriptExternalImportsProvider::class.java) } } fun getScriptExternalDependencies(file: VirtualFile, project: Project): KotlinScriptExternalDependencies? = - KotlinScriptExternalImportsProvider.getInstance(project)?.getExternalImports(file) + KotlinScriptExternalImportsProvider.getInstance(project).getExternalImports(file) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ScriptModuleInfos.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ScriptModuleInfos.kt index c116a995d19..f2c722d714d 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ScriptModuleInfos.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ScriptModuleInfos.kt @@ -44,7 +44,7 @@ data class ScriptModuleInfo(val project: Project, val scriptFile: VirtualFile, get() = ModuleOrigin.OTHER val externalDependencies: KotlinScriptExternalDependencies? - get() = KotlinScriptExternalImportsProvider.getInstance(project)?.getExternalImports(scriptFile) + get() = KotlinScriptConfigurationManager.getInstance(project).getExternalImports(scriptFile) override val name: Name = Name.special("