From c227fffbe69d8db4ff506c035a58fba3d86a0d58 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Tue, 1 Dec 2015 16:45:59 +0100 Subject: [PATCH] WEB-16337 unprefixed package debug --- .../src/org/jetbrains/io/NettyUtil.java | 2 +- .../jetbrains/debugger/sourcemap/SourceMap.kt | 7 +- .../debugger/sourcemap/SourceResolver.kt | 196 ++++++++---------- .../debugger/connection/RemoteVmConnection.kt | 62 +++--- 4 files changed, 119 insertions(+), 148 deletions(-) diff --git a/platform/platform-impl/src/org/jetbrains/io/NettyUtil.java b/platform/platform-impl/src/org/jetbrains/io/NettyUtil.java index 2926b4e2c683..ffd38062e8c8 100644 --- a/platform/platform-impl/src/org/jetbrains/io/NettyUtil.java +++ b/platform/platform-impl/src/org/jetbrains/io/NettyUtil.java @@ -140,7 +140,7 @@ public final class NettyUtil { break; } catch (IOException e) { - if (stopCondition.value(null) || (promise != null && promise.getState() == Promise.State.REJECTED)) { + if (stopCondition.value(null) || (promise != null && promise.getState() != Promise.State.PENDING)) { return null; } else if (maxAttemptCount == -1) { diff --git a/platform/script-debugger/backend/src/org/jetbrains/debugger/sourcemap/SourceMap.kt b/platform/script-debugger/backend/src/org/jetbrains/debugger/sourcemap/SourceMap.kt index e8a128739057..80128eda7eb7 100644 --- a/platform/script-debugger/backend/src/org/jetbrains/debugger/sourcemap/SourceMap.kt +++ b/platform/script-debugger/backend/src/org/jetbrains/debugger/sourcemap/SourceMap.kt @@ -22,17 +22,14 @@ import com.intellij.util.Url // sources - is not originally specified, but canonicalized/normalized class SourceMap(val outFile: String?, val mappings: MappingList, internal val sourceIndexToMappings: Array, val sourceResolver: SourceResolver, val hasNameMappings: Boolean) { val sources: Array - get() = sourceResolver.canonicalizedSources + get() = sourceResolver.canonicalizedUrls fun getSourceLineByRawLocation(rawLine: Int, rawColumn: Int) = mappings.get(rawLine, rawColumn)?.sourceLine ?: -1 fun findMappingList(sourceUrls: List, sourceFile: VirtualFile?, resolver: NullableLazyValue?): MappingList? { var mappings = sourceResolver.findMappings(sourceUrls, this, sourceFile) if (mappings == null && resolver != null) { - val resolverValue = resolver.value - if (resolverValue != null) { - mappings = sourceResolver.findMappings(sourceFile, this, resolverValue) - } + mappings = resolver.value?.let { sourceResolver.findMappings(sourceFile, this, it) } } return mappings } diff --git a/platform/script-debugger/backend/src/org/jetbrains/debugger/sourcemap/SourceResolver.kt b/platform/script-debugger/backend/src/org/jetbrains/debugger/sourcemap/SourceResolver.kt index 925c9ca00332..2edeccd99557 100644 --- a/platform/script-debugger/backend/src/org/jetbrains/debugger/sourcemap/SourceResolver.kt +++ b/platform/script-debugger/backend/src/org/jetbrains/debugger/sourcemap/SourceResolver.kt @@ -27,62 +27,35 @@ import com.intellij.util.Urls import com.intellij.util.containers.ObjectIntHashMap import com.intellij.util.containers.isNullOrEmpty import com.intellij.util.io.URLUtil -import com.intellij.util.text.CaseInsensitiveStringHashingStrategy -import gnu.trove.TObjectIntHashMap -import org.jetbrains.io.LocalFileFinder +import java.io.File -open class SourceResolver(private val rawSources: List, trimFileScheme: Boolean, baseFileUrl: Url?, private val sourceContents: List?, baseUrlIsFile: Boolean = true) { - private val canonicalizedSourcesMap: ObjectIntHashMap = if (SystemInfo.isFileSystemCaseSensitive) ObjectIntHashMap(rawSources.size) else ObjectIntHashMap(rawSources.size, Urls.getCaseInsensitiveUrlHashingStrategy()) +inline fun SourceResolver(rawSources: List, sourceContents: List?, urlCanonicalizer: (String) -> Url): SourceResolver { + return SourceResolver(rawSources, Array(rawSources.size) { urlCanonicalizer(rawSources[it]) }, sourceContents) +} - internal val canonicalizedSources = Array(rawSources.size) { i -> - val rawSource = rawSources[i] - val url = canonicalizeUrl(rawSource, baseFileUrl, trimFileScheme, i, baseUrlIsFile) - canonicalizedSourcesMap.put(url, i) - url +fun SourceResolver(rawSources: List, + trimFileScheme: Boolean, + baseFileUrl: Url?, sourceContents: List?, + baseUrlIsFile: Boolean = true): SourceResolver { + return SourceResolver(rawSources, sourceContents) { canonicalizeUrl(it, baseFileUrl, trimFileScheme, baseUrlIsFile) } +} + +class SourceResolver(private val rawSources: List, internal val canonicalizedUrls: Array, private val sourceContents: List?) { + private val canonicalizedUrlToSourceIndex: ObjectIntHashMap = if (SystemInfo.isFileSystemCaseSensitive) ObjectIntHashMap(rawSources.size) else ObjectIntHashMap(rawSources.size, Urls.getCaseInsensitiveUrlHashingStrategy()) + + init { + for (i in rawSources.indices) { + canonicalizedUrlToSourceIndex.put(canonicalizedUrls[i], i) + } } - private var absoluteLocalPathToSourceIndex: TObjectIntHashMap? = null - // absoluteLocalPathToSourceIndex contains canonical paths too, but this map contains only used (specified in the source map) path - private var sourceIndexToAbsoluteLocalPath: Array? = null - - // see canonicalizeUri kotlin impl and https://trac.webkit.org/browser/trunk/Source/WebCore/inspector/front-end/ParsedURL.js completeURL - protected open fun canonicalizeUrl(url: String, baseUrl: Url?, trimFileScheme: Boolean, sourceIndex: Int, baseUrlIsFile: Boolean): Url { - if (trimFileScheme && url.startsWith(StandardFileSystems.FILE_PROTOCOL_PREFIX)) { - return Urls.newLocalFileUrl(FileUtil.toCanonicalPath(VfsUtilCore.toIdeaUrl(url, true).substring(StandardFileSystems.FILE_PROTOCOL_PREFIX.length), '/')) - } - else if (baseUrl == null || url.contains(URLUtil.SCHEME_SEPARATOR) || url.startsWith("data:") || url.startsWith("blob:") || url.startsWith("javascript:")) { - return Urls.parseEncoded(url) ?: UrlImpl(url) - } - - val path = canonicalizePath(url, baseUrl, baseUrlIsFile) - if (baseUrl.scheme == null && baseUrl.isInLocalFileSystem) { - return Urls.newLocalFileUrl(path) - } - - // browserify produces absolute path in the local filesystem - if (isAbsolute(path)) { - val file = LocalFileFinder.findFile(path) - if (file != null) { - if (absoluteLocalPathToSourceIndex == null) { - // must be linked, on iterate original path must be first - absoluteLocalPathToSourceIndex = createStringIntMap(rawSources.size) - sourceIndexToAbsoluteLocalPath = arrayOfNulls(rawSources.size) - } - absoluteLocalPathToSourceIndex!!.put(path, sourceIndex) - sourceIndexToAbsoluteLocalPath!![sourceIndex] = path - val canonicalPath = file.canonicalPath - if (canonicalPath != null && canonicalPath != path) { - absoluteLocalPathToSourceIndex!!.put(canonicalPath, sourceIndex) - } - return Urls.newLocalFileUrl(path) - } - } - return UrlImpl(baseUrl.scheme, baseUrl.authority, path, null) + interface Resolver { + fun resolve(sourceFile: VirtualFile?, map: ObjectIntHashMap): Int } fun getSource(entry: MappingEntry): Url? { val index = entry.source - return if (index < 0) null else canonicalizedSources[index] + return if (index < 0) null else canonicalizedUrls[index] } fun getSourceContent(entry: MappingEntry): String? { @@ -101,30 +74,21 @@ open class SourceResolver(private val rawSources: List, trimFileScheme: return if (sourceIndex < 0 || sourceIndex >= sourceContents!!.size) null else sourceContents[sourceIndex] } - fun getSourceIndex(url: Url) = ArrayUtil.indexOf(canonicalizedSources, url) + fun getSourceIndex(url: Url) = ArrayUtil.indexOf(canonicalizedUrls, url) fun getRawSource(entry: MappingEntry): String? { val index = entry.source return if (index < 0) null else rawSources[index] } - fun getLocalFilePath(entry: MappingEntry): String? { - val index = entry.source - return if (index < 0 || sourceIndexToAbsoluteLocalPath == null) null else sourceIndexToAbsoluteLocalPath!![index] - } - - interface Resolver { - fun resolve(sourceFile: VirtualFile?, map: ObjectIntHashMap): Int - } - fun findMappings(sourceFile: VirtualFile?, sourceMap: SourceMap, resolver: Resolver): MappingList? { - val index = resolver.resolve(sourceFile, canonicalizedSourcesMap) + val index = resolver.resolve(sourceFile, canonicalizedUrlToSourceIndex) return if (index < 0) null else sourceMap.sourceIndexToMappings[index] } fun findMappings(sourceUrls: List, sourceMap: SourceMap, sourceFile: VirtualFile?): MappingList? { for (sourceUrl in sourceUrls) { - val index = canonicalizedSourcesMap.get(sourceUrl) + val index = canonicalizedUrlToSourceIndex.get(sourceUrl) if (index != -1) { return sourceMap.sourceIndexToMappings[index] } @@ -139,69 +103,81 @@ open class SourceResolver(private val rawSources: List, trimFileScheme: return null } - private fun findByFile(sourceMap: SourceMap, sourceFile: VirtualFile): MappingList? { - var mappings: MappingList? = null - if (absoluteLocalPathToSourceIndex != null && sourceFile.isInLocalFileSystem) { - mappings = getMappingsBySource(sourceMap, absoluteLocalPathToSourceIndex!!.get(sourceFile.path)) - if (mappings == null) { - val sourceFileCanonicalPath = sourceFile.canonicalPath - if (sourceFileCanonicalPath != null) { - mappings = getMappingsBySource(sourceMap, absoluteLocalPathToSourceIndex!!.get(sourceFileCanonicalPath)) - } - } + fun findByFile(sourceMap: SourceMap, sourceFile: VirtualFile): MappingList? { + var index = canonicalizedUrlToSourceIndex.get(Urls.newFromVirtualFile(sourceFile).trimParameters()) + if (index != -1) { + return sourceMap.sourceIndexToMappings[index] } - if (mappings == null) { - val index = canonicalizedSourcesMap.get(Urls.newFromVirtualFile(sourceFile).trimParameters()) + if (sourceFile.isInLocalFileSystem) { + // local file url - without "file" scheme, just path + index = canonicalizedUrlToSourceIndex.get(Urls.newLocalFileUrl(sourceFile)) if (index != -1) { return sourceMap.sourceIndexToMappings[index] } + } - for (i in canonicalizedSources.indices) { - val url = canonicalizedSources[i] - if (Urls.equalsIgnoreParameters(url, sourceFile)) { - return sourceMap.sourceIndexToMappings[i] - } - - val canonicalFile = sourceFile.canonicalFile - if (canonicalFile != null && canonicalFile != sourceFile && Urls.equalsIgnoreParameters(url, canonicalFile)) { + // ok, search by canonical path + val canonicalFile = sourceFile.canonicalFile + if (canonicalFile != null && canonicalFile != sourceFile) { + for (i in canonicalizedUrls.indices) { + val url = canonicalizedUrls[i] + if (Urls.equalsIgnoreParameters(url, canonicalFile)) { return sourceMap.sourceIndexToMappings[i] } } } - return mappings + return null } + fun getLocalFilePath(entry: MappingEntry) = canonicalizedUrls.getOrNull(entry.source)?.let { if (it.isInLocalFileSystem) it.path else null } + companion object { - fun isAbsolute(path: String): Boolean { - return !path.isEmpty() && (path[0] == '/' || (SystemInfo.isWindows && (path.length > 2 && path[1] == ':'))) - } - - fun canonicalizePath(url: String, baseUrl: Url, baseUrlIsFile: Boolean): String { - var path = url - if (url[0] != '/') { - val basePath = baseUrl.path - if (baseUrlIsFile) { - val lastSlashIndex = basePath.lastIndexOf('/') - val pathBuilder = StringBuilder() - if (lastSlashIndex == -1) { - pathBuilder.append('/') - } - else { - pathBuilder.append(basePath, 0, lastSlashIndex + 1) - } - path = pathBuilder.append(url).toString() - } - else { - path = "$basePath/$url" - } - } - path = FileUtil.toCanonicalPath(path, '/') - return path - } - - private fun getMappingsBySource(sourceMap: SourceMap, index: Int) = if (index == -1) null else sourceMap.sourceIndexToMappings[index] + fun isAbsolute(path: String) = path.firstOrNull() == '/' || (SystemInfo.isWindows && (path.length > 2 && path[1] == ':')) } } -private fun createStringIntMap(initialCapacity: Int) = if (SystemInfo.isFileSystemCaseSensitive) ObjectIntHashMap(initialCapacity) else ObjectIntHashMap(initialCapacity, CaseInsensitiveStringHashingStrategy.INSTANCE) \ No newline at end of file +fun canonicalizePath(url: String, baseUrl: Url, baseUrlIsFile: Boolean): String { + var path = url + if (url[0] != '/') { + val basePath = baseUrl.path + if (baseUrlIsFile) { + val lastSlashIndex = basePath.lastIndexOf('/') + val pathBuilder = StringBuilder() + if (lastSlashIndex == -1) { + pathBuilder.append('/') + } + else { + pathBuilder.append(basePath, 0, lastSlashIndex + 1) + } + path = pathBuilder.append(url).toString() + } + else { + path = "$basePath/$url" + } + } + return FileUtil.toCanonicalPath(path, '/') +} + +// see canonicalizeUri kotlin impl and https://trac.webkit.org/browser/trunk/Source/WebCore/inspector/front-end/ParsedURL.js completeURL +fun canonicalizeUrl(url: String, baseUrl: Url?, trimFileScheme: Boolean, baseUrlIsFile: Boolean = true): Url { + if (trimFileScheme && url.startsWith(StandardFileSystems.FILE_PROTOCOL_PREFIX)) { + return Urls.newLocalFileUrl(FileUtil.toCanonicalPath(VfsUtilCore.toIdeaUrl(url, true).substring(StandardFileSystems.FILE_PROTOCOL_PREFIX.length), '/')) + } + else if (baseUrl == null || url.contains(URLUtil.SCHEME_SEPARATOR) || url.startsWith("data:") || url.startsWith("blob:") || url.startsWith("javascript:")) { + return Urls.parseEncoded(url) ?: UrlImpl(url) + } + else { + return doCanonicalize(url, baseUrl, baseUrlIsFile, true) + } +} + +fun doCanonicalize(url: String, baseUrl: Url, baseUrlIsFile: Boolean, asLocalFileIfAbsoluteAndExists: Boolean): Url { + val path = canonicalizePath(url, baseUrl, baseUrlIsFile) + if ((baseUrl.scheme == null && baseUrl.isInLocalFileSystem) || (asLocalFileIfAbsoluteAndExists && SourceResolver.isAbsolute(path) && File(path).exists())) { + return Urls.newLocalFileUrl(path) + } + else { + return UrlImpl(baseUrl.scheme, baseUrl.authority, path, null) + } +} \ No newline at end of file diff --git a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/connection/RemoteVmConnection.kt b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/connection/RemoteVmConnection.kt index 40489768ec36..81a5efbd03f2 100644 --- a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/connection/RemoteVmConnection.kt +++ b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/connection/RemoteVmConnection.kt @@ -35,50 +35,48 @@ import java.net.InetSocketAddress import java.util.concurrent.atomic.AtomicReference abstract class RemoteVmConnection : VmConnection() { - private val connectCancelHandler = AtomicReference() + private val connectCancelHandler = AtomicReference<() -> Unit>() abstract fun createBootstrap(address: InetSocketAddress, vmResult: org.jetbrains.concurrency.AsyncPromise): Bootstrap @JvmOverloads fun open(address: InetSocketAddress, stopCondition: Condition? = null) { setState(ConnectionStatus.WAITING_FOR_CONNECTION, "Connecting to ${address.hostName}:${address.port}") - val future = ApplicationManager.getApplication().executeOnPooledThread(object : Runnable { - override fun run() { - if (Thread.interrupted()) { - return - } - - val result = org.jetbrains.concurrency.AsyncPromise() - connectCancelHandler.set(Runnable { result.setError("Closed explicitly") }) - - val connectionPromise = AsyncPromise() - connectionPromise.rejected { result.setError(it) } - - result - .done { - vm = it - setState(ConnectionStatus.CONNECTED, "Connected to ${connectedAddressToPresentation(address, it)}") - startProcessing() - } - .rejected { - if (it !is ConnectException) { - Promise.logError(LOG, it) - } - setState(ConnectionStatus.CONNECTION_FAILED, it.message) - } - .processed { connectCancelHandler.set(null) } - - createBootstrap(address, result).connect(address, connectionPromise, maxAttemptCount = if (stopCondition == null) NettyUtil.DEFAULT_CONNECT_ATTEMPT_COUNT else -1, stopCondition = stopCondition) + val future = ApplicationManager.getApplication().executeOnPooledThread(Runnable { + if (Thread.interrupted()) { + return@Runnable } + + val result = org.jetbrains.concurrency.AsyncPromise() + connectCancelHandler.set({ result.setError("Closed explicitly") }) + + val connectionPromise = AsyncPromise() + connectionPromise.rejected { result.setError(it) } + + result + .done { + vm = it + setState(ConnectionStatus.CONNECTED, "Connected to ${connectedAddressToPresentation(address, it)}") + startProcessing() + } + .rejected { + if (it !is ConnectException) { + Promise.logError(LOG, it) + } + setState(ConnectionStatus.CONNECTION_FAILED, it.message) + } + .processed { connectCancelHandler.set(null) } + + createBootstrap(address, result).connect(address, connectionPromise, maxAttemptCount = if (stopCondition == null) NettyUtil.DEFAULT_CONNECT_ATTEMPT_COUNT else -1, stopCondition = stopCondition) }) - connectCancelHandler.set(Runnable { future.cancel(true) }) + connectCancelHandler.set({ future.cancel(true) }) } - protected open fun connectedAddressToPresentation(address: InetSocketAddress, vm: Vm): String = address.hostName + ":" + address.port + protected open fun connectedAddressToPresentation(address: InetSocketAddress, vm: Vm): String = "${address.hostName}:${address.port}" override fun detachAndClose(): Promise<*> { try { - connectCancelHandler.getAndSet(null)?.run() + connectCancelHandler.getAndSet(null)?.invoke() } finally { return super.detachAndClose() @@ -86,7 +84,7 @@ abstract class RemoteVmConnection : VmConnection() { } } -fun chooseDebuggee(targets: Collection, selectedIndex: Int, itemToString: (T) -> String): org.jetbrains.concurrency.Promise { +fun chooseDebuggee(targets: Collection, selectedIndex: Int, itemToString: (T) -> String): Promise { if (targets.size == 1) { return resolvedPromise(targets.first()) }